* 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.
+
+ * 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.
+
* archive.cc: Include incremental.h.
// 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);
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
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);
this->plt_->add_entry(gsym);
}
+// Return the number of entries in the PLT.
+
+template<bool big_endian>
+unsigned int
+Target_arm<big_endian>::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<bool big_endian>
+unsigned int
+Target_arm<big_endian>::first_plt_entry_offset() const
+{
+ return Output_data_plt_arm<big_endian>::first_plt_entry_offset();
+}
+
+// Return the size of each PLT entry.
+
+template<bool big_endian>
+unsigned int
+Target_arm<big_endian>::plt_entry_size() const
+{
+ return Output_data_plt_arm<big_endian>::get_plt_entry_size();
+}
+
// Get the section to use for TLS_DESC relocations.
template<bool 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->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
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
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->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*
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;
// 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,
printf("\nInput files:\n");
for (unsigned int i = 0; i < incremental_inputs.input_file_count(); ++i)
{
- typedef Incremental_inputs_reader<size, big_endian> 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)
printf("\nInput sections:\n");
for (unsigned int i = 0; i < incremental_inputs.input_file_count(); ++i)
{
- typedef Incremental_inputs_reader<size, big_endian> 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
printf("\nGlobal symbols per input file:\n");
for (unsigned int i = 0; i < incremental_inputs.input_file_count(); ++i)
{
- typedef Incremental_inputs_reader<size, big_endian> 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
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<big_endian> 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<size, big_endian> sym(sym_p);
+ const char* symname;
+ if (!strtab.get_c_string(sym.get_st_name(), &symname))
+ symname = "<unknown>";
+ 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<size, big_endian> sym(sym_p);
+ const char* symname;
+ if (!strtab.get_c_string(sym.get_st_name(), &symname))
+ symname = "<unknown>";
+ printf("%s (%d)\n", symname, plt_desc);
+ }
+
printf("\nUnused archive symbols:\n");
for (unsigned int i = 0; i < incremental_inputs.input_file_count(); ++i)
{
#include "archive.h"
#include "output.h"
#include "target-select.h"
+#include "target.h"
namespace gold {
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;
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 =
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()
*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;
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;
}
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.
// 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
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
}
}
+// 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
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
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
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
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
// 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_;
{ }
// 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:
// 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<size, big_endian>::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<size, big_endian>::readval(this->p_ + off + 8
+ this->field_size);
const unsigned char* p_;
};
+// Reader class for the .gnu_incremental_got_plt section.
+
+template<bool big_endian>
+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)
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);
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
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<typename F>
+ 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_;
}
}
+ // 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
// powerpc.cc -- powerpc target support for gold.
-// Copyright 2008, 2009 Free Software Foundation, Inc.
+// Copyright 2008, 2009, 2010 Free Software Foundation, Inc.
// 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.
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
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);
this->plt_->add_entry(gsym);
}
+// Return the number of entries in the PLT.
+
+template<int size, bool big_endian>
+unsigned int
+Target_powerpc<size, big_endian>::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<int size, bool big_endian>
+unsigned int
+Target_powerpc<size, big_endian>::first_plt_entry_offset() const
+{
+ return Output_data_plt_powerpc<size, big_endian>::first_plt_entry_offset();
+}
+
+// Return the size of each PLT entry.
+
+template<int size, bool big_endian>
+unsigned int
+Target_powerpc<size, big_endian>::plt_entry_size() const
+{
+ return Output_data_plt_powerpc<size, big_endian>::get_plt_entry_size();
+}
+
// Create a GOT entry for the TLS module index.
template<int size, bool big_endian>
// sparc.cc -- sparc target support for gold.
-// Copyright 2008, 2009 Free Software Foundation, Inc.
+// Copyright 2008, 2009, 2010 Free Software Foundation, Inc.
// This file is part of gold.
// 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.
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
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);
this->plt_->add_entry(gsym);
}
+// Return the number of entries in the PLT.
+
+template<int size, bool big_endian>
+unsigned int
+Target_sparc<size, big_endian>::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<int size, bool big_endian>
+unsigned int
+Target_sparc<size, big_endian>::first_plt_entry_offset() const
+{
+ return Output_data_plt_sparc<size, big_endian>::first_plt_entry_offset();
+}
+
+// Return the size of each PLT entry.
+
+template<int size, bool big_endian>
+unsigned int
+Target_sparc<size, big_endian>::plt_entry_size() const
+{
+ return Output_data_plt_sparc<size, big_endian>::get_plt_entry_size();
+}
+
// Create a GOT entry for the TLS module index.
template<int size, bool big_endian>
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
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<int size, typename F>
+ void
+ for_all_symbols(F f) const
+ {
+ for (Symbol_table_type::const_iterator p = this->table_.begin();
+ p != this->table_.end();
+ ++p)
+ {
+ Sized_symbol<size>* sym = static_cast<Sized_symbol<size>*>(p->second);
+ f(sym);
+ }
+ }
+
// Dump statistical information to stderr.
void
print_stats() const;
// 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.
// This file is part of gold.
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)
// 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)
// 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
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);
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