summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--gold/ChangeLog75
-rw-r--r--gold/arm.cc70
-rw-r--r--gold/i386.cc67
-rw-r--r--gold/incremental-dump.cc64
-rw-r--r--gold/incremental.cc227
-rw-r--r--gold/incremental.h83
-rw-r--r--gold/layout.cc11
-rw-r--r--gold/object.h31
-rw-r--r--gold/powerpc.cc72
-rw-r--r--gold/sparc.cc72
-rw-r--r--gold/symtab.h19
-rw-r--r--gold/target.h34
-rw-r--r--gold/x86_64.cc68
13 files changed, 866 insertions, 27 deletions
diff --git a/gold/ChangeLog b/gold/ChangeLog
index c77f2d7cc1..47814f0251 100644
--- a/gold/ChangeLog
+++ b/gold/ChangeLog
@@ -1,5 +1,80 @@
2010-08-12 Cary Coutant <ccoutant@google.com>
+ * 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 <ccoutant@google.com>
+
* archive.cc: Include incremental.h.
(Archive::Archive): Initialize incremental_info_.
(Archive::include_member): Record archive members in incremental info.
diff --git a/gold/arm.cc b/gold/arm.cc
index 51ce38c2dd..123f896e9d 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<big_endian>::make_plt_entry(Symbol_table* symtab, Layout* layout,
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>
diff --git a/gold/i386.cc b/gold/i386.cc
index b4040c198c..b27296769a 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 98555cdb14..68fba5ca1e 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<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)
@@ -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<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
@@ -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<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
@@ -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<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)
{
diff --git a/gold/incremental.cc b/gold/incremental.cc
index b279c72ead..b2ec781d89 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
diff --git a/gold/incremental.h b/gold/incremental.h
index 6fb1a324e7..c1f3c99089 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<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);
@@ -950,6 +962,65 @@ class Incremental_relocs_reader
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)
diff --git a/gold/layout.cc b/gold/layout.cc
index eb1322ae6a..1dd41f3df2 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 99ceabfb44..94ad64312e 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<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_;
@@ -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 88bc378c5f..aca75f286d 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 <davem@davemloft.net>
// and David Edelsohn <edelsohn@gnu.org>
@@ -151,12 +151,33 @@ class Target_powerpc : public Sized_target<size, 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() / (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<size, big_endian>
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<size, big_endian>::make_plt_entry(Symbol_table* symtab,
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>
diff --git a/gold/sparc.cc b/gold/sparc.cc
index 1635f33cdb..2f8ef7a43e 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 <davem@davemloft.net>.
// This file is part of gold.
@@ -161,12 +161,33 @@ class Target_sparc : public Sized_target<size, 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() / (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<size, big_endian>
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<size, big_endian>::make_plt_entry(Symbol_table* symtab,
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>
diff --git a/gold/symtab.h b/gold/symtab.h
index 4e5b7b05ab..8ccbca9a41 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<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;
diff --git a/gold/target.h b/gold/target.h
index 9f9c4f9dfa..6ab31d05c5 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 <iant@google.com>.
// 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 bfa494c33d..df46f2b977 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