This patch adds IFUNC support for arm gold backend.
This is a feature required in chromeos arm development work. Tested: 1) Built passed all-gold on x86_64 machine 2) Tested with basic gold aarch64 ifunc unittests - a) global ifunc, statically/non-statically linked b) local ifunc, statically/non-statically linked c) global/local, other shared library routine mixed, statically/non-statically linked d) arm/thumb mode ifunc e) linking chrome browser passed
This commit is contained in:
parent
716db898b7
commit
fa89cc82f5
@ -1,3 +1,7 @@
|
||||
2015-01-22 Han Shen <shenhan@google.com>
|
||||
|
||||
* arm.h (R_ARM_IRELATIVE): New dynamic relocation.
|
||||
|
||||
2015-01-01 Alan Modra <amodra@gmail.com>
|
||||
|
||||
Update year range in copyright notice of all files.
|
||||
|
@ -196,7 +196,8 @@ enum
|
||||
R_ARM_THM_TLS_DESCSEQ32 = 130,// Static Thumb32
|
||||
// 131 - 139 Unallocated
|
||||
// 140 - 159 Dynamic Reserved for future allocation
|
||||
// 160 - 255 Unallocated
|
||||
R_ARM_IRELATIVE = 160, // Dynamic
|
||||
// 161 - 255 Unallocated
|
||||
};
|
||||
|
||||
// e_flags values used for ARM. We only support flags defined in AAELF.
|
||||
|
@ -1,3 +1,51 @@
|
||||
2015-01-22 Han Shen <shenhan@google.com>
|
||||
|
||||
* arm.cc (Target_arm::Target_arm): Add initialization for new members.
|
||||
(Target_arm::do_plt_address_for_global): New method.
|
||||
(Target_arm::do_plt_address_for_local): New method.
|
||||
(Target_arm::rel_irelative_section): New method.
|
||||
(Target_arm::make_data_plt): Add more parameters for plt ctor.
|
||||
(Target_arm::do_make_data_plt): Add more parameters for plt ctor.
|
||||
(Target_arm::Scan::symbol_needs_plt_entry): Add ifunc support.
|
||||
(Target_arm::Scan::reloc_needs_plt_for_ifunc): Add ifunc support.
|
||||
(Target_arm::Scan::check_non_pic): Add ifunc support.
|
||||
(Target_arm::Scan::local): Add ifunc support.
|
||||
(Target_arm::Scan::global): Add ifunc support.
|
||||
(Target_arm::make_plt_section): New method.
|
||||
(Target_arm::make_plt_entry): Change to call to make_plt_section.
|
||||
(Target_arm::make_local_ifunc_plt_entry): New method.
|
||||
(Target_arm::got_irelative_): New member.
|
||||
(Target_arm::rel_irelative_): New member.
|
||||
(Target_arm::got_section): Add creation for got_irelative_.
|
||||
(Target_arm::rel_dyn_section): Add creation for rel_irelative_.
|
||||
(Target_arm::Relocate::relocate): Properly set local ifunc address.
|
||||
(Target_arm::do_dynsym_value): Properly set global ifunc address.
|
||||
(Target_arm::scan_reloc_for_stub): Properly set global ifunc address.
|
||||
(Output_data_plt_arm::IRelative_data): New type.
|
||||
(Output_data_plt_arm::Output_data_plt_arm): Add more parameters.
|
||||
(Output_data_plt_arm::add_entry): Add more parameters.
|
||||
(Output_data_plt_arm::add_relocation): New method.
|
||||
(Output_data_plt_arm::add_local_ifunc_entry): New method.
|
||||
(Output_data_plt_arm::rel_irelative): New method.
|
||||
(Output_data_plt_arm::entry_count): Modified.
|
||||
(Output_data_plt_arm::address_for_global): New method.
|
||||
(Output_data_plt_arm::address_for_local): New method.
|
||||
(Output_data_plt_arm::set_final_data_size): Add irelative_count_.
|
||||
(Output_data_plt_arm::insert_irelative_data): New method.
|
||||
(Output_data_plt_arm::irelative_rel_): New member.
|
||||
(Output_data_plt_arm::got_): New member.
|
||||
(Output_data_plt_arm::got_irelative_): New member.
|
||||
(Output_data_plt_arm::irelative_count_): New member.
|
||||
(Output_data_plt_arm::IRelative_data_vec): New typedef.
|
||||
(Output_data_plt_arm::irelative_data_vec_): New member.
|
||||
(Output_data_plt_arm::do_write): Write out irelative entries.
|
||||
(Output_data_plt_arm_standard::Output_data_plt_arm_standard): Add
|
||||
more parameters to ctor.
|
||||
(Output_data_plt_arm_nacl::Output_data_plt_arm_nacl): Add
|
||||
more parameters to ctor.
|
||||
* output.h (Output_data_reloc::add_local_relative): New method.
|
||||
* aarch64.cc (Output_data_plt_aarch64): Fixed typo in comment.
|
||||
|
||||
2015-01-29 Alan Modra <amodra@gmail.com>
|
||||
|
||||
* powerpc.cc (Target_powerpc::Relocate::relocate): Correct GOT_TLSLD
|
||||
|
@ -3082,7 +3082,7 @@ class Output_data_plt_aarch64 : public Output_section_data
|
||||
// The number of PLT entries.
|
||||
unsigned int count_;
|
||||
|
||||
// Number of PLT entries with R_X86_64_IRELATIVE relocs. These
|
||||
// Number of PLT entries with R_AARCH64_IRELATIVE relocs. These
|
||||
// follow the regular PLT entries.
|
||||
unsigned int irelative_count_;
|
||||
|
||||
|
593
gold/arm.cc
593
gold/arm.cc
@ -2119,8 +2119,8 @@ class Target_arm : public Sized_target<32, big_endian>
|
||||
|
||||
Target_arm(const Target::Target_info* info = &arm_info)
|
||||
: Sized_target<32, big_endian>(info),
|
||||
got_(NULL), plt_(NULL), got_plt_(NULL), rel_dyn_(NULL),
|
||||
copy_relocs_(elfcpp::R_ARM_COPY),
|
||||
got_(NULL), plt_(NULL), got_plt_(NULL), got_irelative_(NULL),
|
||||
rel_dyn_(NULL), rel_irelative_(NULL), copy_relocs_(elfcpp::R_ARM_COPY),
|
||||
got_mod_index_offset_(-1U), tls_base_symbol_defined_(false),
|
||||
stub_tables_(), stub_factory_(Stub_factory::get_instance()),
|
||||
should_force_pic_veneer_(false),
|
||||
@ -2258,6 +2258,18 @@ class Target_arm : public Sized_target<32, big_endian>
|
||||
uint64_t
|
||||
do_dynsym_value(const Symbol*) const;
|
||||
|
||||
// Return the plt address for globals. Since we have irelative plt entries,
|
||||
// address calculation is not as straightforward as plt_address + plt_offset.
|
||||
uint64_t
|
||||
do_plt_address_for_global(const Symbol* gsym) const
|
||||
{ return this->plt_section()->address_for_global(gsym); }
|
||||
|
||||
// Return the plt address for locals. Since we have irelative plt entries,
|
||||
// address calculation is not as straightforward as plt_address + plt_offset.
|
||||
uint64_t
|
||||
do_plt_address_for_local(const Relobj* relobj, unsigned int symndx) const
|
||||
{ return this->plt_section()->address_for_local(relobj, symndx); }
|
||||
|
||||
// Relocate a section.
|
||||
void
|
||||
relocate_section(const Relocate_info<32, big_endian>*,
|
||||
@ -2357,6 +2369,10 @@ class Target_arm : public Sized_target<32, big_endian>
|
||||
unsigned int
|
||||
plt_entry_size() const;
|
||||
|
||||
// Get the section to use for IRELATIVE relocations, create it if necessary.
|
||||
Reloc_section*
|
||||
rel_irelative_section(Layout*);
|
||||
|
||||
// Map platform-specific reloc types
|
||||
static unsigned int
|
||||
get_real_reloc_type(unsigned int r_type);
|
||||
@ -2448,8 +2464,11 @@ class Target_arm : public Sized_target<32, big_endian>
|
||||
protected:
|
||||
// Make the PLT-generator object.
|
||||
Output_data_plt_arm<big_endian>*
|
||||
make_data_plt(Layout* layout, Output_data_space* got_plt)
|
||||
{ return this->do_make_data_plt(layout, got_plt); }
|
||||
make_data_plt(Layout* layout,
|
||||
Arm_output_data_got<big_endian>* got,
|
||||
Output_data_space* got_plt,
|
||||
Output_data_space* got_irelative)
|
||||
{ return this->do_make_data_plt(layout, got, got_plt, got_irelative); }
|
||||
|
||||
// Make an ELF object.
|
||||
Object*
|
||||
@ -2530,9 +2549,14 @@ class Target_arm : public Sized_target<32, big_endian>
|
||||
do_define_standard_symbols(Symbol_table*, Layout*);
|
||||
|
||||
virtual Output_data_plt_arm<big_endian>*
|
||||
do_make_data_plt(Layout* layout, Output_data_space* got_plt)
|
||||
do_make_data_plt(Layout* layout,
|
||||
Arm_output_data_got<big_endian>* got,
|
||||
Output_data_space* got_plt,
|
||||
Output_data_space* got_irelative)
|
||||
{
|
||||
return new Output_data_plt_arm_standard<big_endian>(layout, got_plt);
|
||||
gold_assert(got_plt != NULL && got_irelative != NULL);
|
||||
return new Output_data_plt_arm_standard<big_endian>(
|
||||
layout, got, got_plt, got_irelative);
|
||||
}
|
||||
|
||||
private:
|
||||
@ -2602,6 +2626,9 @@ class Target_arm : public Sized_target<32, big_endian>
|
||||
if (sym->is_undefined() && !parameters->options().shared())
|
||||
return false;
|
||||
|
||||
if (sym->type() == elfcpp::STT_GNU_IFUNC)
|
||||
return true;
|
||||
|
||||
return (!parameters->doing_static_link()
|
||||
&& (sym->type() == elfcpp::STT_FUNC
|
||||
|| sym->type() == elfcpp::STT_ARM_TFUNC)
|
||||
@ -2613,6 +2640,11 @@ class Target_arm : public Sized_target<32, big_endian>
|
||||
inline bool
|
||||
possible_function_pointer_reloc(unsigned int r_type);
|
||||
|
||||
// Whether a plt entry is needed for ifunc.
|
||||
bool
|
||||
reloc_needs_plt_for_ifunc(Sized_relobj_file<32, big_endian>*,
|
||||
unsigned int r_type);
|
||||
|
||||
// Whether we have issued an error about a non-PIC compilation.
|
||||
bool issued_non_pic_error_;
|
||||
};
|
||||
@ -2718,10 +2750,20 @@ class Target_arm : public Sized_target<32, big_endian>
|
||||
return this->got_plt_;
|
||||
}
|
||||
|
||||
// Create the PLT section.
|
||||
void
|
||||
make_plt_section(Symbol_table* symtab, Layout* layout);
|
||||
|
||||
// Create a PLT entry for a global symbol.
|
||||
void
|
||||
make_plt_entry(Symbol_table*, Layout*, Symbol*);
|
||||
|
||||
// Create a PLT entry for a local STT_GNU_IFUNC symbol.
|
||||
void
|
||||
make_local_ifunc_plt_entry(Symbol_table*, Layout*,
|
||||
Sized_relobj_file<32, big_endian>* relobj,
|
||||
unsigned int local_sym_index);
|
||||
|
||||
// Define the _TLS_MODULE_BASE_ symbol in the TLS segment.
|
||||
void
|
||||
define_tls_base_symbol(Symbol_table*, Layout*);
|
||||
@ -2903,8 +2945,12 @@ class Target_arm : public Sized_target<32, big_endian>
|
||||
Output_data_plt_arm<big_endian>* plt_;
|
||||
// The GOT PLT section.
|
||||
Output_data_space* got_plt_;
|
||||
// The GOT section for IRELATIVE relocations.
|
||||
Output_data_space* got_irelative_;
|
||||
// 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, big_endian> copy_relocs_;
|
||||
// Offset of the GOT entry for the TLS module index.
|
||||
@ -4244,6 +4290,15 @@ Target_arm<big_endian>::got_section(Symbol_table* symtab, Layout* layout)
|
||||
elfcpp::STB_LOCAL,
|
||||
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(4, "** GOT IRELATIVE PLT");
|
||||
layout->add_output_section_data(".got", elfcpp::SHT_PROGBITS,
|
||||
(elfcpp::SHF_ALLOC | elfcpp::SHF_WRITE),
|
||||
this->got_irelative_,
|
||||
got_order, is_got_relro);
|
||||
|
||||
}
|
||||
return this->got_;
|
||||
}
|
||||
@ -4257,14 +4312,43 @@ Target_arm<big_endian>::rel_dyn_section(Layout* layout)
|
||||
if (this->rel_dyn_ == NULL)
|
||||
{
|
||||
gold_assert(layout != NULL);
|
||||
// Create both relocation sections in the same place, so as to ensure
|
||||
// their relative order in the output section.
|
||||
this->rel_dyn_ = new Reloc_section(parameters->options().combreloc());
|
||||
this->rel_irelative_ = new Reloc_section(false);
|
||||
layout->add_output_section_data(".rel.dyn", elfcpp::SHT_REL,
|
||||
elfcpp::SHF_ALLOC, this->rel_dyn_,
|
||||
ORDER_DYNAMIC_RELOCS, false);
|
||||
layout->add_output_section_data(".rel.dyn", elfcpp::SHT_REL,
|
||||
elfcpp::SHF_ALLOC, this->rel_irelative_,
|
||||
ORDER_DYNAMIC_RELOCS, false);
|
||||
}
|
||||
return this->rel_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.
|
||||
|
||||
template<bool big_endian>
|
||||
typename Target_arm<big_endian>::Reloc_section*
|
||||
Target_arm<big_endian>::rel_irelative_section(Layout* layout)
|
||||
{
|
||||
if (this->rel_irelative_ == NULL)
|
||||
{
|
||||
// Delegate the creation to rel_dyn_section so as to ensure their order in
|
||||
// the output section.
|
||||
this->rel_dyn_section(layout);
|
||||
gold_assert(this->rel_irelative_ != NULL
|
||||
&& (this->rel_dyn_->output_section()
|
||||
== this->rel_irelative_->output_section()));
|
||||
}
|
||||
return this->rel_irelative_;
|
||||
}
|
||||
|
||||
|
||||
// Insn_template methods.
|
||||
|
||||
// Return byte size of an instruction template.
|
||||
@ -7221,24 +7305,80 @@ template<bool big_endian>
|
||||
class Output_data_plt_arm : public Output_section_data
|
||||
{
|
||||
public:
|
||||
// Unlike aarch64, which records symbol value in "addend" field of relocations
|
||||
// and could be done at the same time an IRelative reloc is created for the
|
||||
// symbol, arm puts the symbol value into "GOT" table, which, however, is
|
||||
// issued later in Output_data_plt_arm::do_write(). So we have a struct here
|
||||
// to keep necessary symbol information for later use in do_write. We usually
|
||||
// have only a very limited number of ifuncs, so the extra data required here
|
||||
// is also limited.
|
||||
|
||||
struct IRelative_data
|
||||
{
|
||||
IRelative_data(Sized_symbol<32>* sized_symbol)
|
||||
: symbol_is_global_(true)
|
||||
{
|
||||
u_.global = sized_symbol;
|
||||
}
|
||||
|
||||
IRelative_data(Sized_relobj_file<32, big_endian>* relobj,
|
||||
unsigned int index)
|
||||
: symbol_is_global_(false)
|
||||
{
|
||||
u_.local.relobj = relobj;
|
||||
u_.local.index = index;
|
||||
}
|
||||
|
||||
union
|
||||
{
|
||||
Sized_symbol<32>* global;
|
||||
|
||||
struct
|
||||
{
|
||||
Sized_relobj_file<32, big_endian>* relobj;
|
||||
unsigned int index;
|
||||
} local;
|
||||
} u_;
|
||||
|
||||
bool symbol_is_global_;
|
||||
};
|
||||
|
||||
typedef Output_data_reloc<elfcpp::SHT_REL, true, 32, big_endian>
|
||||
Reloc_section;
|
||||
|
||||
Output_data_plt_arm(Layout*, uint64_t addralign, Output_data_space*);
|
||||
Output_data_plt_arm(Layout* layout, uint64_t addralign,
|
||||
Arm_output_data_got<big_endian>* got,
|
||||
Output_data_space* got_plt,
|
||||
Output_data_space* got_irelative);
|
||||
|
||||
// Add an entry to the PLT.
|
||||
void
|
||||
add_entry(Symbol* gsym);
|
||||
add_entry(Symbol_table* symtab, Layout* layout, Symbol* gsym);
|
||||
|
||||
// Add the relocation for a plt entry.
|
||||
void
|
||||
add_relocation(Symbol_table* symtab, Layout* layout,
|
||||
Symbol* gsym, unsigned int got_offset);
|
||||
|
||||
// Add an entry to the PLT for a local STT_GNU_IFUNC symbol.
|
||||
unsigned int
|
||||
add_local_ifunc_entry(Symbol_table* symtab, Layout*,
|
||||
Sized_relobj_file<32, big_endian>* relobj,
|
||||
unsigned int local_sym_index);
|
||||
|
||||
// Return the .rel.plt section data.
|
||||
const Reloc_section*
|
||||
rel_plt() const
|
||||
{ return this->rel_; }
|
||||
|
||||
// Return the PLT relocation container for IRELATIVE.
|
||||
Reloc_section*
|
||||
rel_irelative(Symbol_table*, Layout*);
|
||||
|
||||
// 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.
|
||||
unsigned int
|
||||
@ -7250,6 +7390,14 @@ class Output_data_plt_arm : public Output_section_data
|
||||
get_plt_entry_size() const
|
||||
{ return this->do_get_plt_entry_size(); }
|
||||
|
||||
// Return the PLT address for globals.
|
||||
uint32_t
|
||||
address_for_global(const Symbol*) const;
|
||||
|
||||
// Return the PLT address for locals.
|
||||
uint32_t
|
||||
address_for_local(const Relobj*, unsigned int symndx) const;
|
||||
|
||||
protected:
|
||||
// Fill in the first PLT entry.
|
||||
void
|
||||
@ -7298,19 +7446,37 @@ class Output_data_plt_arm : public Output_section_data
|
||||
set_final_data_size()
|
||||
{
|
||||
this->set_data_size(this->first_plt_entry_offset()
|
||||
+ this->count_ * this->get_plt_entry_size());
|
||||
+ ((this->count_ + this->irelative_count_)
|
||||
* this->get_plt_entry_size()));
|
||||
}
|
||||
|
||||
// Write out the PLT data.
|
||||
void
|
||||
do_write(Output_file*);
|
||||
|
||||
// Record irelative symbol data.
|
||||
void insert_irelative_data(const IRelative_data& idata)
|
||||
{ irelative_data_vec_.push_back(idata); }
|
||||
|
||||
// The reloc section.
|
||||
Reloc_section* rel_;
|
||||
// The IRELATIVE relocs, if necessary. These must follow the
|
||||
// regular PLT relocations.
|
||||
Reloc_section* irelative_rel_;
|
||||
// The .got section.
|
||||
Arm_output_data_got<big_endian>* 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_ARM_IRELATIVE relocs. These
|
||||
// follow the regular PLT entries.
|
||||
unsigned int irelative_count_;
|
||||
// Vector for irelative data.
|
||||
typedef std::vector<IRelative_data> IRelative_data_vec;
|
||||
IRelative_data_vec irelative_data_vec_;
|
||||
};
|
||||
|
||||
// Create the PLT section. The ordinary .got section is an argument,
|
||||
@ -7318,10 +7484,14 @@ class Output_data_plt_arm : public Output_section_data
|
||||
// section just for PLT entries.
|
||||
|
||||
template<bool big_endian>
|
||||
Output_data_plt_arm<big_endian>::Output_data_plt_arm(Layout* layout,
|
||||
uint64_t addralign,
|
||||
Output_data_space* got_plt)
|
||||
: Output_section_data(addralign), got_plt_(got_plt), count_(0)
|
||||
Output_data_plt_arm<big_endian>::Output_data_plt_arm(
|
||||
Layout* layout, uint64_t addralign,
|
||||
Arm_output_data_got<big_endian>* got,
|
||||
Output_data_space* got_plt,
|
||||
Output_data_space* got_irelative)
|
||||
: Output_section_data(addralign), irelative_rel_(NULL),
|
||||
got_(got), got_plt_(got_plt), got_irelative_(got_irelative),
|
||||
count_(0), irelative_count_(0)
|
||||
{
|
||||
this->rel_ = new Reloc_section(false);
|
||||
layout->add_output_section_data(".rel.plt", elfcpp::SHT_REL,
|
||||
@ -7340,40 +7510,210 @@ Output_data_plt_arm<big_endian>::do_adjust_output_section(Output_section* os)
|
||||
|
||||
template<bool big_endian>
|
||||
void
|
||||
Output_data_plt_arm<big_endian>::add_entry(Symbol* gsym)
|
||||
Output_data_plt_arm<big_endian>::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_) * this->get_plt_entry_size()
|
||||
+ this->first_plt_entry_offset());
|
||||
unsigned int* entry_count;
|
||||
Output_section_data_build* got;
|
||||
|
||||
++this->count_;
|
||||
// We have 2 different types of plt entry here, normal and ifunc.
|
||||
|
||||
section_offset_type got_offset = this->got_plt_->current_data_size();
|
||||
// For normal plt, the offset begins with first_plt_entry_offset(20), and the
|
||||
// 1st entry offset would be 20, the second 32, third 44 ... etc.
|
||||
|
||||
// For ifunc plt, the offset begins with 0. So the first offset would 0,
|
||||
// second 12, third 24 ... etc.
|
||||
|
||||
// IFunc plt entries *always* come after *normal* plt entries.
|
||||
|
||||
// Notice, when computing the plt address of a certain symbol, "plt_address +
|
||||
// plt_offset" is no longer correct. Use target->plt_address_for_global() or
|
||||
// target->plt_address_for_local() instead.
|
||||
|
||||
int begin_offset = 0;
|
||||
if (gsym->type() == elfcpp::STT_GNU_IFUNC
|
||||
&& gsym->can_use_relative_reloc(false))
|
||||
{
|
||||
entry_count = &this->irelative_count_;
|
||||
got = this->got_irelative_;
|
||||
// For irelative plt entries, offset is relative to the end of normal plt
|
||||
// entries, so it starts from 0.
|
||||
begin_offset = 0;
|
||||
// Record symbol information.
|
||||
this->insert_irelative_data(
|
||||
IRelative_data(symtab->get_sized_symbol<32>(gsym)));
|
||||
}
|
||||
else
|
||||
{
|
||||
entry_count = &this->count_;
|
||||
got = this->got_plt_;
|
||||
// Note that for normal plt entries, when setting the PLT offset we skip
|
||||
// the initial reserved PLT entry.
|
||||
begin_offset = this->first_plt_entry_offset();
|
||||
}
|
||||
|
||||
gsym->set_plt_offset(begin_offset
|
||||
+ (*entry_count) * this->get_plt_entry_size());
|
||||
|
||||
++(*entry_count);
|
||||
|
||||
section_offset_type 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 + 4);
|
||||
got->set_current_data_size(got_offset + 4);
|
||||
|
||||
// Every PLT entry needs a reloc.
|
||||
gsym->set_needs_dynsym_entry();
|
||||
this->rel_->add_global(gsym, elfcpp::R_ARM_JUMP_SLOT, this->got_plt_,
|
||||
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
|
||||
// appear in the relocations.
|
||||
}
|
||||
|
||||
// Add an entry to the PLT for a local STT_GNU_IFUNC symbol. Return
|
||||
// the PLT offset.
|
||||
|
||||
template<bool big_endian>
|
||||
unsigned int
|
||||
Output_data_plt_arm<big_endian>::add_local_ifunc_entry(
|
||||
Symbol_table* symtab,
|
||||
Layout* layout,
|
||||
Sized_relobj_file<32, big_endian>* relobj,
|
||||
unsigned int local_sym_index)
|
||||
{
|
||||
this->insert_irelative_data(IRelative_data(relobj, local_sym_index));
|
||||
|
||||
// Notice, when computingthe plt entry address, "plt_address + plt_offset" is
|
||||
// no longer correct. Use target->plt_address_for_local() instead.
|
||||
unsigned int plt_offset = this->irelative_count_ * this->get_plt_entry_size();
|
||||
++this->irelative_count_;
|
||||
|
||||
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_irelative_->set_current_data_size(got_offset + 4);
|
||||
|
||||
|
||||
// Every PLT entry needs a reloc.
|
||||
Reloc_section* rel = this->rel_irelative(symtab, layout);
|
||||
rel->add_symbolless_local_addend(relobj, local_sym_index,
|
||||
elfcpp::R_ARM_IRELATIVE,
|
||||
this->got_irelative_, got_offset);
|
||||
return plt_offset;
|
||||
}
|
||||
|
||||
|
||||
// Add the relocation for a PLT entry.
|
||||
|
||||
template<bool big_endian>
|
||||
void
|
||||
Output_data_plt_arm<big_endian>::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))
|
||||
{
|
||||
Reloc_section* rel = this->rel_irelative(symtab, layout);
|
||||
rel->add_symbolless_global_addend(gsym, elfcpp::R_ARM_IRELATIVE,
|
||||
this->got_irelative_, got_offset);
|
||||
}
|
||||
else
|
||||
{
|
||||
gsym->set_needs_dynsym_entry();
|
||||
this->rel_->add_global(gsym, elfcpp::R_ARM_JUMP_SLOT, this->got_plt_,
|
||||
got_offset);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Create the irelative relocation data.
|
||||
|
||||
template<bool big_endian>
|
||||
typename Output_data_plt_arm<big_endian>::Reloc_section*
|
||||
Output_data_plt_arm<big_endian>::rel_irelative(Symbol_table* symtab,
|
||||
Layout* layout)
|
||||
{
|
||||
if (this->irelative_rel_ == NULL)
|
||||
{
|
||||
// Since irelative relocations goes into 'rel.dyn', we delegate the
|
||||
// creation of irelative_rel_ to where rel_dyn section gets created.
|
||||
Target_arm<big_endian>* arm_target =
|
||||
Target_arm<big_endian>::default_target();
|
||||
this->irelative_rel_ = arm_target->rel_irelative_section(layout);
|
||||
|
||||
// Make sure we have a place for the TLSDESC relocations, in
|
||||
// case we see any later on.
|
||||
// this->rel_tlsdesc(layout);
|
||||
if (parameters->doing_static_link())
|
||||
{
|
||||
// A statically linked executable will only have a .rel.plt section to
|
||||
// hold R_ARM_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 for a global symbol.
|
||||
|
||||
template<bool big_endian>
|
||||
uint32_t
|
||||
Output_data_plt_arm<big_endian>::address_for_global(const Symbol* gsym) const
|
||||
{
|
||||
uint64_t begin_offset = 0;
|
||||
if (gsym->type() == elfcpp::STT_GNU_IFUNC
|
||||
&& gsym->can_use_relative_reloc(false))
|
||||
{
|
||||
begin_offset = (this->first_plt_entry_offset() +
|
||||
this->count_ * this->get_plt_entry_size());
|
||||
}
|
||||
return this->address() + begin_offset + gsym->plt_offset();
|
||||
}
|
||||
|
||||
|
||||
// Return the PLT address for a local symbol. These are always
|
||||
// IRELATIVE relocs.
|
||||
|
||||
template<bool big_endian>
|
||||
uint32_t
|
||||
Output_data_plt_arm<big_endian>::address_for_local(
|
||||
const Relobj* object,
|
||||
unsigned int r_sym) const
|
||||
{
|
||||
return (this->address()
|
||||
+ this->first_plt_entry_offset()
|
||||
+ this->count_ * this->get_plt_entry_size()
|
||||
+ object->local_plt_offset(r_sym));
|
||||
}
|
||||
|
||||
|
||||
template<bool big_endian>
|
||||
class Output_data_plt_arm_standard : public Output_data_plt_arm<big_endian>
|
||||
{
|
||||
public:
|
||||
Output_data_plt_arm_standard(Layout* layout, Output_data_space* got_plt)
|
||||
: Output_data_plt_arm<big_endian>(layout, 4, got_plt)
|
||||
Output_data_plt_arm_standard(Layout* layout,
|
||||
Arm_output_data_got<big_endian>* got,
|
||||
Output_data_space* got_plt,
|
||||
Output_data_space* got_irelative)
|
||||
: Output_data_plt_arm<big_endian>(layout, 4, got, got_plt, got_irelative)
|
||||
{ }
|
||||
|
||||
protected:
|
||||
@ -7485,8 +7825,11 @@ Output_data_plt_arm<big_endian>::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(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);
|
||||
unsigned char* pov = oview;
|
||||
@ -7505,7 +7848,8 @@ Output_data_plt_arm<big_endian>::do_write(Output_file* of)
|
||||
|
||||
unsigned int plt_offset = this->first_plt_entry_offset();
|
||||
unsigned int got_offset = 12;
|
||||
const unsigned int count = this->count_;
|
||||
const unsigned int count = this->count_ + this->irelative_count_;
|
||||
gold_assert(this->irelative_count_ == this->irelative_data_vec_.size());
|
||||
for (unsigned int i = 0;
|
||||
i < count;
|
||||
++i,
|
||||
@ -7518,8 +7862,33 @@ Output_data_plt_arm<big_endian>::do_write(Output_file* of)
|
||||
this->fill_plt_entry(pov, got_address, plt_address,
|
||||
got_offset, plt_offset);
|
||||
|
||||
// Set the entry in the GOT.
|
||||
elfcpp::Swap<32, big_endian>::writeval(got_pov, plt_address);
|
||||
Arm_address value;
|
||||
if (i < this->count_)
|
||||
{
|
||||
// For non-irelative got entries, the value is the beginning of plt.
|
||||
value = plt_address;
|
||||
}
|
||||
else
|
||||
{
|
||||
// For irelative got entries, the value is the (global/local) symbol
|
||||
// address.
|
||||
const IRelative_data& idata =
|
||||
this->irelative_data_vec_[i - this->count_];
|
||||
if (idata.symbol_is_global_)
|
||||
{
|
||||
// Set the entry in the GOT for irelative symbols. The content is
|
||||
// the address of the ifunc, not the address of plt start.
|
||||
const Sized_symbol<32>* sized_symbol = idata.u_.global;
|
||||
gold_assert(sized_symbol->type() == elfcpp::STT_GNU_IFUNC);
|
||||
value = sized_symbol->value();
|
||||
}
|
||||
else
|
||||
{
|
||||
value = idata.u_.local.relobj->local_symbol_value(
|
||||
idata.u_.local.index, 0);
|
||||
}
|
||||
}
|
||||
elfcpp::Swap<32, big_endian>::writeval(got_pov, value);
|
||||
}
|
||||
|
||||
gold_assert(static_cast<section_size_type>(pov - oview) == oview_size);
|
||||
@ -7529,6 +7898,7 @@ Output_data_plt_arm<big_endian>::do_write(Output_file* of)
|
||||
of->write_output_view(got_file_offset, got_size, got_view);
|
||||
}
|
||||
|
||||
|
||||
// Create a PLT entry for a global symbol.
|
||||
|
||||
template<bool big_endian>
|
||||
@ -7539,21 +7909,59 @@ Target_arm<big_endian>::make_plt_entry(Symbol_table* symtab, Layout* layout,
|
||||
if (gsym->has_plt_offset())
|
||||
return;
|
||||
|
||||
if (this->plt_ == NULL)
|
||||
this->make_plt_section(symtab, layout);
|
||||
|
||||
this->plt_->add_entry(symtab, layout, gsym);
|
||||
}
|
||||
|
||||
|
||||
// Create the PLT section.
|
||||
template<bool big_endian>
|
||||
void
|
||||
Target_arm<big_endian>::make_plt_section(
|
||||
Symbol_table* symtab, Layout* layout)
|
||||
{
|
||||
if (this->plt_ == NULL)
|
||||
{
|
||||
// Create the GOT sections first.
|
||||
// Create the GOT section first.
|
||||
this->got_section(symtab, layout);
|
||||
|
||||
this->plt_ = this->make_data_plt(layout, this->got_plt_);
|
||||
// GOT for irelatives is create along with got.plt.
|
||||
gold_assert(this->got_ != NULL
|
||||
&& this->got_plt_ != NULL
|
||||
&& this->got_irelative_ != NULL);
|
||||
this->plt_ = this->make_data_plt(layout, this->got_, this->got_plt_,
|
||||
this->got_irelative_);
|
||||
|
||||
layout->add_output_section_data(".plt", elfcpp::SHT_PROGBITS,
|
||||
(elfcpp::SHF_ALLOC
|
||||
| elfcpp::SHF_EXECINSTR),
|
||||
this->plt_, ORDER_PLT, false);
|
||||
}
|
||||
this->plt_->add_entry(gsym);
|
||||
}
|
||||
|
||||
|
||||
// Make a PLT entry for a local STT_GNU_IFUNC symbol.
|
||||
|
||||
template<bool big_endian>
|
||||
void
|
||||
Target_arm<big_endian>::make_local_ifunc_plt_entry(
|
||||
Symbol_table* symtab, Layout* layout,
|
||||
Sized_relobj_file<32, big_endian>* relobj,
|
||||
unsigned int local_sym_index)
|
||||
{
|
||||
if (relobj->local_has_plt_offset(local_sym_index))
|
||||
return;
|
||||
if (this->plt_ == NULL)
|
||||
this->make_plt_section(symtab, layout);
|
||||
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);
|
||||
}
|
||||
|
||||
|
||||
// Return the number of entries in the PLT.
|
||||
|
||||
template<bool big_endian>
|
||||
@ -7823,6 +8231,7 @@ Target_arm<big_endian>::Scan::check_non_pic(Relobj* object,
|
||||
case elfcpp::R_ARM_JUMP_SLOT:
|
||||
case elfcpp::R_ARM_ABS32:
|
||||
case elfcpp::R_ARM_ABS32_NOI:
|
||||
case elfcpp::R_ARM_IRELATIVE:
|
||||
case elfcpp::R_ARM_PC24:
|
||||
// FIXME: The following 3 types are not supported by Android's dynamic
|
||||
// linker.
|
||||
@ -7853,6 +8262,27 @@ Target_arm<big_endian>::Scan::check_non_pic(Relobj* object,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Return whether we need to make a PLT entry for a relocation of the
|
||||
// given type against a STT_GNU_IFUNC symbol.
|
||||
|
||||
template<bool big_endian>
|
||||
bool
|
||||
Target_arm<big_endian>::Scan::reloc_needs_plt_for_ifunc(
|
||||
Sized_relobj_file<32, big_endian>* object,
|
||||
unsigned int r_type)
|
||||
{
|
||||
int flags = Scan::get_reference_flags(r_type);
|
||||
if (flags & Symbol::TLS_REF)
|
||||
{
|
||||
gold_error(_("%s: unsupported TLS reloc %u for IFUNC symbol"),
|
||||
object->name().c_str(), r_type);
|
||||
return false;
|
||||
}
|
||||
return flags != 0;
|
||||
}
|
||||
|
||||
|
||||
// Scan a relocation for a local symbol.
|
||||
// FIXME: This only handles a subset of relocation types used by Android
|
||||
// on ARM v5te devices.
|
||||
@ -7874,6 +8304,15 @@ Target_arm<big_endian>::Scan::local(Symbol_table* symtab,
|
||||
return;
|
||||
|
||||
r_type = get_real_reloc_type(r_type);
|
||||
|
||||
// A local STT_GNU_IFUNC symbol may require a PLT entry.
|
||||
bool is_ifunc = lsym.get_st_type() == elfcpp::STT_GNU_IFUNC;
|
||||
if (is_ifunc && this->reloc_needs_plt_for_ifunc(object, r_type))
|
||||
{
|
||||
unsigned int r_sym = elfcpp::elf_r_sym<32>(reloc.get_r_info());
|
||||
target->make_local_ifunc_plt_entry(symtab, layout, object, r_sym);
|
||||
}
|
||||
|
||||
switch (r_type)
|
||||
{
|
||||
case elfcpp::R_ARM_NONE:
|
||||
@ -7898,7 +8337,7 @@ Target_arm<big_endian>::Scan::local(Symbol_table* symtab,
|
||||
// we need to add check_non_pic(object, r_type) here.
|
||||
rel_dyn->add_local_relative(object, r_sym, elfcpp::R_ARM_RELATIVE,
|
||||
output_section, data_shndx,
|
||||
reloc.get_r_offset());
|
||||
reloc.get_r_offset(), is_ifunc);
|
||||
}
|
||||
break;
|
||||
|
||||
@ -8265,6 +8704,11 @@ Target_arm<big_endian>::Scan::global(Symbol_table* symtab,
|
||||
&& strcmp(gsym->name(), "_GLOBAL_OFFSET_TABLE_") == 0)
|
||||
target->got_section(symtab, layout);
|
||||
|
||||
// A STT_GNU_IFUNC symbol may require a PLT entry.
|
||||
if (gsym->type() == elfcpp::STT_GNU_IFUNC
|
||||
&& this->reloc_needs_plt_for_ifunc(object, r_type))
|
||||
target->make_plt_entry(symtab, layout, gsym);
|
||||
|
||||
r_type = get_real_reloc_type(r_type);
|
||||
switch (r_type)
|
||||
{
|
||||
@ -8307,6 +8751,24 @@ Target_arm<big_endian>::Scan::global(Symbol_table* symtab,
|
||||
target->copy_reloc(symtab, layout, object,
|
||||
data_shndx, output_section, gsym, reloc);
|
||||
}
|
||||
else if ((r_type == elfcpp::R_ARM_ABS32
|
||||
|| r_type == elfcpp::R_ARM_ABS32_NOI)
|
||||
&& gsym->type() == elfcpp::STT_GNU_IFUNC
|
||||
&& gsym->can_use_relative_reloc(false)
|
||||
&& !gsym->is_from_dynobj()
|
||||
&& !gsym->is_undefined()
|
||||
&& !gsym->is_preemptible())
|
||||
{
|
||||
// Use an IRELATIVE reloc for a locally defined 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_irelative =
|
||||
target->rel_irelative_section(layout);
|
||||
unsigned int r_type = elfcpp::R_ARM_IRELATIVE;
|
||||
rel_irelative->add_symbolless_global_addend(
|
||||
gsym, r_type, output_section, object,
|
||||
data_shndx, reloc.get_r_offset());
|
||||
}
|
||||
else if ((r_type == elfcpp::R_ARM_ABS32
|
||||
|| r_type == elfcpp::R_ARM_ABS32_NOI)
|
||||
&& gsym->can_use_relative_reloc(false))
|
||||
@ -8442,7 +8904,13 @@ Target_arm<big_endian>::Scan::global(Symbol_table* symtab,
|
||||
Arm_output_data_got<big_endian>* got =
|
||||
target->got_section(symtab, layout);
|
||||
if (gsym->final_value_is_known())
|
||||
got->add_global(gsym, GOT_TYPE_STANDARD);
|
||||
{
|
||||
// For a STT_GNU_IFUNC symbol we want the PLT address.
|
||||
if (gsym->type() == elfcpp::STT_GNU_IFUNC)
|
||||
got->add_global_plt(gsym, GOT_TYPE_STANDARD);
|
||||
else
|
||||
got->add_global(gsym, GOT_TYPE_STANDARD);
|
||||
}
|
||||
else
|
||||
{
|
||||
// If this symbol is not fully resolved, we need to add a
|
||||
@ -8452,12 +8920,29 @@ Target_arm<big_endian>::Scan::global(Symbol_table* symtab,
|
||||
|| gsym->is_undefined()
|
||||
|| gsym->is_preemptible()
|
||||
|| (gsym->visibility() == elfcpp::STV_PROTECTED
|
||||
&& parameters->options().shared()))
|
||||
&& parameters->options().shared())
|
||||
|| (gsym->type() == elfcpp::STT_GNU_IFUNC
|
||||
&& parameters->options().output_is_position_independent()))
|
||||
got->add_global_with_rel(gsym, GOT_TYPE_STANDARD,
|
||||
rel_dyn, elfcpp::R_ARM_GLOB_DAT);
|
||||
else
|
||||
{
|
||||
if (got->add_global(gsym, GOT_TYPE_STANDARD))
|
||||
// For a STT_GNU_IFUNC symbol we want to write the PLT
|
||||
// offset into the GOT, so that function pointer
|
||||
// comparisons work correctly.
|
||||
bool is_new;
|
||||
if (gsym->type() != elfcpp::STT_GNU_IFUNC)
|
||||
is_new = got->add_global(gsym, GOT_TYPE_STANDARD);
|
||||
else
|
||||
{
|
||||
is_new = got->add_global_plt(gsym, GOT_TYPE_STANDARD);
|
||||
// Tell the dynamic linker to use the PLT address
|
||||
// when resolving relocations.
|
||||
if (gsym->is_from_dynobj()
|
||||
&& !parameters->options().shared())
|
||||
gsym->set_needs_dynsym_value();
|
||||
}
|
||||
if (is_new)
|
||||
rel_dyn->add_global_relative(
|
||||
gsym, elfcpp::R_ARM_RELATIVE, got,
|
||||
gsym->got_offset(GOT_TYPE_STANDARD));
|
||||
@ -8919,8 +9404,7 @@ Target_arm<big_endian>::Relocate::relocate(
|
||||
if (gsym->use_plt_offset(Scan::get_reference_flags(r_type)))
|
||||
{
|
||||
// This uses a PLT, change the symbol value.
|
||||
symval.set_output_value(target->plt_section()->address()
|
||||
+ gsym->plt_offset());
|
||||
symval.set_output_value(target->plt_address_for_global(gsym));
|
||||
psymval = &symval;
|
||||
}
|
||||
else if (gsym->is_weak_undefined())
|
||||
@ -8958,6 +9442,13 @@ Target_arm<big_endian>::Relocate::relocate(
|
||||
elfcpp::Elf_types<32>::Elf_WXword r_info = rel.get_r_info();
|
||||
unsigned int r_sym = elfcpp::elf_r_sym<32>(r_info);
|
||||
thumb_bit = object->local_symbol_is_thumb_function(r_sym) ? 1 : 0;
|
||||
|
||||
if (psymval->is_ifunc_symbol() && object->local_has_plt_offset(r_sym))
|
||||
{
|
||||
symval.set_output_value(
|
||||
target->plt_address_for_local(object, r_sym));
|
||||
psymval = &symval;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
@ -9936,7 +10427,7 @@ uint64_t
|
||||
Target_arm<big_endian>::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);
|
||||
}
|
||||
|
||||
// Map platform-specific relocs to real relocs
|
||||
@ -11091,8 +11582,7 @@ Target_arm<big_endian>::scan_reloc_for_stub(
|
||||
if (gsym->use_plt_offset(Scan::get_reference_flags(r_type)))
|
||||
{
|
||||
// This uses a PLT, change the symbol value.
|
||||
symval.set_output_value(this->plt_section()->address()
|
||||
+ gsym->plt_offset());
|
||||
symval.set_output_value(this->plt_address_for_global(gsym));
|
||||
psymval = &symval;
|
||||
target_is_thumb = false;
|
||||
}
|
||||
@ -12195,8 +12685,13 @@ class Target_arm_nacl : public Target_arm<big_endian>
|
||||
|
||||
protected:
|
||||
virtual Output_data_plt_arm<big_endian>*
|
||||
do_make_data_plt(Layout* layout, Output_data_space* got_plt)
|
||||
{ return new Output_data_plt_arm_nacl<big_endian>(layout, got_plt); }
|
||||
do_make_data_plt(
|
||||
Layout* layout,
|
||||
Arm_output_data_got<big_endian>* got,
|
||||
Output_data_space* got_plt,
|
||||
Output_data_space* got_irelative)
|
||||
{ return new Output_data_plt_arm_nacl<big_endian>(
|
||||
layout, got, got_plt, got_irelative); }
|
||||
|
||||
private:
|
||||
static const Target::Target_info arm_nacl_info;
|
||||
@ -12233,8 +12728,12 @@ template<bool big_endian>
|
||||
class Output_data_plt_arm_nacl : public Output_data_plt_arm<big_endian>
|
||||
{
|
||||
public:
|
||||
Output_data_plt_arm_nacl(Layout* layout, Output_data_space* got_plt)
|
||||
: Output_data_plt_arm<big_endian>(layout, 16, got_plt)
|
||||
Output_data_plt_arm_nacl(
|
||||
Layout* layout,
|
||||
Arm_output_data_got<big_endian>* got,
|
||||
Output_data_space* got_plt,
|
||||
Output_data_space* got_irelative)
|
||||
: Output_data_plt_arm<big_endian>(layout, 16, got, got_plt, got_irelative)
|
||||
{ }
|
||||
|
||||
protected:
|
||||
|
@ -1714,6 +1714,17 @@ class Output_data_reloc<elfcpp::SHT_REL, dynamic, size, big_endian>
|
||||
address, true, true, false, false));
|
||||
}
|
||||
|
||||
void
|
||||
add_local_relative(Sized_relobj<size, big_endian>* relobj,
|
||||
unsigned int local_sym_index, unsigned int type,
|
||||
Output_data* od, unsigned int shndx, Address address,
|
||||
bool use_plt_offset)
|
||||
{
|
||||
this->add(od, Output_reloc_type(relobj, local_sym_index, type, shndx,
|
||||
address, true, true, false,
|
||||
use_plt_offset));
|
||||
}
|
||||
|
||||
// Add a local relocation which does not use a symbol for the relocation,
|
||||
// but which gets its addend from a symbol.
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user