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
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()
public:
Relocate()
: skip_call_tls_get_addr_(false),
- local_dynamic_type_(LOCAL_DYNAMIC_NONE)
+ local_dynamic_type_(LOCAL_DYNAMIC_NONE), ldo_addrs_()
{ }
~Relocate()
unsigned char* view,
section_size_type view_size);
+ // Fix up LDO_32 relocations we've already seen.
+ void
+ fix_up_ldo(const Relocate_info<32, false>*);
+
// We need to keep track of which type of local dynamic relocation
// we have seen, so that we can optimize R_386_TLS_LDO_32 correctly.
enum Local_dynamic_type
// The type of local dynamic relocation we have seen in the section
// being relocated, if any.
Local_dynamic_type local_dynamic_type_;
+ // A list of LDO_32 offsets, in case we find LDM after LDO_32.
+ std::vector<unsigned char*> ldo_addrs_;
};
// A class which returns the size required for a relocation type,
Reloc_section*
rel_dyn_section(Layout*);
- // Return true if the symbol may need a COPY relocation.
- // References from an executable object to non-function symbols
- // defined in a dynamic object may need a COPY relocation.
- bool
- may_need_copy_reloc(Symbol* gsym)
- {
- return (!parameters->options().shared()
- && gsym->is_from_dynobj()
- && gsym->type() != elfcpp::STT_FUNC);
- }
-
// Add a potential copy relocation.
void
copy_reloc(Symbol_table* symtab, Layout* layout,
"/usr/lib/libc.so.1", // dynamic_linker
0x08048000, // default_text_segment_address
0x1000, // abi_pagesize (overridable by -z max-page-size)
- 0x1000 // common_pagesize (overridable by -z common-page-size)
+ 0x1000, // common_pagesize (overridable by -z common-page-size)
+ elfcpp::SHN_UNDEF, // small_common_shndx
+ elfcpp::SHN_UNDEF, // large_common_shndx
+ 0, // small_common_section_flags
+ 0 // large_common_section_flags
};
// Get the GOT section, creating it if necessary.
// Make a dynamic relocation if necessary.
if (gsym->needs_dynamic_reloc(Symbol::ABSOLUTE_REF))
{
- if (target->may_need_copy_reloc(gsym))
+ if (gsym->may_need_copy_reloc())
{
target->copy_reloc(symtab, layout, object,
data_shndx, output_section, gsym, reloc);
flags |= Symbol::FUNCTION_CALL;
if (gsym->needs_dynamic_reloc(flags))
{
- if (target->may_need_copy_reloc(gsym))
+ if (gsym->may_need_copy_reloc())
{
target->copy_reloc(symtab, layout, object,
data_shndx, output_section, gsym, reloc);
case elfcpp::R_386_TLS_GOTDESC: // Global-dynamic (from ~oliva url)
case elfcpp::R_386_TLS_DESC_CALL:
+ if (this->local_dynamic_type_ == LOCAL_DYNAMIC_NONE)
+ this->fix_up_ldo(relinfo);
this->local_dynamic_type_ = LOCAL_DYNAMIC_GNU;
if (optimized_type == tls::TLSOPT_TO_LE)
{
"TLS relocations"));
break;
}
+ else if (this->local_dynamic_type_ == LOCAL_DYNAMIC_NONE)
+ this->fix_up_ldo(relinfo);
this->local_dynamic_type_ = LOCAL_DYNAMIC_GNU;
if (optimized_type == tls::TLSOPT_TO_LE)
{
// This reloc can appear in debugging sections, in which case we
// won't see the TLS_LDM reloc. The local_dynamic_type field
// tells us this.
- if (optimized_type == tls::TLSOPT_TO_LE
- && this->local_dynamic_type_ != LOCAL_DYNAMIC_NONE)
+ if (optimized_type == tls::TLSOPT_TO_LE)
{
- gold_assert(tls_segment != NULL);
- value -= tls_segment->memsz();
+ if (this->local_dynamic_type_ != LOCAL_DYNAMIC_NONE)
+ {
+ gold_assert(tls_segment != NULL);
+ value -= tls_segment->memsz();
+ }
+ else
+ {
+ // We may see the LDM later.
+ this->ldo_addrs_.push_back(view);
+ }
}
Relocate_functions<32, false>::rel32(view, value);
break;
Relocate_functions<32, false>::rel32(view, value);
}
+// If we see an LDM reloc after we handled any LDO_32 relocs, fix up
+// the LDO_32 relocs.
+
+void
+Target_i386::Relocate::fix_up_ldo(const Relocate_info<32, false>* relinfo)
+{
+ if (this->ldo_addrs_.empty())
+ return;
+ Output_segment* tls_segment = relinfo->layout->tls_segment();
+ gold_assert(tls_segment != NULL);
+ elfcpp::Elf_types<32>::Elf_Addr value = - tls_segment->memsz();
+ for (std::vector<unsigned char*>::const_iterator p = this->ldo_addrs_.begin();
+ p != this->ldo_addrs_.end();
+ ++p)
+ Relocate_functions<32, false>::rel32(*p, value);
+ this->ldo_addrs_.clear();
+}
+
// Relocate section data.
void
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);
needs_special_offset_handling,
view,
address,
- view_size);
+ view_size,
+ reloc_symbol_changes);
}
// Return the size of a relocation while scanning during a relocatable
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