2010-02-18 Doug Kwan <dougkwan@google.com>

* arm-reloc.def: Mark R_ARM_TLS_GD32, R_ARM_TLS_LDM32,
	R_ARM_TLS_LDO32, R_ARM_TLS_IE32 and R_ARM_TLS_LE32 are implemented.
	* arm.cc (Arm_relocation_functions): New forward declaration.
	(Target_arm::Target_arm): Initialize new data members
	got_mod_index_offset_ and tls_base_symbol_defined_.
	(Target_arm::Relocate::relocate_tls): New method.
	(Target_arm::optimize_tls_reloc, Target_arm::define_tls_base_symbol,
	 Target_arm::got_mod_index_entry, Target_arm::rel_tls_desc_section):
	New methods.
   	(Target_arm::Got_type): Add GOT_TYPE_TLS_NOFFSET, GOT_TYPE_OFFSET,
	GOT_TYPE_TLS_PAIR and GOT_TYPE_TLS_DESC.
	(Target_arm::got_mod_index_offset_,
	Target_arm::tls_base_symbol_defined_): New data members.
	(Target_arm::Scan::local, Target::Scan::global,
	Target_arm::Relocate::relocate): Handle 32-bit initial TLS
	relocations.
This commit is contained in:
Doug Kwan 2010-02-19 22:53:54 +00:00
parent 48ea67a755
commit f96accdf2b
3 changed files with 448 additions and 12 deletions

View file

@ -1,3 +1,22 @@
2010-02-19 Doug Kwan <dougkwan@google.com>
* arm-reloc.def: Mark R_ARM_TLS_GD32, R_ARM_TLS_LDM32,
R_ARM_TLS_LDO32, R_ARM_TLS_IE32 and R_ARM_TLS_LE32 are implemented.
* arm.cc (Arm_relocation_functions): New forward declaration.
(Target_arm::Target_arm): Initialize new data members
got_mod_index_offset_ and tls_base_symbol_defined_.
(Target_arm::Relocate::relocate_tls): New method.
(Target_arm::optimize_tls_reloc, Target_arm::define_tls_base_symbol,
Target_arm::got_mod_index_entry, Target_arm::rel_tls_desc_section):
New methods.
(Target_arm::Got_type): Add GOT_TYPE_TLS_NOFFSET, GOT_TYPE_OFFSET,
GOT_TYPE_TLS_PAIR and GOT_TYPE_TLS_DESC.
(Target_arm::got_mod_index_offset_,
Target_arm::tls_base_symbol_defined_): New data members.
(Target_arm::Scan::local, Target::Scan::global,
Target_arm::Relocate::relocate): Handle 32-bit initial TLS
relocations.
2010-02-18 Doug Kwan <dougkwan@google.com>
* arm.cc (Arm_relobj::find_linked_text_section): New method.

View file

@ -165,11 +165,11 @@ RD(GNU_VTENTRY , STATIC , Y, DATA , NONE , Y, -1, N)
RD(GNU_VTINHERIT , STATIC , Y, DATA , NONE , Y, -1, N)
RD(THM_JUMP11 , STATIC , N, THM16, S + A - P , Y, -1, Y)
RD(THM_JUMP8 , STATIC , N, THM16, S + A - P , Y, -1, Y)
RD(TLS_GD32 , STATIC , N, DATA , GOT(S) + A - P , N, -1, N)
RD(TLS_LDM32 , STATIC , N, DATA , GOT(S) + A - P , N, -1, N)
RD(TLS_LDO32 , STATIC , N, DATA , S + A - TLS , N, -1, N)
RD(TLS_IE32 , STATIC , N, DATA , GOT(S) + A - P , N, -1, N)
RD(TLS_LE32 , STATIC , N, DATA , S + A - tp , N, -1, N)
RD(TLS_GD32 , STATIC , N, DATA , GOT(S) + A - P , Y, -1, N)
RD(TLS_LDM32 , STATIC , N, DATA , GOT(S) + A - P , Y, -1, N)
RD(TLS_LDO32 , STATIC , N, DATA , S + A - TLS , Y, -1, N)
RD(TLS_IE32 , STATIC , N, DATA , GOT(S) + A - P , Y, -1, N)
RD(TLS_LE32 , STATIC , N, DATA , S + A - tp , Y, -1, N)
RD(TLS_LDO12 , STATIC , N, ARM , S + A - TLS , N, -1, Y)
RD(TLS_LE12 , STATIC , N, ARM , S + A - tp , N, -1, Y)
RD(TLS_IE12GP , STATIC , N, ARM , GOT(S) + A - GOT_ORG , N, -1, Y)

