aboutsummaryrefslogtreecommitdiff
path: root/gold/i386.cc
diff options
context:
space:
mode:
Diffstat (limited to 'gold/i386.cc')
-rw-r--r--gold/i386.cc73
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