diff options
Diffstat (limited to 'gold/i386.cc')
-rw-r--r-- | gold/i386.cc | 73 |
1 files changed, 70 insertions, 3 deletions
diff --git a/gold/i386.cc b/gold/i386.cc index 04a2fa9..c01b5f2 100644 --- a/gold/i386.cc +++ b/gold/i386.cc @@ -113,7 +113,8 @@ class Target_i386 : public Target_freebsd<32, false> bool needs_special_offset_handling, unsigned char* view, elfcpp::Elf_types<32>::Elf_Addr view_address, - section_size_type view_size); + section_size_type view_size, + const Reloc_symbol_changes*); // Scan the relocs during a relocatable link. void @@ -168,6 +169,13 @@ class Target_i386 : public Target_freebsd<32, false> return Target::do_is_local_label_name(name); } + // Adjust -fstack-split code which calls non-stack-split code. + void + do_calls_non_split(Relobj* object, unsigned int shndx, + section_offset_type fnoffset, section_size_type fnsize, + unsigned char* view, section_size_type view_size, + std::string* from, std::string* to) const; + // Return the size of the GOT section. section_size_type got_size() @@ -2465,7 +2473,8 @@ Target_i386::relocate_section(const Relocate_info<32, false>* relinfo, bool needs_special_offset_handling, unsigned char* view, elfcpp::Elf_types<32>::Elf_Addr address, - section_size_type view_size) + section_size_type view_size, + const Reloc_symbol_changes* reloc_symbol_changes) { gold_assert(sh_type == elfcpp::SHT_REL); @@ -2479,7 +2488,8 @@ Target_i386::relocate_section(const Relocate_info<32, false>* relinfo, needs_special_offset_handling, view, address, - view_size); + view_size, + reloc_symbol_changes); } // Return the size of a relocation while scanning during a relocatable @@ -2699,6 +2709,63 @@ Target_i386::do_code_fill(section_size_type length) const return std::string(nops[length], length); } +// FNOFFSET in section SHNDX in OBJECT is the start of a function +// compiled with -fstack-split. The function calls non-stack-split +// code. We have to change the function so that it always ensures +// that it has enough stack space to run some random function. + +void +Target_i386::do_calls_non_split(Relobj* object, unsigned int shndx, + section_offset_type fnoffset, + section_size_type fnsize, + unsigned char* view, + section_size_type view_size, + std::string* from, + std::string* to) const +{ + // The function starts with a comparison of the stack pointer and a + // field in the TCB. This is followed by a jump. + + // cmp %gs:NN,%esp + if (this->match_view(view, view_size, fnoffset, "\x65\x3b\x25", 3) + && fnsize > 7) + { + // We will call __morestack if the carry flag is set after this + // comparison. We turn the comparison into an stc instruction + // and some nops. + view[fnoffset] = '\xf9'; + this->set_view_to_nop(view, view_size, fnoffset + 1, 6); + } + // lea NN(%esp),%ecx + else if (this->match_view(view, view_size, fnoffset, "\x8d\x8c\x24", 3) + && fnsize > 7) + { + // This is loading an offset from the stack pointer for a + // comparison. The offset is negative, so we decrease the + // offset by the amount of space we need for the stack. This + // means we will avoid calling __morestack if there happens to + // be plenty of space on the stack already. + unsigned char* pval = view + fnoffset + 3; + uint32_t val = elfcpp::Swap_unaligned<32, false>::readval(pval); + val -= parameters->options().split_stack_adjust_size(); + elfcpp::Swap_unaligned<32, false>::writeval(pval, val); + } + else + { + if (!object->has_no_split_stack()) + object->error(_("failed to match split-stack sequence at " + "section %u offset %0zx"), + shndx, fnoffset); + return; + } + + // We have to change the function so that it calls + // __morestack_non_split instead of __morestack. The former will + // allocate additional stack space. + *from = "__morestack"; + *to = "__morestack_non_split"; +} + // The selector for i386 object files. class Target_selector_i386 : public Target_selector_freebsd |