aboutsummaryrefslogtreecommitdiff
path: root/gold/x86_64.cc
diff options
context:
space:
mode:
authorCary Coutant <ccoutant@google.com>2011-05-23 23:27:11 +0000
committerCary Coutant <ccoutant@google.com>2011-05-23 23:27:11 +0000
commit4829d394dedd7953e0ee0cf540ffccc01936499d (patch)
treeeb77be5d59cedf93ed8a5ed3e7feb32530d51a65 /gold/x86_64.cc
parentdd931b2ff2bf7cecc09dba03e8916e4adc9406be (diff)
downloadgdb-4829d394dedd7953e0ee0cf540ffccc01936499d.zip
gdb-4829d394dedd7953e0ee0cf540ffccc01936499d.tar.gz
gdb-4829d394dedd7953e0ee0cf540ffccc01936499d.tar.bz2
* gold.cc (queue_middle_tasks): Process existing GOT/PLT entries.
* incremental-dump.cc (dump_incremental_inputs): Mask high-order bit when checking got_type. * incremental.cc (Sized_incremental_binary::setup_readers): Store symbol table and string table locations; initialize bit vector of file status flags. (Sized_incremental_binary::do_reserve_layout): Set bit flag for unchanged files. (Sized_incremental_binary::do_process_got_plt): New function. (Sized_incremental_binary::get_symtab_view): Use stored locations. (Output_section_incremental_inputs::set_final_data_size): Record file index for each input file. (Output_section_incremental_inputs::write_got_plt): Store file index instead of input entry offset for each GOT entry. * incremental.h (Incremental_input_entry::Incremental_input_entry): Initialize new data member. (Incremental_input_entry::set_offset): Store file index. (Incremental_input_entry::get_file_index): New function. (Incremental_input_entry::file_index_): New data member. (Incremental_binary::process_got_plt): New function. (Incremental_binary::do_process_got_plt): New function. (Sized_incremental_binary::Sized_incremental_binary): Initialize new data members. (Sized_incremental_binary::~Sized_incremental_binary): New destructor. (Sized_incremental_binary::set_file_is_unchanged): New function. (Sized_incremental_binary::file_is_unchanged): New function. (Sized_incremental_binary::do_process_got_plt): New function. (Sized_incremental_binary::file_status_): New data member. (Sized_incremental_binary::main_symtab_loc_): New data member. (Sized_incremental_binary::main_strtab_loc_): New data member. * output.cc (Output_data_got::Got_entry::write): Add case RESERVED_CODE. (Output_data_got::add_global): Call add_got_entry. (Output_data_got::add_global_plt): Likewise. (Output_data_got::add_global_with_rel): Likewise. (Output_data_got::add_global_with_rela): Likewise. (Output_data_got::add_global_pair_with_rel): Call add_got_entry_pair. (Output_data_got::add_global_pair_with_rela): Likewise. (Output_data_got::add_local): Call add_got_entry. (Output_data_got::add_local_plt): Likewise. (Output_data_got::add_local_with_rel): Likewise. (Output_data_got::add_local_with_rela): Likewise. (Output_data_got::add_local_pair_with_rel): Call add_got_entry_pair. (Output_data_got::add_local_pair_with_rela): Likewise. (Output_data_got::reserve_slot): New function. (Output_data_got::reserve_slot_for_global): New function. (Output_data_got::add_got_entry): New function. (Output_data_got::add_got_entry_pair): New function. (Output_section::add_output_section_data): Edit FIXME. * output.h (Output_section_data_build::Output_section_data_build): New constructor with size parameter. (Output_data_space::Output_data_space): Likewise. (Output_data_got::Output_data_got): Initialize new data member; new constructor with size parameter. (Output_data_got::add_constant): Call add_got_entry. (Output_data_got::reserve_slot): New function. (Output_data_got::reserve_slot_for_global): New function. (class Output_data_got::Got_entry): Add RESERVED_CODE. (Output_data_got::add_got_entry): New function. (Output_data_got::add_got_entry_pair): New function. (Output_data_got::free_list_): New data member. * target.h (Sized_target::init_got_plt_for_update): New function. (Sized_target::register_global_plt_entry): New function. * x86_64.cc (Output_data_plt_x86_64::Output_data_plt_x86_64): Initialize new data member; call init; add constructor with PLT count. (Output_data_plt_x86_64::init): New function. (Output_data_plt_x86_64::add_relocation): New function. (Output_data_plt_x86_64::reserve_slot): New function. (Output_data_plt_x86_64::free_list_): New data member. (Target_x86_64::init_got_plt_for_update): New function. (Target_x86_64::register_global_plt_entry): New function. (Output_data_plt_x86_64::add_entry): Allocate from free list for incremental updates. (Output_data_plt_x86_64::add_relocation): New function. * testsuite/object_unittest.cc (Object_test): Set default options.
Diffstat (limited to 'gold/x86_64.cc')
-rw-r--r--gold/x86_64.cc208
1 files changed, 180 insertions, 28 deletions
diff --git a/gold/x86_64.cc b/gold/x86_64.cc
index e4a7043..9b9a3b1 100644
--- a/gold/x86_64.cc
+++ b/gold/x86_64.cc
@@ -53,8 +53,31 @@ class Output_data_plt_x86_64 : public Output_section_data
public:
typedef Output_data_reloc<elfcpp::SHT_RELA, true, 64, false> Reloc_section;
- Output_data_plt_x86_64(Symbol_table*, Layout*, Output_data_got<64, false>*,
- Output_data_space*);
+ Output_data_plt_x86_64(Symbol_table* symtab, Layout* layout,
+ Output_data_got<64, false>* got,
+ Output_data_space* got_plt)
+ : Output_section_data(8), tlsdesc_rel_(NULL), got_(got), got_plt_(got_plt),
+ count_(0), tlsdesc_got_offset_(-1U), free_list_()
+ { this->init(symtab, layout); }
+
+ Output_data_plt_x86_64(Symbol_table* symtab, Layout* layout,
+ Output_data_got<64, false>* got,
+ Output_data_space* got_plt,
+ unsigned int plt_count)
+ : Output_section_data((plt_count + 1) * plt_entry_size, 8, false),
+ tlsdesc_rel_(NULL), got_(got), got_plt_(got_plt),
+ count_(plt_count), tlsdesc_got_offset_(-1U), free_list_()
+ {
+ this->init(symtab, layout);
+
+ // Initialize the free list and reserve the first entry.
+ this->free_list_.init((plt_count + 1) * plt_entry_size, false);
+ this->free_list_.remove(0, plt_entry_size);
+ }
+
+ // Initialize the PLT section.
+ void
+ init(Symbol_table* symtab, Layout* layout);
// Add an entry to the PLT.
void
@@ -65,6 +88,10 @@ class Output_data_plt_x86_64 : public Output_section_data
add_local_ifunc_entry(Sized_relobj<64, false>* relobj,
unsigned int local_sym_index);
+ // Add the relocation for a PLT entry.
+ void
+ add_relocation(Symbol* gsym, unsigned int got_offset);
+
// Add the reserved TLSDESC_PLT entry to the PLT.
void
reserve_tlsdesc_entry(unsigned int got_offset)
@@ -109,6 +136,14 @@ class Output_data_plt_x86_64 : public Output_section_data
get_plt_entry_size()
{ return plt_entry_size; }
+ // Reserve a slot in the PLT for an existing symbol in an incremental update.
+ void
+ reserve_slot(unsigned int plt_index)
+ {
+ this->free_list_.remove((plt_index + 1) * plt_entry_size,
+ (plt_index + 2) * plt_entry_size);
+ }
+
protected:
void
do_adjust_output_section(Output_section* os);
@@ -154,6 +189,9 @@ class Output_data_plt_x86_64 : public Output_section_data
unsigned int count_;
// Offset of the reserved TLSDESC_GOT entry when needed.
unsigned int tlsdesc_got_offset_;
+ // List of available regions within the section, for incremental
+ // update links.
+ Free_list free_list_;
};
// The x86_64 target class.
@@ -345,6 +383,18 @@ class Target_x86_64 : public Target_freebsd<64, false>
unsigned int
plt_entry_size() const;
+ // Create the GOT section for an incremental update.
+ Output_data_got<64, false>*
+ init_got_plt_for_update(Symbol_table* symtab,
+ Layout* layout,
+ unsigned int got_count,
+ unsigned int plt_count);
+
+ // Register an existing PLT entry for a global symbol.
+ // A target needs to implement this to support incremental linking.
+ void
+ register_global_plt_entry(unsigned int plt_index, Symbol* gsym);
+
// Apply an incremental relocation.
void
apply_relocation(const Relocate_info<64, false>* relinfo,
@@ -779,16 +829,10 @@ Target_x86_64::rela_dyn_section(Layout* layout)
return this->rela_dyn_;
}
-// Create the PLT section. The ordinary .got section is an argument,
-// since we need to refer to the start. We also create our own .got
-// section just for PLT entries.
+// Initialize the PLT section.
-Output_data_plt_x86_64::Output_data_plt_x86_64(Symbol_table* symtab,
- Layout* layout,
- Output_data_got<64, false>* got,
- Output_data_space* got_plt)
- : Output_section_data(8), tlsdesc_rel_(NULL), got_(got), got_plt_(got_plt),
- count_(0), tlsdesc_got_offset_(-1U)
+void
+Output_data_plt_x86_64::init(Symbol_table* symtab, Layout* layout)
{
this->rel_ = new Reloc_section(false);
layout->add_output_section_data(".rela.plt", elfcpp::SHT_RELA,
@@ -827,31 +871,47 @@ Output_data_plt_x86_64::add_entry(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_ + 1) * plt_entry_size);
+ unsigned int plt_index;
+ off_t plt_offset;
+ section_offset_type got_offset;
- ++this->count_;
+ if (!this->is_data_size_valid())
+ {
+ // Note that when setting the PLT offset we skip the initial
+ // reserved PLT entry.
+ plt_index = this->count_ + 1;
+ plt_offset = plt_index * plt_entry_size;
- section_offset_type got_offset = this->got_plt_->current_data_size();
+ ++this->count_;
- // 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 + 8);
+ got_offset = (plt_index - 1 + 3) * 8;
+ gold_assert(got_offset == this->got_plt_->current_data_size());
- // Every PLT entry needs a reloc.
- if (gsym->type() == elfcpp::STT_GNU_IFUNC
- && gsym->can_use_relative_reloc(false))
- this->rel_->add_symbolless_global_addend(gsym, elfcpp::R_X86_64_IRELATIVE,
- this->got_plt_, got_offset, 0);
+ // 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 + 8);
+ }
else
{
- gsym->set_needs_dynsym_entry();
- this->rel_->add_global(gsym, elfcpp::R_X86_64_JUMP_SLOT, this->got_plt_,
- got_offset, 0);
+ // For incremental updates, find an available slot.
+ plt_offset = this->free_list_.allocate(plt_entry_size, plt_entry_size, 0);
+ if (plt_offset == -1)
+ gold_fatal(_("out of patch space (PLT);"
+ " relink with --incremental-full"));
+
+ // The GOT and PLT entries have a 1-1 correspondance, so the GOT offset
+ // can be calculated from the PLT index, adjusting for the three
+ // reserved entries at the beginning of the GOT.
+ plt_index = plt_offset / plt_entry_size - 1;
+ got_offset = (plt_index - 1 + 3) * 8;
}
+ gsym->set_plt_offset(plt_offset);
+
+ // Every PLT entry needs a reloc.
+ this->add_relocation(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.
@@ -881,6 +941,23 @@ Output_data_plt_x86_64::add_local_ifunc_entry(Sized_relobj<64, false>* relobj,
return plt_offset;
}
+// Add the relocation for a PLT entry.
+
+void
+Output_data_plt_x86_64::add_relocation(Symbol* gsym, unsigned int got_offset)
+{
+ if (gsym->type() == elfcpp::STT_GNU_IFUNC
+ && gsym->can_use_relative_reloc(false))
+ this->rel_->add_symbolless_global_addend(gsym, elfcpp::R_X86_64_IRELATIVE,
+ this->got_plt_, got_offset, 0);
+ else
+ {
+ gsym->set_needs_dynsym_entry();
+ this->rel_->add_global(gsym, elfcpp::R_X86_64_JUMP_SLOT, this->got_plt_,
+ got_offset, 0);
+ }
+}
+
// Return where the TLSDESC relocations should go, creating it if
// necessary. These follow the JUMP_SLOT relocations.
@@ -1129,6 +1206,81 @@ Target_x86_64::plt_entry_size() const
return Output_data_plt_x86_64::get_plt_entry_size();
}
+// Create the GOT and PLT sections for an incremental update.
+
+Output_data_got<64, false>*
+Target_x86_64::init_got_plt_for_update(Symbol_table* symtab,
+ Layout* layout,
+ unsigned int got_count,
+ unsigned int plt_count)
+{
+ gold_assert(this->got_ == NULL);
+
+ this->got_ = new Output_data_got<64, false>(got_count * 8);
+ layout->add_output_section_data(".got", elfcpp::SHT_PROGBITS,
+ (elfcpp::SHF_ALLOC
+ | elfcpp::SHF_WRITE),
+ this->got_, ORDER_RELRO_LAST,
+ true);
+
+ // Add the three reserved entries.
+ this->got_plt_ = new Output_data_space((plt_count + 3) * 8, 8, "** GOT PLT");
+ layout->add_output_section_data(".got.plt", elfcpp::SHT_PROGBITS,
+ (elfcpp::SHF_ALLOC
+ | elfcpp::SHF_WRITE),
+ this->got_plt_, ORDER_NON_RELRO_FIRST,
+ false);
+
+ // Define _GLOBAL_OFFSET_TABLE_ at the start of the PLT.
+ this->global_offset_table_ =
+ symtab->define_in_output_data("_GLOBAL_OFFSET_TABLE_", NULL,
+ Symbol_table::PREDEFINED,
+ this->got_plt_,
+ 0, 0, elfcpp::STT_OBJECT,
+ 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.
+ // FIXME: Get the count for TLSDESC entries.
+ this->got_tlsdesc_ = new Output_data_got<64, false>(0);
+ layout->add_output_section_data(".got.plt", elfcpp::SHT_PROGBITS,
+ elfcpp::SHF_ALLOC | elfcpp::SHF_WRITE,
+ this->got_tlsdesc_,
+ ORDER_NON_RELRO_FIRST, false);
+
+ // Create the PLT section.
+ this->plt_ = new Output_data_plt_x86_64(symtab, layout, this->got_,
+ this->got_plt_, plt_count);
+ layout->add_output_section_data(".plt", elfcpp::SHT_PROGBITS,
+ elfcpp::SHF_ALLOC | elfcpp::SHF_EXECINSTR,
+ this->plt_, ORDER_PLT, false);
+
+ // Make the sh_info field of .rela.plt point to .plt.
+ Output_section* rela_plt_os = this->plt_->rela_plt()->output_section();
+ rela_plt_os->set_info_section(this->plt_->output_section());
+
+ return this->got_;
+}
+
+// Register an existing PLT entry for a global symbol.
+
+void
+Target_x86_64::register_global_plt_entry(unsigned int plt_index,
+ Symbol* gsym)
+{
+ gold_assert(this->plt_ != NULL);
+ gold_assert(!gsym->has_plt_offset());
+
+ this->plt_->reserve_slot(plt_index);
+
+ gsym->set_plt_offset((plt_index + 1) * this->plt_entry_size());
+
+ unsigned int got_offset = (plt_index + 3) * 8;
+ this->plt_->add_relocation(gsym, got_offset);
+}
+
// Define the _TLS_MODULE_BASE_ symbol in the TLS segment.
void