diff options
author | Cary Coutant <ccoutant@google.com> | 2010-08-12 22:15:00 +0000 |
---|---|---|
committer | Cary Coutant <ccoutant@google.com> | 2010-08-12 22:15:00 +0000 |
commit | 0e70b9111a696f5b70cade541df55de14c31f9f1 (patch) | |
tree | 6f83a4c1e2c4431cbffd2ee3bb5e71f1fe8cece0 /gold/incremental.cc | |
parent | 09ec0418c0d4144afba5947499425e27900d953f (diff) | |
download | fsf-binutils-gdb-0e70b9111a696f5b70cade541df55de14c31f9f1.zip fsf-binutils-gdb-0e70b9111a696f5b70cade541df55de14c31f9f1.tar.gz fsf-binutils-gdb-0e70b9111a696f5b70cade541df55de14c31f9f1.tar.bz2 |
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.
Diffstat (limited to 'gold/incremental.cc')
-rw-r--r-- | gold/incremental.cc | 227 |
1 files changed, 226 insertions, 1 deletions
diff --git a/gold/incremental.cc b/gold/incremental.cc index b279c72..b2ec781 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<size, big_endian> Swap; typedef elfcpp::Swap<16, big_endian> Swap16; @@ -153,6 +158,7 @@ Sized_incremental_binary<size, big_endian>::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<size, big_endian>::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<size, big_endian>::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<size, big_endian>::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<size, big_endian>::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<size, big_endian>* target = + parameters->sized_target<size, big_endian>(); + 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<size, big_endian>::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<size, big_endian>::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<int size, bool big_endian> +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<int size, bool big_endian> +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<int size, bool big_endian> +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<size>* sym) + { + typedef Global_got_offset_visitor<size, big_endian> 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<int size, bool big_endian> +void +Output_section_incremental_inputs<size, big_endian>::write_got_plt( + unsigned char* pov, + off_t view_size) +{ + Sized_target<size, big_endian>* target = + parameters->sized_target<size, big_endian>(); + + // 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<size, big_endian>* obj = + static_cast<Sized_relobj<size, big_endian>*>(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<size, big_endian> 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<size, big_endian> Symbol_visitor; + symtab_->for_all_symbols<size, Symbol_visitor>(Symbol_visitor(view_info)); +} + // Instantiate the templates we need. #ifdef HAVE_TARGET_32_LITTLE |