PR 10287
PR 11063 * i386.cc (class Target_i386): Change return type of plt_section to be non-const. (class Output_data_plt_i386): Add tls_desc_rel_ field. (Output_data_plt_i386::Output_data_plt_i386): Initialize tls_desc_rel_ field. (Output_data_plt_i386::rel_tls_desc): New function. (Target_i386::rel_tls_desc_section): New function. (Target_i386::Scan::local): Rewrite R_386_TLS_GOTDESC handling. (Target_i386::Scan::global): For R_386_TLS_GOTDESC put R_386_TLS_DESC reloc in rel_tls_desc_section. * x86_64.cc (class Target_x86_64): Add tlsdesc_reloc_info_ field. Define struct Tlsdesc_info. (Target_x86_64::Target_x86_64): Initialize tlsdesc_reloc_info_. (Target_x86_64::do_reloc_symbol_index): New function. (Target_x86_64::add_tlsdesc_info): New function. (class Output_data_plt_x86_64): Add tlsdesc_rel_ field. (Output_data_plt_x86_64::Output_data_plt_x86_64): Initialize tlsdesc_rel_ field. (Output_data_plt_x86_64::rela_plt): Rename from rel_plt. Change all callers. (Output_data_plt_x86_64::rela_tlsdesc): New function. (Target_x86_64::rela_tlsdesc_section): New function. (Target_x86_64::Scan::local): Rewrite R_X86_64_GOTPC32_TLSDESC handling. (Target_x86_64::Scan::global): For R_X86_64_GOTPC32_TLSDESC put (Target_x86_64::do_reloc_addend): New function. R_X86_64_TLSDESC reloc in rela_tlsdesc_section. * output.h (class Output_reloc) [SHT_REL]: Add new constructor declarations. Define TARGET_CODE. Add arg field to u1_ union. (Output_reloc::type): New function. (Output_reloc::is_local_section_symbol): Check for TARGET_CODE. (Output_reloc::is_target_specific): New function. (Output_reloc::target_arg): New function. (class Output_reloc) [SHT_RELA]: Add four new constructors for absolute relocs and target specific relocs. (class Output_data_reloc) [SHT_REL]: Add add_absolute and add_target_specific. (class Output_data_reloc) [SHT_RELA]: Likewise. * output.cc (Output_reloc::Output_reloc): Add four new versions for absolute relocs and target specific relocs. (Output_reloc::set_needs_dynsym_index): Add TARGET_CODE case. (Output_reloc::get_symbol_index): Likewise. (Output_reloc::local_section_offset): Check that local_sym_index_ is not TARGET_CODE or 0. (Output_reloc::symbol_value): Likewise. (Output_reloc::write) [SHT_RELA]: Call target for target specific reloc. * target.h (class Target): Add reloc_symbol_index and reloc_addend functions. Add do_reloc_symbol_index and do_reloc_addend virtual functions. * layout.cc (add_target_dynamic_tags): Use output section for DT_PLTRELSZ and DT_JMPREL.
This commit is contained in:
parent
dd35de7434
commit
e291e7b9c9
7 changed files with 477 additions and 47 deletions
|
@ -1,3 +1,60 @@
|
|||
2010-01-08 Ian Lance Taylor <iant@google.com>
|
||||
|
||||
PR 10287
|
||||
PR 11063
|
||||
* i386.cc (class Target_i386): Change return type of plt_section
|
||||
to be non-const.
|
||||
(class Output_data_plt_i386): Add tls_desc_rel_ field.
|
||||
(Output_data_plt_i386::Output_data_plt_i386): Initialize
|
||||
tls_desc_rel_ field.
|
||||
(Output_data_plt_i386::rel_tls_desc): New function.
|
||||
(Target_i386::rel_tls_desc_section): New function.
|
||||
(Target_i386::Scan::local): Rewrite R_386_TLS_GOTDESC handling.
|
||||
(Target_i386::Scan::global): For R_386_TLS_GOTDESC put
|
||||
R_386_TLS_DESC reloc in rel_tls_desc_section.
|
||||
* x86_64.cc (class Target_x86_64): Add tlsdesc_reloc_info_ field.
|
||||
Define struct Tlsdesc_info.
|
||||
(Target_x86_64::Target_x86_64): Initialize tlsdesc_reloc_info_.
|
||||
(Target_x86_64::do_reloc_symbol_index): New function.
|
||||
(Target_x86_64::add_tlsdesc_info): New function.
|
||||
(class Output_data_plt_x86_64): Add tlsdesc_rel_ field.
|
||||
(Output_data_plt_x86_64::Output_data_plt_x86_64): Initialize
|
||||
tlsdesc_rel_ field.
|
||||
(Output_data_plt_x86_64::rela_plt): Rename from rel_plt. Change
|
||||
all callers.
|
||||
(Output_data_plt_x86_64::rela_tlsdesc): New function.
|
||||
(Target_x86_64::rela_tlsdesc_section): New function.
|
||||
(Target_x86_64::Scan::local): Rewrite R_X86_64_GOTPC32_TLSDESC
|
||||
handling.
|
||||
(Target_x86_64::Scan::global): For R_X86_64_GOTPC32_TLSDESC put
|
||||
(Target_x86_64::do_reloc_addend): New function.
|
||||
R_X86_64_TLSDESC reloc in rela_tlsdesc_section.
|
||||
* output.h (class Output_reloc) [SHT_REL]: Add new constructor
|
||||
declarations. Define TARGET_CODE. Add arg field to u1_ union.
|
||||
(Output_reloc::type): New function.
|
||||
(Output_reloc::is_local_section_symbol): Check for TARGET_CODE.
|
||||
(Output_reloc::is_target_specific): New function.
|
||||
(Output_reloc::target_arg): New function.
|
||||
(class Output_reloc) [SHT_RELA]: Add four new constructors for
|
||||
absolute relocs and target specific relocs.
|
||||
(class Output_data_reloc) [SHT_REL]: Add add_absolute and
|
||||
add_target_specific.
|
||||
(class Output_data_reloc) [SHT_RELA]: Likewise.
|
||||
* output.cc (Output_reloc::Output_reloc): Add four new versions
|
||||
for absolute relocs and target specific relocs.
|
||||
(Output_reloc::set_needs_dynsym_index): Add TARGET_CODE case.
|
||||
(Output_reloc::get_symbol_index): Likewise.
|
||||
(Output_reloc::local_section_offset): Check that local_sym_index_
|
||||
is not TARGET_CODE or 0.
|
||||
(Output_reloc::symbol_value): Likewise.
|
||||
(Output_reloc::write) [SHT_RELA]: Call target for target specific
|
||||
reloc.
|
||||
* target.h (class Target): Add reloc_symbol_index and reloc_addend
|
||||
functions. Add do_reloc_symbol_index and do_reloc_addend virtual
|
||||
functions.
|
||||
* layout.cc (add_target_dynamic_tags): Use output section for
|
||||
DT_PLTRELSZ and DT_JMPREL.
|
||||
|
||||
2010-01-07 Ian Lance Taylor <iant@google.com>
|
||||
|
||||
PR 11061
|
||||
|
|
70
gold/i386.cc
70
gold/i386.cc
|
@ -368,7 +368,7 @@ class Target_i386 : public Target_freebsd<32, false>
|
|||
Sized_relobj<32, false>* object);
|
||||
|
||||
// Get the PLT section.
|
||||
const Output_data_plt_i386*
|
||||
Output_data_plt_i386*
|
||||
plt_section() const
|
||||
{
|
||||
gold_assert(this->plt_ != NULL);
|
||||
|
@ -379,6 +379,10 @@ class Target_i386 : public Target_freebsd<32, false>
|
|||
Reloc_section*
|
||||
rel_dyn_section(Layout*);
|
||||
|
||||
// Get the section to use for TLS_DESC relocations.
|
||||
Reloc_section*
|
||||
rel_tls_desc_section(Layout*) const;
|
||||
|
||||
// Add a potential copy relocation.
|
||||
void
|
||||
copy_reloc(Symbol_table* symtab, Layout* layout,
|
||||
|
@ -527,6 +531,10 @@ class Output_data_plt_i386 : public Output_section_data
|
|||
rel_plt() const
|
||||
{ return this->rel_; }
|
||||
|
||||
// Return where the TLS_DESC relocations should go.
|
||||
Reloc_section*
|
||||
rel_tls_desc(Layout*);
|
||||
|
||||
protected:
|
||||
void
|
||||
do_adjust_output_section(Output_section* os);
|
||||
|
@ -563,6 +571,9 @@ class Output_data_plt_i386 : public Output_section_data
|
|||
|
||||
// The reloc section.
|
||||
Reloc_section* rel_;
|
||||
// The TLS_DESC relocations, if necessary. These must follow the
|
||||
// regular PLT relocs.
|
||||
Reloc_section* tls_desc_rel_;
|
||||
// The .got.plt section.
|
||||
Output_data_space* got_plt_;
|
||||
// The number of PLT entries.
|
||||
|
@ -575,7 +586,7 @@ class Output_data_plt_i386 : public Output_section_data
|
|||
|
||||
Output_data_plt_i386::Output_data_plt_i386(Layout* layout,
|
||||
Output_data_space* got_plt)
|
||||
: Output_section_data(4), got_plt_(got_plt), count_(0)
|
||||
: Output_section_data(4), tls_desc_rel_(NULL), got_plt_(got_plt), count_(0)
|
||||
{
|
||||
this->rel_ = new Reloc_section(false);
|
||||
layout->add_output_section_data(".rel.plt", elfcpp::SHT_REL,
|
||||
|
@ -621,6 +632,24 @@ Output_data_plt_i386::add_entry(Symbol* gsym)
|
|||
// appear in the relocations.
|
||||
}
|
||||
|
||||
// Return where the TLS_DESC relocations should go, creating it if
|
||||
// necessary. These follow the JUMP_SLOT relocations.
|
||||
|
||||
Output_data_plt_i386::Reloc_section*
|
||||
Output_data_plt_i386::rel_tls_desc(Layout* layout)
|
||||
{
|
||||
if (this->tls_desc_rel_ == NULL)
|
||||
{
|
||||
this->tls_desc_rel_ = new Reloc_section(false);
|
||||
layout->add_output_section_data(".rel.plt", elfcpp::SHT_REL,
|
||||
elfcpp::SHF_ALLOC, this->tls_desc_rel_,
|
||||
true, false, false, false);
|
||||
gold_assert(this->tls_desc_rel_->output_section() ==
|
||||
this->rel_->output_section());
|
||||
}
|
||||
return this->tls_desc_rel_;
|
||||
}
|
||||
|
||||
// The first entry in the PLT for an executable.
|
||||
|
||||
unsigned char Output_data_plt_i386::exec_first_plt_entry[plt_entry_size] =
|
||||
|
@ -771,6 +800,14 @@ Target_i386::make_plt_entry(Symbol_table* symtab, Layout* layout, Symbol* gsym)
|
|||
this->plt_->add_entry(gsym);
|
||||
}
|
||||
|
||||
// Get the section to use for TLS_DESC relocations.
|
||||
|
||||
Target_i386::Reloc_section*
|
||||
Target_i386::rel_tls_desc_section(Layout* layout) const
|
||||
{
|
||||
return this->plt_section()->rel_tls_desc(layout);
|
||||
}
|
||||
|
||||
// Define the _TLS_MODULE_BASE_ symbol in the TLS segment.
|
||||
|
||||
void
|
||||
|
@ -1055,17 +1092,20 @@ Target_i386::Scan::local(Symbol_table* symtab,
|
|||
Output_data_got<32, false>* got
|
||||
= target->got_section(symtab, layout);
|
||||
unsigned int r_sym = elfcpp::elf_r_sym<32>(reloc.get_r_info());
|
||||
unsigned int shndx = lsym.get_st_shndx();
|
||||
bool is_ordinary;
|
||||
shndx = object->adjust_sym_shndx(r_sym, shndx, &is_ordinary);
|
||||
if (!is_ordinary)
|
||||
object->error(_("local symbol %u has bad shndx %u"),
|
||||
r_sym, shndx);
|
||||
else
|
||||
got->add_local_pair_with_rel(object, r_sym, shndx,
|
||||
GOT_TYPE_TLS_DESC,
|
||||
target->rel_dyn_section(layout),
|
||||
elfcpp::R_386_TLS_DESC, 0);
|
||||
if (!object->local_has_got_offset(r_sym, GOT_TYPE_TLS_DESC))
|
||||
{
|
||||
unsigned int got_offset = got->add_constant(0);
|
||||
// The local symbol value is stored in the second
|
||||
// GOT entry.
|
||||
got->add_local(object, r_sym, GOT_TYPE_TLS_DESC);
|
||||
// That set the GOT offset of the local symbol to
|
||||
// point to the second entry, but we want it to
|
||||
// point to the first.
|
||||
object->set_local_got_offset(r_sym, GOT_TYPE_TLS_DESC,
|
||||
got_offset);
|
||||
Reloc_section* rt = target->rel_tls_desc_section(layout);
|
||||
rt->add_absolute(elfcpp::R_386_TLS_DESC, got, got_offset);
|
||||
}
|
||||
}
|
||||
else if (optimized_type != tls::TLSOPT_TO_LE)
|
||||
unsupported_reloc_local(object, r_type);
|
||||
|
@ -1386,8 +1426,8 @@ Target_i386::Scan::global(Symbol_table* symtab,
|
|||
// Create a double GOT entry with an R_386_TLS_DESC reloc.
|
||||
Output_data_got<32, false>* got
|
||||
= target->got_section(symtab, layout);
|
||||
got->add_global_pair_with_rel(gsym, GOT_TYPE_TLS_DESC,
|
||||
target->rel_dyn_section(layout),
|
||||
Reloc_section* rt = target->rel_tls_desc_section(layout);
|
||||
got->add_global_pair_with_rel(gsym, GOT_TYPE_TLS_DESC, rt,
|
||||
elfcpp::R_386_TLS_DESC, 0);
|
||||
}
|
||||
else if (optimized_type == tls::TLSOPT_TO_IE)
|
||||
|
|
|
@ -3215,7 +3215,8 @@ Layout::create_interp(const Target* target)
|
|||
// If PLT_GOT is not NULL, then DT_PLTGOT points to it.
|
||||
|
||||
// If PLT_REL is not NULL, it is used for DT_PLTRELSZ, and DT_JMPREL,
|
||||
// and we also set DT_PLTREL.
|
||||
// and we also set DT_PLTREL. We use PLT_REL's output section, since
|
||||
// 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.
|
||||
|
@ -3238,8 +3239,8 @@ Layout::add_target_dynamic_tags(bool use_rel, const Output_data* plt_got,
|
|||
|
||||
if (plt_rel != NULL && plt_rel->output_section() != NULL)
|
||||
{
|
||||
odyn->add_section_size(elfcpp::DT_PLTRELSZ, plt_rel);
|
||||
odyn->add_section_address(elfcpp::DT_JMPREL, plt_rel);
|
||||
odyn->add_section_size(elfcpp::DT_PLTRELSZ, plt_rel->output_section());
|
||||
odyn->add_section_address(elfcpp::DT_JMPREL, plt_rel->output_section());
|
||||
odyn->add_constant(elfcpp::DT_PLTREL,
|
||||
use_rel ? elfcpp::DT_REL : elfcpp::DT_RELA);
|
||||
}
|
||||
|
|
|
@ -756,6 +756,72 @@ Output_reloc<elfcpp::SHT_REL, dynamic, size, big_endian>::Output_reloc(
|
|||
os->set_needs_symtab_index();
|
||||
}
|
||||
|
||||
// An absolute relocation.
|
||||
|
||||
template<bool dynamic, int size, bool big_endian>
|
||||
Output_reloc<elfcpp::SHT_REL, dynamic, size, big_endian>::Output_reloc(
|
||||
unsigned int type,
|
||||
Output_data* od,
|
||||
Address address)
|
||||
: address_(address), local_sym_index_(0), type_(type),
|
||||
is_relative_(false), is_section_symbol_(false), shndx_(INVALID_CODE)
|
||||
{
|
||||
// this->type_ is a bitfield; make sure TYPE fits.
|
||||
gold_assert(this->type_ == type);
|
||||
this->u1_.relobj = NULL;
|
||||
this->u2_.od = od;
|
||||
}
|
||||
|
||||
template<bool dynamic, int size, bool big_endian>
|
||||
Output_reloc<elfcpp::SHT_REL, dynamic, size, big_endian>::Output_reloc(
|
||||
unsigned int type,
|
||||
Sized_relobj<size, big_endian>* relobj,
|
||||
unsigned int shndx,
|
||||
Address address)
|
||||
: address_(address), local_sym_index_(0), type_(type),
|
||||
is_relative_(false), is_section_symbol_(false), shndx_(shndx)
|
||||
{
|
||||
gold_assert(shndx != INVALID_CODE);
|
||||
// this->type_ is a bitfield; make sure TYPE fits.
|
||||
gold_assert(this->type_ == type);
|
||||
this->u1_.relobj = NULL;
|
||||
this->u2_.relobj = relobj;
|
||||
}
|
||||
|
||||
// A target specific relocation.
|
||||
|
||||
template<bool dynamic, int size, bool big_endian>
|
||||
Output_reloc<elfcpp::SHT_REL, dynamic, size, big_endian>::Output_reloc(
|
||||
unsigned int type,
|
||||
void* arg,
|
||||
Output_data* od,
|
||||
Address address)
|
||||
: address_(address), local_sym_index_(TARGET_CODE), type_(type),
|
||||
is_relative_(false), is_section_symbol_(false), shndx_(INVALID_CODE)
|
||||
{
|
||||
// this->type_ is a bitfield; make sure TYPE fits.
|
||||
gold_assert(this->type_ == type);
|
||||
this->u1_.arg = arg;
|
||||
this->u2_.od = od;
|
||||
}
|
||||
|
||||
template<bool dynamic, int size, bool big_endian>
|
||||
Output_reloc<elfcpp::SHT_REL, dynamic, size, big_endian>::Output_reloc(
|
||||
unsigned int type,
|
||||
void* arg,
|
||||
Sized_relobj<size, big_endian>* relobj,
|
||||
unsigned int shndx,
|
||||
Address address)
|
||||
: address_(address), local_sym_index_(TARGET_CODE), type_(type),
|
||||
is_relative_(false), is_section_symbol_(false), shndx_(shndx)
|
||||
{
|
||||
gold_assert(shndx != INVALID_CODE);
|
||||
// this->type_ is a bitfield; make sure TYPE fits.
|
||||
gold_assert(this->type_ == type);
|
||||
this->u1_.arg = arg;
|
||||
this->u2_.relobj = relobj;
|
||||
}
|
||||
|
||||
// Record that we need a dynamic symbol index for this relocation.
|
||||
|
||||
template<bool dynamic, int size, bool big_endian>
|
||||
|
@ -778,6 +844,10 @@ set_needs_dynsym_index()
|
|||
this->u1_.os->set_needs_dynsym_index();
|
||||
break;
|
||||
|
||||
case TARGET_CODE:
|
||||
// The target must take care of this if necessary.
|
||||
break;
|
||||
|
||||
case 0:
|
||||
break;
|
||||
|
||||
|
@ -822,6 +892,11 @@ Output_reloc<elfcpp::SHT_REL, dynamic, size, big_endian>::get_symbol_index()
|
|||
index = this->u1_.os->symtab_index();
|
||||
break;
|
||||
|
||||
case TARGET_CODE:
|
||||
index = parameters->target().reloc_symbol_index(this->u1_.arg,
|
||||
this->type_);
|
||||
break;
|
||||
|
||||
case 0:
|
||||
// Relocations without symbols use a symbol index of 0.
|
||||
index = 0;
|
||||
|
@ -863,7 +938,9 @@ Output_reloc<elfcpp::SHT_REL, dynamic, size, big_endian>::
|
|||
{
|
||||
gold_assert(this->local_sym_index_ != GSYM_CODE
|
||||
&& this->local_sym_index_ != SECTION_CODE
|
||||
&& this->local_sym_index_ != TARGET_CODE
|
||||
&& this->local_sym_index_ != INVALID_CODE
|
||||
&& this->local_sym_index_ != 0
|
||||
&& this->is_section_symbol_);
|
||||
const unsigned int lsi = this->local_sym_index_;
|
||||
Output_section* os = this->u1_.relobj->output_section(lsi);
|
||||
|
@ -942,7 +1019,9 @@ Output_reloc<elfcpp::SHT_REL, dynamic, size, big_endian>::symbol_value(
|
|||
return sym->value() + addend;
|
||||
}
|
||||
gold_assert(this->local_sym_index_ != SECTION_CODE
|
||||
&& this->local_sym_index_ != TARGET_CODE
|
||||
&& this->local_sym_index_ != INVALID_CODE
|
||||
&& this->local_sym_index_ != 0
|
||||
&& !this->is_section_symbol_);
|
||||
const unsigned int lsi = this->local_sym_index_;
|
||||
const Symbol_value<size>* symval = this->u1_.relobj->local_symbol(lsi);
|
||||
|
@ -1010,7 +1089,10 @@ Output_reloc<elfcpp::SHT_RELA, dynamic, size, big_endian>::write(
|
|||
elfcpp::Rela_write<size, big_endian> orel(pov);
|
||||
this->rel_.write_rel(&orel);
|
||||
Addend addend = this->addend_;
|
||||
if (this->rel_.is_relative())
|
||||
if (this->rel_.is_target_specific())
|
||||
addend = parameters->target().reloc_addend(this->rel_.target_arg(),
|
||||
this->rel_.type(), addend);
|
||||
else if (this->rel_.is_relative())
|
||||
addend = this->rel_.symbol_value(addend);
|
||||
else if (this->rel_.is_local_section_symbol())
|
||||
addend = this->rel_.local_section_offset(addend);
|
||||
|
|
143
gold/output.h
143
gold/output.h
|
@ -1057,7 +1057,30 @@ class Output_reloc<elfcpp::SHT_REL, dynamic, size, big_endian>
|
|||
Sized_relobj<size, big_endian>* relobj,
|
||||
unsigned int shndx, Address address);
|
||||
|
||||
// Return TRUE if this is a RELATIVE relocation.
|
||||
// An absolute relocation with no symbol.
|
||||
|
||||
Output_reloc(unsigned int type, Output_data* od, Address address);
|
||||
|
||||
Output_reloc(unsigned int type, Sized_relobj<size, big_endian>* relobj,
|
||||
unsigned int shndx, Address address);
|
||||
|
||||
// A target specific relocation. The target will be called to get
|
||||
// the symbol index, passing ARG. The type and offset will be set
|
||||
// as for other relocation types.
|
||||
|
||||
Output_reloc(unsigned int type, void* arg, Output_data* od,
|
||||
Address address);
|
||||
|
||||
Output_reloc(unsigned int type, void* arg,
|
||||
Sized_relobj<size, big_endian>* relobj,
|
||||
unsigned int shndx, Address address);
|
||||
|
||||
// Return the reloc type.
|
||||
unsigned int
|
||||
type() const
|
||||
{ return this->type_; }
|
||||
|
||||
// Return whether this is a RELATIVE relocation.
|
||||
bool
|
||||
is_relative() const
|
||||
{ return this->is_relative_; }
|
||||
|
@ -1069,9 +1092,24 @@ class Output_reloc<elfcpp::SHT_REL, dynamic, size, big_endian>
|
|||
return (this->local_sym_index_ != GSYM_CODE
|
||||
&& this->local_sym_index_ != SECTION_CODE
|
||||
&& this->local_sym_index_ != INVALID_CODE
|
||||
&& this->local_sym_index_ != TARGET_CODE
|
||||
&& this->is_section_symbol_);
|
||||
}
|
||||
|
||||
// Return whether this is a target specific relocation.
|
||||
bool
|
||||
is_target_specific() const
|
||||
{ return this->local_sym_index_ == TARGET_CODE; }
|
||||
|
||||
// Return the argument to pass to the target for a target specific
|
||||
// relocation.
|
||||
void*
|
||||
target_arg() const
|
||||
{
|
||||
gold_assert(this->local_sym_index_ == TARGET_CODE);
|
||||
return this->u1_.arg;
|
||||
}
|
||||
|
||||
// For a local section symbol, return the offset of the input
|
||||
// section within the output section. ADDEND is the addend being
|
||||
// applied to the input section.
|
||||
|
@ -1124,8 +1162,10 @@ class Output_reloc<elfcpp::SHT_REL, dynamic, size, big_endian>
|
|||
GSYM_CODE = -1U,
|
||||
// Output section.
|
||||
SECTION_CODE = -2U,
|
||||
// Target specific.
|
||||
TARGET_CODE = -3U,
|
||||
// Invalid uninitialized entry.
|
||||
INVALID_CODE = -3U
|
||||
INVALID_CODE = -4U
|
||||
};
|
||||
|
||||
union
|
||||
|
@ -1143,6 +1183,9 @@ class Output_reloc<elfcpp::SHT_REL, dynamic, size, big_endian>
|
|||
// For a relocation against an output section
|
||||
// (this->local_sym_index_ == SECTION_CODE), the output section.
|
||||
Output_section* os;
|
||||
// For a target specific relocation, an argument to pass to the
|
||||
// target.
|
||||
void* arg;
|
||||
} u1_;
|
||||
union
|
||||
{
|
||||
|
@ -1157,11 +1200,12 @@ class Output_reloc<elfcpp::SHT_REL, dynamic, size, big_endian>
|
|||
// The address offset within the input section or the Output_data.
|
||||
Address address_;
|
||||
// This is GSYM_CODE for a global symbol, or SECTION_CODE for a
|
||||
// relocation against an output section, or INVALID_CODE for an
|
||||
// uninitialized value. Otherwise, for a local symbol
|
||||
// (this->is_section_symbol_ is false), the local symbol index. For
|
||||
// a local section symbol (this->is_section_symbol_ is true), the
|
||||
// section index in the input file.
|
||||
// relocation against an output section, or TARGET_CODE for a target
|
||||
// specific relocation, or INVALID_CODE for an uninitialized value.
|
||||
// Otherwise, for a local symbol (this->is_section_symbol_ is
|
||||
// false), the local symbol index. For a local section symbol
|
||||
// (this->is_section_symbol_ is true), the section index in the
|
||||
// input file.
|
||||
unsigned int local_sym_index_;
|
||||
// The reloc type--a processor specific code.
|
||||
unsigned int type_ : 30;
|
||||
|
@ -1237,7 +1281,34 @@ class Output_reloc<elfcpp::SHT_RELA, dynamic, size, big_endian>
|
|||
: rel_(os, type, relobj, shndx, address), addend_(addend)
|
||||
{ }
|
||||
|
||||
// Return TRUE if this is a RELATIVE relocation.
|
||||
// An absolute relocation with no symbol.
|
||||
|
||||
Output_reloc(unsigned int type, Output_data* od, Address address,
|
||||
Addend addend)
|
||||
: rel_(type, od, address), addend_(addend)
|
||||
{ }
|
||||
|
||||
Output_reloc(unsigned int type, Sized_relobj<size, big_endian>* relobj,
|
||||
unsigned int shndx, Address address, Addend addend)
|
||||
: rel_(type, relobj, shndx, address), addend_(addend)
|
||||
{ }
|
||||
|
||||
// A target specific relocation. The target will be called to get
|
||||
// the symbol index and the addend, passing ARG. The type and
|
||||
// offset will be set as for other relocation types.
|
||||
|
||||
Output_reloc(unsigned int type, void* arg, Output_data* od,
|
||||
Address address, Addend addend)
|
||||
: rel_(type, arg, od, address), addend_(addend)
|
||||
{ }
|
||||
|
||||
Output_reloc(unsigned int type, void* arg,
|
||||
Sized_relobj<size, big_endian>* relobj,
|
||||
unsigned int shndx, Address address, Addend addend)
|
||||
: rel_(type, arg, relobj, shndx, address), addend_(addend)
|
||||
{ }
|
||||
|
||||
// Return whether this is a RELATIVE relocation.
|
||||
bool
|
||||
is_relative() const
|
||||
{ return this->rel_.is_relative(); }
|
||||
|
@ -1519,6 +1590,32 @@ class Output_data_reloc<elfcpp::SHT_REL, dynamic, size, big_endian>
|
|||
Sized_relobj<size, big_endian>* relobj,
|
||||
unsigned int shndx, Address address)
|
||||
{ this->add(od, Output_reloc_type(os, type, relobj, shndx, address)); }
|
||||
|
||||
// Add an absolute relocation.
|
||||
|
||||
void
|
||||
add_absolute(unsigned int type, Output_data* od, Address address)
|
||||
{ this->add(od, Output_reloc_type(type, od, address)); }
|
||||
|
||||
void
|
||||
add_absolute(unsigned int type, Output_data* od,
|
||||
Sized_relobj<size, big_endian>* relobj,
|
||||
unsigned int shndx, Address address)
|
||||
{ this->add(od, Output_reloc_type(type, relobj, shndx, address)); }
|
||||
|
||||
// Add a target specific relocation. A target which calls this must
|
||||
// define the reloc_symbol_index and reloc_addend virtual functions.
|
||||
|
||||
void
|
||||
add_target_specific(unsigned int type, void* arg, Output_data* od,
|
||||
Address address)
|
||||
{ this->add(od, Output_reloc_type(type, arg, od, address)); }
|
||||
|
||||
void
|
||||
add_target_specific(unsigned int type, void* arg, Output_data* od,
|
||||
Sized_relobj<size, big_endian>* relobj,
|
||||
unsigned int shndx, Address address)
|
||||
{ this->add(od, Output_reloc_type(type, arg, relobj, shndx, address)); }
|
||||
};
|
||||
|
||||
// The SHT_RELA version of Output_data_reloc.
|
||||
|
@ -1651,6 +1748,36 @@ class Output_data_reloc<elfcpp::SHT_RELA, dynamic, size, big_endian>
|
|||
unsigned int shndx, Address address, Addend addend)
|
||||
{ this->add(os, Output_reloc_type(os, type, relobj, shndx, address,
|
||||
addend)); }
|
||||
|
||||
// Add an absolute relocation.
|
||||
|
||||
void
|
||||
add_absolute(unsigned int type, Output_data* od, Address address,
|
||||
Addend addend)
|
||||
{ this->add(od, Output_reloc_type(type, od, address, addend)); }
|
||||
|
||||
void
|
||||
add_absolute(unsigned int type, Output_data* od,
|
||||
Sized_relobj<size, big_endian>* relobj,
|
||||
unsigned int shndx, Address address, Addend addend)
|
||||
{ this->add(od, Output_reloc_type(type, relobj, shndx, address, addend)); }
|
||||
|
||||
// Add a target specific relocation. A target which calls this must
|
||||
// define the reloc_symbol_index and reloc_addend virtual functions.
|
||||
|
||||
void
|
||||
add_target_specific(unsigned int type, void* arg, Output_data* od,
|
||||
Address address, Addend addend)
|
||||
{ this->add(od, Output_reloc_type(type, arg, od, address, addend)); }
|
||||
|
||||
void
|
||||
add_target_specific(unsigned int type, void* arg, Output_data* od,
|
||||
Sized_relobj<size, big_endian>* relobj,
|
||||
unsigned int shndx, Address address, Addend addend)
|
||||
{
|
||||
this->add(od, Output_reloc_type(type, arg, relobj, shndx, address,
|
||||
addend));
|
||||
}
|
||||
};
|
||||
|
||||
// Output_relocatable_relocs represents a relocation section in a
|
||||
|
|
|
@ -230,6 +230,16 @@ class Target
|
|||
is_local_label_name(const char* name) const
|
||||
{ return this->do_is_local_label_name(name); }
|
||||
|
||||
// Get the symbol index to use for a target specific reloc.
|
||||
unsigned int
|
||||
reloc_symbol_index(void* arg, unsigned int type) const
|
||||
{ return this->do_reloc_symbol_index(arg, type); }
|
||||
|
||||
// Get the addend to use for a target specific reloc.
|
||||
uint64_t
|
||||
reloc_addend(void* arg, unsigned int type, uint64_t addend) const
|
||||
{ return this->do_reloc_addend(arg, type, addend); }
|
||||
|
||||
// A function starts at OFFSET in section SHNDX in OBJECT. That
|
||||
// function was compiled with -fsplit-stack, but it refers to a
|
||||
// function which was compiled without -fsplit-stack. VIEW is a
|
||||
|
@ -405,6 +415,18 @@ class Target
|
|||
virtual bool
|
||||
do_is_local_label_name(const char*) const;
|
||||
|
||||
// Virtual function that must be overridden by a target which uses
|
||||
// target specific relocations.
|
||||
virtual unsigned int
|
||||
do_reloc_symbol_index(void*, unsigned int) const
|
||||
{ gold_unreachable(); }
|
||||
|
||||
// Virtual function that must be overidden by a target which uses
|
||||
// target specific relocations.
|
||||
virtual uint64_t
|
||||
do_reloc_addend(void*, unsigned int, uint64_t) const
|
||||
{ gold_unreachable(); }
|
||||
|
||||
// Virtual function which may be overridden by the child class.
|
||||
virtual void
|
||||
do_calls_non_split(Relobj* object, unsigned int, section_offset_type,
|
||||
|
|
141
gold/x86_64.cc
141
gold/x86_64.cc
|
@ -65,7 +65,8 @@ class Target_x86_64 : public Target_freebsd<64, false>
|
|||
: Target_freebsd<64, false>(&x86_64_info),
|
||||
got_(NULL), plt_(NULL), got_plt_(NULL), global_offset_table_(NULL),
|
||||
rela_dyn_(NULL), copy_relocs_(elfcpp::R_X86_64_COPY), dynbss_(NULL),
|
||||
got_mod_index_offset_(-1U), tls_base_symbol_defined_(false)
|
||||
got_mod_index_offset_(-1U), tlsdesc_reloc_info_(),
|
||||
tls_base_symbol_defined_(false)
|
||||
{ }
|
||||
|
||||
// Hook for a new output section.
|
||||
|
@ -161,6 +162,20 @@ class Target_x86_64 : public Target_freebsd<64, false>
|
|||
do_is_defined_by_abi(const Symbol* sym) const
|
||||
{ return strcmp(sym->name(), "__tls_get_addr") == 0; }
|
||||
|
||||
// Return the symbol index to use for a target specific relocation.
|
||||
// The only target specific relocation is R_X86_64_TLSDESC for a
|
||||
// local symbol, which is an absolute reloc.
|
||||
unsigned int
|
||||
do_reloc_symbol_index(void*, unsigned int r_type) const
|
||||
{
|
||||
gold_assert(r_type == elfcpp::R_X86_64_TLSDESC);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Return the addend to use for a target specific relocation.
|
||||
uint64_t
|
||||
do_reloc_addend(void* arg, unsigned int r_type, uint64_t addend) const;
|
||||
|
||||
// Adjust -fstack-split code which calls non-stack-split code.
|
||||
void
|
||||
do_calls_non_split(Relobj* object, unsigned int shndx,
|
||||
|
@ -176,6 +191,14 @@ class Target_x86_64 : public Target_freebsd<64, false>
|
|||
return this->got_->data_size();
|
||||
}
|
||||
|
||||
// Add a new reloc argument, returning the index in the vector.
|
||||
size_t
|
||||
add_tlsdesc_info(Sized_relobj<64, false>* object, unsigned int r_sym)
|
||||
{
|
||||
this->tlsdesc_reloc_info_.push_back(Tlsdesc_info(object, r_sym));
|
||||
return this->tlsdesc_reloc_info_.size() - 1;
|
||||
}
|
||||
|
||||
private:
|
||||
// The class which scans relocations.
|
||||
class Scan
|
||||
|
@ -379,6 +402,10 @@ class Target_x86_64 : public Target_freebsd<64, false>
|
|||
Reloc_section*
|
||||
rela_dyn_section(Layout*);
|
||||
|
||||
// Get the section to use for TLSDESC relocations.
|
||||
Reloc_section*
|
||||
rela_tlsdesc_section(Layout*) const;
|
||||
|
||||
// Add a potential copy relocation.
|
||||
void
|
||||
copy_reloc(Symbol_table* symtab, Layout* layout,
|
||||
|
@ -404,6 +431,21 @@ class Target_x86_64 : public Target_freebsd<64, false>
|
|||
GOT_TYPE_TLS_DESC = 3 // GOT entry for TLS_DESC pair
|
||||
};
|
||||
|
||||
// This type is used as the argument to the target specific
|
||||
// relocation routines. The only target specific reloc is
|
||||
// R_X86_64_TLSDESC against a local symbol.
|
||||
struct Tlsdesc_info
|
||||
{
|
||||
Tlsdesc_info(Sized_relobj<64, false>* a_object, unsigned int a_r_sym)
|
||||
: object(a_object), r_sym(a_r_sym)
|
||||
{ }
|
||||
|
||||
// The object in which the local symbol is defined.
|
||||
Sized_relobj<64, false>* object;
|
||||
// The local symbol index in the object.
|
||||
unsigned int r_sym;
|
||||
};
|
||||
|
||||
// The GOT section.
|
||||
Output_data_got<64, false>* got_;
|
||||
// The PLT section.
|
||||
|
@ -420,6 +462,10 @@ class Target_x86_64 : public Target_freebsd<64, false>
|
|||
Output_data_space* dynbss_;
|
||||
// Offset of the GOT entry for the TLS module index.
|
||||
unsigned int got_mod_index_offset_;
|
||||
// We handle R_X86_64_TLSDESC against a local symbol as a target
|
||||
// specific relocation. Here we store the object and local symbol
|
||||
// index for the relocation.
|
||||
std::vector<Tlsdesc_info> tlsdesc_reloc_info_;
|
||||
// True if the _TLS_MODULE_BASE_ symbol has been defined.
|
||||
bool tls_base_symbol_defined_;
|
||||
};
|
||||
|
@ -551,11 +597,15 @@ class Output_data_plt_x86_64 : public Output_section_data
|
|||
get_tlsdesc_plt_offset() const
|
||||
{ return (this->count_ + 1) * plt_entry_size; }
|
||||
|
||||
// Return the .rel.plt section data.
|
||||
// Return the .rela.plt section data.
|
||||
const Reloc_section*
|
||||
rel_plt() const
|
||||
rela_plt() const
|
||||
{ return this->rel_; }
|
||||
|
||||
// Return where the TLSDESC relocations should go.
|
||||
Reloc_section*
|
||||
rela_tlsdesc(Layout*);
|
||||
|
||||
protected:
|
||||
void
|
||||
do_adjust_output_section(Output_section* os);
|
||||
|
@ -590,6 +640,9 @@ class Output_data_plt_x86_64 : public Output_section_data
|
|||
|
||||
// The reloc section.
|
||||
Reloc_section* rel_;
|
||||
// The TLSDESC relocs, if necessary. These must follow the regular
|
||||
// PLT relocs.
|
||||
Reloc_section* tlsdesc_rel_;
|
||||
// The .got section.
|
||||
Output_data_got<64, false>* got_;
|
||||
// The .got.plt section.
|
||||
|
@ -607,8 +660,8 @@ class Output_data_plt_x86_64 : public Output_section_data
|
|||
Output_data_plt_x86_64::Output_data_plt_x86_64(Layout* layout,
|
||||
Output_data_got<64, false>* got,
|
||||
Output_data_space* got_plt)
|
||||
: Output_section_data(8), got_(got), got_plt_(got_plt), count_(0),
|
||||
tlsdesc_got_offset_(-1U)
|
||||
: Output_section_data(8), tlsdesc_rel_(NULL), got_(got), got_plt_(got_plt),
|
||||
count_(0), tlsdesc_got_offset_(-1U)
|
||||
{
|
||||
this->rel_ = new Reloc_section(false);
|
||||
layout->add_output_section_data(".rela.plt", elfcpp::SHT_RELA,
|
||||
|
@ -652,6 +705,24 @@ Output_data_plt_x86_64::add_entry(Symbol* gsym)
|
|||
// appear in the relocations.
|
||||
}
|
||||
|
||||
// Return where the TLSDESC relocations should go, creating it if
|
||||
// necessary. These follow the JUMP_SLOT relocations.
|
||||
|
||||
Output_data_plt_x86_64::Reloc_section*
|
||||
Output_data_plt_x86_64::rela_tlsdesc(Layout* layout)
|
||||
{
|
||||
if (this->tlsdesc_rel_ == NULL)
|
||||
{
|
||||
this->tlsdesc_rel_ = new Reloc_section(false);
|
||||
layout->add_output_section_data(".rela.plt", elfcpp::SHT_RELA,
|
||||
elfcpp::SHF_ALLOC, this->tlsdesc_rel_,
|
||||
true, false, false, false);
|
||||
gold_assert(this->tlsdesc_rel_->output_section() ==
|
||||
this->rel_->output_section());
|
||||
}
|
||||
return this->tlsdesc_rel_;
|
||||
}
|
||||
|
||||
// Set the final size.
|
||||
void
|
||||
Output_data_plt_x86_64::set_final_data_size()
|
||||
|
@ -813,6 +884,14 @@ Target_x86_64::make_plt_section(Symbol_table* symtab, Layout* layout)
|
|||
}
|
||||
}
|
||||
|
||||
// Return the section for TLSDESC relocations.
|
||||
|
||||
Target_x86_64::Reloc_section*
|
||||
Target_x86_64::rela_tlsdesc_section(Layout* layout) const
|
||||
{
|
||||
return this->plt_section()->rela_tlsdesc(layout);
|
||||
}
|
||||
|
||||
// Create a PLT entry for a global symbol.
|
||||
|
||||
void
|
||||
|
@ -1199,18 +1278,21 @@ Target_x86_64::Scan::local(Symbol_table* symtab,
|
|||
Output_data_got<64, false>* got
|
||||
= target->got_section(symtab, layout);
|
||||
unsigned int r_sym = elfcpp::elf_r_sym<64>(reloc.get_r_info());
|
||||
unsigned int shndx = lsym.get_st_shndx();
|
||||
bool is_ordinary;
|
||||
shndx = object->adjust_sym_shndx(r_sym, shndx, &is_ordinary);
|
||||
if (!is_ordinary)
|
||||
object->error(_("local symbol %u has bad shndx %u"),
|
||||
r_sym, shndx);
|
||||
else
|
||||
got->add_local_pair_with_rela(object, r_sym,
|
||||
shndx,
|
||||
GOT_TYPE_TLS_DESC,
|
||||
target->rela_dyn_section(layout),
|
||||
elfcpp::R_X86_64_TLSDESC, 0);
|
||||
if (!object->local_has_got_offset(r_sym, GOT_TYPE_TLS_DESC))
|
||||
{
|
||||
unsigned int got_offset = got->add_constant(0);
|
||||
got->add_constant(0);
|
||||
object->set_local_got_offset(r_sym, GOT_TYPE_TLS_DESC,
|
||||
got_offset);
|
||||
Reloc_section* rt = target->rela_tlsdesc_section(layout);
|
||||
// We store the arguments we need in a vector, and
|
||||
// use the index into the vector as the parameter
|
||||
// to pass to the target specific routines.
|
||||
uintptr_t intarg = target->add_tlsdesc_info(object, r_sym);
|
||||
void* arg = reinterpret_cast<void*>(intarg);
|
||||
rt->add_target_specific(elfcpp::R_X86_64_TLSDESC, arg,
|
||||
got, got_offset, 0);
|
||||
}
|
||||
}
|
||||
else if (optimized_type != tls::TLSOPT_TO_LE)
|
||||
unsupported_reloc_local(object, r_type);
|
||||
|
@ -1505,8 +1587,8 @@ Target_x86_64::Scan::global(Symbol_table* symtab,
|
|||
// Create a double GOT entry with an R_X86_64_TLSDESC reloc.
|
||||
Output_data_got<64, false>* got
|
||||
= target->got_section(symtab, layout);
|
||||
got->add_global_pair_with_rela(gsym, GOT_TYPE_TLS_DESC,
|
||||
target->rela_dyn_section(layout),
|
||||
Reloc_section *rt = target->rela_tlsdesc_section(layout);
|
||||
got->add_global_pair_with_rela(gsym, GOT_TYPE_TLS_DESC, rt,
|
||||
elfcpp::R_X86_64_TLSDESC, 0);
|
||||
}
|
||||
else if (optimized_type == tls::TLSOPT_TO_IE)
|
||||
|
@ -1657,7 +1739,7 @@ Target_x86_64::do_finalize_sections(
|
|||
{
|
||||
const Reloc_section* rel_plt = (this->plt_ == NULL
|
||||
? NULL
|
||||
: this->plt_->rel_plt());
|
||||
: this->plt_->rela_plt());
|
||||
layout->add_target_dynamic_tags(false, this->got_plt_, rel_plt,
|
||||
this->rela_dyn_, true);
|
||||
|
||||
|
@ -2658,6 +2740,25 @@ Target_x86_64::do_code_fill(section_size_type length) const
|
|||
return std::string(nops[length], length);
|
||||
}
|
||||
|
||||
// Return the addend to use for a target specific relocation. The
|
||||
// only target specific relocation is R_X86_64_TLSDESC for a local
|
||||
// symbol. We want to set the addend is the offset of the local
|
||||
// symbol in the TLS segment.
|
||||
|
||||
uint64_t
|
||||
Target_x86_64::do_reloc_addend(void* arg, unsigned int r_type,
|
||||
uint64_t) const
|
||||
{
|
||||
gold_assert(r_type == elfcpp::R_X86_64_TLSDESC);
|
||||
uintptr_t intarg = reinterpret_cast<uintptr_t>(arg);
|
||||
gold_assert(intarg < this->tlsdesc_reloc_info_.size());
|
||||
const Tlsdesc_info& ti(this->tlsdesc_reloc_info_[intarg]);
|
||||
const Symbol_value<64>* psymval = ti.object->local_symbol(ti.r_sym);
|
||||
gold_assert(psymval->is_tls_symbol());
|
||||
// The value of a TLS symbol is the offset in the TLS segment.
|
||||
return psymval->value(ti.object, 0);
|
||||
}
|
||||
|
||||
// FNOFFSET in section SHNDX in OBJECT is the start of a function
|
||||
// compiled with -fstack-split. The function calls non-stack-split
|
||||
// code. We have to change the function so that it always ensures
|
||||
|
|
Loading…
Reference in a new issue