View file

@ -80,6 +80,9 @@ class Arm_exidx_input_section;
template<bool big_endian>
class Arm_relobj;
template<bool big_endian>
class Arm_relocate_functions;
template<bool big_endian>
class Target_arm;
@ -1847,11 +1850,12 @@ class Target_arm : public Sized_target<32, big_endian>
Target_arm()
: Sized_target<32, big_endian>(&arm_info),
got_(NULL), plt_(NULL), got_plt_(NULL), rel_dyn_(NULL),
copy_relocs_(elfcpp::R_ARM_COPY), dynbss_(NULL), stub_tables_(),
stub_factory_(Stub_factory::get_instance()), may_use_blx_(false),
should_force_pic_veneer_(false), arm_input_section_map_(),
attributes_section_data_(NULL), fix_cortex_a8_(false),
cortex_a8_relocs_info_()
copy_relocs_(elfcpp::R_ARM_COPY), dynbss_(NULL),
got_mod_index_offset_(-1U), tls_base_symbol_defined_(false),
stub_tables_(), stub_factory_(Stub_factory::get_instance()),
may_use_blx_(false), should_force_pic_veneer_(false),
arm_input_section_map_(), attributes_section_data_(NULL),
fix_cortex_a8_(false), cortex_a8_relocs_info_()
{ }
// Whether we can use BLX.
@ -2301,6 +2305,16 @@ class Target_arm : public Sized_target<32, big_endian>
return true;
}
}
private:
// Do a TLS relocation.
inline typename Arm_relocate_functions<big_endian>::Status
relocate_tls(const Relocate_info<32, big_endian>*, Target_arm<big_endian>*,
size_t, const elfcpp::Rel<32, big_endian>&, unsigned int,
const Sized_symbol<32>*, const Symbol_value<32>*,
unsigned char*, elfcpp::Elf_types<32>::Elf_Addr,
section_size_type);
};
// A class which returns the size required for a relocation type,
@ -2312,6 +2326,11 @@ class Target_arm : public Sized_target<32, big_endian>
get_size_for_reloc(unsigned int, Relobj*);
};
// Adjust TLS relocation type based on the options and whether this
// is a local symbol.
static tls::Tls_optimization
optimize_tls_reloc(bool is_final, int r_type);
// Get the GOT section, creating it if necessary.
Output_data_got<32, big_endian>*
got_section(Symbol_table*, Layout*);
@ -2328,6 +2347,15 @@ class Target_arm : public Sized_target<32, big_endian>
void
make_plt_entry(Symbol_table*, Layout*, Symbol*);
// Define the _TLS_MODULE_BASE_ symbol in the TLS segment.
void
define_tls_base_symbol(Symbol_table*, Layout*);
// Create a GOT entry for the TLS module index.
unsigned int
got_mod_index_entry(Symbol_table* symtab, Layout* layout,
Sized_relobj<32, big_endian>* object);
// Get the PLT section.
const Output_data_plt_arm<big_endian>*
plt_section() const
@ -2340,6 +2368,10 @@ class Target_arm : public Sized_target<32, big_endian>
Reloc_section*
rel_dyn_section(Layout*);
// Get the section to use for TLS_DESC relocations.
Reloc_section*
rel_tls_desc_section(Layout*) const;
// Return true if the symbol may need a COPY relocation.
// References from an executable object to non-function symbols
// defined in a dynamic object may need a COPY relocation.
@ -2454,7 +2486,11 @@ class Target_arm : public Sized_target<32, big_endian>
// The types of GOT entries needed for this platform.
enum Got_type
{
GOT_TYPE_STANDARD = 0 // GOT entry for a regular symbol
GOT_TYPE_STANDARD = 0, // GOT entry for a regular symbol
GOT_TYPE_TLS_NOFFSET = 1, // GOT entry for negative TLS offset
GOT_TYPE_TLS_OFFSET = 2, // GOT entry for positive TLS offset
GOT_TYPE_TLS_PAIR = 3, // GOT entry for TLS module/offset pair
GOT_TYPE_TLS_DESC = 4 // GOT entry for TLS_DESC pair
};
typedef typename std::vector<Stub_table<big_endian>*> Stub_table_list;
@ -2481,6 +2517,10 @@ class Target_arm : public Sized_target<32, big_endian>
Copy_relocs<elfcpp::SHT_REL, 32, big_endian> copy_relocs_;
// Space for variables copied with a COPY reloc.
Output_data_space* dynbss_;
// Offset of the GOT entry for the TLS module index.
unsigned int got_mod_index_offset_;
// True if the _TLS_MODULE_BASE_ symbol has been defined.
bool tls_base_symbol_defined_;
// Vector of Stub_tables created.
Stub_table_list stub_tables_;
// Stub factory.
@ -6673,6 +6713,79 @@ Target_arm<big_endian>::make_plt_entry(Symbol_table* symtab, Layout* layout,
this->plt_->add_entry(gsym);
}
// Get the section to use for TLS_DESC relocations.
template<bool big_endian>
typename Target_arm<big_endian>::Reloc_section*
Target_arm<big_endian>::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.
template<bool big_endian>
void
Target_arm<big_endian>::define_tls_base_symbol(
Symbol_table* symtab,
Layout* layout)
{
if (this->tls_base_symbol_defined_)
return;
Output_segment* tls_segment = layout->tls_segment();
if (tls_segment != NULL)
{
bool is_exec = parameters->options().output_is_executable();
symtab->define_in_output_segment("_TLS_MODULE_BASE_", NULL,
Symbol_table::PREDEFINED,
tls_segment, 0, 0,
elfcpp::STT_TLS,
elfcpp::STB_LOCAL,
elfcpp::STV_HIDDEN, 0,
(is_exec
? Symbol::SEGMENT_END
: Symbol::SEGMENT_START),
true);
}
this->tls_base_symbol_defined_ = true;
}
// Create a GOT entry for the TLS module index.
template<bool big_endian>
unsigned int
Target_arm<big_endian>::got_mod_index_entry(
Symbol_table* symtab,
Layout* layout,
Sized_relobj<32, big_endian>* object)
{
if (this->got_mod_index_offset_ == -1U)
{
gold_assert(symtab != NULL && layout != NULL && object != NULL);
Reloc_section* rel_dyn = this->rel_dyn_section(layout);
Output_data_got<32, big_endian>* got = this->got_section(symtab, layout);
unsigned int got_offset = got->add_constant(0);
rel_dyn->add_local(object, 0, elfcpp::R_ARM_TLS_DTPMOD32, got,
got_offset);
got->add_constant(0);
this->got_mod_index_offset_ = got_offset;
}
return this->got_mod_index_offset_;
}
// Optimize the TLS relocation type based on what we know about the
// symbol. IS_FINAL is true if the final address of this symbol is
// known at link time.
template<bool big_endian>
tls::Tls_optimization
Target_arm<big_endian>::optimize_tls_reloc(bool, int)
{
// FIXME: Currently we do not do any TLS optimization.
return tls::TLSOPT_NONE;
}
// Report an unsupported relocation against a local symbol.
template<bool big_endian>
@ -6929,6 +7042,97 @@ Target_arm<big_endian>::Scan::local(Symbol_table* symtab,
object->name().c_str(), r_type);
break;
// These are initial TLS relocs, which are expected when
// linking.
case elfcpp::R_ARM_TLS_GD32: // Global-dynamic
case elfcpp::R_ARM_TLS_LDM32: // Local-dynamic
case elfcpp::R_ARM_TLS_LDO32: // Alternate local-dynamic
case elfcpp::R_ARM_TLS_IE32: // Initial-exec
case elfcpp::R_ARM_TLS_LE32: // Local-exec
{
bool output_is_shared = parameters->options().shared();
const tls::Tls_optimization optimized_type
= Target_arm<big_endian>::optimize_tls_reloc(!output_is_shared,
r_type);
switch (r_type)
{
case elfcpp::R_ARM_TLS_GD32: // Global-dynamic
if (optimized_type == tls::TLSOPT_NONE)
{
// Create a pair of GOT entries for the module index and
// dtv-relative offset.
Output_data_got<32, big_endian>* 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_PAIR,
target->rel_dyn_section(layout),
elfcpp::R_ARM_TLS_DTPMOD32, 0);
}
else
// FIXME: TLS optimization not supported yet.
gold_unreachable();
break;
case elfcpp::R_ARM_TLS_LDM32: // Local-dynamic
if (optimized_type == tls::TLSOPT_NONE)
{
// Create a GOT entry for the module index.
target->got_mod_index_entry(symtab, layout, object);
}
else
// FIXME: TLS optimization not supported yet.
gold_unreachable();
break;
case elfcpp::R_ARM_TLS_LDO32: // Alternate local-dynamic
break;
case elfcpp::R_ARM_TLS_IE32: // Initial-exec
layout->set_has_static_tls();
if (optimized_type == tls::TLSOPT_NONE)
{
// Create a GOT entry for the tp-relative offset.
Output_data_got<32, big_endian>* got
= target->got_section(symtab, layout);
unsigned int r_sym = elfcpp::elf_r_sym<32>(reloc.get_r_info());
got->add_local_with_rel(object, r_sym, GOT_TYPE_TLS_OFFSET,
target->rel_dyn_section(layout),
elfcpp::R_ARM_TLS_TPOFF32);
}
else
// FIXME: TLS optimization not supported yet.
gold_unreachable();
break;
case elfcpp::R_ARM_TLS_LE32: // Local-exec
layout->set_has_static_tls();
if (output_is_shared)
{
// We need to create a dynamic relocation.
gold_assert(lsym.get_st_type() != elfcpp::STT_SECTION);
unsigned int r_sym = elfcpp::elf_r_sym<32>(reloc.get_r_info());
Reloc_section* rel_dyn = target->rel_dyn_section(layout);
rel_dyn->add_local(object, r_sym, elfcpp::R_ARM_TLS_TPOFF32,
output_section, data_shndx,
reloc.get_r_offset());
}
break;
default:
gold_unreachable();
}
}
break;
default:
unsupported_reloc_local(object, r_type);
break;
@ -7185,6 +7389,84 @@ Target_arm<big_endian>::Scan::global(Symbol_table* symtab,
object->name().c_str(), r_type);
break;
// These are initial tls relocs, which are expected when
// linking.
case elfcpp::R_ARM_TLS_GD32: // Global-dynamic
case elfcpp::R_ARM_TLS_LDM32: // Local-dynamic
case elfcpp::R_ARM_TLS_LDO32: // Alternate local-dynamic
case elfcpp::R_ARM_TLS_IE32: // Initial-exec
case elfcpp::R_ARM_TLS_LE32: // Local-exec
{
const bool is_final = gsym->final_value_is_known();
const tls::Tls_optimization optimized_type
= Target_arm<big_endian>::optimize_tls_reloc(is_final, r_type);
switch (r_type)
{
case elfcpp::R_ARM_TLS_GD32: // Global-dynamic
if (optimized_type == tls::TLSOPT_NONE)
{
// Create a pair of GOT entries for the module index and
// dtv-relative offset.
Output_data_got<32, big_endian>* got
= target->got_section(symtab, layout);
got->add_global_pair_with_rel(gsym, GOT_TYPE_TLS_PAIR,
target->rel_dyn_section(layout),
elfcpp::R_ARM_TLS_DTPMOD32,
elfcpp::R_ARM_TLS_DTPOFF32);
}
else
// FIXME: TLS optimization not supported yet.
gold_unreachable();
break;
case elfcpp::R_ARM_TLS_LDM32: // Local-dynamic
if (optimized_type == tls::TLSOPT_NONE)
{
// Create a GOT entry for the module index.
target->got_mod_index_entry(symtab, layout, object);
}
else
// FIXME: TLS optimization not supported yet.
gold_unreachable();
break;
case elfcpp::R_ARM_TLS_LDO32: // Alternate local-dynamic
break;
case elfcpp::R_ARM_TLS_IE32: // Initial-exec
layout->set_has_static_tls();
if (optimized_type == tls::TLSOPT_NONE)
{
// Create a GOT entry for the tp-relative offset.
Output_data_got<32, big_endian>* got
= target->got_section(symtab, layout);
got->add_global_with_rel(gsym, GOT_TYPE_TLS_OFFSET,
target->rel_dyn_section(layout),
elfcpp::R_ARM_TLS_TPOFF32);
}
else
// FIXME: TLS optimization not supported yet.
gold_unreachable();
break;
case elfcpp::R_ARM_TLS_LE32: // Local-exec
layout->set_has_static_tls();
if (parameters->options().shared())
{
// We need to create a dynamic relocation.
Reloc_section* rel_dyn = target->rel_dyn_section(layout);
rel_dyn->add_global(gsym, elfcpp::R_ARM_TLS_TPOFF32,
output_section, object,
data_shndx, reloc.get_r_offset());
}
break;
default:
gold_unreachable();
}
}
break;
default:
unsupported_reloc_global(object, r_type, gsym);
break;
@ -7436,7 +7718,7 @@ Target_arm<big_endian>::Relocate::relocate(
const Symbol_value<32>* psymval,
unsigned char* view,
Arm_address address,
section_size_type /* view_size */ )
section_size_type view_size)
{
typedef Arm_relocate_functions<big_endian> Arm_relocate_functions;
@ -7584,6 +7866,10 @@ Target_arm<big_endian>::Relocate::relocate(
switch(reloc_property->relative_address_base())
{
case Arm_reloc_property::RAB_NONE:
// Relocations with relative address bases RAB_TLS and RAB_tp are
// handled by relocate_tls. So we do not need to do anything here.
case Arm_reloc_property::RAB_TLS:
case Arm_reloc_property::RAB_tp:
break;
case Arm_reloc_property::RAB_B_S:
relative_address_base = sym_origin;
@ -7887,6 +8173,18 @@ Target_arm<big_endian>::Relocate::relocate(
relative_address_base);
break;
// These are initial tls relocs, which are expected when
// linking.
case elfcpp::R_ARM_TLS_GD32: // Global-dynamic
case elfcpp::R_ARM_TLS_LDM32: // Local-dynamic
case elfcpp::R_ARM_TLS_LDO32: // Alternate local-dynamic
case elfcpp::R_ARM_TLS_IE32: // Initial-exec
case elfcpp::R_ARM_TLS_LE32: // Local-exec
reloc_status =
this->relocate_tls(relinfo, target, relnum, rel, r_type, gsym, psymval,
view, address, view_size);
break;
default:
gold_unreachable();
}
@ -7916,6 +8214,125 @@ Target_arm<big_endian>::Relocate::relocate(
return true;
}
// Perform a TLS relocation.
template<bool big_endian>
inline typename Arm_relocate_functions<big_endian>::Status
Target_arm<big_endian>::Relocate::relocate_tls(
const Relocate_info<32, big_endian>* relinfo,
Target_arm<big_endian>* target,
size_t relnum,
const elfcpp::Rel<32, big_endian>& rel,
unsigned int r_type,
const Sized_symbol<32>* gsym,
const Symbol_value<32>* psymval,
unsigned char* view,
elfcpp::Elf_types<32>::Elf_Addr,
section_size_type /*view_size*/ )
{
typedef Arm_relocate_functions<big_endian> ArmRelocFuncs;
Output_segment* tls_segment = relinfo->layout->tls_segment();
const Sized_relobj<32, big_endian>* object = relinfo->object;
elfcpp::Elf_types<32>::Elf_Addr value = psymval->value(object, 0);
const bool is_final = (gsym == NULL
? !parameters->options().shared()
: gsym->final_value_is_known());
const tls::Tls_optimization optimized_type
= Target_arm<big_endian>::optimize_tls_reloc(is_final, r_type);
switch (r_type)
{
case elfcpp::R_ARM_TLS_GD32: // Global-dynamic
{
unsigned int got_type = GOT_TYPE_TLS_PAIR;
unsigned int got_offset;
if (gsym != NULL)
{
gold_assert(gsym->has_got_offset(got_type));
got_offset = gsym->got_offset(got_type) - target->got_size();
}
else
{
unsigned int r_sym = elfcpp::elf_r_sym<32>(rel.get_r_info());
gold_assert(object->local_has_got_offset(r_sym, got_type));
got_offset = (object->local_got_offset(r_sym, got_type)
- target->got_size());
}
if (optimized_type == tls::TLSOPT_NONE)
{
// Relocate the field with the offset of the pair of GOT
// entries.
Relocate_functions<32, big_endian>::rel32(view, got_offset);
return ArmRelocFuncs::STATUS_OKAY;
}
}
break;
case elfcpp::R_ARM_TLS_LDM32: // Local-dynamic
if (optimized_type == tls::TLSOPT_NONE)
{
// Relocate the field with the offset of the GOT entry for
// the module index.
unsigned int got_offset;
got_offset = (target->got_mod_index_entry(NULL, NULL, NULL)
- target->got_size());
Relocate_functions<32, big_endian>::rel32(view, got_offset);
return ArmRelocFuncs::STATUS_OKAY;
}
break;
case elfcpp::R_ARM_TLS_LDO32: // Alternate local-dynamic
Relocate_functions<32, big_endian>::rel32(view, value);
return ArmRelocFuncs::STATUS_OKAY;
case elfcpp::R_ARM_TLS_IE32: // Initial-exec
if (optimized_type == tls::TLSOPT_NONE)
{
// Relocate the field with the offset of the GOT entry for
// the tp-relative offset of the symbol.
unsigned int got_type = GOT_TYPE_TLS_OFFSET;
unsigned int got_offset;
if (gsym != NULL)
{
gold_assert(gsym->has_got_offset(got_type));
got_offset = gsym->got_offset(got_type);
}
else
{
unsigned int r_sym = elfcpp::elf_r_sym<32>(rel.get_r_info());
gold_assert(object->local_has_got_offset(r_sym, got_type));
got_offset = object->local_got_offset(r_sym, got_type);
}
// All GOT offsets are relative to the end of the GOT.
got_offset -= target->got_size();
Relocate_functions<32, big_endian>::rel32(view, got_offset);
return ArmRelocFuncs::STATUS_OKAY;
}
break;
case elfcpp::R_ARM_TLS_LE32: // Local-exec
// If we're creating a shared library, a dynamic relocation will
// have been created for this location, so do not apply it now.
if (!parameters->options().shared())
{
gold_assert(tls_segment != NULL);
value = tls_segment->memsz() - value;
Relocate_functions<32, false>::rel32(view, value);
}
return ArmRelocFuncs::STATUS_OKAY;
default:
gold_unreachable();
}
gold_error_at_location(relinfo, relnum, rel.get_r_offset(),
_("unsupported reloc %u"),
r_type);
return ArmRelocFuncs::STATUS_BAD_RELOC;
}
// Relocate section data.
template<bool big_endian>