aboutsummaryrefslogtreecommitdiff
path: root/gold/incremental.cc
diff options
context:
space:
mode:
authorCary Coutant <ccoutant@google.com>2010-08-12 22:15:00 +0000
committerCary Coutant <ccoutant@google.com>2010-08-12 22:15:00 +0000
commit0e70b9111a696f5b70cade541df55de14c31f9f1 (patch)
tree6f83a4c1e2c4431cbffd2ee3bb5e71f1fe8cece0 /gold/incremental.cc
parent09ec0418c0d4144afba5947499425e27900d953f (diff)
downloadfsf-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.cc227
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