: Sized_target<64, false>(&x86_64_info),
got_(NULL), plt_(NULL), got_plt_(NULL), rela_dyn_(NULL),
copy_relocs_(elfcpp::R_X86_64_COPY), dynbss_(NULL),
- got_mod_index_offset_(-1U)
+ got_mod_index_offset_(-1U), tls_base_symbol_defined_(false)
{ }
// Scan the relocations to look for symbol adjustments.
{
public:
Relocate()
- : skip_call_tls_get_addr_(false)
+ : skip_call_tls_get_addr_(false), saw_tls_block_reloc_(false)
{ }
~Relocate()
// This is set if we should skip the next reloc, which should be a
// PLT32 reloc against ___tls_get_addr.
bool skip_call_tls_get_addr_;
+
+ // This is set if we see a relocation which could load the address
+ // of the TLS block. Whether we see such a relocation determines
+ // how we handle the R_X86_64_DTPOFF32 relocation, which is used
+ // in debugging sections.
+ bool saw_tls_block_reloc_;
};
// A class which returns the size required for a relocation type,
void
make_plt_entry(Symbol_table*, Layout*, Symbol*);
+ // Define the _TLS_MODULE_BASE_ symbol at the end of the TLS segment.
+ void
+ define_tls_base_symbol(Symbol_table*, Layout*);
+
// Create the reserved PLT and GOT entries for the TLS descriptor resolver.
void
reserve_tlsdesc_entries(Symbol_table* symtab, Layout* layout);
// Add a potential copy relocation.
void
- copy_reloc(Symbol_table* symtab, Layout* layout, Relobj* object,
+ copy_reloc(Symbol_table* symtab, Layout* layout,
+ Sized_relobj<64, false>* object,
unsigned int shndx, Output_section* output_section,
Symbol* sym, const elfcpp::Rela<64, false>& 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_;
};
const Target::Target_info Target_x86_64::x86_64_info =
this->got_ = new Output_data_got<64, false>();
- layout->add_output_section_data(".got", elfcpp::SHT_PROGBITS,
- elfcpp::SHF_ALLOC | elfcpp::SHF_WRITE,
- this->got_);
+ Output_section* os;
+ os = layout->add_output_section_data(".got", elfcpp::SHT_PROGBITS,
+ (elfcpp::SHF_ALLOC
+ | elfcpp::SHF_WRITE),
+ this->got_);
+ os->set_is_relro();
// The old GNU linker creates a .got.plt section. We just
// create another set of data in the .got section. Note that we
// always create a PLT if we create a GOT, although the PLT
// might be empty.
- this->got_plt_ = new Output_data_space(8);
- layout->add_output_section_data(".got", elfcpp::SHT_PROGBITS,
- elfcpp::SHF_ALLOC | elfcpp::SHF_WRITE,
- this->got_plt_);
+ this->got_plt_ = new Output_data_space(8, "** GOT PLT");
+ os = layout->add_output_section_data(".got", elfcpp::SHT_PROGBITS,
+ (elfcpp::SHF_ALLOC
+ | elfcpp::SHF_WRITE),
+ this->got_plt_);
+ os->set_is_relro();
// The first three entries are reserved.
this->got_plt_->set_current_data_size(3 * 8);
if (this->rela_dyn_ == NULL)
{
gold_assert(layout != NULL);
- this->rela_dyn_ = new Reloc_section();
+ this->rela_dyn_ = new Reloc_section(parameters->options().combreloc());
layout->add_output_section_data(".rela.dyn", elfcpp::SHT_RELA,
elfcpp::SHF_ALLOC, this->rela_dyn_);
}
void
do_adjust_output_section(Output_section* os);
+ // Write to a map file.
+ void
+ do_print_to_mapfile(Mapfile* mapfile) const
+ { mapfile->print_output_data(this, _("** PLT")); }
+
private:
// The size of an entry in the PLT.
static const int plt_entry_size = 16;
: Output_section_data(8), got_(got), got_plt_(got_plt), count_(0),
tlsdesc_got_offset_(-1U)
{
- this->rel_ = new Reloc_section();
+ this->rel_ = new Reloc_section(false);
layout->add_output_section_data(".rela.plt", elfcpp::SHT_RELA,
elfcpp::SHF_ALLOC, this->rel_);
}
unsigned char* pov = oview;
// The base address of the .plt section.
- elfcpp::Elf_types<32>::Elf_Addr plt_address = this->address();
+ elfcpp::Elf_types<64>::Elf_Addr plt_address = this->address();
// The base address of the .got section.
- elfcpp::Elf_types<32>::Elf_Addr got_base = this->got_->address();
+ elfcpp::Elf_types<64>::Elf_Addr got_base = this->got_->address();
// The base address of the PLT portion of the .got section,
// which is where the GOT pointer will point, and where the
// three reserved GOT entries are located.
- elfcpp::Elf_types<32>::Elf_Addr got_address = this->got_plt_->address();
+ elfcpp::Elf_types<64>::Elf_Addr got_address = this->got_plt_->address();
memcpy(pov, first_plt_entry, plt_entry_size);
// We do a jmp relative to the PC at the end of this instruction.
- elfcpp::Swap_unaligned<32, false>::writeval(pov + 2, got_address + 8
- - (plt_address + 6));
- elfcpp::Swap<32, false>::writeval(pov + 8, got_address + 16
- - (plt_address + 12));
+ elfcpp::Swap_unaligned<32, false>::writeval(pov + 2,
+ (got_address + 8
+ - (plt_address + 6)));
+ elfcpp::Swap<32, false>::writeval(pov + 8,
+ (got_address + 16
+ - (plt_address + 12)));
pov += plt_entry_size;
unsigned char* got_pov = got_view;
this->plt_->add_entry(gsym);
}
+// Define the _TLS_MODULE_BASE_ symbol at the end of the TLS segment.
+
+void
+Target_x86_64::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)
+ {
+ symtab->define_in_output_segment("_TLS_MODULE_BASE_", NULL,
+ tls_segment, 0, 0,
+ elfcpp::STT_TLS,
+ elfcpp::STB_LOCAL,
+ elfcpp::STV_HIDDEN, 0,
+ Symbol::SEGMENT_END, true);
+ }
+ this->tls_base_symbol_defined_ = true;
+}
+
// Create the reserved PLT and GOT entries for the TLS descriptor resolver.
void
this->check_non_pic(object, r_type);
Reloc_section* rela_dyn = target->rela_dyn_section(layout);
+ unsigned int r_sym = elfcpp::elf_r_sym<64>(reloc.get_r_info());
if (lsym.get_st_type() != elfcpp::STT_SECTION)
- {
- unsigned int r_sym = elfcpp::elf_r_sym<64>(reloc.get_r_info());
- rela_dyn->add_local(object, r_sym, r_type, output_section,
- data_shndx, reloc.get_r_offset(),
- reloc.get_r_addend());
- }
+ rela_dyn->add_local(object, r_sym, r_type, output_section,
+ data_shndx, reloc.get_r_offset(),
+ reloc.get_r_addend());
else
{
gold_assert(lsym.get_st_value() == 0);
- rela_dyn->add_local_section(object, lsym.get_st_shndx(),
- r_type, output_section,
- data_shndx, reloc.get_r_offset(),
- reloc.get_r_addend());
+ 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(_("section symbol %u has bad shndx %u"),
+ r_sym, shndx);
+ else
+ rela_dyn->add_local_section(object, shndx,
+ r_type, output_section,
+ data_shndx, reloc.get_r_offset(),
+ reloc.get_r_addend());
}
}
break;
Output_data_got<64, false>* got
= target->got_section(symtab, layout);
unsigned int r_sym = elfcpp::elf_r_sym<64>(reloc.get_r_info());
- got->add_local_pair_with_rela(object, r_sym,
- lsym.get_st_shndx(),
- GOT_TYPE_TLS_PAIR,
- target->rela_dyn_section(layout),
- elfcpp::R_X86_64_DTPMOD64, 0);
+ 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_PAIR,
+ target->rela_dyn_section(layout),
+ elfcpp::R_X86_64_DTPMOD64, 0);
}
else if (optimized_type != tls::TLSOPT_TO_LE)
unsupported_reloc_local(object, r_type);
break;
case elfcpp::R_X86_64_GOTPC32_TLSDESC:
+ target->define_tls_base_symbol(symtab, layout);
if (optimized_type == tls::TLSOPT_NONE)
{
// Create reserved PLT and GOT entries for the resolver.
Output_data_got<64, false>* got
= target->got_section(symtab, layout);
unsigned int r_sym = elfcpp::elf_r_sym<64>(reloc.get_r_info());
- got->add_local_pair_with_rela(object, r_sym,
- lsym.get_st_shndx(),
- GOT_TYPE_TLS_DESC,
- target->rela_dyn_section(layout),
- elfcpp::R_X86_64_TLSDESC, 0);
+ 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);
}
else if (optimized_type != tls::TLSOPT_TO_LE)
unsupported_reloc_local(object, r_type);
break;
case elfcpp::R_X86_64_GOTPC32_TLSDESC:
+ target->define_tls_base_symbol(symtab, layout);
if (optimized_type == tls::TLSOPT_NONE)
{
// Create reserved PLT and GOT entries for the resolver.
switch (r_type)
{
case elfcpp::R_X86_64_TLSGD: // Global-dynamic
+ this->saw_tls_block_reloc_ = true;
if (optimized_type == tls::TLSOPT_TO_LE)
{
gold_assert(tls_segment != NULL);
case elfcpp::R_X86_64_GOTPC32_TLSDESC: // Global-dynamic (from ~oliva url)
case elfcpp::R_X86_64_TLSDESC_CALL:
+ this->saw_tls_block_reloc_ = true;
if (optimized_type == tls::TLSOPT_TO_LE)
{
gold_assert(tls_segment != NULL);
break;
case elfcpp::R_X86_64_TLSLD: // Local-dynamic
+ this->saw_tls_block_reloc_ = true;
if (optimized_type == tls::TLSOPT_TO_LE)
{
gold_assert(tls_segment != NULL);
case elfcpp::R_X86_64_DTPOFF32:
gold_assert(tls_segment != NULL);
if (optimized_type == tls::TLSOPT_TO_LE)
- value -= tls_segment->memsz();
+ {
+ // This relocation type is used in debugging information.
+ // In that case we need to not optimize the value. If we
+ // haven't seen a TLSLD reloc, then we assume we should not
+ // optimize this reloc.
+ if (this->saw_tls_block_reloc_)
+ value -= tls_segment->memsz();
+ }
Relocate_functions<64, false>::rela32(view, value, 0);
break;
case elfcpp::R_X86_64_DTPOFF64:
gold_assert(tls_segment != NULL);
if (optimized_type == tls::TLSOPT_TO_LE)
- value -= tls_segment->memsz();
+ {
+ // See R_X86_64_DTPOFF32, just above, for why we test this.
+ if (this->saw_tls_block_reloc_)
+ value -= tls_segment->memsz();
+ }
Relocate_functions<64, false>::rela64(view, value, 0);
break;