mirror of
https://github.com/darlinghq/darling-gdb.git
synced 2025-01-31 14:04:12 +00:00
PR gold/12372
* target.h (Target::plt_address_for_global): New function. (Target::plt_address_for_local): New function. (Target::plt_section_for_global): Remove. (Target::plt_section_for_local): Remove. (Target::do_plt_address_for_global): New virtual function. (Target::do_plt_address_for_local): New virtual function. (Target::do_plt_section_for_global): Remove. (Target::do_plt_section_for_local): Remove. (Target::register_global_plt_entry): Add Symbol_table and Layout parameters. * output.cc (Output_data_got::Got_entry::write): Use plt_address_for_global and plt_address_for_local. * layout.cc (Layout::add_target_dynamic_tags): Use size and address of output section. * i386.cc (class Output_data_plt_i386): Add irelative_rel_, got_irelative_, and irelative_count_ fields. Update declarations. (Output_data_plt_i386::has_irelative_section): New function. (Output_data_plt_i386::entry_count): Add irelative_count_. (Output_data_plt_i386::set_final_data_size): Likewise. (class Target_i386): Add got_irelative_ and rel_irelative_ fields. Update declarations. (Target_i386::Target_i386): Initialize new fields. (Target_i386::do_plt_address_for_global): New function replacing do_plt_section_for_global. (Target_i386::do_plt_address_for_local): New function replacing do_plt_section_for_local. (Target_i386::got_section): Create got_irelative_. (Target_i386::rel_irelative_section): New function. (Output_data_plt_i386::Output_data_plt_i386): Initialize new fields. Don't define __rel_iplt_{start,end}. (Output_data_plt_i386::add_entry): Add symtab and layout parameters. Change all callers. Use different PLT and GOT for IFUNC symbols. (Output_data_plt_i386::add_local_ifunc_entry): Add symtab and layout parameters. Change all callers. Use different PLT and GOT. (Output_data_plt_i386::rel_tls_desc): Fix formatting. (Output_data_plt_i386::rel_irelative): New function. (Output_data_plt_i386::address_for_global): New function. (Output_data_plt_i386::address_for_local): New function. (Output_data_plt_i386::do_write): Write out IRELATIVE area. Use IRELATIVE GOT when changing IFUNC GOT entries. (Target_i386::Scan::global): Use IRELATIVE GOT for IRELATIVE reloc. (Target_i386::do_finalize_sections): Create the __rel_iplt symbols if we didn't create an IRELATIVE GOT. (Target_i386::Relocate::relocate): Use plt_address_for_global and plt_address_for_local. (Target_i386::do_dynsym_value): Use plt_address_for_global. * x86_64.cc (class Output_data_plt_x86_64): Add irelative_rel_, got_irelative_, and irelative_count_ fields. Update declarations. (Output_data_plt_x86_64::Output_data_plt_x86_64) [both versions]: Initialize new fields. Remove symtab parameter. Change all callers. (Output_data_plt_x86_64::get_tlsdesc_plt_offset): Add irelative_count_. (Output_data_plt_x86_64::has_irelative_section): New function. (Output_data_plt_x86_64::entry_count): Add irelative_count_. (class Target_x86_64): Add got_irelative_ and rel_irelative_ fields. Update declarations. (Target_x86_64::Target_x86_64): Initialize new fields. (Target_x86_64::do_plt_address_for_global): New function replacing do_plt_section_for_global. (Target_x86_64::do_plt_address_for_local): New function replacing do_plt_section_for_local. (Target_x86_64::got_section): Create got_irelative_. (Target_x86_64::rela_irelative_section): New function. (Output_data_plt_x86_64::init): Remove symtab parameter. Change all callers. Don't create __rel_iplt_{start,end}. (Output_data_plt_x86_64::add_entry): Add symtab and layout parameters. Change all callers. Use different PLT and GOT for IFUNC symbols. (Output_data_plt_x86_64::add_local_ifunc_entry): Add symtab and layout parameters. Change all callers. Use different PLT and GOT. (Output_data_plt_x86_64::add_relocation): Add symtab and layout parameters. Change all callers. Use different PLT and GOT for IFUNC symbols. (Output_data_plt_x86_64::rela_tlsdesc): Fix formatting. (Output_data_plt_x86_64::rela_irelative): New function. (Output_data_plt_x86_64::address_for_global): New function. (Output_data_plt_x86_64::address_for_local): New function. (Output_data_plt_x86_64::set_final_data_size): Likewise. (Output_data_plt_x86_64::do_write): Write out IRELATIVE area. (Target_x86_64::init_got_plt_for_update): Create got_irelative_. (Target_x86_64::register_global_plt_entry): Add symtab and layout parameters. (Target_x86_64::Scan::global): Use IRELATIVE GOT for IRELATIVE reloc. (Target_x86_64::do_finalize_sections): Create the __rela_iplt symbols if we didn't create an IRELATIVE GOT. (Target_x86_64::Relocate::relocate): Use plt_address_for_global and plt_address_for_local. (Target_x86_64::do_dynsym_value): Use plt_address_for_global. * testsuite/ifuncvar1.c: New test file. * testsuite/ifuncvar2.c: New test file. * testsuite/ifuncvar3.c: New test file. * testsuite/Makefile.am (check_PROGRAMS): Add ifuncvar. (ifuncvar1_pic.o, ifuncvar2_pic.o, ifuncvar.so): New targets. (ifuncvar_SOURCES, ifuncvar_DEPENDENCIES): New variables. (ifuncvar_LDFLAGS, ifuncvar_LDADD): New variables. * testsuite/Makefile.in: Rebuild.
This commit is contained in:
parent
5e44ecb338
commit
67181c72fb
108
gold/ChangeLog
108
gold/ChangeLog
@ -1,3 +1,111 @@
|
||||
2011-07-08 Ian Lance Taylor <iant@google.com>
|
||||
|
||||
PR gold/12372
|
||||
* target.h (Target::plt_address_for_global): New function.
|
||||
(Target::plt_address_for_local): New function.
|
||||
(Target::plt_section_for_global): Remove.
|
||||
(Target::plt_section_for_local): Remove.
|
||||
(Target::do_plt_address_for_global): New virtual function.
|
||||
(Target::do_plt_address_for_local): New virtual function.
|
||||
(Target::do_plt_section_for_global): Remove.
|
||||
(Target::do_plt_section_for_local): Remove.
|
||||
(Target::register_global_plt_entry): Add Symbol_table and Layout
|
||||
parameters.
|
||||
* output.cc (Output_data_got::Got_entry::write): Use
|
||||
plt_address_for_global and plt_address_for_local.
|
||||
* layout.cc (Layout::add_target_dynamic_tags): Use size and
|
||||
address of output section.
|
||||
* i386.cc (class Output_data_plt_i386): Add irelative_rel_,
|
||||
got_irelative_, and irelative_count_ fields. Update
|
||||
declarations.
|
||||
(Output_data_plt_i386::has_irelative_section): New function.
|
||||
(Output_data_plt_i386::entry_count): Add irelative_count_.
|
||||
(Output_data_plt_i386::set_final_data_size): Likewise.
|
||||
(class Target_i386): Add got_irelative_ and rel_irelative_
|
||||
fields. Update declarations.
|
||||
(Target_i386::Target_i386): Initialize new fields.
|
||||
(Target_i386::do_plt_address_for_global): New function replacing
|
||||
do_plt_section_for_global.
|
||||
(Target_i386::do_plt_address_for_local): New function replacing
|
||||
do_plt_section_for_local.
|
||||
(Target_i386::got_section): Create got_irelative_.
|
||||
(Target_i386::rel_irelative_section): New function.
|
||||
(Output_data_plt_i386::Output_data_plt_i386): Initialize new
|
||||
fields. Don't define __rel_iplt_{start,end}.
|
||||
(Output_data_plt_i386::add_entry): Add symtab and layout
|
||||
parameters. Change all callers. Use different PLT and GOT for
|
||||
IFUNC symbols.
|
||||
(Output_data_plt_i386::add_local_ifunc_entry): Add symtab and
|
||||
layout parameters. Change all callers. Use different PLT and
|
||||
GOT.
|
||||
(Output_data_plt_i386::rel_tls_desc): Fix formatting.
|
||||
(Output_data_plt_i386::rel_irelative): New function.
|
||||
(Output_data_plt_i386::address_for_global): New function.
|
||||
(Output_data_plt_i386::address_for_local): New function.
|
||||
(Output_data_plt_i386::do_write): Write out IRELATIVE area. Use
|
||||
IRELATIVE GOT when changing IFUNC GOT entries.
|
||||
(Target_i386::Scan::global): Use IRELATIVE GOT for IRELATIVE
|
||||
reloc.
|
||||
(Target_i386::do_finalize_sections): Create the __rel_iplt symbols
|
||||
if we didn't create an IRELATIVE GOT.
|
||||
(Target_i386::Relocate::relocate): Use plt_address_for_global and
|
||||
plt_address_for_local.
|
||||
(Target_i386::do_dynsym_value): Use plt_address_for_global.
|
||||
* x86_64.cc (class Output_data_plt_x86_64): Add irelative_rel_,
|
||||
got_irelative_, and irelative_count_ fields. Update
|
||||
declarations.
|
||||
(Output_data_plt_x86_64::Output_data_plt_x86_64) [both versions]:
|
||||
Initialize new fields. Remove symtab parameter. Change all
|
||||
callers.
|
||||
(Output_data_plt_x86_64::get_tlsdesc_plt_offset): Add
|
||||
irelative_count_.
|
||||
(Output_data_plt_x86_64::has_irelative_section): New function.
|
||||
(Output_data_plt_x86_64::entry_count): Add irelative_count_.
|
||||
(class Target_x86_64): Add got_irelative_ and rel_irelative_
|
||||
fields. Update declarations.
|
||||
(Target_x86_64::Target_x86_64): Initialize new fields.
|
||||
(Target_x86_64::do_plt_address_for_global): New function replacing
|
||||
do_plt_section_for_global.
|
||||
(Target_x86_64::do_plt_address_for_local): New function replacing
|
||||
do_plt_section_for_local.
|
||||
(Target_x86_64::got_section): Create got_irelative_.
|
||||
(Target_x86_64::rela_irelative_section): New function.
|
||||
(Output_data_plt_x86_64::init): Remove symtab parameter. Change
|
||||
all callers. Don't create __rel_iplt_{start,end}.
|
||||
(Output_data_plt_x86_64::add_entry): Add symtab and layout
|
||||
parameters. Change all callers. Use different PLT and GOT for
|
||||
IFUNC symbols.
|
||||
(Output_data_plt_x86_64::add_local_ifunc_entry): Add symtab and
|
||||
layout parameters. Change all callers. Use different PLT and
|
||||
GOT.
|
||||
(Output_data_plt_x86_64::add_relocation): Add symtab and layout
|
||||
parameters. Change all callers. Use different PLT and GOT for
|
||||
IFUNC symbols.
|
||||
(Output_data_plt_x86_64::rela_tlsdesc): Fix formatting.
|
||||
(Output_data_plt_x86_64::rela_irelative): New function.
|
||||
(Output_data_plt_x86_64::address_for_global): New function.
|
||||
(Output_data_plt_x86_64::address_for_local): New function.
|
||||
(Output_data_plt_x86_64::set_final_data_size): Likewise.
|
||||
(Output_data_plt_x86_64::do_write): Write out IRELATIVE area.
|
||||
(Target_x86_64::init_got_plt_for_update): Create got_irelative_.
|
||||
(Target_x86_64::register_global_plt_entry): Add symtab and layout
|
||||
parameters.
|
||||
(Target_x86_64::Scan::global): Use IRELATIVE GOT for IRELATIVE
|
||||
reloc.
|
||||
(Target_x86_64::do_finalize_sections): Create the __rela_iplt
|
||||
symbols if we didn't create an IRELATIVE GOT.
|
||||
(Target_x86_64::Relocate::relocate): Use plt_address_for_global and
|
||||
plt_address_for_local.
|
||||
(Target_x86_64::do_dynsym_value): Use plt_address_for_global.
|
||||
* testsuite/ifuncvar1.c: New test file.
|
||||
* testsuite/ifuncvar2.c: New test file.
|
||||
* testsuite/ifuncvar3.c: New test file.
|
||||
* testsuite/Makefile.am (check_PROGRAMS): Add ifuncvar.
|
||||
(ifuncvar1_pic.o, ifuncvar2_pic.o, ifuncvar.so): New targets.
|
||||
(ifuncvar_SOURCES, ifuncvar_DEPENDENCIES): New variables.
|
||||
(ifuncvar_LDFLAGS, ifuncvar_LDADD): New variables.
|
||||
* testsuite/Makefile.in: Rebuild.
|
||||
|
||||
2011-07-07 Cary Coutant <ccoutant@google.com>
|
||||
|
||||
* testsuite/Makefile.am (two_file_test_1_v1_ndebug.o): New target.
|
||||
|
280
gold/i386.cc
280
gold/i386.cc
@ -53,15 +53,16 @@ class Output_data_plt_i386 : public Output_section_data
|
||||
public:
|
||||
typedef Output_data_reloc<elfcpp::SHT_REL, true, 32, false> Reloc_section;
|
||||
|
||||
Output_data_plt_i386(Symbol_table*, Layout*, Output_data_space*);
|
||||
Output_data_plt_i386(Layout*, Output_data_space*, Output_data_space*);
|
||||
|
||||
// Add an entry to the PLT.
|
||||
void
|
||||
add_entry(Symbol* gsym);
|
||||
add_entry(Symbol_table*, Layout*, Symbol* gsym);
|
||||
|
||||
// Add an entry to the PLT for a local STT_GNU_IFUNC symbol.
|
||||
unsigned int
|
||||
add_local_ifunc_entry(Sized_relobj_file<32, false>* relobj,
|
||||
add_local_ifunc_entry(Symbol_table*, Layout*,
|
||||
Sized_relobj_file<32, false>* relobj,
|
||||
unsigned int local_sym_index);
|
||||
|
||||
// Return the .rel.plt section data.
|
||||
@ -73,10 +74,19 @@ class Output_data_plt_i386 : public Output_section_data
|
||||
Reloc_section*
|
||||
rel_tls_desc(Layout*);
|
||||
|
||||
// Return where the IRELATIVE relocations should go.
|
||||
Reloc_section*
|
||||
rel_irelative(Symbol_table*, Layout*);
|
||||
|
||||
// Return whether we created a section for IRELATIVE relocations.
|
||||
bool
|
||||
has_irelative_section() const
|
||||
{ return this->irelative_rel_ != NULL; }
|
||||
|
||||
// Return the number of PLT entries.
|
||||
unsigned int
|
||||
entry_count() const
|
||||
{ return this->count_; }
|
||||
{ return this->count_ + this->irelative_count_; }
|
||||
|
||||
// Return the offset of the first non-reserved PLT entry.
|
||||
static unsigned int
|
||||
@ -88,6 +98,14 @@ class Output_data_plt_i386 : public Output_section_data
|
||||
get_plt_entry_size()
|
||||
{ return plt_entry_size; }
|
||||
|
||||
// Return the PLT address to use for a global symbol.
|
||||
uint64_t
|
||||
address_for_global(const Symbol*);
|
||||
|
||||
// Return the PLT address to use for a local symbol.
|
||||
uint64_t
|
||||
address_for_local(const Relobj*, unsigned int symndx);
|
||||
|
||||
protected:
|
||||
void
|
||||
do_adjust_output_section(Output_section* os);
|
||||
@ -122,7 +140,10 @@ class Output_data_plt_i386 : public Output_section_data
|
||||
// Set the final size.
|
||||
void
|
||||
set_final_data_size()
|
||||
{ this->set_data_size((this->count_ + 1) * plt_entry_size); }
|
||||
{
|
||||
this->set_data_size((this->count_ + this->irelative_count_ + 1)
|
||||
* plt_entry_size);
|
||||
}
|
||||
|
||||
// Write out the PLT data.
|
||||
void
|
||||
@ -150,10 +171,18 @@ class Output_data_plt_i386 : public Output_section_data
|
||||
// The TLS_DESC relocations, if necessary. These must follow the
|
||||
// regular PLT relocs.
|
||||
Reloc_section* tls_desc_rel_;
|
||||
// The IRELATIVE relocations, if necessary. These must follow the
|
||||
// regular relocatoins and the TLS_DESC relocations.
|
||||
Reloc_section* irelative_rel_;
|
||||
// The .got.plt section.
|
||||
Output_data_space* got_plt_;
|
||||
// The part of the .got.plt section used for IRELATIVE relocs.
|
||||
Output_data_space* got_irelative_;
|
||||
// The number of PLT entries.
|
||||
unsigned int count_;
|
||||
// Number of PLT entries with R_386_IRELATIVE relocs. These follow
|
||||
// the regular PLT entries.
|
||||
unsigned int irelative_count_;
|
||||
// Global STT_GNU_IFUNC symbols.
|
||||
std::vector<Global_ifunc> global_ifuncs_;
|
||||
// Local STT_GNU_IFUNC symbols.
|
||||
@ -172,9 +201,9 @@ class Target_i386 : public Sized_target<32, false>
|
||||
|
||||
Target_i386()
|
||||
: Sized_target<32, false>(&i386_info),
|
||||
got_(NULL), plt_(NULL), got_plt_(NULL), got_tlsdesc_(NULL),
|
||||
global_offset_table_(NULL), rel_dyn_(NULL),
|
||||
copy_relocs_(elfcpp::R_386_COPY), dynbss_(NULL),
|
||||
got_(NULL), plt_(NULL), got_plt_(NULL), got_irelative_(NULL),
|
||||
got_tlsdesc_(NULL), global_offset_table_(NULL), rel_dyn_(NULL),
|
||||
rel_irelative_(NULL), copy_relocs_(elfcpp::R_386_COPY), dynbss_(NULL),
|
||||
got_mod_index_offset_(-1U), tls_base_symbol_defined_(false)
|
||||
{ }
|
||||
|
||||
@ -281,14 +310,14 @@ class Target_i386 : public Sized_target<32, false>
|
||||
return Target::do_is_local_label_name(name);
|
||||
}
|
||||
|
||||
// Return the PLT section.
|
||||
Output_data*
|
||||
do_plt_section_for_global(const Symbol*) const
|
||||
{ return this->plt_section(); }
|
||||
// Return the PLT address to use for a global symbol.
|
||||
uint64_t
|
||||
do_plt_address_for_global(const Symbol* gsym) const
|
||||
{ return this->plt_section()->address_for_global(gsym); }
|
||||
|
||||
Output_data*
|
||||
do_plt_section_for_local(const Relobj*, unsigned int) const
|
||||
{ return this->plt_section(); }
|
||||
uint64_t
|
||||
do_plt_address_for_local(const Relobj* relobj, unsigned int symndx) const
|
||||
{ return this->plt_section()->address_for_local(relobj, symndx); }
|
||||
|
||||
// We can tell whether we take the address of a function.
|
||||
inline bool
|
||||
@ -589,6 +618,10 @@ class Target_i386 : public Sized_target<32, false>
|
||||
Reloc_section*
|
||||
rel_tls_desc_section(Layout*) const;
|
||||
|
||||
// Get the section to use for IRELATIVE relocations.
|
||||
Reloc_section*
|
||||
rel_irelative_section(Layout*);
|
||||
|
||||
// Add a potential copy relocation.
|
||||
void
|
||||
copy_reloc(Symbol_table* symtab, Layout* layout,
|
||||
@ -625,12 +658,16 @@ class Target_i386 : public Sized_target<32, false>
|
||||
Output_data_plt_i386* plt_;
|
||||
// The GOT PLT section.
|
||||
Output_data_space* got_plt_;
|
||||
// The GOT section for IRELATIVE relocations.
|
||||
Output_data_space* got_irelative_;
|
||||
// The GOT section for TLSDESC relocations.
|
||||
Output_data_got<32, false>* got_tlsdesc_;
|
||||
// The _GLOBAL_OFFSET_TABLE_ symbol.
|
||||
Symbol* global_offset_table_;
|
||||
// The dynamic reloc section.
|
||||
Reloc_section* rel_dyn_;
|
||||
// The section to use for IRELATIVE relocs.
|
||||
Reloc_section* rel_irelative_;
|
||||
// Relocs saved to avoid a COPY reloc.
|
||||
Copy_relocs<elfcpp::SHT_REL, 32, false> copy_relocs_;
|
||||
// Space for variables copied with a COPY reloc.
|
||||
@ -703,6 +740,15 @@ Target_i386::got_section(Symbol_table* symtab, Layout* layout)
|
||||
elfcpp::STV_HIDDEN, 0,
|
||||
false, false);
|
||||
|
||||
// If there are any IRELATIVE relocations, they get GOT entries
|
||||
// in .got.plt after the jump slot relocations.
|
||||
this->got_irelative_ = new Output_data_space(4, "** GOT IRELATIVE PLT");
|
||||
layout->add_output_section_data(".got.plt", elfcpp::SHT_PROGBITS,
|
||||
(elfcpp::SHF_ALLOC
|
||||
| elfcpp::SHF_WRITE),
|
||||
this->got_irelative_,
|
||||
ORDER_NON_RELRO_FIRST, false);
|
||||
|
||||
// If there are any TLSDESC relocations, they get GOT entries in
|
||||
// .got.plt after the jump slot entries.
|
||||
this->got_tlsdesc_ = new Output_data_got<32, false>();
|
||||
@ -732,39 +778,45 @@ Target_i386::rel_dyn_section(Layout* layout)
|
||||
return this->rel_dyn_;
|
||||
}
|
||||
|
||||
// Get the section to use for IRELATIVE relocs, creating it if
|
||||
// necessary. These go in .rel.dyn, but only after all other dynamic
|
||||
// relocations. They need to follow the other dynamic relocations so
|
||||
// that they can refer to global variables initialized by those
|
||||
// relocs.
|
||||
|
||||
Target_i386::Reloc_section*
|
||||
Target_i386::rel_irelative_section(Layout* layout)
|
||||
{
|
||||
if (this->rel_irelative_ == NULL)
|
||||
{
|
||||
// Make sure we have already create the dynamic reloc section.
|
||||
this->rel_dyn_section(layout);
|
||||
this->rel_irelative_ = new Reloc_section(false);
|
||||
layout->add_output_section_data(".rel.dyn", elfcpp::SHT_REL,
|
||||
elfcpp::SHF_ALLOC, this->rel_irelative_,
|
||||
ORDER_DYNAMIC_RELOCS, false);
|
||||
gold_assert(this->rel_dyn_->output_section()
|
||||
== this->rel_irelative_->output_section());
|
||||
}
|
||||
return this->rel_irelative_;
|
||||
}
|
||||
|
||||
// Create the PLT section. The ordinary .got section is an argument,
|
||||
// since we need to refer to the start. We also create our own .got
|
||||
// section just for PLT entries.
|
||||
|
||||
Output_data_plt_i386::Output_data_plt_i386(Symbol_table* symtab,
|
||||
Layout* layout,
|
||||
Output_data_space* got_plt)
|
||||
: Output_section_data(16), tls_desc_rel_(NULL), got_plt_(got_plt), count_(0),
|
||||
global_ifuncs_(), local_ifuncs_()
|
||||
Output_data_plt_i386::Output_data_plt_i386(Layout* layout,
|
||||
Output_data_space* got_plt,
|
||||
Output_data_space* got_irelative)
|
||||
: Output_section_data(16), tls_desc_rel_(NULL), irelative_rel_(NULL),
|
||||
got_plt_(got_plt), got_irelative_(got_irelative), count_(0),
|
||||
irelative_count_(0), global_ifuncs_(), local_ifuncs_()
|
||||
{
|
||||
this->rel_ = new Reloc_section(false);
|
||||
layout->add_output_section_data(".rel.plt", elfcpp::SHT_REL,
|
||||
elfcpp::SHF_ALLOC, this->rel_,
|
||||
ORDER_DYNAMIC_PLT_RELOCS, false);
|
||||
|
||||
if (parameters->doing_static_link())
|
||||
{
|
||||
// A statically linked executable will only have a .rel.plt
|
||||
// section to hold R_386_IRELATIVE relocs for STT_GNU_IFUNC
|
||||
// symbols. The library will use these symbols to locate the
|
||||
// IRELATIVE relocs at program startup time.
|
||||
symtab->define_in_output_data("__rel_iplt_start", NULL,
|
||||
Symbol_table::PREDEFINED,
|
||||
this->rel_, 0, 0, elfcpp::STT_NOTYPE,
|
||||
elfcpp::STB_GLOBAL, elfcpp::STV_HIDDEN,
|
||||
0, false, true);
|
||||
symtab->define_in_output_data("__rel_iplt_end", NULL,
|
||||
Symbol_table::PREDEFINED,
|
||||
this->rel_, 0, 0, elfcpp::STT_NOTYPE,
|
||||
elfcpp::STB_GLOBAL, elfcpp::STV_HIDDEN,
|
||||
0, true, true);
|
||||
}
|
||||
|
||||
// Add unwind information if requested.
|
||||
if (parameters->options().ld_generated_unwind_info())
|
||||
layout->add_eh_frame_for_plt(this, plt_eh_frame_cie, plt_eh_frame_cie_size,
|
||||
@ -782,29 +834,23 @@ Output_data_plt_i386::do_adjust_output_section(Output_section* os)
|
||||
// Add an entry to the PLT.
|
||||
|
||||
void
|
||||
Output_data_plt_i386::add_entry(Symbol* gsym)
|
||||
Output_data_plt_i386::add_entry(Symbol_table* symtab, Layout* layout,
|
||||
Symbol* gsym)
|
||||
{
|
||||
gold_assert(!gsym->has_plt_offset());
|
||||
|
||||
// Note that when setting the PLT offset we skip the initial
|
||||
// reserved PLT entry.
|
||||
gsym->set_plt_offset((this->count_ + 1) * plt_entry_size);
|
||||
|
||||
++this->count_;
|
||||
|
||||
section_offset_type got_offset = this->got_plt_->current_data_size();
|
||||
|
||||
// Every PLT entry needs a GOT entry which points back to the PLT
|
||||
// entry (this will be changed by the dynamic linker, normally
|
||||
// lazily when the function is called).
|
||||
this->got_plt_->set_current_data_size(got_offset + 4);
|
||||
|
||||
// Every PLT entry needs a reloc.
|
||||
if (gsym->type() == elfcpp::STT_GNU_IFUNC
|
||||
&& gsym->can_use_relative_reloc(false))
|
||||
{
|
||||
this->rel_->add_symbolless_global_addend(gsym, elfcpp::R_386_IRELATIVE,
|
||||
this->got_plt_, got_offset);
|
||||
gsym->set_plt_offset(this->irelative_count_ * plt_entry_size);
|
||||
++this->irelative_count_;
|
||||
section_offset_type got_offset =
|
||||
this->got_irelative_->current_data_size();
|
||||
this->got_irelative_->set_current_data_size(got_offset + 4);
|
||||
Reloc_section* rel = this->rel_irelative(symtab, layout);
|
||||
rel->add_symbolless_global_addend(gsym, elfcpp::R_386_IRELATIVE,
|
||||
this->got_irelative_, got_offset);
|
||||
struct Global_ifunc gi;
|
||||
gi.sym = gsym;
|
||||
gi.got_offset = got_offset;
|
||||
@ -812,6 +858,19 @@ Output_data_plt_i386::add_entry(Symbol* gsym)
|
||||
}
|
||||
else
|
||||
{
|
||||
// When setting the PLT offset we skip the initial reserved PLT
|
||||
// entry.
|
||||
gsym->set_plt_offset((this->count_ + 1) * plt_entry_size);
|
||||
|
||||
++this->count_;
|
||||
|
||||
section_offset_type got_offset = this->got_plt_->current_data_size();
|
||||
|
||||
// Every PLT entry needs a GOT entry which points back to the
|
||||
// PLT entry (this will be changed by the dynamic linker,
|
||||
// normally lazily when the function is called).
|
||||
this->got_plt_->set_current_data_size(got_offset + 4);
|
||||
|
||||
gsym->set_needs_dynsym_entry();
|
||||
this->rel_->add_global(gsym, elfcpp::R_386_JUMP_SLOT, this->got_plt_,
|
||||
got_offset);
|
||||
@ -827,22 +886,25 @@ Output_data_plt_i386::add_entry(Symbol* gsym)
|
||||
|
||||
unsigned int
|
||||
Output_data_plt_i386::add_local_ifunc_entry(
|
||||
Symbol_table* symtab,
|
||||
Layout* layout,
|
||||
Sized_relobj_file<32, false>* relobj,
|
||||
unsigned int local_sym_index)
|
||||
{
|
||||
unsigned int plt_offset = (this->count_ + 1) * plt_entry_size;
|
||||
++this->count_;
|
||||
unsigned int plt_offset = this->irelative_count_ * plt_entry_size;
|
||||
++this->irelative_count_;
|
||||
|
||||
section_offset_type got_offset = this->got_plt_->current_data_size();
|
||||
section_offset_type got_offset = this->got_irelative_->current_data_size();
|
||||
|
||||
// Every PLT entry needs a GOT entry which points back to the PLT
|
||||
// entry.
|
||||
this->got_plt_->set_current_data_size(got_offset + 4);
|
||||
this->got_irelative_->set_current_data_size(got_offset + 4);
|
||||
|
||||
// Every PLT entry needs a reloc.
|
||||
this->rel_->add_symbolless_local_addend(relobj, local_sym_index,
|
||||
elfcpp::R_386_IRELATIVE,
|
||||
this->got_plt_, got_offset);
|
||||
Reloc_section* rel = this->rel_irelative(symtab, layout);
|
||||
rel->add_symbolless_local_addend(relobj, local_sym_index,
|
||||
elfcpp::R_386_IRELATIVE,
|
||||
this->got_irelative_, got_offset);
|
||||
|
||||
struct Local_ifunc li;
|
||||
li.object = relobj;
|
||||
@ -865,12 +927,72 @@ Output_data_plt_i386::rel_tls_desc(Layout* layout)
|
||||
layout->add_output_section_data(".rel.plt", elfcpp::SHT_REL,
|
||||
elfcpp::SHF_ALLOC, this->tls_desc_rel_,
|
||||
ORDER_DYNAMIC_PLT_RELOCS, false);
|
||||
gold_assert(this->tls_desc_rel_->output_section() ==
|
||||
this->rel_->output_section());
|
||||
gold_assert(this->tls_desc_rel_->output_section()
|
||||
== this->rel_->output_section());
|
||||
}
|
||||
return this->tls_desc_rel_;
|
||||
}
|
||||
|
||||
// Return where the IRELATIVE relocations should go in the PLT. These
|
||||
// follow the JUMP_SLOT and TLS_DESC relocations.
|
||||
|
||||
Output_data_plt_i386::Reloc_section*
|
||||
Output_data_plt_i386::rel_irelative(Symbol_table* symtab, Layout* layout)
|
||||
{
|
||||
if (this->irelative_rel_ == NULL)
|
||||
{
|
||||
// Make sure we have a place for the TLS_DESC relocations, in
|
||||
// case we see any later on.
|
||||
this->rel_tls_desc(layout);
|
||||
this->irelative_rel_ = new Reloc_section(false);
|
||||
layout->add_output_section_data(".rel.plt", elfcpp::SHT_REL,
|
||||
elfcpp::SHF_ALLOC, this->irelative_rel_,
|
||||
ORDER_DYNAMIC_PLT_RELOCS, false);
|
||||
gold_assert(this->irelative_rel_->output_section()
|
||||
== this->rel_->output_section());
|
||||
|
||||
if (parameters->doing_static_link())
|
||||
{
|
||||
// A statically linked executable will only have a .rel.plt
|
||||
// section to hold R_386_IRELATIVE relocs for STT_GNU_IFUNC
|
||||
// symbols. The library will use these symbols to locate
|
||||
// the IRELATIVE relocs at program startup time.
|
||||
symtab->define_in_output_data("__rel_iplt_start", NULL,
|
||||
Symbol_table::PREDEFINED,
|
||||
this->irelative_rel_, 0, 0,
|
||||
elfcpp::STT_NOTYPE, elfcpp::STB_GLOBAL,
|
||||
elfcpp::STV_HIDDEN, 0, false, true);
|
||||
symtab->define_in_output_data("__rel_iplt_end", NULL,
|
||||
Symbol_table::PREDEFINED,
|
||||
this->irelative_rel_, 0, 0,
|
||||
elfcpp::STT_NOTYPE, elfcpp::STB_GLOBAL,
|
||||
elfcpp::STV_HIDDEN, 0, true, true);
|
||||
}
|
||||
}
|
||||
return this->irelative_rel_;
|
||||
}
|
||||
|
||||
// Return the PLT address to use for a global symbol.
|
||||
|
||||
uint64_t
|
||||
Output_data_plt_i386::address_for_global(const Symbol* gsym)
|
||||
{
|
||||
uint64_t offset = 0;
|
||||
if (gsym->type() == elfcpp::STT_GNU_IFUNC
|
||||
&& gsym->can_use_relative_reloc(false))
|
||||
offset = (this->count_ + 1) * plt_entry_size;
|
||||
return this->address() + offset;
|
||||
}
|
||||
|
||||
// Return the PLT address to use for a local symbol. These are always
|
||||
// IRELATIVE relocs.
|
||||
|
||||
uint64_t
|
||||
Output_data_plt_i386::address_for_local(const Relobj*, unsigned int)
|
||||
{
|
||||
return this->address() + (this->count_ + 1) * plt_entry_size;
|
||||
}
|
||||
|
||||
// The first entry in the PLT for an executable.
|
||||
|
||||
const unsigned char Output_data_plt_i386::exec_first_plt_entry[plt_entry_size] =
|
||||
@ -976,8 +1098,12 @@ Output_data_plt_i386::do_write(Output_file* of)
|
||||
unsigned char* const oview = of->get_output_view(offset, oview_size);
|
||||
|
||||
const off_t got_file_offset = this->got_plt_->offset();
|
||||
gold_assert(parameters->incremental_update()
|
||||
|| (got_file_offset + this->got_plt_->data_size()
|
||||
== this->got_irelative_->offset()));
|
||||
const section_size_type got_size =
|
||||
convert_to_section_size_type(this->got_plt_->data_size());
|
||||
convert_to_section_size_type(this->got_plt_->data_size()
|
||||
+ this->got_irelative_->data_size());
|
||||
unsigned char* const got_view = of->get_output_view(got_file_offset,
|
||||
got_size);
|
||||
|
||||
@ -1006,7 +1132,7 @@ Output_data_plt_i386::do_write(Output_file* of)
|
||||
unsigned int plt_offset = plt_entry_size;
|
||||
unsigned int plt_rel_offset = 0;
|
||||
unsigned int got_offset = 12;
|
||||
const unsigned int count = this->count_;
|
||||
const unsigned int count = this->count_ + this->irelative_count_;
|
||||
for (unsigned int i = 0;
|
||||
i < count;
|
||||
++i,
|
||||
@ -1043,6 +1169,7 @@ Output_data_plt_i386::do_write(Output_file* of)
|
||||
// the GOT to point to the actual symbol value, rather than point to
|
||||
// the PLT entry. That will let the dynamic linker call the right
|
||||
// function when resolving IRELATIVE relocations.
|
||||
unsigned char* got_irelative_view = got_view + this->got_plt_->data_size();
|
||||
for (std::vector<Global_ifunc>::const_iterator p =
|
||||
this->global_ifuncs_.begin();
|
||||
p != this->global_ifuncs_.end();
|
||||
@ -1050,7 +1177,7 @@ Output_data_plt_i386::do_write(Output_file* of)
|
||||
{
|
||||
const Sized_symbol<32>* ssym =
|
||||
static_cast<const Sized_symbol<32>*>(p->sym);
|
||||
elfcpp::Swap<32, false>::writeval(got_view + p->got_offset,
|
||||
elfcpp::Swap<32, false>::writeval(got_irelative_view + p->got_offset,
|
||||
ssym->value());
|
||||
}
|
||||
|
||||
@ -1061,7 +1188,7 @@ Output_data_plt_i386::do_write(Output_file* of)
|
||||
{
|
||||
const Symbol_value<32>* psymval =
|
||||
p->object->local_symbol(p->local_sym_index);
|
||||
elfcpp::Swap<32, false>::writeval(got_view + p->got_offset,
|
||||
elfcpp::Swap<32, false>::writeval(got_irelative_view + p->got_offset,
|
||||
psymval->value(p->object, 0));
|
||||
}
|
||||
|
||||
@ -1082,7 +1209,8 @@ Target_i386::make_plt_section(Symbol_table* symtab, Layout* layout)
|
||||
// Create the GOT sections first.
|
||||
this->got_section(symtab, layout);
|
||||
|
||||
this->plt_ = new Output_data_plt_i386(symtab, layout, this->got_plt_);
|
||||
this->plt_ = new Output_data_plt_i386(layout, this->got_plt_,
|
||||
this->got_irelative_);
|
||||
layout->add_output_section_data(".plt", elfcpp::SHT_PROGBITS,
|
||||
(elfcpp::SHF_ALLOC
|
||||
| elfcpp::SHF_EXECINSTR),
|
||||
@ -1103,7 +1231,7 @@ Target_i386::make_plt_entry(Symbol_table* symtab, Layout* layout, Symbol* gsym)
|
||||
return;
|
||||
if (this->plt_ == NULL)
|
||||
this->make_plt_section(symtab, layout);
|
||||
this->plt_->add_entry(gsym);
|
||||
this->plt_->add_entry(symtab, layout, gsym);
|
||||
}
|
||||
|
||||
// Make a PLT entry for a local STT_GNU_IFUNC symbol.
|
||||
@ -1117,7 +1245,8 @@ Target_i386::make_local_ifunc_plt_entry(Symbol_table* symtab, Layout* layout,
|
||||
return;
|
||||
if (this->plt_ == NULL)
|
||||
this->make_plt_section(symtab, layout);
|
||||
unsigned int plt_offset = this->plt_->add_local_ifunc_entry(relobj,
|
||||
unsigned int plt_offset = this->plt_->add_local_ifunc_entry(symtab, layout,
|
||||
relobj,
|
||||
local_sym_index);
|
||||
relobj->set_local_plt_offset(local_sym_index, plt_offset);
|
||||
}
|
||||
@ -1779,7 +1908,7 @@ Target_i386::Scan::global(Symbol_table* symtab,
|
||||
// STT_GNU_IFUNC symbol. This makes a function
|
||||
// address in a PIE executable match the address in a
|
||||
// shared library that it links against.
|
||||
Reloc_section* rel_dyn = target->rel_dyn_section(layout);
|
||||
Reloc_section* rel_dyn = target->rel_irelative_section(layout);
|
||||
rel_dyn->add_symbolless_global_addend(gsym,
|
||||
elfcpp::R_386_IRELATIVE,
|
||||
output_section,
|
||||
@ -2182,7 +2311,8 @@ Target_i386::do_finalize_sections(
|
||||
symtab->get_sized_symbol<32>(sym)->set_symsize(data_size);
|
||||
}
|
||||
|
||||
if (parameters->doing_static_link() && this->plt_ == NULL)
|
||||
if (parameters->doing_static_link()
|
||||
&& (this->plt_ == NULL || !this->plt_->has_irelative_section()))
|
||||
{
|
||||
// If linking statically, make sure that the __rel_iplt symbols
|
||||
// were defined if necessary, even if we didn't create a PLT.
|
||||
@ -2312,7 +2442,7 @@ Target_i386::Relocate::relocate(const Relocate_info<32, false>* relinfo,
|
||||
else if (gsym != NULL
|
||||
&& gsym->use_plt_offset(Scan::get_reference_flags(r_type)))
|
||||
{
|
||||
symval.set_output_value(target->plt_section()->address()
|
||||
symval.set_output_value(target->plt_address_for_global(gsym)
|
||||
+ gsym->plt_offset());
|
||||
psymval = &symval;
|
||||
}
|
||||
@ -2321,7 +2451,7 @@ Target_i386::Relocate::relocate(const Relocate_info<32, false>* relinfo,
|
||||
unsigned int r_sym = elfcpp::elf_r_sym<32>(rel.get_r_info());
|
||||
if (object->local_has_plt_offset(r_sym))
|
||||
{
|
||||
symval.set_output_value(target->plt_section()->address()
|
||||
symval.set_output_value(target->plt_address_for_local(object, r_sym)
|
||||
+ object->local_plt_offset(r_sym));
|
||||
psymval = &symval;
|
||||
}
|
||||
@ -3245,7 +3375,7 @@ uint64_t
|
||||
Target_i386::do_dynsym_value(const Symbol* gsym) const
|
||||
{
|
||||
gold_assert(gsym->is_from_dynobj() && gsym->has_plt_offset());
|
||||
return this->plt_section()->address() + gsym->plt_offset();
|
||||
return this->plt_address_for_global(gsym) + gsym->plt_offset();
|
||||
}
|
||||
|
||||
// Return a string used to fill a code section with nops to take up
|
||||
|
@ -1,6 +1,6 @@
|
||||
// inremental.cc -- incremental linking support for gold
|
||||
|
||||
// Copyright 2009, 2010 Free Software Foundation, Inc.
|
||||
// Copyright 2009, 2010, 2011 Free Software Foundation, Inc.
|
||||
// Written by Mikolaj Zalewski <mikolajz@google.com>.
|
||||
|
||||
// This file is part of gold.
|
||||
@ -674,7 +674,7 @@ Sized_incremental_binary<size, big_endian>::do_process_got_plt(
|
||||
gold_debug(DEBUG_INCREMENTAL,
|
||||
"PLT entry %d: %s",
|
||||
i, sym->name());
|
||||
target->register_global_plt_entry(i, sym);
|
||||
target->register_global_plt_entry(symtab, layout, i, sym);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -4027,7 +4027,8 @@ Layout::create_interp(const Target* target)
|
||||
// some targets have multiple reloc sections in PLT_REL.
|
||||
|
||||
// If DYN_REL is not NULL, it is used for DT_REL/DT_RELA,
|
||||
// DT_RELSZ/DT_RELASZ, DT_RELENT/DT_RELAENT.
|
||||
// DT_RELSZ/DT_RELASZ, DT_RELENT/DT_RELAENT. Again we use the output
|
||||
// section.
|
||||
|
||||
// If ADD_DEBUG is true, we add a DT_DEBUG entry when generating an
|
||||
// executable.
|
||||
@ -4056,13 +4057,16 @@ Layout::add_target_dynamic_tags(bool use_rel, const Output_data* plt_got,
|
||||
if (dyn_rel != NULL && dyn_rel->output_section() != NULL)
|
||||
{
|
||||
odyn->add_section_address(use_rel ? elfcpp::DT_REL : elfcpp::DT_RELA,
|
||||
dyn_rel);
|
||||
if (plt_rel != NULL && dynrel_includes_plt)
|
||||
dyn_rel->output_section());
|
||||
if (plt_rel != NULL
|
||||
&& plt_rel->output_section() != NULL
|
||||
&& dynrel_includes_plt)
|
||||
odyn->add_section_size(use_rel ? elfcpp::DT_RELSZ : elfcpp::DT_RELASZ,
|
||||
dyn_rel, plt_rel);
|
||||
dyn_rel->output_section(),
|
||||
plt_rel->output_section());
|
||||
else
|
||||
odyn->add_section_size(use_rel ? elfcpp::DT_RELSZ : elfcpp::DT_RELASZ,
|
||||
dyn_rel);
|
||||
dyn_rel->output_section());
|
||||
const int size = parameters->target().get_size();
|
||||
elfcpp::DT rel_tag;
|
||||
int rel_size;
|
||||
|
@ -1347,7 +1347,7 @@ Output_data_got<size, big_endian>::Got_entry::write(unsigned char* pov) const
|
||||
// RELATIVE relocation.
|
||||
Symbol* gsym = this->u_.gsym;
|
||||
if (this->use_plt_offset_ && gsym->has_plt_offset())
|
||||
val = (parameters->target().plt_section_for_global(gsym)->address()
|
||||
val = (parameters->target().plt_address_for_global(gsym)
|
||||
+ gsym->plt_offset());
|
||||
else
|
||||
{
|
||||
@ -1381,9 +1381,9 @@ Output_data_got<size, big_endian>::Got_entry::write(unsigned char* pov) const
|
||||
val = symval->value(this->u_.object, 0);
|
||||
else
|
||||
{
|
||||
const Output_data* plt =
|
||||
parameters->target().plt_section_for_local(object, lsi);
|
||||
val = plt->address() + object->local_plt_offset(lsi);
|
||||
uint64_t plt_address =
|
||||
parameters->target().plt_address_for_local(object, lsi);
|
||||
val = plt_address + object->local_plt_offset(lsi);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
@ -246,17 +246,19 @@ class Target
|
||||
reloc_addend(void* arg, unsigned int type, uint64_t addend) const
|
||||
{ return this->do_reloc_addend(arg, type, addend); }
|
||||
|
||||
// Return the PLT section to use for a global symbol. This is used
|
||||
// for STT_GNU_IFUNC symbols.
|
||||
Output_data*
|
||||
plt_section_for_global(const Symbol* sym) const
|
||||
{ return this->do_plt_section_for_global(sym); }
|
||||
// Return the PLT address to use for a global symbol. This is used
|
||||
// for STT_GNU_IFUNC symbols. The symbol's plt_offset is relative
|
||||
// to this PLT address.
|
||||
uint64_t
|
||||
plt_address_for_global(const Symbol* sym) const
|
||||
{ return this->do_plt_address_for_global(sym); }
|
||||
|
||||
// Return the PLT section to use for a local symbol. This is used
|
||||
// for STT_GNU_IFUNC symbols.
|
||||
Output_data*
|
||||
plt_section_for_local(const Relobj* object, unsigned int symndx) const
|
||||
{ return this->do_plt_section_for_local(object, symndx); }
|
||||
// Return the PLT address to use for a local symbol. This is used
|
||||
// for STT_GNU_IFUNC symbols. The symbol's plt_offset is relative
|
||||
// to this PLT address.
|
||||
uint64_t
|
||||
plt_address_for_local(const Relobj* object, unsigned int symndx) const
|
||||
{ return this->do_plt_address_for_local(object, symndx); }
|
||||
|
||||
// Return whether this target can use relocation types to determine
|
||||
// if a function's address is taken.
|
||||
@ -502,12 +504,12 @@ class Target
|
||||
|
||||
// Virtual functions that must be overridden by a target that uses
|
||||
// STT_GNU_IFUNC symbols.
|
||||
virtual Output_data*
|
||||
do_plt_section_for_global(const Symbol*) const
|
||||
virtual uint64_t
|
||||
do_plt_address_for_global(const Symbol*) const
|
||||
{ gold_unreachable(); }
|
||||
|
||||
virtual Output_data*
|
||||
do_plt_section_for_local(const Relobj*, unsigned int) const
|
||||
virtual uint64_t
|
||||
do_plt_address_for_local(const Relobj*, unsigned int) const
|
||||
{ gold_unreachable(); }
|
||||
|
||||
// Virtual function which may be overriden by the child class.
|
||||
@ -870,7 +872,8 @@ class Sized_target : public Target
|
||||
// A target needs to implement this to support incremental linking.
|
||||
|
||||
virtual void
|
||||
register_global_plt_entry(unsigned int /* plt_index */,
|
||||
register_global_plt_entry(Symbol_table*, Layout*,
|
||||
unsigned int /* plt_index */,
|
||||
Symbol*)
|
||||
{ gold_unreachable(); }
|
||||
|
||||
|
@ -1833,6 +1833,18 @@ check_PROGRAMS += ifuncmain7pie
|
||||
ifuncmain7pie: ifuncmain7pie.o gcctestdir/ld
|
||||
$(LINK) -Bgcctestdir/ -pie ifuncmain7pie.o
|
||||
|
||||
check_PROGRAMS += ifuncvar
|
||||
ifuncvar1_pic.o: ifuncvar1.c
|
||||
$(COMPILE) -c -fpic -o $@ $<
|
||||
ifuncvar2_pic.o: ifuncvar2.c
|
||||
$(COMPILE) -c -fpic -o $@ $<
|
||||
ifuncvar.so: ifuncvar1_pic.o ifuncvar2_pic.o gcctestdir/ld
|
||||
$(LINK) -Bgcctestdir/ -shared ifuncvar1_pic.o ifuncvar2_pic.o
|
||||
ifuncvar_SOURCES = ifuncvar3.c
|
||||
ifuncvar_DEPENDENCIES = gcctestdir/ld ifuncvar.so
|
||||
ifuncvar_LDFLAGS = -Bgcctestdir/ -Wl,-R,.
|
||||
ifuncvar_LDADD = ifuncvar.so
|
||||
|
||||
endif IFUNC
|
||||
|
||||
# Test that strong reference to a weak symbol in a DSO remains strong.
|
||||
|
@ -442,7 +442,8 @@ check_PROGRAMS = $(am__EXEEXT_1) $(am__EXEEXT_2) $(am__EXEEXT_3) \
|
||||
@NATIVE_LINKER_FALSE@ifuncmain7static_DEPENDENCIES =
|
||||
@GCC_TRUE@@IFUNC_TRUE@@NATIVE_LINKER_TRUE@am__append_52 = ifuncmain7 \
|
||||
@GCC_TRUE@@IFUNC_TRUE@@NATIVE_LINKER_TRUE@ ifuncmain7pic \
|
||||
@GCC_TRUE@@IFUNC_TRUE@@NATIVE_LINKER_TRUE@ ifuncmain7pie
|
||||
@GCC_TRUE@@IFUNC_TRUE@@NATIVE_LINKER_TRUE@ ifuncmain7pie \
|
||||
@GCC_TRUE@@IFUNC_TRUE@@NATIVE_LINKER_TRUE@ ifuncvar
|
||||
@GCC_FALSE@ifuncmain7_DEPENDENCIES =
|
||||
@IFUNC_FALSE@ifuncmain7_DEPENDENCIES =
|
||||
@NATIVE_LINKER_FALSE@ifuncmain7_DEPENDENCIES =
|
||||
@ -722,7 +723,8 @@ libgoldtest_a_OBJECTS = $(am_libgoldtest_a_OBJECTS)
|
||||
@GCC_TRUE@@IFUNC_TRUE@@NATIVE_LINKER_TRUE@am__EXEEXT_36 = \
|
||||
@GCC_TRUE@@IFUNC_TRUE@@NATIVE_LINKER_TRUE@ ifuncmain7$(EXEEXT) \
|
||||
@GCC_TRUE@@IFUNC_TRUE@@NATIVE_LINKER_TRUE@ ifuncmain7pic$(EXEEXT) \
|
||||
@GCC_TRUE@@IFUNC_TRUE@@NATIVE_LINKER_TRUE@ ifuncmain7pie$(EXEEXT)
|
||||
@GCC_TRUE@@IFUNC_TRUE@@NATIVE_LINKER_TRUE@ ifuncmain7pie$(EXEEXT) \
|
||||
@GCC_TRUE@@IFUNC_TRUE@@NATIVE_LINKER_TRUE@ ifuncvar$(EXEEXT)
|
||||
@GCC_TRUE@@NATIVE_LINKER_TRUE@am__EXEEXT_37 = start_lib_test$(EXEEXT)
|
||||
@DEFAULT_TARGET_X86_64_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@am__EXEEXT_38 = incremental_test_2$(EXEEXT) \
|
||||
@DEFAULT_TARGET_X86_64_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@ incremental_test_3$(EXEEXT) \
|
||||
@ -1053,6 +1055,11 @@ ifuncmain7pie_DEPENDENCIES = libgoldtest.a ../libgold.a \
|
||||
ifuncmain7static_OBJECTS = $(am_ifuncmain7static_OBJECTS)
|
||||
ifuncmain7static_LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
|
||||
$(ifuncmain7static_LDFLAGS) $(LDFLAGS) -o $@
|
||||
@GCC_TRUE@@IFUNC_TRUE@@NATIVE_LINKER_TRUE@am_ifuncvar_OBJECTS = \
|
||||
@GCC_TRUE@@IFUNC_TRUE@@NATIVE_LINKER_TRUE@ ifuncvar3.$(OBJEXT)
|
||||
ifuncvar_OBJECTS = $(am_ifuncvar_OBJECTS)
|
||||
ifuncvar_LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(ifuncvar_LDFLAGS) \
|
||||
$(LDFLAGS) -o $@
|
||||
incremental_common_test_1_SOURCES = incremental_common_test_1.c
|
||||
incremental_common_test_1_OBJECTS = \
|
||||
incremental_common_test_1.$(OBJEXT)
|
||||
@ -1594,17 +1601,17 @@ SOURCES = $(libgoldtest_a_SOURCES) basic_pic_test.c basic_pie_test.c \
|
||||
$(ifuncmain5static_SOURCES) ifuncmain5staticpic.c \
|
||||
ifuncmain6pie.c $(ifuncmain7_SOURCES) ifuncmain7pic.c \
|
||||
ifuncmain7picstatic.c ifuncmain7pie.c \
|
||||
$(ifuncmain7static_SOURCES) incremental_common_test_1.c \
|
||||
incremental_copy_test.c incremental_test_2.c \
|
||||
incremental_test_3.c incremental_test_4.c incremental_test_5.c \
|
||||
incremental_test_6.c $(initpri1_SOURCES) $(initpri2_SOURCES) \
|
||||
$(initpri3a_SOURCES) $(initpri3b_SOURCES) $(justsyms_SOURCES) \
|
||||
$(large_SOURCES) local_labels_test.c many_sections_r_test.c \
|
||||
$(many_sections_test_SOURCES) $(object_unittest_SOURCES) \
|
||||
permission_test.c plugin_test_1.c plugin_test_2.c \
|
||||
plugin_test_3.c plugin_test_4.c plugin_test_5.c \
|
||||
plugin_test_6.c plugin_test_7.c plugin_test_8.c \
|
||||
$(protected_1_SOURCES) $(protected_2_SOURCES) \
|
||||
$(ifuncmain7static_SOURCES) $(ifuncvar_SOURCES) \
|
||||
incremental_common_test_1.c incremental_copy_test.c \
|
||||
incremental_test_2.c incremental_test_3.c incremental_test_4.c \
|
||||
incremental_test_5.c incremental_test_6.c $(initpri1_SOURCES) \
|
||||
$(initpri2_SOURCES) $(initpri3a_SOURCES) $(initpri3b_SOURCES) \
|
||||
$(justsyms_SOURCES) $(large_SOURCES) local_labels_test.c \
|
||||
many_sections_r_test.c $(many_sections_test_SOURCES) \
|
||||
$(object_unittest_SOURCES) permission_test.c plugin_test_1.c \
|
||||
plugin_test_2.c plugin_test_3.c plugin_test_4.c \
|
||||
plugin_test_5.c plugin_test_6.c plugin_test_7.c \
|
||||
plugin_test_8.c $(protected_1_SOURCES) $(protected_2_SOURCES) \
|
||||
$(relro_script_test_SOURCES) $(relro_strip_test_SOURCES) \
|
||||
$(relro_test_SOURCES) $(script_test_1_SOURCES) \
|
||||
$(script_test_2_SOURCES) script_test_3.c \
|
||||
@ -2334,6 +2341,10 @@ LDADD = libgoldtest.a ../libgold.a ../../libiberty/libiberty.a $(LIBINTL) \
|
||||
@GCC_TRUE@@IFUNC_TRUE@@NATIVE_LINKER_TRUE@ifuncmain7_DEPENDENCIES = gcctestdir/ld
|
||||
@GCC_TRUE@@IFUNC_TRUE@@NATIVE_LINKER_TRUE@ifuncmain7_LDFLAGS = -Bgcctestdir/
|
||||
@GCC_TRUE@@IFUNC_TRUE@@NATIVE_LINKER_TRUE@ifuncmain7_LDADD =
|
||||
@GCC_TRUE@@IFUNC_TRUE@@NATIVE_LINKER_TRUE@ifuncvar_SOURCES = ifuncvar3.c
|
||||
@GCC_TRUE@@IFUNC_TRUE@@NATIVE_LINKER_TRUE@ifuncvar_DEPENDENCIES = gcctestdir/ld ifuncvar.so
|
||||
@GCC_TRUE@@IFUNC_TRUE@@NATIVE_LINKER_TRUE@ifuncvar_LDFLAGS = -Bgcctestdir/ -Wl,-R,.
|
||||
@GCC_TRUE@@IFUNC_TRUE@@NATIVE_LINKER_TRUE@ifuncvar_LDADD = ifuncvar.so
|
||||
@DEFAULT_TARGET_I386_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@SPLIT_DEFSYMS = --defsym __morestack=0x100 --defsym __morestack_non_split=0x200
|
||||
@DEFAULT_TARGET_X86_64_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@SPLIT_DEFSYMS = --defsym __morestack=0x100 --defsym __morestack_non_split=0x200
|
||||
all: $(BUILT_SOURCES)
|
||||
@ -2708,6 +2719,9 @@ ifuncmain7$(EXEEXT): $(ifuncmain7_OBJECTS) $(ifuncmain7_DEPENDENCIES)
|
||||
ifuncmain7static$(EXEEXT): $(ifuncmain7static_OBJECTS) $(ifuncmain7static_DEPENDENCIES)
|
||||
@rm -f ifuncmain7static$(EXEEXT)
|
||||
$(ifuncmain7static_LINK) $(ifuncmain7static_OBJECTS) $(ifuncmain7static_LDADD) $(LIBS)
|
||||
ifuncvar$(EXEEXT): $(ifuncvar_OBJECTS) $(ifuncvar_DEPENDENCIES)
|
||||
@rm -f ifuncvar$(EXEEXT)
|
||||
$(ifuncvar_LINK) $(ifuncvar_OBJECTS) $(ifuncvar_LDADD) $(LIBS)
|
||||
@DEFAULT_TARGET_X86_64_FALSE@incremental_common_test_1$(EXEEXT): $(incremental_common_test_1_OBJECTS) $(incremental_common_test_1_DEPENDENCIES)
|
||||
@DEFAULT_TARGET_X86_64_FALSE@ @rm -f incremental_common_test_1$(EXEEXT)
|
||||
@DEFAULT_TARGET_X86_64_FALSE@ $(LINK) $(incremental_common_test_1_OBJECTS) $(incremental_common_test_1_LDADD) $(LIBS)
|
||||
@ -3150,6 +3164,7 @@ distclean-compile:
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ifuncmain7pic.Po@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ifuncmain7picstatic.Po@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ifuncmain7pie.Po@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ifuncvar3.Po@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/incremental_common_test_1.Po@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/incremental_copy_test.Po@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/incremental_test_2.Po@am__quote@
|
||||
@ -3839,6 +3854,8 @@ ifuncmain7pic.log: ifuncmain7pic$(EXEEXT)
|
||||
@p='ifuncmain7pic$(EXEEXT)'; $(am__check_pre) $(LOG_COMPILE) "$$tst" $(am__check_post)
|
||||
ifuncmain7pie.log: ifuncmain7pie$(EXEEXT)
|
||||
@p='ifuncmain7pie$(EXEEXT)'; $(am__check_pre) $(LOG_COMPILE) "$$tst" $(am__check_post)
|
||||
ifuncvar.log: ifuncvar$(EXEEXT)
|
||||
@p='ifuncvar$(EXEEXT)'; $(am__check_pre) $(LOG_COMPILE) "$$tst" $(am__check_post)
|
||||
start_lib_test.log: start_lib_test$(EXEEXT)
|
||||
@p='start_lib_test$(EXEEXT)'; $(am__check_pre) $(LOG_COMPILE) "$$tst" $(am__check_post)
|
||||
incremental_test_2.log: incremental_test_2$(EXEEXT)
|
||||
@ -4787,6 +4804,12 @@ uninstall-am:
|
||||
@GCC_TRUE@@IFUNC_TRUE@@NATIVE_LINKER_TRUE@ $(LINK) -Bgcctestdir/ ifuncmain7pic.o
|
||||
@GCC_TRUE@@IFUNC_TRUE@@NATIVE_LINKER_TRUE@ifuncmain7pie: ifuncmain7pie.o gcctestdir/ld
|
||||
@GCC_TRUE@@IFUNC_TRUE@@NATIVE_LINKER_TRUE@ $(LINK) -Bgcctestdir/ -pie ifuncmain7pie.o
|
||||
@GCC_TRUE@@IFUNC_TRUE@@NATIVE_LINKER_TRUE@ifuncvar1_pic.o: ifuncvar1.c
|
||||
@GCC_TRUE@@IFUNC_TRUE@@NATIVE_LINKER_TRUE@ $(COMPILE) -c -fpic -o $@ $<
|
||||
@GCC_TRUE@@IFUNC_TRUE@@NATIVE_LINKER_TRUE@ifuncvar2_pic.o: ifuncvar2.c
|
||||
@GCC_TRUE@@IFUNC_TRUE@@NATIVE_LINKER_TRUE@ $(COMPILE) -c -fpic -o $@ $<
|
||||
@GCC_TRUE@@IFUNC_TRUE@@NATIVE_LINKER_TRUE@ifuncvar.so: ifuncvar1_pic.o ifuncvar2_pic.o gcctestdir/ld
|
||||
@GCC_TRUE@@IFUNC_TRUE@@NATIVE_LINKER_TRUE@ $(LINK) -Bgcctestdir/ -shared ifuncvar1_pic.o ifuncvar2_pic.o
|
||||
@GCC_TRUE@@NATIVE_LINKER_TRUE@strong_ref_weak_def_2.o: strong_ref_weak_def_2.c
|
||||
@GCC_TRUE@@NATIVE_LINKER_TRUE@ $(COMPILE) -o $@ -c -fPIC $<
|
||||
@GCC_TRUE@@NATIVE_LINKER_TRUE@strong_ref_weak_def_2.so: strong_ref_weak_def_2.o gcctestdir/ld
|
||||
|
20
gold/testsuite/ifuncvar1.c
Normal file
20
gold/testsuite/ifuncvar1.c
Normal file
@ -0,0 +1,20 @@
|
||||
/* Test global variable initialized to hidden STT_GNU_IFUNC symbol. */
|
||||
|
||||
int didit;
|
||||
|
||||
extern void doit (void);
|
||||
|
||||
void
|
||||
doit (void)
|
||||
{
|
||||
didit = 1;
|
||||
}
|
||||
|
||||
void (*get_foo (void)) (void) __asm__ ("foo");
|
||||
__asm__ (".type foo, %gnu_indirect_function");
|
||||
__asm__ (".hidden foo");
|
||||
|
||||
void (*get_foo (void)) (void)
|
||||
{
|
||||
return &doit;
|
||||
}
|
12
gold/testsuite/ifuncvar2.c
Normal file
12
gold/testsuite/ifuncvar2.c
Normal file
@ -0,0 +1,12 @@
|
||||
/* Test global variable initialized to hidden STT_GNU_IFUNC symbol. */
|
||||
|
||||
extern void foo (void);
|
||||
void (*f) (void) = &foo;
|
||||
|
||||
extern void bar (void);
|
||||
|
||||
void
|
||||
bar (void)
|
||||
{
|
||||
f ();
|
||||
}
|
14
gold/testsuite/ifuncvar3.c
Normal file
14
gold/testsuite/ifuncvar3.c
Normal file
@ -0,0 +1,14 @@
|
||||
/* Test global variable initialized to hidden STT_GNU_IFUNC symbol. */
|
||||
|
||||
#include <assert.h>
|
||||
|
||||
extern void bar (void);
|
||||
extern int didit;
|
||||
|
||||
int
|
||||
main (void)
|
||||
{
|
||||
bar ();
|
||||
assert (didit == 1);
|
||||
return 0;
|
||||
}
|
336
gold/x86_64.cc
336
gold/x86_64.cc
@ -54,22 +54,24 @@ class Output_data_plt_x86_64 : public Output_section_data
|
||||
public:
|
||||
typedef Output_data_reloc<elfcpp::SHT_RELA, true, 64, false> Reloc_section;
|
||||
|
||||
Output_data_plt_x86_64(Symbol_table* symtab, Layout* layout,
|
||||
Output_data_got<64, false>* got,
|
||||
Output_data_space* got_plt)
|
||||
: Output_section_data(16), tlsdesc_rel_(NULL), got_(got), got_plt_(got_plt),
|
||||
count_(0), tlsdesc_got_offset_(-1U), free_list_()
|
||||
{ this->init(symtab, layout); }
|
||||
|
||||
Output_data_plt_x86_64(Symbol_table* symtab, Layout* layout,
|
||||
Output_data_got<64, false>* got,
|
||||
Output_data_plt_x86_64(Layout* layout, Output_data_got<64, false>* got,
|
||||
Output_data_space* got_plt,
|
||||
Output_data_space* got_irelative)
|
||||
: Output_section_data(16), tlsdesc_rel_(NULL), irelative_rel_(NULL),
|
||||
got_(got), got_plt_(got_plt), got_irelative_(got_irelative), count_(0),
|
||||
irelative_count_(0), tlsdesc_got_offset_(-1U), free_list_()
|
||||
{ this->init(layout); }
|
||||
|
||||
Output_data_plt_x86_64(Layout* layout, Output_data_got<64, false>* got,
|
||||
Output_data_space* got_plt,
|
||||
Output_data_space* got_irelative,
|
||||
unsigned int plt_count)
|
||||
: Output_section_data((plt_count + 1) * plt_entry_size, 16, false),
|
||||
tlsdesc_rel_(NULL), got_(got), got_plt_(got_plt),
|
||||
count_(plt_count), tlsdesc_got_offset_(-1U), free_list_()
|
||||
tlsdesc_rel_(NULL), irelative_rel_(NULL), got_(got), got_plt_(got_plt),
|
||||
got_irelative_(got_irelative), count_(plt_count), irelative_count_(0),
|
||||
tlsdesc_got_offset_(-1U), free_list_()
|
||||
{
|
||||
this->init(symtab, layout);
|
||||
this->init(layout);
|
||||
|
||||
// Initialize the free list and reserve the first entry.
|
||||
this->free_list_.init((plt_count + 1) * plt_entry_size, false);
|
||||
@ -78,20 +80,22 @@ class Output_data_plt_x86_64 : public Output_section_data
|
||||
|
||||
// Initialize the PLT section.
|
||||
void
|
||||
init(Symbol_table* symtab, Layout* layout);
|
||||
init(Layout* layout);
|
||||
|
||||
// Add an entry to the PLT.
|
||||
void
|
||||
add_entry(Symbol* gsym);
|
||||
add_entry(Symbol_table*, Layout*, Symbol* gsym);
|
||||
|
||||
// Add an entry to the PLT for a local STT_GNU_IFUNC symbol.
|
||||
unsigned int
|
||||
add_local_ifunc_entry(Sized_relobj_file<64, false>* relobj,
|
||||
add_local_ifunc_entry(Symbol_table* symtab, Layout*,
|
||||
Sized_relobj_file<64, false>* relobj,
|
||||
unsigned int local_sym_index);
|
||||
|
||||
// Add the relocation for a PLT entry.
|
||||
void
|
||||
add_relocation(Symbol* gsym, unsigned int got_offset);
|
||||
add_relocation(Symbol_table*, Layout*, Symbol* gsym,
|
||||
unsigned int got_offset);
|
||||
|
||||
// Add the reserved TLSDESC_PLT entry to the PLT.
|
||||
void
|
||||
@ -111,7 +115,7 @@ class Output_data_plt_x86_64 : public Output_section_data
|
||||
// Return the offset of the reserved TLSDESC_PLT entry.
|
||||
unsigned int
|
||||
get_tlsdesc_plt_offset() const
|
||||
{ return (this->count_ + 1) * plt_entry_size; }
|
||||
{ return (this->count_ + this->irelative_count_ + 1) * plt_entry_size; }
|
||||
|
||||
// Return the .rela.plt section data.
|
||||
Reloc_section*
|
||||
@ -122,10 +126,20 @@ class Output_data_plt_x86_64 : public Output_section_data
|
||||
Reloc_section*
|
||||
rela_tlsdesc(Layout*);
|
||||
|
||||
// Return where the IRELATIVE relocations should go in the PLT
|
||||
// relocations.
|
||||
Reloc_section*
|
||||
rela_irelative(Symbol_table*, Layout*);
|
||||
|
||||
// Return whether we created a section for IRELATIVE relocations.
|
||||
bool
|
||||
has_irelative_section() const
|
||||
{ return this->irelative_rel_ != NULL; }
|
||||
|
||||
// Return the number of PLT entries.
|
||||
unsigned int
|
||||
entry_count() const
|
||||
{ return this->count_; }
|
||||
{ return this->count_ + this->irelative_count_; }
|
||||
|
||||
// Return the offset of the first non-reserved PLT entry.
|
||||
static unsigned int
|
||||
@ -145,6 +159,14 @@ class Output_data_plt_x86_64 : public Output_section_data
|
||||
(plt_index + 2) * plt_entry_size);
|
||||
}
|
||||
|
||||
// Return the PLT address to use for a global symbol.
|
||||
uint64_t
|
||||
address_for_global(const Symbol*);
|
||||
|
||||
// Return the PLT address to use for a local symbol.
|
||||
uint64_t
|
||||
address_for_local(const Relobj*, unsigned int symndx);
|
||||
|
||||
protected:
|
||||
void
|
||||
do_adjust_output_section(Output_section* os);
|
||||
@ -188,12 +210,20 @@ class Output_data_plt_x86_64 : public Output_section_data
|
||||
// The TLSDESC relocs, if necessary. These must follow the regular
|
||||
// PLT relocs.
|
||||
Reloc_section* tlsdesc_rel_;
|
||||
// The IRELATIVE relocs, if necessary. These must follow the
|
||||
// regular PLT relocations and the TLSDESC relocations.
|
||||
Reloc_section* irelative_rel_;
|
||||
// The .got section.
|
||||
Output_data_got<64, false>* got_;
|
||||
// The .got.plt section.
|
||||
Output_data_space* got_plt_;
|
||||
// The part of the .got.plt section used for IRELATIVE relocs.
|
||||
Output_data_space* got_irelative_;
|
||||
// The number of PLT entries.
|
||||
unsigned int count_;
|
||||
// Number of PLT entries with R_X86_64_IRELATIVE relocs. These
|
||||
// follow the regular PLT entries.
|
||||
unsigned int irelative_count_;
|
||||
// Offset of the reserved TLSDESC_GOT entry when needed.
|
||||
unsigned int tlsdesc_got_offset_;
|
||||
// List of available regions within the section, for incremental
|
||||
@ -217,10 +247,10 @@ class Target_x86_64 : public Sized_target<64, false>
|
||||
|
||||
Target_x86_64()
|
||||
: Sized_target<64, false>(&x86_64_info),
|
||||
got_(NULL), plt_(NULL), got_plt_(NULL), got_tlsdesc_(NULL),
|
||||
global_offset_table_(NULL), rela_dyn_(NULL),
|
||||
copy_relocs_(elfcpp::R_X86_64_COPY), dynbss_(NULL),
|
||||
got_mod_index_offset_(-1U), tlsdesc_reloc_info_(),
|
||||
got_(NULL), plt_(NULL), got_plt_(NULL), got_irelative_(NULL),
|
||||
got_tlsdesc_(NULL), global_offset_table_(NULL), rela_dyn_(NULL),
|
||||
rela_irelative_(NULL), copy_relocs_(elfcpp::R_X86_64_COPY),
|
||||
dynbss_(NULL), got_mod_index_offset_(-1U), tlsdesc_reloc_info_(),
|
||||
tls_base_symbol_defined_(false)
|
||||
{ }
|
||||
|
||||
@ -332,13 +362,13 @@ class Target_x86_64 : public Sized_target<64, false>
|
||||
do_reloc_addend(void* arg, unsigned int r_type, uint64_t addend) const;
|
||||
|
||||
// Return the PLT section.
|
||||
Output_data*
|
||||
do_plt_section_for_global(const Symbol*) const
|
||||
{ return this->plt_section(); }
|
||||
uint64_t
|
||||
do_plt_address_for_global(const Symbol* gsym) const
|
||||
{ return this->plt_section()->address_for_global(gsym); }
|
||||
|
||||
Output_data*
|
||||
do_plt_section_for_local(const Relobj*, unsigned int) const
|
||||
{ return this->plt_section(); }
|
||||
uint64_t
|
||||
do_plt_address_for_local(const Relobj* relobj, unsigned int symndx) const
|
||||
{ return this->plt_section()->address_for_local(relobj, symndx); }
|
||||
|
||||
// This function should be defined in targets that can use relocation
|
||||
// types to determine (implemented in local_reloc_may_be_function_pointer
|
||||
@ -413,7 +443,8 @@ class Target_x86_64 : public Sized_target<64, false>
|
||||
|
||||
// Register an existing PLT entry for a global symbol.
|
||||
void
|
||||
register_global_plt_entry(unsigned int plt_index, Symbol* gsym);
|
||||
register_global_plt_entry(Symbol_table*, Layout*, unsigned int plt_index,
|
||||
Symbol* gsym);
|
||||
|
||||
// Force a COPY relocation for a given symbol.
|
||||
void
|
||||
@ -683,6 +714,10 @@ class Target_x86_64 : public Sized_target<64, false>
|
||||
Reloc_section*
|
||||
rela_tlsdesc_section(Layout*) const;
|
||||
|
||||
// Get the section to use for IRELATIVE relocations.
|
||||
Reloc_section*
|
||||
rela_irelative_section(Layout*);
|
||||
|
||||
// Add a potential copy relocation.
|
||||
void
|
||||
copy_reloc(Symbol_table* symtab, Layout* layout,
|
||||
@ -733,12 +768,16 @@ class Target_x86_64 : public Sized_target<64, false>
|
||||
Output_data_plt_x86_64* plt_;
|
||||
// The GOT PLT section.
|
||||
Output_data_space* got_plt_;
|
||||
// The GOT section for IRELATIVE relocations.
|
||||
Output_data_space* got_irelative_;
|
||||
// The GOT section for TLSDESC relocations.
|
||||
Output_data_got<64, false>* got_tlsdesc_;
|
||||
// The _GLOBAL_OFFSET_TABLE_ symbol.
|
||||
Symbol* global_offset_table_;
|
||||
// The dynamic reloc section.
|
||||
Reloc_section* rela_dyn_;
|
||||
// The section to use for IRELATIVE relocs.
|
||||
Reloc_section* rela_irelative_;
|
||||
// Relocs saved to avoid a COPY reloc.
|
||||
Copy_relocs<elfcpp::SHT_RELA, 64, false> copy_relocs_;
|
||||
// Space for variables copied with a COPY reloc.
|
||||
@ -826,8 +865,17 @@ Target_x86_64::got_section(Symbol_table* symtab, Layout* layout)
|
||||
elfcpp::STV_HIDDEN, 0,
|
||||
false, false);
|
||||
|
||||
// If there are any IRELATIVE relocations, they get GOT entries
|
||||
// in .got.plt after the jump slot entries.
|
||||
this->got_irelative_ = new Output_data_space(8, "** GOT IRELATIVE PLT");
|
||||
layout->add_output_section_data(".got.plt", elfcpp::SHT_PROGBITS,
|
||||
(elfcpp::SHF_ALLOC
|
||||
| elfcpp::SHF_WRITE),
|
||||
this->got_irelative_,
|
||||
ORDER_NON_RELRO_FIRST, false);
|
||||
|
||||
// If there are any TLSDESC relocations, they get GOT entries in
|
||||
// .got.plt after the jump slot entries.
|
||||
// .got.plt after the jump slot and IRELATIVE entries.
|
||||
this->got_tlsdesc_ = new Output_data_got<64, false>();
|
||||
layout->add_output_section_data(".got.plt", elfcpp::SHT_PROGBITS,
|
||||
(elfcpp::SHF_ALLOC
|
||||
@ -855,34 +903,39 @@ Target_x86_64::rela_dyn_section(Layout* layout)
|
||||
return this->rela_dyn_;
|
||||
}
|
||||
|
||||
// Get the section to use for IRELATIVE relocs, creating it if
|
||||
// necessary. These go in .rela.dyn, but only after all other dynamic
|
||||
// relocations. They need to follow the other dynamic relocations so
|
||||
// that they can refer to global variables initialized by those
|
||||
// relocs.
|
||||
|
||||
Target_x86_64::Reloc_section*
|
||||
Target_x86_64::rela_irelative_section(Layout* layout)
|
||||
{
|
||||
if (this->rela_irelative_ == NULL)
|
||||
{
|
||||
// Make sure we have already created the dynamic reloc section.
|
||||
this->rela_dyn_section(layout);
|
||||
this->rela_irelative_ = new Reloc_section(false);
|
||||
layout->add_output_section_data(".rela.dyn", elfcpp::SHT_RELA,
|
||||
elfcpp::SHF_ALLOC, this->rela_irelative_,
|
||||
ORDER_DYNAMIC_RELOCS, false);
|
||||
gold_assert(this->rela_dyn_->output_section()
|
||||
== this->rela_irelative_->output_section());
|
||||
}
|
||||
return this->rela_irelative_;
|
||||
}
|
||||
|
||||
// Initialize the PLT section.
|
||||
|
||||
void
|
||||
Output_data_plt_x86_64::init(Symbol_table* symtab, Layout* layout)
|
||||
Output_data_plt_x86_64::init(Layout* layout)
|
||||
{
|
||||
this->rel_ = new Reloc_section(false);
|
||||
layout->add_output_section_data(".rela.plt", elfcpp::SHT_RELA,
|
||||
elfcpp::SHF_ALLOC, this->rel_,
|
||||
ORDER_DYNAMIC_PLT_RELOCS, false);
|
||||
|
||||
if (parameters->doing_static_link())
|
||||
{
|
||||
// A statically linked executable will only have a .rela.plt
|
||||
// section to hold R_X86_64_IRELATIVE relocs for STT_GNU_IFUNC
|
||||
// symbols. The library will use these symbols to locate the
|
||||
// IRELATIVE relocs at program startup time.
|
||||
symtab->define_in_output_data("__rela_iplt_start", NULL,
|
||||
Symbol_table::PREDEFINED,
|
||||
this->rel_, 0, 0, elfcpp::STT_NOTYPE,
|
||||
elfcpp::STB_GLOBAL, elfcpp::STV_HIDDEN,
|
||||
0, false, true);
|
||||
symtab->define_in_output_data("__rela_iplt_end", NULL,
|
||||
Symbol_table::PREDEFINED,
|
||||
this->rel_, 0, 0, elfcpp::STT_NOTYPE,
|
||||
elfcpp::STB_GLOBAL, elfcpp::STV_HIDDEN,
|
||||
0, true, true);
|
||||
}
|
||||
|
||||
// Add unwind information if requested.
|
||||
if (parameters->options().ld_generated_unwind_info())
|
||||
layout->add_eh_frame_for_plt(this, plt_eh_frame_cie, plt_eh_frame_cie_size,
|
||||
@ -898,7 +951,8 @@ Output_data_plt_x86_64::do_adjust_output_section(Output_section* os)
|
||||
// Add an entry to the PLT.
|
||||
|
||||
void
|
||||
Output_data_plt_x86_64::add_entry(Symbol* gsym)
|
||||
Output_data_plt_x86_64::add_entry(Symbol_table* symtab, Layout* layout,
|
||||
Symbol* gsym)
|
||||
{
|
||||
gold_assert(!gsym->has_plt_offset());
|
||||
|
||||
@ -906,25 +960,47 @@ Output_data_plt_x86_64::add_entry(Symbol* gsym)
|
||||
off_t plt_offset;
|
||||
section_offset_type got_offset;
|
||||
|
||||
unsigned int* pcount;
|
||||
unsigned int offset;
|
||||
unsigned int reserved;
|
||||
Output_data_space* got;
|
||||
if (gsym->type() == elfcpp::STT_GNU_IFUNC
|
||||
&& gsym->can_use_relative_reloc(false))
|
||||
{
|
||||
pcount = &this->irelative_count_;
|
||||
offset = 0;
|
||||
reserved = 0;
|
||||
got = this->got_irelative_;
|
||||
}
|
||||
else
|
||||
{
|
||||
pcount = &this->count_;
|
||||
offset = 1;
|
||||
reserved = 3;
|
||||
got = this->got_plt_;
|
||||
}
|
||||
|
||||
if (!this->is_data_size_valid())
|
||||
{
|
||||
// Note that when setting the PLT offset we skip the initial
|
||||
// reserved PLT entry.
|
||||
plt_index = this->count_ + 1;
|
||||
// Note that when setting the PLT offset for a non-IRELATIVE
|
||||
// entry we skip the initial reserved PLT entry.
|
||||
plt_index = *pcount + offset;
|
||||
plt_offset = plt_index * plt_entry_size;
|
||||
|
||||
++this->count_;
|
||||
++*pcount;
|
||||
|
||||
got_offset = (plt_index - 1 + 3) * 8;
|
||||
gold_assert(got_offset == this->got_plt_->current_data_size());
|
||||
got_offset = (plt_index - offset + reserved) * 8;
|
||||
gold_assert(got_offset == got->current_data_size());
|
||||
|
||||
// Every PLT entry needs a GOT entry which points back to the PLT
|
||||
// entry (this will be changed by the dynamic linker, normally
|
||||
// lazily when the function is called).
|
||||
this->got_plt_->set_current_data_size(got_offset + 8);
|
||||
got->set_current_data_size(got_offset + 8);
|
||||
}
|
||||
else
|
||||
{
|
||||
// FIXME: This is probably not correct for IRELATIVE relocs.
|
||||
|
||||
// For incremental updates, find an available slot.
|
||||
plt_offset = this->free_list_.allocate(plt_entry_size, plt_entry_size, 0);
|
||||
if (plt_offset == -1)
|
||||
@ -935,13 +1011,13 @@ Output_data_plt_x86_64::add_entry(Symbol* gsym)
|
||||
// can be calculated from the PLT index, adjusting for the three
|
||||
// reserved entries at the beginning of the GOT.
|
||||
plt_index = plt_offset / plt_entry_size - 1;
|
||||
got_offset = (plt_index - 1 + 3) * 8;
|
||||
got_offset = (plt_index - offset + reserved) * 8;
|
||||
}
|
||||
|
||||
gsym->set_plt_offset(plt_offset);
|
||||
|
||||
// Every PLT entry needs a reloc.
|
||||
this->add_relocation(gsym, got_offset);
|
||||
this->add_relocation(symtab, layout, gsym, got_offset);
|
||||
|
||||
// Note that we don't need to save the symbol. The contents of the
|
||||
// PLT are independent of which symbols are used. The symbols only
|
||||
@ -953,22 +1029,25 @@ Output_data_plt_x86_64::add_entry(Symbol* gsym)
|
||||
|
||||
unsigned int
|
||||
Output_data_plt_x86_64::add_local_ifunc_entry(
|
||||
Symbol_table* symtab,
|
||||
Layout* layout,
|
||||
Sized_relobj_file<64, false>* relobj,
|
||||
unsigned int local_sym_index)
|
||||
{
|
||||
unsigned int plt_offset = (this->count_ + 1) * plt_entry_size;
|
||||
++this->count_;
|
||||
unsigned int plt_offset = this->irelative_count_ * plt_entry_size;
|
||||
++this->irelative_count_;
|
||||
|
||||
section_offset_type got_offset = this->got_plt_->current_data_size();
|
||||
section_offset_type got_offset = this->got_irelative_->current_data_size();
|
||||
|
||||
// Every PLT entry needs a GOT entry which points back to the PLT
|
||||
// entry.
|
||||
this->got_plt_->set_current_data_size(got_offset + 8);
|
||||
this->got_irelative_->set_current_data_size(got_offset + 8);
|
||||
|
||||
// Every PLT entry needs a reloc.
|
||||
this->rel_->add_symbolless_local_addend(relobj, local_sym_index,
|
||||
elfcpp::R_X86_64_IRELATIVE,
|
||||
this->got_plt_, got_offset, 0);
|
||||
Reloc_section* rela = this->rela_irelative(symtab, layout);
|
||||
rela->add_symbolless_local_addend(relobj, local_sym_index,
|
||||
elfcpp::R_X86_64_IRELATIVE,
|
||||
this->got_irelative_, got_offset, 0);
|
||||
|
||||
return plt_offset;
|
||||
}
|
||||
@ -976,12 +1055,16 @@ Output_data_plt_x86_64::add_local_ifunc_entry(
|
||||
// Add the relocation for a PLT entry.
|
||||
|
||||
void
|
||||
Output_data_plt_x86_64::add_relocation(Symbol* gsym, unsigned int got_offset)
|
||||
Output_data_plt_x86_64::add_relocation(Symbol_table* symtab, Layout* layout,
|
||||
Symbol* gsym, unsigned int got_offset)
|
||||
{
|
||||
if (gsym->type() == elfcpp::STT_GNU_IFUNC
|
||||
&& gsym->can_use_relative_reloc(false))
|
||||
this->rel_->add_symbolless_global_addend(gsym, elfcpp::R_X86_64_IRELATIVE,
|
||||
this->got_plt_, got_offset, 0);
|
||||
{
|
||||
Reloc_section* rela = this->rela_irelative(symtab, layout);
|
||||
rela->add_symbolless_global_addend(gsym, elfcpp::R_X86_64_IRELATIVE,
|
||||
this->got_irelative_, got_offset, 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
gsym->set_needs_dynsym_entry();
|
||||
@ -1002,17 +1085,78 @@ Output_data_plt_x86_64::rela_tlsdesc(Layout* layout)
|
||||
layout->add_output_section_data(".rela.plt", elfcpp::SHT_RELA,
|
||||
elfcpp::SHF_ALLOC, this->tlsdesc_rel_,
|
||||
ORDER_DYNAMIC_PLT_RELOCS, false);
|
||||
gold_assert(this->tlsdesc_rel_->output_section() ==
|
||||
this->rel_->output_section());
|
||||
gold_assert(this->tlsdesc_rel_->output_section()
|
||||
== this->rel_->output_section());
|
||||
}
|
||||
return this->tlsdesc_rel_;
|
||||
}
|
||||
|
||||
// Return where the IRELATIVE relocations should go in the PLT. These
|
||||
// follow the JUMP_SLOT and the TLSDESC relocations.
|
||||
|
||||
Output_data_plt_x86_64::Reloc_section*
|
||||
Output_data_plt_x86_64::rela_irelative(Symbol_table* symtab, Layout* layout)
|
||||
{
|
||||
if (this->irelative_rel_ == NULL)
|
||||
{
|
||||
// Make sure we have a place for the TLSDESC relocations, in
|
||||
// case we see any later on.
|
||||
this->rela_tlsdesc(layout);
|
||||
this->irelative_rel_ = new Reloc_section(false);
|
||||
layout->add_output_section_data(".rela.plt", elfcpp::SHT_RELA,
|
||||
elfcpp::SHF_ALLOC, this->irelative_rel_,
|
||||
ORDER_DYNAMIC_PLT_RELOCS, false);
|
||||
gold_assert(this->irelative_rel_->output_section()
|
||||
== this->rel_->output_section());
|
||||
|
||||
if (parameters->doing_static_link())
|
||||
{
|
||||
// A statically linked executable will only have a .rela.plt
|
||||
// section to hold R_X86_64_IRELATIVE relocs for
|
||||
// STT_GNU_IFUNC symbols. The library will use these
|
||||
// symbols to locate the IRELATIVE relocs at program startup
|
||||
// time.
|
||||
symtab->define_in_output_data("__rela_iplt_start", NULL,
|
||||
Symbol_table::PREDEFINED,
|
||||
this->irelative_rel_, 0, 0,
|
||||
elfcpp::STT_NOTYPE, elfcpp::STB_GLOBAL,
|
||||
elfcpp::STV_HIDDEN, 0, false, true);
|
||||
symtab->define_in_output_data("__rela_iplt_end", NULL,
|
||||
Symbol_table::PREDEFINED,
|
||||
this->irelative_rel_, 0, 0,
|
||||
elfcpp::STT_NOTYPE, elfcpp::STB_GLOBAL,
|
||||
elfcpp::STV_HIDDEN, 0, true, true);
|
||||
}
|
||||
}
|
||||
return this->irelative_rel_;
|
||||
}
|
||||
|
||||
// Return the PLT address to use for a global symbol.
|
||||
|
||||
uint64_t
|
||||
Output_data_plt_x86_64::address_for_global(const Symbol* gsym)
|
||||
{
|
||||
uint64_t offset = 0;
|
||||
if (gsym->type() == elfcpp::STT_GNU_IFUNC
|
||||
&& gsym->can_use_relative_reloc(false))
|
||||
offset = (this->count_ + 1) * plt_entry_size;
|
||||
return this->address() + offset;
|
||||
}
|
||||
|
||||
// Return the PLT address to use for a local symbol. These are always
|
||||
// IRELATIVE relocs.
|
||||
|
||||
uint64_t
|
||||
Output_data_plt_x86_64::address_for_local(const Relobj*, unsigned int)
|
||||
{
|
||||
return this->address() + (this->count_ + 1) * plt_entry_size;
|
||||
}
|
||||
|
||||
// Set the final size.
|
||||
void
|
||||
Output_data_plt_x86_64::set_final_data_size()
|
||||
{
|
||||
unsigned int count = this->count_;
|
||||
unsigned int count = this->count_ + this->irelative_count_;
|
||||
if (this->has_tlsdesc_entry())
|
||||
++count;
|
||||
this->set_data_size((count + 1) * plt_entry_size);
|
||||
@ -1117,8 +1261,12 @@ Output_data_plt_x86_64::do_write(Output_file* of)
|
||||
unsigned char* const oview = of->get_output_view(offset, oview_size);
|
||||
|
||||
const off_t got_file_offset = this->got_plt_->offset();
|
||||
gold_assert(parameters->incremental_update()
|
||||
|| (got_file_offset + this->got_plt_->data_size()
|
||||
== this->got_irelative_->offset()));
|
||||
const section_size_type got_size =
|
||||
convert_to_section_size_type(this->got_plt_->data_size());
|
||||
convert_to_section_size_type(this->got_plt_->data_size()
|
||||
+ this->got_irelative_->data_size());
|
||||
unsigned char* const got_view = of->get_output_view(got_file_offset,
|
||||
got_size);
|
||||
|
||||
@ -1150,7 +1298,7 @@ Output_data_plt_x86_64::do_write(Output_file* of)
|
||||
|
||||
unsigned int plt_offset = plt_entry_size;
|
||||
unsigned int got_offset = 24;
|
||||
const unsigned int count = this->count_;
|
||||
const unsigned int count = this->count_ + this->irelative_count_;
|
||||
for (unsigned int plt_index = 0;
|
||||
plt_index < count;
|
||||
++plt_index,
|
||||
@ -1208,8 +1356,9 @@ Target_x86_64::make_plt_section(Symbol_table* symtab, Layout* layout)
|
||||
// Create the GOT sections first.
|
||||
this->got_section(symtab, layout);
|
||||
|
||||
this->plt_ = new Output_data_plt_x86_64(symtab, layout, this->got_,
|
||||
this->got_plt_);
|
||||
this->plt_ = new Output_data_plt_x86_64(layout, this->got_,
|
||||
this->got_plt_,
|
||||
this->got_irelative_);
|
||||
layout->add_output_section_data(".plt", elfcpp::SHT_PROGBITS,
|
||||
(elfcpp::SHF_ALLOC
|
||||
| elfcpp::SHF_EXECINSTR),
|
||||
@ -1241,7 +1390,7 @@ Target_x86_64::make_plt_entry(Symbol_table* symtab, Layout* layout,
|
||||
if (this->plt_ == NULL)
|
||||
this->make_plt_section(symtab, layout);
|
||||
|
||||
this->plt_->add_entry(gsym);
|
||||
this->plt_->add_entry(symtab, layout, gsym);
|
||||
}
|
||||
|
||||
// Make a PLT entry for a local STT_GNU_IFUNC symbol.
|
||||
@ -1255,7 +1404,8 @@ Target_x86_64::make_local_ifunc_plt_entry(Symbol_table* symtab, Layout* layout,
|
||||
return;
|
||||
if (this->plt_ == NULL)
|
||||
this->make_plt_section(symtab, layout);
|
||||
unsigned int plt_offset = this->plt_->add_local_ifunc_entry(relobj,
|
||||
unsigned int plt_offset = this->plt_->add_local_ifunc_entry(symtab, layout,
|
||||
relobj,
|
||||
local_sym_index);
|
||||
relobj->set_local_plt_offset(local_sym_index, plt_offset);
|
||||
}
|
||||
@ -1330,9 +1480,17 @@ Target_x86_64::init_got_plt_for_update(Symbol_table* symtab,
|
||||
this->got_tlsdesc_,
|
||||
ORDER_NON_RELRO_FIRST, false);
|
||||
|
||||
// If there are any IRELATIVE relocations, they get GOT entries in
|
||||
// .got.plt after the jump slot and TLSDESC entries.
|
||||
this->got_irelative_ = new Output_data_space(0, 8, "** GOT IRELATIVE PLT");
|
||||
layout->add_output_section_data(".got.plt", elfcpp::SHT_PROGBITS,
|
||||
elfcpp::SHF_ALLOC | elfcpp::SHF_WRITE,
|
||||
this->got_irelative_,
|
||||
ORDER_NON_RELRO_FIRST, false);
|
||||
|
||||
// Create the PLT section.
|
||||
this->plt_ = new Output_data_plt_x86_64(symtab, layout, this->got_,
|
||||
this->got_plt_, plt_count);
|
||||
this->plt_ = new Output_data_plt_x86_64(layout, this->got_, this->got_plt_,
|
||||
this->got_irelative_, plt_count);
|
||||
layout->add_output_section_data(".plt", elfcpp::SHT_PROGBITS,
|
||||
elfcpp::SHF_ALLOC | elfcpp::SHF_EXECINSTR,
|
||||
this->plt_, ORDER_PLT, false);
|
||||
@ -1439,7 +1597,9 @@ Target_x86_64::reserve_global_got_entry(unsigned int got_index, Symbol* gsym,
|
||||
// Register an existing PLT entry for a global symbol.
|
||||
|
||||
void
|
||||
Target_x86_64::register_global_plt_entry(unsigned int plt_index,
|
||||
Target_x86_64::register_global_plt_entry(Symbol_table* symtab,
|
||||
Layout* layout,
|
||||
unsigned int plt_index,
|
||||
Symbol* gsym)
|
||||
{
|
||||
gold_assert(this->plt_ != NULL);
|
||||
@ -1450,7 +1610,7 @@ Target_x86_64::register_global_plt_entry(unsigned int plt_index,
|
||||
gsym->set_plt_offset((plt_index + 1) * this->plt_entry_size());
|
||||
|
||||
unsigned int got_offset = (plt_index + 3) * 8;
|
||||
this->plt_->add_relocation(gsym, got_offset);
|
||||
this->plt_->add_relocation(symtab, layout, gsym, got_offset);
|
||||
}
|
||||
|
||||
// Force a COPY relocation for a given symbol.
|
||||
@ -2196,7 +2356,8 @@ Target_x86_64::Scan::global(Symbol_table* symtab,
|
||||
// STT_GNU_IFUNC symbol. This makes a function
|
||||
// address in a PIE executable match the address in a
|
||||
// shared library that it links against.
|
||||
Reloc_section* rela_dyn = target->rela_dyn_section(layout);
|
||||
Reloc_section* rela_dyn =
|
||||
target->rela_irelative_section(layout);
|
||||
unsigned int r_type = elfcpp::R_X86_64_IRELATIVE;
|
||||
rela_dyn->add_symbolless_global_addend(gsym, r_type,
|
||||
output_section, object,
|
||||
@ -2600,7 +2761,8 @@ Target_x86_64::do_finalize_sections(
|
||||
symtab->get_sized_symbol<64>(sym)->set_symsize(data_size);
|
||||
}
|
||||
|
||||
if (parameters->doing_static_link() && this->plt_ == NULL)
|
||||
if (parameters->doing_static_link()
|
||||
&& (this->plt_ == NULL || !this->plt_->has_irelative_section()))
|
||||
{
|
||||
// If linking statically, make sure that the __rela_iplt symbols
|
||||
// were defined if necessary, even if we didn't create a PLT.
|
||||
@ -2680,7 +2842,7 @@ Target_x86_64::Relocate::relocate(const Relocate_info<64, false>* relinfo,
|
||||
if (gsym != NULL
|
||||
&& gsym->use_plt_offset(Scan::get_reference_flags(r_type)))
|
||||
{
|
||||
symval.set_output_value(target->plt_section()->address()
|
||||
symval.set_output_value(target->plt_address_for_global(gsym)
|
||||
+ gsym->plt_offset());
|
||||
psymval = &symval;
|
||||
}
|
||||
@ -2689,7 +2851,7 @@ Target_x86_64::Relocate::relocate(const Relocate_info<64, false>* relinfo,
|
||||
unsigned int r_sym = elfcpp::elf_r_sym<64>(rela.get_r_info());
|
||||
if (object->local_has_plt_offset(r_sym))
|
||||
{
|
||||
symval.set_output_value(target->plt_section()->address()
|
||||
symval.set_output_value(target->plt_address_for_local(object, r_sym)
|
||||
+ object->local_plt_offset(r_sym));
|
||||
psymval = &symval;
|
||||
}
|
||||
@ -3599,7 +3761,7 @@ uint64_t
|
||||
Target_x86_64::do_dynsym_value(const Symbol* gsym) const
|
||||
{
|
||||
gold_assert(gsym->is_from_dynobj() && gsym->has_plt_offset());
|
||||
return this->plt_section()->address() + gsym->plt_offset();
|
||||
return this->plt_address_for_global(gsym) + gsym->plt_offset();
|
||||
}
|
||||
|
||||
// Return a string used to fill a code section with nops to take up
|
||||
|
Loading…
x
Reference in New Issue
Block a user