From 0e70b9111a696f5b70cade541df55de14c31f9f1 Mon Sep 17 00:00:00 2001 From: Cary Coutant Date: Thu, 12 Aug 2010 22:15:00 +0000 Subject: [PATCH] elfcpp/ChangeLog: * elfcpp.h (enum SHT): Add SHT_GNU_INCREMENTAL_GOT_PLT. gold/ChangeLog: * arm.cc (Target_arm::got_size): Add const. (Target_arm::got_entry_count): New function. (Target_arm::plt_entry_count): New function. (Target_arm::first_plt_entry_offset): New function. (Target_arm::plt_entry_size): New function. (Output_data_plt_arm::entry_count): New function. (Output_data_plt_arm::first_plt_entry_offset): New function. (Output_data_plt_arm::get_plt_entry_size): New function. * i386.cc (Target_i386::got_size): Add const. (Target_i386::got_entry_count): New function. (Target_i386::plt_entry_count): New function. (Target_i386::first_plt_entry_offset): New function. (Target_i386::plt_entry_size): New function. (Output_data_plt_i386::entry_count): New function. (Output_data_plt_i386::first_plt_entry_offset): New function. (Output_data_plt_i386::get_plt_entry_size): New function. * incremental-dump.cc (dump_incremental_inputs): Adjust call to find_incremental_inputs_sections. Dump incremental_got_plt section. * incremental.cc: Include target.h. (Sized_incremental_binary::do_find_incremental_inputs_sections): Add parameter. Adjust all callers. Find incremental_got_plt section. (Incremental_inputs::create_data_sections): Create incremental_got_plt section. (Output_section_incremental_inputs::set_final_data_size): Calculate size of incremental_got_plt section. (Output_section_incremental_inputs::do_write): Write the incremental_got_plt section. (Got_plt_view_info): New struct. (Local_got_offset_visitor): New class. (Global_got_offset_visitor): New class. (Global_symbol_visitor_got_plt): New class. (Output_section_incremental_inputs::write_got_plt): New function. * incremental.h (Incremental_binary::find_incremental_inputs_sections): Add parameter. Adjust all callers. (Incremental_binary::do_find_incremental_inputs_sections): Likewise. (Incremental_inputs::got_plt_section): New function. (Incremental_inputs::got_plt_section_): New data member. (Incremental_got_plt_reader): New class. * layout.cc (Layout::create_incremental_info_sections): Add the incremental_got_plt section. * object.h (Got_offset_list::get_list): New function. (Got offset_list::for_all_got_offsets): New function. (Sized_relobj::local_got_offset_list): New function. * powerpc.cc (Target_powerpc::got_size): Add const. (Target_powerpc::got_entry_count): New function. (Target_powerpc::plt_entry_count): New function. (Target_powerpc::first_plt_entry_offset): New function. (Target_powerpc::plt_entry_size): New function. (Output_data_plt_powerpc::entry_count): New function. (Output_data_plt_powerpc::first_plt_entry_offset): New function. (Output_data_plt_powerpc::get_plt_entry_size): New function. * sparc.cc (Target_sparc::got_size): Add const. (Target_sparc::got_entry_count): New function. (Target_sparc::plt_entry_count): New function. (Target_sparc::first_plt_entry_offset): New function. (Target_sparc::plt_entry_size): New function. (Output_data_plt_sparc::entry_count): New function. (Output_data_plt_sparc::first_plt_entry_offset): New function. (Output_data_plt_sparc::get_plt_entry_size): New function. * symtab.h (Symbol::got_offset_list): New function. (Symbol_table::for_all_symbols): New function. * target.h (Sized_target::got_entry_count): New function. (Sized_target::plt_entry_count): New function. (Sized_target::plt_entry_size): New function. * x86_64.cc (Target_x86_64::got_size): Add const. (Target_x86_64::got_entry_count): New function. (Target_x86_64::plt_entry_count): New function. (Target_x86_64::first_plt_entry_offset): New function. (Target_x86_64::plt_entry_size): New function. (Output_data_plt_x86_64::entry_count): New function. (Output_data_plt_x86_64::first_plt_entry_offset): New function. (Output_data_plt_x86_64::get_plt_entry_size): New function. --- gold/ChangeLog | 75 +++++++++++++ gold/arm.cc | 70 +++++++++++- gold/i386.cc | 67 +++++++++++- gold/incremental-dump.cc | 64 ++++++++--- gold/incremental.cc | 227 ++++++++++++++++++++++++++++++++++++++- gold/incremental.h | 83 ++++++++++++-- gold/layout.cc | 11 ++ gold/object.h | 31 ++++++ gold/powerpc.cc | 72 ++++++++++++- gold/sparc.cc | 72 ++++++++++++- gold/symtab.h | 19 ++++ gold/target.h | 34 +++++- gold/x86_64.cc | 68 +++++++++++- 13 files changed, 866 insertions(+), 27 deletions(-) diff --git a/gold/ChangeLog b/gold/ChangeLog index c77f2d7cc1b..47814f02511 100644 --- a/gold/ChangeLog +++ b/gold/ChangeLog @@ -1,3 +1,78 @@ +2010-08-12 Cary Coutant + + * arm.cc (Target_arm::got_size): Add const. + (Target_arm::got_entry_count): New function. + (Target_arm::plt_entry_count): New function. + (Target_arm::first_plt_entry_offset): New function. + (Target_arm::plt_entry_size): New function. + (Output_data_plt_arm::entry_count): New function. + (Output_data_plt_arm::first_plt_entry_offset): New function. + (Output_data_plt_arm::get_plt_entry_size): New function. + * i386.cc (Target_i386::got_size): Add const. + (Target_i386::got_entry_count): New function. + (Target_i386::plt_entry_count): New function. + (Target_i386::first_plt_entry_offset): New function. + (Target_i386::plt_entry_size): New function. + (Output_data_plt_i386::entry_count): New function. + (Output_data_plt_i386::first_plt_entry_offset): New function. + (Output_data_plt_i386::get_plt_entry_size): New function. + * incremental-dump.cc (dump_incremental_inputs): Adjust call to + find_incremental_inputs_sections. Dump incremental_got_plt section. + * incremental.cc: Include target.h. + (Sized_incremental_binary::do_find_incremental_inputs_sections): Add + parameter. Adjust all callers. Find incremental_got_plt section. + (Incremental_inputs::create_data_sections): Create incremental_got_plt + section. + (Output_section_incremental_inputs::set_final_data_size): Calculate + size of incremental_got_plt section. + (Output_section_incremental_inputs::do_write): Write the + incremental_got_plt section. + (Got_plt_view_info): New struct. + (Local_got_offset_visitor): New class. + (Global_got_offset_visitor): New class. + (Global_symbol_visitor_got_plt): New class. + (Output_section_incremental_inputs::write_got_plt): New function. + * incremental.h (Incremental_binary::find_incremental_inputs_sections): + Add parameter. Adjust all callers. + (Incremental_binary::do_find_incremental_inputs_sections): Likewise. + (Incremental_inputs::got_plt_section): New function. + (Incremental_inputs::got_plt_section_): New data member. + (Incremental_got_plt_reader): New class. + * layout.cc (Layout::create_incremental_info_sections): Add the + incremental_got_plt section. + * object.h (Got_offset_list::get_list): New function. + (Got offset_list::for_all_got_offsets): New function. + (Sized_relobj::local_got_offset_list): New function. + * powerpc.cc (Target_powerpc::got_size): Add const. + (Target_powerpc::got_entry_count): New function. + (Target_powerpc::plt_entry_count): New function. + (Target_powerpc::first_plt_entry_offset): New function. + (Target_powerpc::plt_entry_size): New function. + (Output_data_plt_powerpc::entry_count): New function. + (Output_data_plt_powerpc::first_plt_entry_offset): New function. + (Output_data_plt_powerpc::get_plt_entry_size): New function. + * sparc.cc (Target_sparc::got_size): Add const. + (Target_sparc::got_entry_count): New function. + (Target_sparc::plt_entry_count): New function. + (Target_sparc::first_plt_entry_offset): New function. + (Target_sparc::plt_entry_size): New function. + (Output_data_plt_sparc::entry_count): New function. + (Output_data_plt_sparc::first_plt_entry_offset): New function. + (Output_data_plt_sparc::get_plt_entry_size): New function. + * symtab.h (Symbol::got_offset_list): New function. + (Symbol_table::for_all_symbols): New function. + * target.h (Sized_target::got_entry_count): New function. + (Sized_target::plt_entry_count): New function. + (Sized_target::plt_entry_size): New function. + * x86_64.cc (Target_x86_64::got_size): Add const. + (Target_x86_64::got_entry_count): New function. + (Target_x86_64::plt_entry_count): New function. + (Target_x86_64::first_plt_entry_offset): New function. + (Target_x86_64::plt_entry_size): New function. + (Output_data_plt_x86_64::entry_count): New function. + (Output_data_plt_x86_64::first_plt_entry_offset): New function. + (Output_data_plt_x86_64::get_plt_entry_size): New function. + 2010-08-12 Cary Coutant * archive.cc: Include incremental.h. diff --git a/gold/arm.cc b/gold/arm.cc index 51ce38c2ddc..123f896e9d3 100644 --- a/gold/arm.cc +++ b/gold/arm.cc @@ -2342,12 +2342,33 @@ class Target_arm : public Sized_target<32, big_endian> // 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->has_got_section()) + 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; + // Map platform-specific reloc types static unsigned int get_real_reloc_type (unsigned int r_type); @@ -2816,6 +2837,9 @@ class Target_arm : public Sized_target<32, big_endian> static const Target::Target_info arm_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 @@ -7111,6 +7135,21 @@ class Output_data_plt_arm : public Output_section_data rel_plt() const { return this->rel_; } + // 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 sizeof(first_plt_entry); } + + // Return the size of a PLT entry. + static unsigned int + get_plt_entry_size() + { return sizeof(plt_entry); } + protected: void do_adjust_output_section(Output_section* os); @@ -7326,6 +7365,35 @@ Target_arm::make_plt_entry(Symbol_table* symtab, Layout* layout, this->plt_->add_entry(gsym); } +// Return the number of entries in the PLT. + +template +unsigned int +Target_arm::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. + +template +unsigned int +Target_arm::first_plt_entry_offset() const +{ + return Output_data_plt_arm::first_plt_entry_offset(); +} + +// Return the size of each PLT entry. + +template +unsigned int +Target_arm::plt_entry_size() const +{ + return Output_data_plt_arm::get_plt_entry_size(); +} + // Get the section to use for TLS_DESC relocations. template diff --git a/gold/i386.cc b/gold/i386.cc index b4040c198cd..b27296769a7 100644 --- a/gold/i386.cc +++ b/gold/i386.cc @@ -185,12 +185,33 @@ class Target_i386 : public Target_freebsd<32, 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 @@ -441,6 +462,9 @@ class Target_i386 : public Target_freebsd<32, false> 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 @@ -584,6 +608,21 @@ class Output_data_plt_i386 : public Output_section_data 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); @@ -849,6 +888,32 @@ Target_i386::make_plt_entry(Symbol_table* symtab, Layout* layout, Symbol* gsym) 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* diff --git a/gold/incremental-dump.cc b/gold/incremental-dump.cc index 98555cdb146..68fba5ca1e1 100644 --- a/gold/incremental-dump.cc +++ b/gold/incremental-dump.cc @@ -79,6 +79,7 @@ dump_incremental_inputs(const char* argv0, const char* filename, unsigned int inputs_shndx; unsigned int isymtab_shndx; unsigned int irelocs_shndx; + unsigned int igot_plt_shndx; unsigned int istrtab_shndx; typedef Incremental_binary::Location Location; typedef Incremental_binary::View View; @@ -88,7 +89,8 @@ dump_incremental_inputs(const char* argv0, const char* filename, // Find the .gnu_incremental_inputs, _symtab, _relocs, and _strtab sections. t = inc->find_incremental_inputs_sections(&inputs_shndx, &isymtab_shndx, - &irelocs_shndx, &istrtab_shndx); + &irelocs_shndx, &igot_plt_shndx, + &istrtab_shndx); if (!t) { fprintf(stderr, "%s: %s: no .gnu_incremental_inputs section\n", argv0, @@ -134,9 +136,7 @@ dump_incremental_inputs(const char* argv0, const char* filename, printf("\nInput files:\n"); for (unsigned int i = 0; i < incremental_inputs.input_file_count(); ++i) { - typedef Incremental_inputs_reader Inputs_reader; - typename Inputs_reader::Incremental_input_entry_reader input_file = - incremental_inputs.input_file(i); + Entry_reader input_file = incremental_inputs.input_file(i); const char* objname = input_file.filename(); if (objname == NULL) @@ -203,10 +203,6 @@ dump_incremental_inputs(const char* argv0, const char* filename, printf("\nInput sections:\n"); for (unsigned int i = 0; i < incremental_inputs.input_file_count(); ++i) { - typedef Incremental_inputs_reader Inputs_reader; - typedef typename Inputs_reader::Incremental_input_entry_reader - Entry_reader; - Entry_reader input_file(incremental_inputs.input_file(i)); if (input_file.type() != INCREMENTAL_INPUT_OBJECT @@ -241,10 +237,6 @@ dump_incremental_inputs(const char* argv0, const char* filename, printf("\nGlobal symbols per input file:\n"); for (unsigned int i = 0; i < incremental_inputs.input_file_count(); ++i) { - typedef Incremental_inputs_reader Inputs_reader; - typedef typename Inputs_reader::Incremental_input_entry_reader - Entry_reader; - Entry_reader input_file(incremental_inputs.input_file(i)); if (input_file.type() != INCREMENTAL_INPUT_OBJECT @@ -374,6 +366,54 @@ dump_incremental_inputs(const char* argv0, const char* filename, isym_p += 4; } + // Get a view of the .gnu_incremental_got_plt section. + + Location igot_plt_location(elf_file.section_contents(igot_plt_shndx)); + View igot_plt_view(inc->view(igot_plt_location)); + + Incremental_got_plt_reader igot_plt(igot_plt_view.data()); + unsigned int ngot = igot_plt.get_got_entry_count(); + unsigned int nplt = igot_plt.get_plt_entry_count(); + + printf("\nGOT entries:\n"); + for (unsigned int i = 0; i < ngot; ++i) + { + unsigned int got_type = igot_plt.get_got_type(i); + unsigned int got_desc = igot_plt.get_got_desc(i); + printf("[%d] type %02x, ", i, got_type & 0x7f); + if (got_type == 0x7f) + printf("reserved"); + else if (got_type & 0x80) + { + Entry_reader input_file = incremental_inputs.input_file(got_desc); + const char* objname = input_file.filename(); + printf("local: %s (%d)", objname, got_desc); + } + else + { + sym_p = symtab_view.data() + got_desc * sym_size; + elfcpp::Sym sym(sym_p); + const char* symname; + if (!strtab.get_c_string(sym.get_st_name(), &symname)) + symname = ""; + printf("global %s (%d)", symname, got_desc); + } + printf("\n"); + } + + printf("\nPLT entries:\n"); + for (unsigned int i = 0; i < nplt; ++i) + { + unsigned int plt_desc = igot_plt.get_plt_desc(i); + printf("[%d] ", i); + sym_p = symtab_view.data() + plt_desc * sym_size; + elfcpp::Sym sym(sym_p); + const char* symname; + if (!strtab.get_c_string(sym.get_st_name(), &symname)) + symname = ""; + printf("%s (%d)\n", symname, plt_desc); + } + printf("\nUnused archive symbols:\n"); for (unsigned int i = 0; i < incremental_inputs.input_file_count(); ++i) { diff --git a/gold/incremental.cc b/gold/incremental.cc index b279c72ead3..b2ec781d896 100644 --- a/gold/incremental.cc +++ b/gold/incremental.cc @@ -32,6 +32,7 @@ #include "archive.h" #include "output.h" #include "target-select.h" +#include "target.h" namespace gold { @@ -88,6 +89,10 @@ class Output_section_incremental_inputs : public Output_section_data write_symtab(unsigned char* pov, unsigned int* global_syms, unsigned int global_sym_count); + // Write the contents of the .gnu_incremental_got_plt section. + void + write_got_plt(unsigned char* pov, off_t view_size); + // Typedefs for writing the data to the output sections. typedef elfcpp::Swap Swap; typedef elfcpp::Swap<16, big_endian> Swap16; @@ -153,6 +158,7 @@ Sized_incremental_binary::do_find_incremental_inputs_sections( unsigned int* p_inputs_shndx, unsigned int* p_symtab_shndx, unsigned int* p_relocs_shndx, + unsigned int* p_got_plt_shndx, unsigned int* p_strtab_shndx) { unsigned int inputs_shndx = @@ -174,6 +180,13 @@ Sized_incremental_binary::do_find_incremental_inputs_sections( if (this->elf_file_.section_link(relocs_shndx) != inputs_shndx) return false; + unsigned int got_plt_shndx = + this->elf_file_.find_section_by_type(elfcpp::SHT_GNU_INCREMENTAL_GOT_PLT); + if (got_plt_shndx == elfcpp::SHN_UNDEF) // Not found. + return false; + if (this->elf_file_.section_link(got_plt_shndx) != inputs_shndx) + return false; + unsigned int strtab_shndx = this->elf_file_.section_link(inputs_shndx); if (strtab_shndx == elfcpp::SHN_UNDEF || strtab_shndx > this->elf_file_.shnum() @@ -186,6 +199,8 @@ Sized_incremental_binary::do_find_incremental_inputs_sections( *p_symtab_shndx = symtab_shndx; if (p_relocs_shndx != NULL) *p_relocs_shndx = relocs_shndx; + if (p_got_plt_shndx != NULL) + *p_got_plt_shndx = got_plt_shndx; if (p_strtab_shndx != NULL) *p_strtab_shndx = strtab_shndx; return true; @@ -202,10 +217,12 @@ Sized_incremental_binary::do_check_inputs( unsigned int inputs_shndx; unsigned int symtab_shndx; unsigned int relocs_shndx; + unsigned int plt_got_shndx; unsigned int strtab_shndx; if (!do_find_incremental_inputs_sections(&inputs_shndx, &symtab_shndx, - &relocs_shndx, &strtab_shndx)) + &relocs_shndx, &plt_got_shndx, + &strtab_shndx)) { explain_no_incremental(_("no incremental data from previous build")); return false; @@ -555,6 +572,7 @@ Incremental_inputs::create_data_sections(Symbol_table* symtab) } this->symtab_section_ = new Output_data_space(4, "** incremental_symtab"); this->relocs_section_ = new Output_data_space(4, "** incremental_relocs"); + this->got_plt_section_ = new Output_data_space(4, "** incremental_got_plt"); } // Return the sh_entsize value for the .gnu_incremental_relocs section. @@ -657,6 +675,16 @@ Output_section_incremental_inputs::set_final_data_size() // Set the size of the .gnu_incremental_relocs section. inputs->relocs_section()->set_current_data_size(inputs->get_reloc_count() * rel_size); + + // Set the size of the .gnu_incremental_got_plt section. + Sized_target* target = + parameters->sized_target(); + unsigned int got_count = target->got_entry_count(); + unsigned int plt_count = target->plt_entry_count(); + unsigned int got_plt_size = 8; // GOT entry count, PLT entry count. + got_plt_size = (got_plt_size + got_count + 3) & ~3; // GOT type array. + got_plt_size += got_count * 4 + plt_count * 4; // GOT array, PLT array. + inputs->got_plt_section()->set_current_data_size(got_plt_size); } // Write the contents of the .gnu_incremental_inputs and @@ -711,8 +739,16 @@ Output_section_incremental_inputs::do_write(Output_file* of) delete[] global_syms; + // Write the .gnu_incremental_got_plt section. + const off_t got_plt_off = inputs->got_plt_section()->offset(); + const off_t got_plt_size = inputs->got_plt_section()->data_size(); + unsigned char* const got_plt_view = of->get_output_view(got_plt_off, + got_plt_size); + this->write_got_plt(got_plt_view, got_plt_size); + of->write_output_view(off, oview_size, oview); of->write_output_view(symtab_off, symtab_size, symtab_view); + of->write_output_view(got_plt_off, got_plt_size, got_plt_view); } // Write the section header: version, input file count, offset of command line @@ -936,6 +972,195 @@ Output_section_incremental_inputs::write_symtab( } } +// This struct holds the view information needed to write the +// .gnu_incremental_got_plt section. + +struct Got_plt_view_info +{ + // Start of the GOT type array in the output view. + unsigned char* got_type_p; + // Start of the GOT descriptor array in the output view. + unsigned char* got_desc_p; + // Start of the PLT descriptor array in the output view. + unsigned char* plt_desc_p; + // Number of GOT entries. + unsigned int got_count; + // Number of PLT entries. + unsigned int plt_count; + // Offset of the first non-reserved PLT entry (this is a target-dependent value). + unsigned int first_plt_entry_offset; + // Size of a PLT entry (this is a target-dependent value). + unsigned int plt_entry_size; + // Value to write in the GOT descriptor array. For global symbols, + // this is the global symbol table index; for local symbols, it is + // the offset of the input file entry in the .gnu_incremental_inputs + // section. + unsigned int got_descriptor; +}; + +// Functor class for processing a GOT offset list for local symbols. +// Writes the GOT type and symbol index into the GOT type and descriptor +// arrays in the output section. + +template +class Local_got_offset_visitor +{ + public: + Local_got_offset_visitor(struct Got_plt_view_info& info) + : info_(info) + { } + + void + operator()(unsigned int got_type, unsigned int got_offset) + { + unsigned int got_index = got_offset / this->got_entry_size_; + gold_assert(got_index < this->info_.got_count); + // We can only handle GOT entry types in the range 0..0x7e + // because we use a byte array to store them, and we use the + // high bit to flag a local symbol. + gold_assert(got_type < 0x7f); + this->info_.got_type_p[got_index] = got_type | 0x80; + unsigned char* pov = this->info_.got_desc_p + got_index * 4; + elfcpp::Swap<32, big_endian>::writeval(pov, this->info_.got_descriptor); + } + + private: + static const unsigned int got_entry_size_ = size / 8; + struct Got_plt_view_info& info_; +}; + +// Functor class for processing a GOT offset list. Writes the GOT type +// and symbol index into the GOT type and descriptor arrays in the output +// section. + +template +class Global_got_offset_visitor +{ + public: + Global_got_offset_visitor(struct Got_plt_view_info& info) + : info_(info) + { } + + void + operator()(unsigned int got_type, unsigned int got_offset) + { + unsigned int got_index = got_offset / this->got_entry_size_; + gold_assert(got_index < this->info_.got_count); + // We can only handle GOT entry types in the range 0..0x7e + // because we use a byte array to store them, and we use the + // high bit to flag a local symbol. + gold_assert(got_type < 0x7f); + this->info_.got_type_p[got_index] = got_type; + unsigned char* pov = this->info_.got_desc_p + got_index * 4; + elfcpp::Swap<32, big_endian>::writeval(pov, this->info_.got_descriptor); + } + + private: + static const unsigned int got_entry_size_ = size / 8; + struct Got_plt_view_info& info_; +}; + +// Functor class for processing the global symbol table. Processes the +// GOT offset list for the symbol, and writes the symbol table index +// into the PLT descriptor array in the output section. + +template +class Global_symbol_visitor_got_plt +{ + public: + Global_symbol_visitor_got_plt(struct Got_plt_view_info& info) + : info_(info) + { } + + void + operator()(const Sized_symbol* sym) + { + typedef Global_got_offset_visitor Got_visitor; + const Got_offset_list* got_offsets = sym->got_offset_list(); + if (got_offsets != NULL) + { + info_.got_descriptor = sym->symtab_index(); + got_offsets->for_all_got_offsets(Got_visitor(info_)); + } + if (sym->has_plt_offset()) + { + unsigned int plt_index = + ((sym->plt_offset() - this->info_.first_plt_entry_offset) + / this->info_.plt_entry_size); + gold_assert(plt_index < this->info_.plt_count); + unsigned char* pov = this->info_.plt_desc_p + plt_index * 4; + elfcpp::Swap<32, big_endian>::writeval(pov, sym->symtab_index()); + } + } + + private: + struct Got_plt_view_info& info_; +}; + +// Write the contents of the .gnu_incremental_got_plt section. + +template +void +Output_section_incremental_inputs::write_got_plt( + unsigned char* pov, + off_t view_size) +{ + Sized_target* target = + parameters->sized_target(); + + // Set up the view information for the functors. + struct Got_plt_view_info view_info; + view_info.got_count = target->got_entry_count(); + view_info.plt_count = target->plt_entry_count(); + view_info.first_plt_entry_offset = target->first_plt_entry_offset(); + view_info.plt_entry_size = target->plt_entry_size(); + view_info.got_type_p = pov + 8; + view_info.got_desc_p = (view_info.got_type_p + + ((view_info.got_count + 3) & ~3)); + view_info.plt_desc_p = view_info.got_desc_p + view_info.got_count * 4; + + gold_assert(pov + view_size == + view_info.plt_desc_p + view_info.plt_count * 4); + + // Write the section header. + Swap32::writeval(pov, view_info.got_count); + Swap32::writeval(pov + 4, view_info.plt_count); + + // Initialize the GOT type array to 0xff (reserved). + memset(view_info.got_type_p, 0xff, view_info.got_count); + + // Write the incremental GOT descriptors for local symbols. + for (Incremental_inputs::Input_list::const_iterator p = + this->inputs_->input_files().begin(); + p != this->inputs_->input_files().end(); + ++p) + { + if ((*p)->type() != INCREMENTAL_INPUT_OBJECT + && (*p)->type() != INCREMENTAL_INPUT_ARCHIVE_MEMBER) + continue; + Incremental_object_entry* entry = (*p)->object_entry(); + gold_assert(entry != NULL); + const Sized_relobj* obj = + static_cast*>(entry->object()); + gold_assert(obj != NULL); + unsigned int nsyms = obj->local_symbol_count(); + for (unsigned int i = 0; i < nsyms; i++) + { + const Got_offset_list* got_offsets = obj->local_got_offset_list(i); + if (got_offsets != NULL) + { + typedef Local_got_offset_visitor Got_visitor; + view_info.got_descriptor = (*p)->get_offset(); + got_offsets->for_all_got_offsets(Got_visitor(view_info)); + } + } + } + + // Write the incremental GOT and PLT descriptors for global symbols. + typedef Global_symbol_visitor_got_plt Symbol_visitor; + symtab_->for_all_symbols(Symbol_visitor(view_info)); +} + // Instantiate the templates we need. #ifdef HAVE_TARGET_32_LITTLE diff --git a/gold/incremental.h b/gold/incremental.h index 6fb1a324e74..c1f3c990894 100644 --- a/gold/incremental.h +++ b/gold/incremental.h @@ -131,10 +131,12 @@ class Incremental_binary find_incremental_inputs_sections(unsigned int* p_inputs_shndx, unsigned int* p_symtab_shndx, unsigned int* p_relocs_shndx, + unsigned int* p_got_plt_shndx, unsigned int* p_strtab_shndx) { return do_find_incremental_inputs_sections(p_inputs_shndx, p_symtab_shndx, - p_relocs_shndx, p_strtab_shndx); + p_relocs_shndx, p_got_plt_shndx, + p_strtab_shndx); } // Check the .gnu_incremental_inputs section to see whether an incremental @@ -153,6 +155,7 @@ class Incremental_binary do_find_incremental_inputs_sections(unsigned int* p_inputs_shndx, unsigned int* p_symtab_shndx, unsigned int* p_relocs_shndx, + unsigned int* p_got_plt_shndx, unsigned int* p_strtab_shndx) = 0; // Check the .gnu_incremental_inputs section to see whether an incremental @@ -182,6 +185,7 @@ class Sized_incremental_binary : public Incremental_binary do_find_incremental_inputs_sections(unsigned int* p_inputs_shndx, unsigned int* p_symtab_shndx, unsigned int* p_relocs_shndx, + unsigned int* p_got_plt_shndx, unsigned int* p_strtab_shndx); virtual bool @@ -577,6 +581,11 @@ class Incremental_inputs relocs_section() const { return this->relocs_section_; } + // Return the .gnu_incremental_got_plt section. + Output_data_space* + got_plt_section() const + { return this->got_plt_section_; } + // Return the .gnu_incremental_strtab stringpool. Stringpool* get_stringpool() const @@ -635,6 +644,9 @@ class Incremental_inputs // The .gnu_incremental_relocs section. Output_data_space* relocs_section_; + // The .gnu_incremental_got_plt section. + Output_data_space* got_plt_section_; + // Total count of incremental relocations. Updated during Scan_relocs // phase at the completion of each object file. unsigned int reloc_count_; @@ -889,7 +901,7 @@ class Incremental_symtab_reader { } // Return the list head for symbol table entry N. - unsigned int get_list_head(unsigned int n) + unsigned int get_list_head(unsigned int n) const { return elfcpp::Swap<32, big_endian>::readval(this->p_ + 4 * n); } private: @@ -918,28 +930,28 @@ class Incremental_relocs_reader // Return the relocation type for relocation entry at offset OFF. unsigned int - get_r_type(unsigned int off) + get_r_type(unsigned int off) const { return elfcpp::Swap<32, big_endian>::readval(this->p_ + off); } // Return the output section index for relocation entry at offset OFF. unsigned int - get_r_shndx(unsigned int off) + get_r_shndx(unsigned int off) const { return elfcpp::Swap<32, big_endian>::readval(this->p_ + off + 4); } // Return the output section offset for relocation entry at offset OFF. Address - get_r_offset(unsigned int off) + get_r_offset(unsigned int off) const { return elfcpp::Swap::readval(this->p_ + off + 8); } // Return the addend for relocation entry at offset OFF. Addend - get_r_addend(unsigned int off) + get_r_addend(unsigned int off) const { return elfcpp::Swap::readval(this->p_ + off + 8 + this->field_size); @@ -950,6 +962,65 @@ class Incremental_relocs_reader const unsigned char* p_; }; +// Reader class for the .gnu_incremental_got_plt section. + +template +class Incremental_got_plt_reader +{ + public: + Incremental_got_plt_reader(const unsigned char* p) : p_(p) + { + this->got_count_ = elfcpp::Swap<32, big_endian>::readval(p); + this->got_desc_p_ = p + 8 + ((this->got_count_ + 3) & ~3); + this->plt_desc_p_ = this->got_desc_p_ + this->got_count_ * 4; + } + + // Return the GOT entry count. + unsigned int + get_got_entry_count() const + { + return this->got_count_; + } + + // Return the PLT entry count. + unsigned int + get_plt_entry_count() const + { + return elfcpp::Swap<32, big_endian>::readval(this->p_ + 4); + } + + // Return the GOT type for GOT entry N. + unsigned int + get_got_type(unsigned int n) + { + return this->p_[8 + n]; + } + + // Return the GOT descriptor for GOT entry N. + unsigned int + get_got_desc(unsigned int n) + { + return elfcpp::Swap<32, big_endian>::readval(this->got_desc_p_ + n * 4); + } + + // Return the PLT descriptor for PLT entry N. + unsigned int + get_plt_desc(unsigned int n) + { + return elfcpp::Swap<32, big_endian>::readval(this->plt_desc_p_ + n * 4); + } + + private: + // Base address of the .gnu_incremental_got_plt section. + const unsigned char* p_; + // GOT entry count. + unsigned int got_count_; + // Base address of the GOT descriptor array. + const unsigned char* got_desc_p_; + // Base address of the PLT descriptor array. + const unsigned char* plt_desc_p_; +}; + } // End namespace gold. #endif // !defined(GOLD_INCREMENTAL_H) diff --git a/gold/layout.cc b/gold/layout.cc index eb1322ae6af..1dd41f3df28 100644 --- a/gold/layout.cc +++ b/gold/layout.cc @@ -2342,6 +2342,15 @@ Layout::create_incremental_info_sections(Symbol_table* symtab) incremental_relocs_os->add_output_section_data(incr->relocs_section()); incremental_relocs_os->set_entsize(incr->relocs_entsize()); + // Add the .gnu_incremental_got_plt section. + const char *incremental_got_plt_name = + this->namepool_.add(".gnu_incremental_got_plt", false, NULL); + Output_section* incremental_got_plt_os = + this->make_output_section(incremental_got_plt_name, + elfcpp::SHT_GNU_INCREMENTAL_GOT_PLT, 0, + ORDER_INVALID, false); + incremental_got_plt_os->add_output_section_data(incr->got_plt_section()); + // Add the .gnu_incremental_strtab section. const char *incremental_strtab_name = this->namepool_.add(".gnu_incremental_strtab", false, NULL); @@ -2355,10 +2364,12 @@ Layout::create_incremental_info_sections(Symbol_table* symtab) incremental_inputs_os->set_after_input_sections(); incremental_symtab_os->set_after_input_sections(); incremental_relocs_os->set_after_input_sections(); + incremental_got_plt_os->set_after_input_sections(); incremental_inputs_os->set_link_section(incremental_strtab_os); incremental_symtab_os->set_link_section(incremental_inputs_os); incremental_relocs_os->set_link_section(incremental_inputs_os); + incremental_got_plt_os->set_link_section(incremental_inputs_os); } // Return whether SEG1 should be before SEG2 in the output file. This diff --git a/gold/object.h b/gold/object.h index 99ceabfb448..94ad64312e1 100644 --- a/gold/object.h +++ b/gold/object.h @@ -1479,6 +1479,26 @@ class Got_offset_list return -1U; } + // Return a pointer to the list, or NULL if the list is empty. + const Got_offset_list* + get_list() const + { + if (this->got_type_ == -1U) + return NULL; + return this; + } + + // Loop over all GOT offset entries, applying the function F to each. + template + void + for_all_got_offsets(F f) const + { + if (this->got_type_ == -1U) + return; + for (const Got_offset_list* g = this; g != NULL; g = g->got_next_) + f(g->got_type_, g->got_offset_); + } + private: unsigned int got_type_; unsigned int got_offset_; @@ -1661,6 +1681,17 @@ class Sized_relobj : public Relobj } } + // Return the GOT offset list for the local symbol SYMNDX. + const Got_offset_list* + local_got_offset_list(unsigned int symndx) const + { + Local_got_offsets::const_iterator p = + this->local_got_offsets_.find(symndx); + if (p == this->local_got_offsets_.end()) + return NULL; + return p->second; + } + // Get the offset of input section SHNDX within its output section. // This is -1 if the input section requires a special mapping, such // as a merge section. The output section can be found in the diff --git a/gold/powerpc.cc b/gold/powerpc.cc index 88bc378c5ff..aca75f286db 100644 --- a/gold/powerpc.cc +++ b/gold/powerpc.cc @@ -1,6 +1,6 @@ // powerpc.cc -- powerpc target support for gold. -// Copyright 2008, 2009 Free Software Foundation, Inc. +// Copyright 2008, 2009, 2010 Free Software Foundation, Inc. // Written by David S. Miller // and David Edelsohn @@ -151,12 +151,33 @@ class Target_powerpc : public Sized_target // 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() / (size / 8); + } + + // 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. @@ -321,6 +342,9 @@ class Target_powerpc : public Sized_target static Target::Target_info powerpc_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 @@ -808,6 +832,21 @@ class Output_data_plt_powerpc : public Output_section_data return this->rel_; } + // 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 4 * base_plt_entry_size; } + + // Return the size of a PLT entry. + static unsigned int + get_plt_entry_size() + { return base_plt_entry_size; } + protected: void do_adjust_output_section(Output_section* os); @@ -993,6 +1032,35 @@ Target_powerpc::make_plt_entry(Symbol_table* symtab, this->plt_->add_entry(gsym); } +// Return the number of entries in the PLT. + +template +unsigned int +Target_powerpc::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. + +template +unsigned int +Target_powerpc::first_plt_entry_offset() const +{ + return Output_data_plt_powerpc::first_plt_entry_offset(); +} + +// Return the size of each PLT entry. + +template +unsigned int +Target_powerpc::plt_entry_size() const +{ + return Output_data_plt_powerpc::get_plt_entry_size(); +} + // Create a GOT entry for the TLS module index. template diff --git a/gold/sparc.cc b/gold/sparc.cc index 1635f33cdbf..2f8ef7a43ec 100644 --- a/gold/sparc.cc +++ b/gold/sparc.cc @@ -1,6 +1,6 @@ // sparc.cc -- sparc target support for gold. -// Copyright 2008, 2009 Free Software Foundation, Inc. +// Copyright 2008, 2009, 2010 Free Software Foundation, Inc. // Written by David S. Miller . // This file is part of gold. @@ -161,12 +161,33 @@ class Target_sparc : public Sized_target // 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() / (size / 8); + } + + // 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. @@ -343,6 +364,9 @@ class Target_sparc : public Sized_target static Target::Target_info sparc_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 @@ -1100,6 +1124,21 @@ class Output_data_plt_sparc : public Output_section_data return this->rel_; } + // 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 4 * base_plt_entry_size; } + + // Return the size of a PLT entry. + static unsigned int + get_plt_entry_size() + { return base_plt_entry_size; } + protected: void do_adjust_output_section(Output_section* os); @@ -1415,6 +1454,35 @@ Target_sparc::make_plt_entry(Symbol_table* symtab, this->plt_->add_entry(gsym); } +// Return the number of entries in the PLT. + +template +unsigned int +Target_sparc::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. + +template +unsigned int +Target_sparc::first_plt_entry_offset() const +{ + return Output_data_plt_sparc::first_plt_entry_offset(); +} + +// Return the size of each PLT entry. + +template +unsigned int +Target_sparc::plt_entry_size() const +{ + return Output_data_plt_sparc::get_plt_entry_size(); +} + // Create a GOT entry for the TLS module index. template diff --git a/gold/symtab.h b/gold/symtab.h index 4e5b7b05ab9..8ccbca9a410 100644 --- a/gold/symtab.h +++ b/gold/symtab.h @@ -409,6 +409,11 @@ class Symbol set_got_offset(unsigned int got_type, unsigned int got_offset) { this->got_offsets_.set_offset(got_type, got_offset); } + // Return the GOT offset list. + const Got_offset_list* + got_offset_list() const + { return this->got_offsets_.get_list(); } + // Return whether this symbol has an entry in the PLT section. bool has_plt_offset() const @@ -1489,6 +1494,20 @@ class Symbol_table write_section_symbol(const Output_section*, Output_symtab_xindex*, Output_file*, off_t) const; + // Loop over all symbols, applying the function F to each. + template + void + for_all_symbols(F f) const + { + for (Symbol_table_type::const_iterator p = this->table_.begin(); + p != this->table_.end(); + ++p) + { + Sized_symbol* sym = static_cast*>(p->second); + f(sym); + } + } + // Dump statistical information to stderr. void print_stats() const; diff --git a/gold/target.h b/gold/target.h index 9f9c4f9dfab..6ab31d05c59 100644 --- a/gold/target.h +++ b/gold/target.h @@ -1,6 +1,6 @@ // target.h -- target support for gold -*- C++ -*- -// Copyright 2006, 2007, 2008, 2009 Free Software Foundation, Inc. +// Copyright 2006, 2007, 2008, 2009, 2010 Free Software Foundation, Inc. // Written by Ian Lance Taylor . // This file is part of gold. @@ -732,6 +732,38 @@ class Sized_target : public Target unsigned char* /* preloc_out*/) { gold_unreachable(); } + // Return the number of entries in the GOT. This is only used for + // laying out the incremental link info sections. A target needs + // to implement this to support incremental linking. + + virtual unsigned int + got_entry_count() const + { gold_unreachable(); } + + // Return the number of entries in the PLT. This is only used for + // laying out the incremental link info sections. A target needs + // to implement this to support incremental linking. + + virtual unsigned int + plt_entry_count() const + { gold_unreachable(); } + + // Return the offset of the first non-reserved PLT entry. This is + // only used for laying out the incremental link info sections. + // A target needs to implement this to support incremental linking. + + virtual unsigned int + first_plt_entry_offset() const + { gold_unreachable(); } + + // Return the size of each PLT entry. This is only used for + // laying out the incremental link info sections. A target needs + // to implement this to support incremental linking. + + virtual unsigned int + plt_entry_size() const + { gold_unreachable(); } + protected: Sized_target(const Target::Target_info* pti) : Target(pti) diff --git a/gold/x86_64.cc b/gold/x86_64.cc index bfa494c33dc..df46f2b9771 100644 --- a/gold/x86_64.cc +++ b/gold/x86_64.cc @@ -197,12 +197,33 @@ class Target_x86_64 : public Target_freebsd<64, 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() / 8; + } + + // 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; + // 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) @@ -466,6 +487,10 @@ class Target_x86_64 : public Target_freebsd<64, false> // general Target structure. static const Target::Target_info x86_64_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 @@ -659,6 +684,21 @@ class Output_data_plt_x86_64 : public Output_section_data Reloc_section* rela_tlsdesc(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); @@ -960,6 +1000,32 @@ Target_x86_64::make_plt_entry(Symbol_table* symtab, Layout* layout, this->plt_->add_entry(gsym); } +// Return the number of entries in the PLT. + +unsigned int +Target_x86_64::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_x86_64::first_plt_entry_offset() const +{ + return Output_data_plt_x86_64::first_plt_entry_offset(); +} + +// Return the size of each PLT entry. + +unsigned int +Target_x86_64::plt_entry_size() const +{ + return Output_data_plt_x86_64::get_plt_entry_size(); +} + // Define the _TLS_MODULE_BASE_ symbol in the TLS segment. void -- 2.30.2