// i386.cc -- i386 target support for gold.
-// Copyright 2006, 2007, 2008, 2009 Free Software Foundation, Inc.
+// Copyright 2006, 2007, 2008, 2009, 2010 Free Software Foundation, Inc.
// This file is part of gold.
Target_i386()
: Target_freebsd<32, false>(&i386_info),
- got_(NULL), plt_(NULL), got_plt_(NULL), global_offset_table_(NULL),
- rel_dyn_(NULL), copy_relocs_(elfcpp::R_386_COPY), dynbss_(NULL),
+ got_(NULL), plt_(NULL), got_plt_(NULL), got_tlsdesc_(NULL),
+ global_offset_table_(NULL), rel_dyn_(NULL),
+ copy_relocs_(elfcpp::R_386_COPY), dynbss_(NULL),
got_mod_index_offset_(-1U), tls_base_symbol_defined_(false)
{ }
// Return the size of the GOT section.
section_size_type
- got_size()
+ got_size() const
{
gold_assert(this->got_ != NULL);
return this->got_->data_size();
}
+ // Return the number of entries in the GOT.
+ unsigned int
+ got_entry_count() const
+ {
+ if (this->got_ == NULL)
+ return 0;
+ return this->got_size() / 4;
+ }
+
+ // Return the number of entries in the PLT.
+ unsigned int
+ plt_entry_count() const;
+
+ // Return the offset of the first non-reserved PLT entry.
+ unsigned int
+ first_plt_entry_offset() const;
+
+ // Return the size of each PLT entry.
+ unsigned int
+ plt_entry_size() const;
+
private:
// The class which scans relocations.
struct Scan
return this->got_plt_;
}
+ // Get the GOT section for TLSDESC entries.
+ Output_data_got<32, false>*
+ got_tlsdesc_section() const
+ {
+ gold_assert(this->got_tlsdesc_ != NULL);
+ return this->got_tlsdesc_;
+ }
+
// Create a PLT entry for a global symbol.
void
make_plt_entry(Symbol_table*, Layout*, Symbol*);
static const Target::Target_info i386_info;
// The types of GOT entries needed for this platform.
+ // These values are exposed to the ABI in an incremental link.
+ // Do not renumber existing values without changing the version
+ // number of the .gnu_incremental_inputs section.
enum Got_type
{
GOT_TYPE_STANDARD = 0, // GOT entry for a regular symbol
Output_data_plt_i386* plt_;
// The GOT PLT section.
Output_data_space* got_plt_;
+ // The GOT section for TLSDESC relocations.
+ Output_data_got<32, false>* got_tlsdesc_;
// The _GLOBAL_OFFSET_TABLE_ symbol.
Symbol* global_offset_table_;
// The dynamic reloc section.
layout->add_output_section_data(".got", elfcpp::SHT_PROGBITS,
(elfcpp::SHF_ALLOC
| elfcpp::SHF_WRITE),
- this->got_, false, true, true, false);
+ this->got_, ORDER_RELRO_LAST, true);
this->got_plt_ = new Output_data_space(4, "** GOT PLT");
layout->add_output_section_data(".got.plt", elfcpp::SHT_PROGBITS,
(elfcpp::SHF_ALLOC
| elfcpp::SHF_WRITE),
- this->got_plt_, false, false, false,
- true);
+ this->got_plt_, ORDER_NON_RELRO_FIRST,
+ false);
// The first three entries are reserved.
this->got_plt_->set_current_data_size(3 * 4);
elfcpp::STB_LOCAL,
elfcpp::STV_HIDDEN, 0,
false, false);
+
+ // If there are any TLSDESC relocations, they get GOT entries in
+ // .got.plt after the jump slot entries.
+ this->got_tlsdesc_ = new Output_data_got<32, false>();
+ layout->add_output_section_data(".got.plt", elfcpp::SHT_PROGBITS,
+ (elfcpp::SHF_ALLOC
+ | elfcpp::SHF_WRITE),
+ this->got_tlsdesc_,
+ ORDER_NON_RELRO_FIRST, false);
}
return this->got_;
gold_assert(layout != NULL);
this->rel_dyn_ = new Reloc_section(parameters->options().combreloc());
layout->add_output_section_data(".rel.dyn", elfcpp::SHT_REL,
- elfcpp::SHF_ALLOC, this->rel_dyn_, true,
- false, false, false);
+ elfcpp::SHF_ALLOC, this->rel_dyn_,
+ ORDER_DYNAMIC_RELOCS, false);
}
return this->rel_dyn_;
}
Reloc_section*
rel_tls_desc(Layout*);
+ // Return the number of PLT entries.
+ unsigned int
+ entry_count() const
+ { return this->count_; }
+
+ // Return the offset of the first non-reserved PLT entry.
+ static unsigned int
+ first_plt_entry_offset()
+ { return plt_entry_size; }
+
+ // Return the size of a PLT entry.
+ static unsigned int
+ get_plt_entry_size()
+ { return plt_entry_size; }
+
protected:
void
do_adjust_output_section(Output_section* os);
{
this->rel_ = new Reloc_section(false);
layout->add_output_section_data(".rel.plt", elfcpp::SHT_REL,
- elfcpp::SHF_ALLOC, this->rel_, true,
- false, false, false);
+ elfcpp::SHF_ALLOC, this->rel_,
+ ORDER_DYNAMIC_PLT_RELOCS, false);
}
void
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);
+ ORDER_DYNAMIC_PLT_RELOCS, false);
gold_assert(this->tls_desc_rel_->output_section() ==
this->rel_->output_section());
}
layout->add_output_section_data(".plt", elfcpp::SHT_PROGBITS,
(elfcpp::SHF_ALLOC
| elfcpp::SHF_EXECINSTR),
- this->plt_, false, false, false, false);
+ this->plt_, ORDER_PLT, false);
}
this->plt_->add_entry(gsym);
}
+// Return the number of entries in the PLT.
+
+unsigned int
+Target_i386::plt_entry_count() const
+{
+ if (this->plt_ == NULL)
+ return 0;
+ return this->plt_->entry_count();
+}
+
+// Return the offset of the first non-reserved PLT entry.
+
+unsigned int
+Target_i386::first_plt_entry_offset() const
+{
+ return Output_data_plt_i386::first_plt_entry_offset();
+}
+
+// Return the size of each PLT entry.
+
+unsigned int
+Target_i386::plt_entry_size() const
+{
+ return Output_data_plt_i386::get_plt_entry_size();
+}
+
// Get the section to use for TLS_DESC relocations.
Target_i386::Reloc_section*
target->define_tls_base_symbol(symtab, layout);
if (optimized_type == tls::TLSOPT_NONE)
{
- // Create a double GOT entry with an R_386_TLS_DESC reloc.
- Output_data_got<32, false>* got
- = target->got_section(symtab, layout);
+ // Create a double GOT entry with an R_386_TLS_DESC
+ // reloc. The R_386_TLS_DESC reloc is resolved
+ // lazily, so the GOT entry needs to be in an area in
+ // .got.plt, not .got. Call got_section to make sure
+ // the section has been created.
+ target->got_section(symtab, layout);
+ Output_data_got<32, false>* got = target->got_tlsdesc_section();
unsigned int r_sym = elfcpp::elf_r_sym<32>(reloc.get_r_info());
if (!object->local_has_got_offset(r_sym, GOT_TYPE_TLS_DESC))
{
target->define_tls_base_symbol(symtab, layout);
if (optimized_type == tls::TLSOPT_NONE)
{
- // Create a double GOT entry with an R_386_TLS_DESC reloc.
- Output_data_got<32, false>* got
- = target->got_section(symtab, layout);
+ // Create a double GOT entry with an R_386_TLS_DESC
+ // reloc. The R_386_TLS_DESC reloc is resolved
+ // lazily, so the GOT entry needs to be in an area in
+ // .got.plt, not .got. Call got_section to make sure
+ // the section has been created.
+ target->got_section(symtab, layout);
+ Output_data_got<32, false>* got = target->got_tlsdesc_section();
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);
unsigned int got_type = (optimized_type == tls::TLSOPT_TO_IE
? GOT_TYPE_TLS_NOFFSET
: GOT_TYPE_TLS_DESC);
- unsigned int got_offset;
+ unsigned int got_offset = 0;
+ if (r_type == elfcpp::R_386_TLS_GOTDESC
+ && optimized_type == tls::TLSOPT_NONE)
+ {
+ // We created GOT entries in the .got.tlsdesc portion of
+ // the .got.plt section, but the offset stored in the
+ // symbol is the offset within .got.tlsdesc.
+ got_offset = (target->got_size()
+ + target->got_plt_section()->data_size());
+ }
if (gsym != NULL)
{
gold_assert(gsym->has_got_offset(got_type));
- got_offset = gsym->got_offset(got_type) - target->got_size();
+ 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());
+ got_offset += (object->local_got_offset(r_sym, got_type)
+ - target->got_size());
}
if (optimized_type == tls::TLSOPT_TO_IE)
{