This is the mail archive of the
binutils@sourceware.org
mailing list for the binutils project.
Re: [PATCH] gold: Native Client target support
Here's what I've actually committed. (This is a diff -b patch for
readability in a few places, but the actual commit has all the indentation
correct.)
Thanks,
Roland
2012-05-02 Roland McGrath <mcgrathr@google.com>
* configure.ac (ENABLE_GOLD): Consider *-*-nacl* targets ELF.
* configure: Regenerate.
gold/
2012-05-02 Roland McGrath <mcgrathr@google.com>
* nacl.cc: New file.
* nacl.h: New file.
* Makefile.am (CCFILES, HFILES): Add them.
* Makefile.in: Regenerate.
* i386.cc (Output_data_plt_i386_nacl): New class.
(Output_data_plt_i386_nacl_exec): New class.
(Output_data_plt_i386_nacl_dyn): New class.
(Target_i386_nacl): New class.
(Target_selector_i386_nacl): New class.
(target_selector_i386): Use it instead of Target_selector_i386.
* x86_64.cc (Output_data_plt_x86_64_nacl): New class.
(Target_x86_64_nacl): New class.
(Target_selector_x86_64_nacl): New class.
(target_selector_x86_64, target_selector_x32): Use it instead of
Target_selector_x86_64.
* arm.cc (Output_data_plt_arm_nacl): New class.
(Target_arm_nacl): New class.
(Target_selector_arm_nacl): New class.
(target_selector_arm, target_selector_armbe): Use it instead of
Target_selector_arm.
* target-select.cc (select_target): Take new Input_file* and off_t
arguments, pass them on to recognize method of selector.
* object.cc (make_elf_sized_object): Update caller.
* parameters.cc (parameters_force_valid_target): Likewise.
* incremental.cc (make_sized_incremental_binary): Likewise.
* target-select.h: Update decl.
(Target_selector::recognize): Take new Input_file* argument,
pass it on to do_recognize.
(Target_selector::do_recognize): Take new Input_file* argument.
* freebsd.h (Target_selector_freebsd::do_recognize): Likewise.
* powerpc.cc (Target_selector_powerpc::do_recognize): Likewise.
* sparc.cc (Target_selector_sparc::do_recognize): Likewise.
* testsuite/testfile.cc (Target_selector::do_recognize): Likewise.
* target.h (Target::Target_info): New members isolate_execinstr
and rosegment_gap.
(Target::isolate_execinstr, Target::rosegment_gap): New methods.
* arm.cc (Target_arm::arm_info): Update initializer.
* i386.cc (Target_i386::i386_info): Likewise.
* powerpc.cc (Target_powerpc::powerpc_info): Likewise.
* sparc.cc (Target_sparc::sparc_info): Likewise.
* x86_64.cc (Target_x86_64::x86_64_info): Likewise.
* testsuite/testfile.cc (Target_test::test_target_info): Likewise.
* layout.cc (Layout::attach_allocated_section_to_segment):
Take new const Target* argument. If target->isolate_execinstr(), act
like --rosegment.
(Layout::find_first_load_seg): Take new const Target* argument;
if target->isolate_execinstr(), reject PF_X segments.
(Layout::relaxation_loop_body): Update caller.
(Layout::set_segment_offsets): If target->isolate_execinstr(),
reset file offset to zero when we hit LOAD_SEG, and then do a second
loop over the segments before LOAD_SEG to reassign offsets after
addresses have been determined. Handle target->rosegment_gap().
(Layout::attach_section_to_segment): Take new const Target* argument;
pass it to attach_allocated_section_to_segment.
(Layout::make_output_section): Update caller.
(Layout::attach_sections_to_segments): Take new const Target* argument;
pass it to attach_section_to_segment.
* gold.cc (queue_middle_tasks): Update caller.
* layout.h (Layout): Update method decls with new arguments.
* arm.cc (Target_arm::Target_arm): Take optional argument for the
Target_info pointer to use.
(Target_arm::do_make_data_plt): New virtual method.
(Target_arm::make_data_plt): New method that calls it.
(Target_arm::make_plt_entry): Use it.
(Output_data_plt_arm::Output_data_plt_arm): Take additional argument
for the section alignment.
(Output_data_plt_arm::do_first_plt_entry_offset): New abstract virtual
method.
(Output_data_plt_arm::first_plt_entry_offset): Call it.
(Output_data_plt_arm::do_get_plt_entry_size): New abstract virtual
method.
(Output_data_plt_arm::get_plt_entry_size): Call it.
(Output_data_plt_arm::do_fill_plt_entry): New abstract virtual method.
(Output_data_plt_arm::fill_plt_entry): New method that calls it.
(Output_data_plt_arm::do_fill_first_plt_entry): New abstract virtual
method.
(Output_data_plt_arm::fill_first_plt_entry): New method that calls it.
(Output_data_plt_arm::set_final_data_size): Use get_plt_entry_size
method instead of sizeof(plt_entry).
(Output_data_plt_arm::add_entry): Likewise.
Use first_plt_entry_offset method instead of sizeof(first_plt_entry).
(Target_arm::first_plt_entry_offset): Call method on this->plt_ rather
than static method.
(Target_arm::plt_entry_size): Likewise.
(Output_data_plt_arm::first_plt_entry, Output_data_plt_arm::plt_entry):
Move to ...
(Output_data_plt_arm_standard): ... here, new class.
(Output_data_plt_arm::do_write): Move guts of PLT filling to...
(Output_data_plt_arm_standard::do_fill_first_plt_entry): ... here ...
(Output_data_plt_arm_standard::do_fill_plt_entry): ... and here.
* x86_64.cc (Output_data_plt_x86_64::Output_data_plt_x86_64):
Take additional argument for the PLT entry size.
(Output_data_plt_x86_64::get_tlsdesc_plt_offset):
Use get_plt_entry_size method rather than plt_entry_size variable.
(Output_data_plt_x86_64::reserve_slot): Likewise.
(Output_data_plt_x86_64::do_adjust_output_section): Likewise.
(Output_data_plt_x86_64::add_entry): Likewise.
(Output_data_plt_x86_64::add_local_ifunc_entry): Likewise.
(Output_data_plt_x86_64::address_for_global): Likewise.
(Output_data_plt_x86_64::address_for_local): Likewise.
(Output_data_plt_x86_64::set_final_data_size): Likewise.
(Output_data_plt_x86_64::first_plt_entry_offset): Likewise.
Make method non-static.
(Output_data_plt_x86_64::do_get_plt_entry_size): New abstract virtual
method.
(Output_data_plt_x86_64::get_plt_entry_size): Just call that.
(Output_data_plt_x86_64::do_add_eh_frame): New abstract virtual method.
(Output_data_plt_x86_64::add_eh_frame): New method to call it.
(Output_data_plt_x86_64::do_fill_first_plt_entry): New abstract
virtual method.
(Output_data_plt_x86_64::fill_first_plt_entry): New method to call it.
(Output_data_plt_x86_64::do_fill_plt_entry): New abstract
virtual method.
(Output_data_plt_x86_64::fill_plt_entry): New method to call it.
(Output_data_plt_x86_64::do_fill_tlsdesc_entry): New abstract
virtual method.
(Output_data_plt_x86_64::fill_tlsdesc_entry): New method to call it.
(Output_data_plt_x86_64::plt_entry_size)
(Output_data_plt_x86_64::first_plt_entry)
(Output_data_plt_x86_64::plt_entry)
(Output_data_plt_x86_64::tlsdesc_plt_entry)
(Output_data_plt_x86_64::plt_eh_frame_fde_size)
(Output_data_plt_x86_64::plt_eh_frame_fde): Move to ...
(Output_data_plt_x86_64_standard): ... here, new class.
(Target_x86_64::Target_x86_64): Take optional argument for the
Target_info pointer to use.
(Target_x86_64::do_make_data_plt): New virtual method.
(Target_x86_64::make_data_plt): New method to call it.
(Target_x86_64::init_got_plt_for_update): Use that.
Call this->plt_->add_eh_frame method here.
(Output_data_plt_x86_64::init): Don't do add_eh_frame_for_plt here.
(Target_x86_64::first_plt_entry_offset): Call method on this->plt_
rather than static method.
(Target_x86_64::plt_entry_size): Likewise.
(Output_data_plt_x86_64::do_write): Use get_plt_entry_size method
rather than plt_entry_size variable. Move guts of PLT filling to...
(Output_data_plt_x86_64_standard::do_fill_first_plt_entry): ... here ...
(Output_data_plt_x86_64_standard::do_fill_plt_entry): ... and here ...
(Output_data_plt_x86_64_standard::do_fill_tlsdesc_entry): ... and here.
* i386.cc (Output_data_plt_i386::Output_data_plt_i386): Take
additional argument for the section alignment.
Don't do add_eh_frame_for_plt here.
(Output_data_plt_i386::first_plt_entry_offset): Make the method
non-static. Use get_plt_entry_size method rather than plt_entry_size
variable.
(Output_data_plt_i386::do_get_plt_entry_size): New abstract virtual
method.
(Output_data_plt_i386::get_plt_entry_size): Call it.
(Output_data_plt_i386::do_add_eh_frame): New abstract virtual method.
(Output_data_plt_i386::add_eh_frame): New method to call it.
(Output_data_plt_i386::do_fill_first_plt_entry): New abstract virtual
method.
(Output_data_plt_i386::fill_first_plt_entry): New method to call it.
(Output_data_plt_i386::do_fill_plt_entry): New abstract virtual
method.
(Output_data_plt_i386::fill_plt_entry): New method to call it.
(Output_data_plt_i386::set_final_data_size): Use get_plt_entry_size
method instead of plt_entry_size.
(Output_data_plt_i386::plt_entry_size)
(Output_data_plt_i386::plt_eh_frame_fde_size)
(Output_data_plt_i386::plt_eh_frame_fde): Move to ...
(Output_data_plt_i386_standard): ... here, new class.
(Output_data_plt_i386_exec): New class.
(Output_data_plt_i386::exec_first_plt_entry): Move to ...
(Output_data_plt_i386_exec::first_plt_entry): ... here.
(Output_data_plt_i386::exec_plt_entry): Move to ...
(Output_data_plt_i386_exec::plt_entry): ... here.
(Output_data_plt_i386_dyn): New class.
(Output_data_plt_i386::first_plt_entry): Move to ...
(Output_data_plt_i386_dyn::first_plt_entry): ... here.
(Output_data_plt_i386::dyn_plt_entry): Move to ...
(Output_data_plt_i386_dyn::plt_entry): ... here.
(Target_i386::Target_i386): Take optional argument for the Target_info
pointer to use.
(Target_i386::do_make_data_plt): New virtual method.
(Target_i386::make_data_plt): New method to call it.
(Target_i386::make_plt_section): Use that.
Call this->plt_->add_eh_frame method here.
(Output_data_plt_i386::add_entry): Use get_plt_entry_size method
rather than plt_entry_size variable.
(Output_data_plt_i386::add_local_ifunc_entry): Likewise.
(Output_data_plt_i386::address_for_local): Likewise.
(Output_data_plt_i386::do_write): Likewise.
Move guts of PLT filling to...
(Output_data_plt_i386_exec::do_fill_first_plt_entry): ... here ...
(Output_data_plt_i386_exec::do_fill_plt_entry): ... and here ...
(Output_data_plt_i386_dyn::do_fill_first_plt_entry): ... and here ...
(Output_data_plt_i386_dyn::do_fill_plt_entry): ... and here.
diff --git a/configure b/configure
index 2fee66b..8554178 100755
--- a/configure
+++ b/configure
@@ -2869,7 +2869,7 @@ case "${ENABLE_GOLD}" in
*-*-elf* | *-*-sysv4* | *-*-unixware* | *-*-eabi* | hppa*64*-*-hpux* \
| *-*-linux* | frv-*-uclinux* | *-*-irix5* | *-*-irix6* \
| *-*-netbsd* | *-*-openbsd* | *-*-freebsd* | *-*-dragonfly* \
- | *-*-solaris2* | *-*-nto*)
+ | *-*-solaris2* | *-*-nto* | *-*-nacl*)
case "${target}" in
*-*-linux*aout* | *-*-linux*oldld*)
;;
diff --git a/configure.ac b/configure.ac
index c279587..396c87b 100644
--- a/configure.ac
+++ b/configure.ac
@@ -313,7 +313,7 @@ case "${ENABLE_GOLD}" in
*-*-elf* | *-*-sysv4* | *-*-unixware* | *-*-eabi* | hppa*64*-*-hpux* \
| *-*-linux* | frv-*-uclinux* | *-*-irix5* | *-*-irix6* \
| *-*-netbsd* | *-*-openbsd* | *-*-freebsd* | *-*-dragonfly* \
- | *-*-solaris2* | *-*-nto*)
+ | *-*-solaris2* | *-*-nto* | *-*-nacl*)
case "${target}" in
*-*-linux*aout* | *-*-linux*oldld*)
;;
diff --git a/gold/Makefile.am b/gold/Makefile.am
index 7d4b725..72ffdf5 100644
--- a/gold/Makefile.am
+++ b/gold/Makefile.am
@@ -64,6 +64,7 @@ CCFILES = \
layout.cc \
mapfile.cc \
merge.cc \
+ nacl.cc \
object.cc \
options.cc \
output.cc \
@@ -111,6 +112,7 @@ HFILES = \
layout.h \
mapfile.h \
merge.h \
+ nacl.h \
object.h \
options.h \
output.h \
diff --git a/gold/Makefile.in b/gold/Makefile.in
index 2998b7b..356b1d6 100644
--- a/gold/Makefile.in
+++ b/gold/Makefile.in
@@ -52,6 +52,7 @@ DIST_COMMON = NEWS README ChangeLog $(srcdir)/Makefile.in \
ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
am__aclocal_m4_deps = $(top_srcdir)/../config/depstand.m4 \
$(top_srcdir)/../config/gettext-sister.m4 \
+ $(top_srcdir)/../config/lcmessage.m4 \
$(top_srcdir)/../config/lead-dot.m4 \
$(top_srcdir)/../config/nls.m4 \
$(top_srcdir)/../config/override.m4 \
@@ -80,13 +81,14 @@ am__objects_1 = archive.$(OBJEXT) attributes.$(OBJEXT) \
gdb-index.$(OBJEXT) gold.$(OBJEXT) gold-threads.$(OBJEXT) \
icf.$(OBJEXT) incremental.$(OBJEXT) int_encoding.$(OBJEXT) \
layout.$(OBJEXT) mapfile.$(OBJEXT) merge.$(OBJEXT) \
- object.$(OBJEXT) options.$(OBJEXT) output.$(OBJEXT) \
- parameters.$(OBJEXT) plugin.$(OBJEXT) readsyms.$(OBJEXT) \
- reduced_debug_output.$(OBJEXT) reloc.$(OBJEXT) \
- resolve.$(OBJEXT) script-sections.$(OBJEXT) script.$(OBJEXT) \
- stringpool.$(OBJEXT) symtab.$(OBJEXT) target.$(OBJEXT) \
- target-select.$(OBJEXT) timer.$(OBJEXT) version.$(OBJEXT) \
- workqueue.$(OBJEXT) workqueue-threads.$(OBJEXT)
+ nacl.$(OBJEXT) object.$(OBJEXT) options.$(OBJEXT) \
+ output.$(OBJEXT) parameters.$(OBJEXT) plugin.$(OBJEXT) \
+ readsyms.$(OBJEXT) reduced_debug_output.$(OBJEXT) \
+ reloc.$(OBJEXT) resolve.$(OBJEXT) script-sections.$(OBJEXT) \
+ script.$(OBJEXT) stringpool.$(OBJEXT) symtab.$(OBJEXT) \
+ target.$(OBJEXT) target-select.$(OBJEXT) timer.$(OBJEXT) \
+ version.$(OBJEXT) workqueue.$(OBJEXT) \
+ workqueue-threads.$(OBJEXT)
am__objects_2 =
am__objects_3 = yyscript.$(OBJEXT)
am_libgold_a_OBJECTS = $(am__objects_1) $(am__objects_2) \
@@ -408,6 +410,7 @@ CCFILES = \
layout.cc \
mapfile.cc \
merge.cc \
+ nacl.cc \
object.cc \
options.cc \
output.cc \
@@ -455,6 +458,7 @@ HFILES = \
layout.h \
mapfile.h \
merge.h \
+ nacl.h \
object.h \
options.h \
output.h \
@@ -664,6 +668,7 @@ distclean-compile:
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/main.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mapfile.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/merge.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nacl.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/object.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/options.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/output.Po@am__quote@
diff --git a/gold/arm.cc b/gold/arm.cc
index 1ddbf7f..92735ea 100644
--- a/gold/arm.cc
+++ b/gold/arm.cc
@@ -51,6 +51,7 @@
#include "gc.h"
#include "attributes.h"
#include "arm-reloc-property.h"
+#include "nacl.h"
namespace
{
@@ -61,6 +62,9 @@ template<bool big_endian>
class Output_data_plt_arm;
template<bool big_endian>
+class Output_data_plt_arm_standard;
+
+template<bool big_endian>
class Stub_table;
template<bool big_endian>
@@ -2113,8 +2117,8 @@ class Target_arm : public Sized_target<32, big_endian>
// When were are relocating a stub, we pass this as the relocation number.
static const size_t fake_relnum_for_stubs = static_cast<size_t>(-1);
- Target_arm()
- : Sized_target<32, big_endian>(&arm_info),
+ Target_arm(const Target::Target_info* info = &arm_info)
+ : Sized_target<32, big_endian>(info),
got_(NULL), plt_(NULL), got_plt_(NULL), rel_dyn_(NULL),
copy_relocs_(elfcpp::R_ARM_COPY), dynbss_(NULL),
got_mod_index_offset_(-1U), tls_base_symbol_defined_(false),
@@ -2440,6 +2444,11 @@ class Target_arm : public Sized_target<32, big_endian>
unsigned char*, Arm_address);
protected:
+ // Make the PLT-generator object.
+ Output_data_plt_arm<big_endian>*
+ make_data_plt(Layout* layout, Output_data_space* got_plt)
+ { return this->do_make_data_plt(layout, got_plt); }
+
// Make an ELF object.
Object*
do_make_elf_object(const std::string&, Input_file*, off_t,
@@ -2518,6 +2527,12 @@ class Target_arm : public Sized_target<32, big_endian>
virtual void
do_define_standard_symbols(Symbol_table*, Layout*);
+ virtual Output_data_plt_arm<big_endian>*
+ do_make_data_plt(Layout* layout, Output_data_space* got_plt)
+ {
+ return new Output_data_plt_arm_standard<big_endian>(layout, got_plt);
+ }
+
private:
// The class which scans relocations.
class Scan
@@ -2915,6 +2930,8 @@ const Target::Target_info
Target_arm<big_endian>::arm_info =
0x8000, // default_text_segment_address
0x1000, // abi_pagesize (overridable by -z max-page-size)
0x1000, // common_pagesize (overridable by -z common-page-size)
+ false, // isolate_execinstr
+ 0, // rosegment_gap
elfcpp::SHN_UNDEF, // small_common_shndx
elfcpp::SHN_UNDEF, // large_common_shndx
0, // small_common_section_flags
@@ -7189,6 +7206,9 @@ Arm_output_data_got<big_endian>::do_write(Output_file* of)
}
// A class to handle the PLT data.
+// This is an abstract base class that handles most of the linker details
+// but does not know the actual contents of PLT entries. The derived
+// classes below fill in those details.
template<bool big_endian>
class Output_data_plt_arm : public Output_section_data
@@ -7197,7 +7217,7 @@ class Output_data_plt_arm : public Output_section_data
typedef Output_data_reloc<elfcpp::SHT_REL, true, 32, big_endian>
Reloc_section;
- Output_data_plt_arm(Layout*, Output_data_space*);
+ Output_data_plt_arm(Layout*, uint64_t addralign, Output_data_space*);
// Add an entry to the PLT.
void
@@ -7214,16 +7234,49 @@ class Output_data_plt_arm : public Output_section_data
{ 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); }
+ unsigned int
+ first_plt_entry_offset() const
+ { return this->do_first_plt_entry_offset(); }
// Return the size of a PLT entry.
- static unsigned int
- get_plt_entry_size()
- { return sizeof(plt_entry); }
+ unsigned int
+ get_plt_entry_size() const
+ { return this->do_get_plt_entry_size(); }
protected:
+ // Fill in the first PLT entry.
+ void
+ fill_first_plt_entry(unsigned char* pov,
+ Arm_address got_address,
+ Arm_address plt_address)
+ { this->do_fill_first_plt_entry(pov, got_address, plt_address); }
+
+ void
+ fill_plt_entry(unsigned char* pov,
+ Arm_address got_address,
+ Arm_address plt_address,
+ unsigned int got_offset,
+ unsigned int plt_offset)
+ { do_fill_plt_entry(pov, got_address, plt_address, got_offset, plt_offset); }
+
+ virtual unsigned int
+ do_first_plt_entry_offset() const = 0;
+
+ virtual unsigned int
+ do_get_plt_entry_size() const = 0;
+
+ virtual void
+ do_fill_first_plt_entry(unsigned char* pov,
+ Arm_address got_address,
+ Arm_address plt_address) = 0;
+
+ virtual void
+ do_fill_plt_entry(unsigned char* pov,
+ Arm_address got_address,
+ Arm_address plt_address,
+ unsigned int got_offset,
+ unsigned int plt_offset) = 0;
+
void
do_adjust_output_section(Output_section* os);
@@ -7233,18 +7286,12 @@ class Output_data_plt_arm : public Output_section_data
{ mapfile->print_output_data(this, _("** PLT")); }
private:
- // Template for the first PLT entry.
- static const uint32_t first_plt_entry[5];
-
- // Template for subsequent PLT entries.
- static const uint32_t plt_entry[3];
-
// Set the final size.
void
set_final_data_size()
{
- this->set_data_size(sizeof(first_plt_entry)
- + this->count_ * sizeof(plt_entry));
+ this->set_data_size(this->first_plt_entry_offset()
+ + this->count_ * this->get_plt_entry_size());
}
// Write out the PLT data.
@@ -7265,8 +7312,9 @@ class Output_data_plt_arm : public Output_section_data
template<bool big_endian>
Output_data_plt_arm<big_endian>::Output_data_plt_arm(Layout* layout,
+ uint64_t addralign,
Output_data_space* got_plt)
- : Output_section_data(4), got_plt_(got_plt), count_(0)
+ : Output_section_data(addralign), got_plt_(got_plt), count_(0)
{
this->rel_ = new Reloc_section(false);
layout->add_output_section_data(".rel.plt", elfcpp::SHT_REL,
@@ -7291,8 +7339,8 @@ Output_data_plt_arm<big_endian>::add_entry(Symbol* gsym)
// Note that when setting the PLT offset we skip the initial
// reserved PLT entry.
- gsym->set_plt_offset((this->count_) * sizeof(plt_entry)
- + sizeof(first_plt_entry));
+ gsym->set_plt_offset((this->count_) * this->get_plt_entry_size()
+ + this->first_plt_entry_offset());
++this->count_;
@@ -7313,6 +7361,45 @@ Output_data_plt_arm<big_endian>::add_entry(Symbol* gsym)
// appear in the relocations.
}
+template<bool big_endian>
+class Output_data_plt_arm_standard : public Output_data_plt_arm<big_endian>
+{
+ public:
+ Output_data_plt_arm_standard(Layout* layout, Output_data_space* got_plt)
+ : Output_data_plt_arm<big_endian>(layout, 4, got_plt)
+ { }
+
+ protected:
+ // Return the offset of the first non-reserved PLT entry.
+ virtual unsigned int
+ do_first_plt_entry_offset() const
+ { return sizeof(first_plt_entry); }
+
+ // Return the size of a PLT entry.
+ virtual unsigned int
+ do_get_plt_entry_size() const
+ { return sizeof(plt_entry); }
+
+ virtual void
+ do_fill_first_plt_entry(unsigned char* pov,
+ Arm_address got_address,
+ Arm_address plt_address);
+
+ virtual void
+ do_fill_plt_entry(unsigned char* pov,
+ Arm_address got_address,
+ Arm_address plt_address,
+ unsigned int got_offset,
+ unsigned int plt_offset);
+
+ private:
+ // Template for the first PLT entry.
+ static const uint32_t first_plt_entry[5];
+
+ // Template for subsequent PLT entries.
+ static const uint32_t plt_entry[3];
+};
+
// ARM PLTs.
// FIXME: This is not very flexible. Right now this has only been tested
// on armv5te. If we are to support additional architecture features like
@@ -7320,7 +7407,7 @@ Output_data_plt_arm<big_endian>::add_entry(Symbol* gsym)
// The first entry in the PLT.
template<bool big_endian>
-const uint32_t Output_data_plt_arm<big_endian>::first_plt_entry[5] =
+const uint32_t Output_data_plt_arm_standard<big_endian>::first_plt_entry[5] =
{
0xe52de004, // str lr, [sp, #-4]!
0xe59fe004, // ldr lr, [pc, #4]
@@ -7329,16 +7416,54 @@ const uint32_t
Output_data_plt_arm<big_endian>::first_plt_entry[5] =
0x00000000, // &GOT[0] - .
};
+template<bool big_endian>
+void
+Output_data_plt_arm_standard<big_endian>::do_fill_first_plt_entry(
+ unsigned char* pov,
+ Arm_address got_address,
+ Arm_address plt_address)
+{
+ // Write first PLT entry. All but the last word are constants.
+ const size_t num_first_plt_words = (sizeof(first_plt_entry)
+ / sizeof(plt_entry[0]));
+ for (size_t i = 0; i < num_first_plt_words - 1; i++)
+ elfcpp::Swap<32, big_endian>::writeval(pov + i * 4, first_plt_entry[i]);
+ // Last word in first PLT entry is &GOT[0] - .
+ elfcpp::Swap<32, big_endian>::writeval(pov + 16,
+ got_address - (plt_address + 16));
+}
+
// Subsequent entries in the PLT.
template<bool big_endian>
-const uint32_t Output_data_plt_arm<big_endian>::plt_entry[3] =
+const uint32_t Output_data_plt_arm_standard<big_endian>::plt_entry[3] =
{
0xe28fc600, // add ip, pc, #0xNN00000
0xe28cca00, // add ip, ip, #0xNN000
0xe5bcf000, // ldr pc, [ip, #0xNNN]!
};
+template<bool big_endian>
+void
+Output_data_plt_arm_standard<big_endian>::do_fill_plt_entry(
+ unsigned char* pov,
+ Arm_address got_address,
+ Arm_address plt_address,
+ unsigned int got_offset,
+ unsigned int plt_offset)
+{
+ int32_t offset = ((got_address + got_offset)
+ - (plt_address + plt_offset + 8));
+
+ gold_assert(offset >= 0 && offset < 0x0fffffff);
+ uint32_t plt_insn0 = plt_entry[0] | ((offset >> 20) & 0xff);
+ elfcpp::Swap<32, big_endian>::writeval(pov, plt_insn0);
+ uint32_t plt_insn1 = plt_entry[1] | ((offset >> 12) & 0xff);
+ elfcpp::Swap<32, big_endian>::writeval(pov + 4, plt_insn1);
+ uint32_t plt_insn2 = plt_entry[2] | (offset & 0xfff);
+ elfcpp::Swap<32, big_endian>::writeval(pov + 8, plt_insn2);
+}
+
// Write out the PLT. This uses the hand-coded instructions above,
// and adjusts them as needed. This is all specified by the arm ELF
// Processor Supplement.
@@ -7362,46 +7487,29 @@
Output_data_plt_arm<big_endian>::do_write(Output_file* of)
Arm_address plt_address = this->address();
Arm_address got_address = this->got_plt_->address();
- // Write first PLT entry. All but the last word are constants.
- const size_t num_first_plt_words = (sizeof(first_plt_entry)
- / sizeof(plt_entry[0]));
- for (size_t i = 0; i < num_first_plt_words - 1; i++)
- elfcpp::Swap<32, big_endian>::writeval(pov + i * 4, first_plt_entry[i]);
- // Last word in first PLT entry is &GOT[0] - .
- elfcpp::Swap<32, big_endian>::writeval(pov + 16,
- got_address - (plt_address + 16));
- pov += sizeof(first_plt_entry);
+ // Write first PLT entry.
+ this->fill_first_plt_entry(pov, got_address, plt_address);
+ pov += this->first_plt_entry_offset();
unsigned char* got_pov = got_view;
memset(got_pov, 0, 12);
got_pov += 12;
- const int rel_size = elfcpp::Elf_sizes<32>::rel_size;
- unsigned int plt_offset = sizeof(first_plt_entry);
- unsigned int plt_rel_offset = 0;
+ unsigned int plt_offset = this->first_plt_entry_offset();
unsigned int got_offset = 12;
const unsigned int count = this->count_;
for (unsigned int i = 0;
i < count;
++i,
- pov += sizeof(plt_entry),
+ pov += this->get_plt_entry_size(),
got_pov += 4,
- plt_offset += sizeof(plt_entry),
- plt_rel_offset += rel_size,
+ plt_offset += this->get_plt_entry_size(),
got_offset += 4)
{
// Set and adjust the PLT entry itself.
- int32_t offset = ((got_address + got_offset)
- - (plt_address + plt_offset + 8));
-
- gold_assert(offset >= 0 && offset < 0x0fffffff);
- uint32_t plt_insn0 = plt_entry[0] | ((offset >> 20) & 0xff);
- elfcpp::Swap<32, big_endian>::writeval(pov, plt_insn0);
- uint32_t plt_insn1 = plt_entry[1] | ((offset >> 12) & 0xff);
- elfcpp::Swap<32, big_endian>::writeval(pov + 4, plt_insn1);
- uint32_t plt_insn2 = plt_entry[2] | (offset & 0xfff);
- elfcpp::Swap<32, big_endian>::writeval(pov + 8, plt_insn2);
+ this->fill_plt_entry(pov, got_address, plt_address,
+ got_offset, plt_offset);
// Set the entry in the GOT.
elfcpp::Swap<32, big_endian>::writeval(got_pov, plt_address);
@@ -7429,7 +7537,8 @@
Target_arm<big_endian>::make_plt_entry(Symbol_table* symtab, Layout*
layout,
// Create the GOT sections first.
this->got_section(symtab, layout);
- this->plt_ = new Output_data_plt_arm<big_endian>(layout, this->got_plt_);
+ this->plt_ = this->make_data_plt(layout, this->got_plt_);
+
layout->add_output_section_data(".plt", elfcpp::SHT_PROGBITS,
(elfcpp::SHF_ALLOC
| elfcpp::SHF_EXECINSTR),
@@ -7455,7 +7564,7 @@ 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 this->plt_->first_plt_entry_offset();
}
// Return the size of each PLT entry.
@@ -7464,7 +7573,7 @@ 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();
+ return this->plt_->get_plt_entry_size();
}
// Get the section to use for TLS_DESC relocations.
@@ -11846,6 +11955,9 @@ Target_arm<big_endian>::apply_cortex_a8_workaround(
elfcpp::Swap<16, big_endian>::writeval(wv + 1, lower_insn);
}
+// Target selector for ARM. Note this is never instantiated directly.
+// It's only used in Target_selector_arm_nacl, below.
+
template<bool big_endian>
class Target_selector_arm : public Target_selector
{
@@ -11980,7 +12092,217 @@ Target_arm<big_endian>::do_define_standard_symbols(
}
}
-Target_selector_arm<false> target_selector_arm;
-Target_selector_arm<true> target_selector_armbe;
+// NaCl variant. It uses different PLT contents.
+
+template<bool big_endian>
+class Output_data_plt_arm_nacl;
+
+template<bool big_endian>
+class Target_arm_nacl : public Target_arm<big_endian>
+{
+ public:
+ Target_arm_nacl()
+ : Target_arm<big_endian>(&arm_nacl_info)
+ { }
+
+ protected:
+ virtual Output_data_plt_arm<big_endian>*
+ do_make_data_plt(Layout* layout, Output_data_space* got_plt)
+ { return new Output_data_plt_arm_nacl<big_endian>(layout, got_plt); }
+
+ private:
+ static const Target::Target_info arm_nacl_info;
+};
+
+template<bool big_endian>
+const Target::Target_info Target_arm_nacl<big_endian>::arm_nacl_info =
+{
+ 32, // size
+ big_endian, // is_big_endian
+ elfcpp::EM_ARM, // machine_code
+ false, // has_make_symbol
+ false, // has_resolve
+ false, // has_code_fill
+ true, // is_default_stack_executable
+ false, // can_icf_inline_merge_sections
+ '\0', // wrap_char
+ "/lib/ld-nacl-arm.so.1", // dynamic_linker
+ 0x20000, // default_text_segment_address
+ 0x10000, // abi_pagesize (overridable by -z max-page-size)
+ 0x10000, // common_pagesize (overridable by -z common-page-size)
+ true, // isolate_execinstr
+ 0x10000000, // rosegment_gap
+ elfcpp::SHN_UNDEF, // small_common_shndx
+ elfcpp::SHN_UNDEF, // large_common_shndx
+ 0, // small_common_section_flags
+ 0, // large_common_section_flags
+ ".ARM.attributes", // attributes_section
+ "aeabi" // attributes_vendor
+};
+
+template<bool big_endian>
+class Output_data_plt_arm_nacl : public Output_data_plt_arm<big_endian>
+{
+ public:
+ Output_data_plt_arm_nacl(Layout* layout, Output_data_space* got_plt)
+ : Output_data_plt_arm<big_endian>(layout, 16, got_plt)
+ { }
+
+ protected:
+ // Return the offset of the first non-reserved PLT entry.
+ virtual unsigned int
+ do_first_plt_entry_offset() const
+ { return sizeof(first_plt_entry); }
+
+ // Return the size of a PLT entry.
+ virtual unsigned int
+ do_get_plt_entry_size() const
+ { return sizeof(plt_entry); }
+
+ virtual void
+ do_fill_first_plt_entry(unsigned char* pov,
+ Arm_address got_address,
+ Arm_address plt_address);
+
+ virtual void
+ do_fill_plt_entry(unsigned char* pov,
+ Arm_address got_address,
+ Arm_address plt_address,
+ unsigned int got_offset,
+ unsigned int plt_offset);
+
+ private:
+ inline uint32_t arm_movw_immediate(uint32_t value)
+ {
+ return (value & 0x00000fff) | ((value & 0x0000f000) << 4);
+ }
+
+ inline uint32_t arm_movt_immediate(uint32_t value)
+ {
+ return ((value & 0x0fff0000) >> 16) | ((value & 0xf0000000) >> 12);
+ }
+
+ // Template for the first PLT entry.
+ static const uint32_t first_plt_entry[16];
+
+ // Template for subsequent PLT entries.
+ static const uint32_t plt_entry[4];
+};
+
+// The first entry in the PLT.
+template<bool big_endian>
+const uint32_t Output_data_plt_arm_nacl<big_endian>::first_plt_entry[16] =
+{
+ // First bundle:
+ 0xe300c000, // movw ip, #:lower16:&GOT[2]-.+8
+ 0xe340c000, // movt ip, #:upper16:&GOT[2]-.+8
+ 0xe08cc00f, // add ip, ip, pc
+ 0xe52dc008, // str ip, [sp, #-8]!
+ // Second bundle:
+ 0xe7dfcf1f, // bfc ip, #30, #2
+ 0xe59cc000, // ldr ip, [ip]
+ 0xe3ccc13f, // bic ip, ip, #0xc000000f
+ 0xe12fff1c, // bx ip
+ // Third bundle:
+ 0xe320f000, // nop
+ 0xe320f000, // nop
+ 0xe320f000, // nop
+ // .Lplt_tail:
+ 0xe50dc004, // str ip, [sp, #-4]
+ // Fourth bundle:
+ 0xe7dfcf1f, // bfc ip, #30, #2
+ 0xe59cc000, // ldr ip, [ip]
+ 0xe3ccc13f, // bic ip, ip, #0xc000000f
+ 0xe12fff1c, // bx ip
+};
+
+template<bool big_endian>
+void
+Output_data_plt_arm_nacl<big_endian>::do_fill_first_plt_entry(
+ unsigned char* pov,
+ Arm_address got_address,
+ Arm_address plt_address)
+{
+ // Write first PLT entry. All but first two words are constants.
+ const size_t num_first_plt_words = (sizeof(first_plt_entry)
+ / sizeof(first_plt_entry[0]));
+
+ int32_t got_displacement = got_address + 8 - (plt_address + 16);
+
+ elfcpp::Swap<32, big_endian>::writeval
+ (pov + 0, first_plt_entry[0] | arm_movw_immediate (got_displacement));
+ elfcpp::Swap<32, big_endian>::writeval
+ (pov + 4, first_plt_entry[1] | arm_movt_immediate (got_displacement));
+
+ for (size_t i = 2; i < num_first_plt_words; ++i)
+ elfcpp::Swap<32, big_endian>::writeval(pov + i * 4, first_plt_entry[i]);
+}
+
+// Subsequent entries in the PLT.
+
+template<bool big_endian>
+const uint32_t Output_data_plt_arm_nacl<big_endian>::plt_entry[4] =
+{
+ 0xe300c000, // movw ip, #:lower16:&GOT[n]-.+8
+ 0xe340c000, // movt ip, #:upper16:&GOT[n]-.+8
+ 0xe08cc00f, // add ip, ip, pc
+ 0xea000000, // b .Lplt_tail
+};
+
+template<bool big_endian>
+void
+Output_data_plt_arm_nacl<big_endian>::do_fill_plt_entry(
+ unsigned char* pov,
+ Arm_address got_address,
+ Arm_address plt_address,
+ unsigned int got_offset,
+ unsigned int plt_offset)
+{
+ // Calculate the displacement between the PLT slot and the
+ // common tail that's part of the special initial PLT slot.
+ int32_t tail_displacement = (plt_address + (11 * sizeof(uint32_t))
+ - (plt_address + plt_offset
+ + sizeof(plt_entry) + sizeof(uint32_t)));
+ gold_assert((tail_displacement & 3) == 0);
+ tail_displacement >>= 2;
+
+ gold_assert ((tail_displacement & 0xff000000) == 0
+ || (-tail_displacement & 0xff000000) == 0);
+
+ // Calculate the displacement between the PLT slot and the entry
+ // in the GOT. The offset accounts for the value produced by
+ // adding to pc in the penultimate instruction of the PLT stub.
+ const int32_t got_displacement = (got_address + got_offset
+ - (plt_address + sizeof(plt_entry)));
+
+ elfcpp::Swap<32, big_endian>::writeval
+ (pov + 0, plt_entry[0] | arm_movw_immediate (got_displacement));
+ elfcpp::Swap<32, big_endian>::writeval
+ (pov + 4, plt_entry[1] | arm_movt_immediate (got_displacement));
+ elfcpp::Swap<32, big_endian>::writeval
+ (pov + 8, plt_entry[2]);
+ elfcpp::Swap<32, big_endian>::writeval
+ (pov + 12, plt_entry[3] | (tail_displacement & 0x00ffffff));
+}
+
+// Target selectors.
+
+template<bool big_endian>
+class Target_selector_arm_nacl
+ : public Target_selector_nacl<Target_selector_arm<big_endian>,
+ Target_arm_nacl<big_endian> >
+{
+ public:
+ Target_selector_arm_nacl()
+ : Target_selector_nacl<Target_selector_arm<big_endian>,
+ Target_arm_nacl<big_endian> >(
+ "arm",
+ big_endian ? "elf32-bigarm-nacl" : "elf32-littlearm-nacl",
+ big_endian ? "armelfb_nacl" : "armelf_nacl")
+ { }
+};
+
+Target_selector_arm_nacl<false> target_selector_arm;
+Target_selector_arm_nacl<true> target_selector_armbe;
} // End anonymous namespace.
diff --git a/gold/freebsd.h b/gold/freebsd.h
index 175dd05..3bdedce 100644
--- a/gold/freebsd.h
+++ b/gold/freebsd.h
@@ -1,6 +1,6 @@
// freebsd.h -- FreeBSD support for gold -*- C++ -*-
-// Copyright 2009, 2011 Free Software Foundation, Inc.
+// Copyright 2009, 2011, 2012 Free Software Foundation, Inc.
// Written by Ian Lance Taylor <iant@google.com>.
// This file is part of gold.
@@ -48,7 +48,7 @@ class Target_selector_freebsd : public Target_selector
// If we see a FreeBSD input file, mark the output file as using
// FreeBSD.
virtual Target*
- do_recognize(int, int osabi, int)
+ do_recognize(Input_file*, off_t, int, int osabi, int)
{
Target* ret = this->instantiate_target();
if (osabi == elfcpp::ELFOSABI_FREEBSD)
diff --git a/gold/gold.cc b/gold/gold.cc
index f810bf9..013702f 100644
--- a/gold/gold.cc
+++ b/gold/gold.cc
@@ -1,6 +1,7 @@
// gold.cc -- main linker functions
-// Copyright 2006, 2007, 2008, 2009, 2010, 2011 Free Software Foundation, Inc.
+// Copyright 2006, 2007, 2008, 2009, 2010, 2011, 2012
+// Free Software Foundation, Inc.
// Written by Ian Lance Taylor <iant@google.com>.
// This file is part of gold.
@@ -676,11 +677,12 @@ queue_middle_tasks(const General_options& options,
// Define symbols from any linker scripts.
layout->define_script_symbols(symtab);
- // Attach sections to segments.
- layout->attach_sections_to_segments();
-
// TODO(csilvers): figure out a more principled way to get the target
Target* target = const_cast<Target*>(¶meters->target());
+
+ // Attach sections to segments.
+ layout->attach_sections_to_segments(target);
+
if (!parameters->options().relocatable())
{
// Predefine standard symbols.
diff --git a/gold/i386.cc b/gold/i386.cc
index b4174bc..47f33a0 100644
--- a/gold/i386.cc
+++ b/gold/i386.cc
@@ -40,6 +40,7 @@
#include "target-select.h"
#include "tls.h"
#include "freebsd.h"
+#include "nacl.h"
#include "gc.h"
namespace
@@ -48,13 +49,17 @@ namespace
using namespace gold;
// A class to handle the PLT data.
+// This is an abstract base class that handles most of the linker details
+// but does not know the actual contents of PLT entries. The derived
+// classes below fill in those details.
class Output_data_plt_i386 : public Output_section_data
{
public:
typedef Output_data_reloc<elfcpp::SHT_REL, true, 32, false> Reloc_section;
- Output_data_plt_i386(Layout*, Output_data_space*, Output_data_space*);
+ Output_data_plt_i386(Layout*, uint64_t addralign,
+ Output_data_space*, Output_data_space*);
// Add an entry to the PLT.
void
@@ -90,14 +95,14 @@ class Output_data_plt_i386 : public Output_section_data
{ return this->count_ + this->irelative_count_; }
// Return the offset of the first non-reserved PLT entry.
- static unsigned int
+ unsigned int
first_plt_entry_offset()
- { return plt_entry_size; }
+ { return this->get_plt_entry_size(); }
// Return the size of a PLT entry.
- static unsigned int
- get_plt_entry_size()
- { return plt_entry_size; }
+ unsigned int
+ get_plt_entry_size() const
+ { return this->do_get_plt_entry_size(); }
// Return the PLT address to use for a global symbol.
uint64_t
@@ -107,43 +112,73 @@ class Output_data_plt_i386 : public Output_section_data
uint64_t
address_for_local(const Relobj*, unsigned int symndx);
- protected:
+ // Add .eh_frame information for the PLT.
void
- do_adjust_output_section(Output_section* os);
+ add_eh_frame(Layout* layout)
+ { this->do_add_eh_frame(layout); }
- // Write to a map file.
+ protected:
+ // Fill the first PLT entry, given the pointer to the PLT section data
+ // and the runtime address of the GOT.
void
- do_print_to_mapfile(Mapfile* mapfile) const
- { mapfile->print_output_data(this, _("** PLT")); }
+ fill_first_plt_entry(unsigned char* pov,
+ elfcpp::Elf_types<32>::Elf_Addr got_address)
+ { this->do_fill_first_plt_entry(pov, got_address); }
+
+ // Fill a normal PLT entry, given the pointer to the entry's data in the
+ // section, the runtime address of the GOT, the offset into the GOT of
+ // the corresponding slot, the offset into the relocation section of the
+ // corresponding reloc, and the offset of this entry within the whole
+ // PLT. Return the offset from this PLT entry's runtime address that
+ // should be used to compute the initial value of the GOT slot.
+ unsigned int
+ fill_plt_entry(unsigned char* pov,
+ elfcpp::Elf_types<32>::Elf_Addr got_address,
+ unsigned int got_offset,
+ unsigned int plt_offset,
+ unsigned int plt_rel_offset)
+ {
+ return this->do_fill_plt_entry(pov, got_address, got_offset,
+ plt_offset, plt_rel_offset);
+ }
- private:
- // The size of an entry in the PLT.
- static const int plt_entry_size = 16;
+ virtual unsigned int
+ do_get_plt_entry_size() const = 0;
- // The first entry in the PLT for an executable.
- static const unsigned char exec_first_plt_entry[plt_entry_size];
+ virtual void
+ do_fill_first_plt_entry(unsigned char* pov,
+ elfcpp::Elf_types<32>::Elf_Addr got_address) = 0;
- // The first entry in the PLT for a shared object.
- static const unsigned char dyn_first_plt_entry[plt_entry_size];
+ virtual unsigned int
+ do_fill_plt_entry(unsigned char* pov,
+ elfcpp::Elf_types<32>::Elf_Addr got_address,
+ unsigned int got_offset,
+ unsigned int plt_offset,
+ unsigned int plt_rel_offset) = 0;
- // Other entries in the PLT for an executable.
- static const unsigned char exec_plt_entry[plt_entry_size];
+ virtual void
+ do_add_eh_frame(Layout*) = 0;
- // Other entries in the PLT for a shared object.
- static const unsigned char dyn_plt_entry[plt_entry_size];
+ void
+ do_adjust_output_section(Output_section* os);
+
+ // Write to a map file.
+ void
+ do_print_to_mapfile(Mapfile* mapfile) const
+ { mapfile->print_output_data(this, _("** PLT")); }
// The .eh_frame unwind information for the PLT.
+ // The CIE is common across variants of the PLT format.
static const int plt_eh_frame_cie_size = 16;
- static const int plt_eh_frame_fde_size = 32;
static const unsigned char plt_eh_frame_cie[plt_eh_frame_cie_size];
- static const unsigned char plt_eh_frame_fde[plt_eh_frame_fde_size];
+ private:
// Set the final size.
void
set_final_data_size()
{
this->set_data_size((this->count_ + this->irelative_count_ + 1)
- * plt_entry_size);
+ * this->get_plt_entry_size());
}
// Write out the PLT data.
@@ -193,6 +228,101 @@ class Output_data_plt_i386 : public Output_section_data
std::vector<Local_ifunc> local_ifuncs_;
};
+// This is an abstract class for the standard PLT layout.
+// The derived classes below handle the actual PLT contents
+// for the executable (non-PIC) and shared-library (PIC) cases.
+// The unwind information is uniform across those two, so it's here.
+
+class Output_data_plt_i386_standard : public Output_data_plt_i386
+{
+ public:
+ Output_data_plt_i386_standard(Layout* layout,
+ Output_data_space* got_plt,
+ Output_data_space* got_irelative)
+ : Output_data_plt_i386(layout, plt_entry_size, got_plt, got_irelative)
+ { }
+
+ protected:
+ virtual unsigned int
+ do_get_plt_entry_size() const
+ { return plt_entry_size; }
+
+ virtual void
+ do_add_eh_frame(Layout* layout)
+ {
+ layout->add_eh_frame_for_plt(this, plt_eh_frame_cie, plt_eh_frame_cie_size,
+ plt_eh_frame_fde, plt_eh_frame_fde_size);
+ }
+
+ // The size of an entry in the PLT.
+ static const int plt_entry_size = 16;
+
+ // The .eh_frame unwind information for the PLT.
+ static const int plt_eh_frame_fde_size = 32;
+ static const unsigned char plt_eh_frame_fde[plt_eh_frame_fde_size];
+};
+
+// Actually fill the PLT contents for an executable (non-PIC).
+
+class Output_data_plt_i386_exec : public Output_data_plt_i386_standard
+{
+public:
+ Output_data_plt_i386_exec(Layout* layout,
+ Output_data_space* got_plt,
+ Output_data_space* got_irelative)
+ : Output_data_plt_i386_standard(layout, got_plt, got_irelative)
+ { }
+
+ protected:
+ virtual void
+ do_fill_first_plt_entry(unsigned char* pov,
+ elfcpp::Elf_types<32>::Elf_Addr got_address);
+
+ virtual unsigned int
+ do_fill_plt_entry(unsigned char* pov,
+ elfcpp::Elf_types<32>::Elf_Addr got_address,
+ unsigned int got_offset,
+ unsigned int plt_offset,
+ unsigned int plt_rel_offset);
+
+ private:
+ // The first entry in the PLT for an executable.
+ static const unsigned char first_plt_entry[plt_entry_size];
+
+ // Other entries in the PLT for an executable.
+ static const unsigned char plt_entry[plt_entry_size];
+};
+
+// Actually fill the PLT contents for a shared library (PIC).
+
+class Output_data_plt_i386_dyn : public Output_data_plt_i386_standard
+{
+ public:
+ Output_data_plt_i386_dyn(Layout* layout,
+ Output_data_space* got_plt,
+ Output_data_space* got_irelative)
+ : Output_data_plt_i386_standard(layout, got_plt, got_irelative)
+ { }
+
+ protected:
+ virtual void
+ do_fill_first_plt_entry(unsigned char* pov, elfcpp::Elf_types<32>::Elf_Addr);
+
+ virtual unsigned int
+ do_fill_plt_entry(unsigned char* pov,
+ elfcpp::Elf_types<32>::Elf_Addr,
+ unsigned int got_offset,
+ unsigned int plt_offset,
+ unsigned int plt_rel_offset);
+
+ private:
+ // The first entry in the PLT for a shared object.
+ static const unsigned char first_plt_entry[plt_entry_size];
+
+ // Other entries in the PLT for a shared object.
+ static const unsigned char plt_entry[plt_entry_size];
+};
+
// The i386 target class.
// TLS info comes from
// http://people.redhat.com/drepper/tls.pdf
@@ -203,8 +333,8 @@ class Target_i386 : public Sized_target<32, false>
public:
typedef Output_data_reloc<elfcpp::SHT_REL, true, 32, false> Reloc_section;
- Target_i386()
- : Sized_target<32, false>(&i386_info),
+ Target_i386(const Target::Target_info* info = &i386_info)
+ : Sized_target<32, false>(info),
got_(NULL), plt_(NULL), got_plt_(NULL), got_irelative_(NULL),
got_tlsdesc_(NULL), global_offset_table_(NULL), rel_dyn_(NULL),
rel_irelative_(NULL), copy_relocs_(elfcpp::R_386_COPY), dynbss_(NULL),
@@ -372,6 +502,28 @@ class Target_i386 : public Sized_target<32, false>
unsigned int
plt_entry_size() const;
+ protected:
+ // Instantiate the plt_ member.
+ // This chooses the right PLT flavor for an executable or a shared object.
+ Output_data_plt_i386*
+ make_data_plt(Layout* layout,
+ Output_data_space* got_plt,
+ Output_data_space* got_irelative,
+ bool dyn)
+ { return this->do_make_data_plt(layout, got_plt, got_irelative, dyn); }
+
+ virtual Output_data_plt_i386*
+ do_make_data_plt(Layout* layout,
+ Output_data_space* got_plt,
+ Output_data_space* got_irelative,
+ bool dyn)
+ {
+ if (dyn)
+ return new Output_data_plt_i386_dyn(layout, got_plt, got_irelative);
+ else
+ return new Output_data_plt_i386_exec(layout, got_plt, got_irelative);
+ }
+
private:
// The class which scans relocations.
struct Scan
@@ -697,6 +849,8 @@ const Target::Target_info Target_i386::i386_info =
0x08048000, // default_text_segment_address
0x1000, // abi_pagesize (overridable by -z max-page-size)
0x1000, // common_pagesize (overridable by -z common-page-size)
+ false, // isolate_execinstr
+ 0, // rosegment_gap
elfcpp::SHN_UNDEF, // small_common_shndx
elfcpp::SHN_UNDEF, // large_common_shndx
0, // small_common_section_flags
@@ -824,9 +978,11 @@ Target_i386::rel_irelative_section(Layout* layout)
// section just for PLT entries.
Output_data_plt_i386::Output_data_plt_i386(Layout* layout,
+ uint64_t addralign,
Output_data_space* got_plt,
Output_data_space* got_irelative)
- : Output_section_data(16), layout_(layout), tls_desc_rel_(NULL),
+ : Output_section_data(addralign),
+ layout_(layout), tls_desc_rel_(NULL),
irelative_rel_(NULL), got_plt_(got_plt), got_irelative_(got_irelative),
count_(0), irelative_count_(0), global_ifuncs_(), local_ifuncs_()
{
@@ -834,11 +990,6 @@ Output_data_plt_i386::Output_data_plt_i386(Layout* layout,
layout->add_output_section_data(".rel.plt", elfcpp::SHT_REL,
elfcpp::SHF_ALLOC, this->rel_,
ORDER_DYNAMIC_PLT_RELOCS, false);
-
- // Add unwind information if requested.
- if (parameters->options().ld_generated_unwind_info())
- layout->add_eh_frame_for_plt(this, plt_eh_frame_cie, plt_eh_frame_cie_size,
- plt_eh_frame_fde, plt_eh_frame_fde_size);
}
void
@@ -861,7 +1012,7 @@ Output_data_plt_i386::add_entry(Symbol_table*
symtab, Layout* layout,
if (gsym->type() == elfcpp::STT_GNU_IFUNC
&& gsym->can_use_relative_reloc(false))
{
- gsym->set_plt_offset(this->irelative_count_ * plt_entry_size);
+ gsym->set_plt_offset(this->irelative_count_ *
this->get_plt_entry_size());
++this->irelative_count_;
section_offset_type got_offset =
this->got_irelative_->current_data_size();
@@ -878,7 +1029,7 @@ Output_data_plt_i386::add_entry(Symbol_table*
symtab, Layout* layout,
{
// When setting the PLT offset we skip the initial reserved PLT
// entry.
- gsym->set_plt_offset((this->count_ + 1) * plt_entry_size);
+ gsym->set_plt_offset((this->count_ + 1) * this->get_plt_entry_size());
++this->count_;
@@ -909,7 +1060,7 @@ Output_data_plt_i386::add_local_ifunc_entry(
Sized_relobj_file<32, false>* relobj,
unsigned int local_sym_index)
{
- unsigned int plt_offset = this->irelative_count_ * plt_entry_size;
+ unsigned int plt_offset = this->irelative_count_ *
this->get_plt_entry_size();
++this->irelative_count_;
section_offset_type got_offset = this->got_irelative_->current_data_size();
@@ -998,7 +1149,7 @@ Output_data_plt_i386::address_for_global(const
Symbol* gsym)
uint64_t offset = 0;
if (gsym->type() == elfcpp::STT_GNU_IFUNC
&& gsym->can_use_relative_reloc(false))
- offset = (this->count_ + 1) * plt_entry_size;
+ offset = (this->count_ + 1) * this->get_plt_entry_size();
return this->address() + offset;
}
@@ -1008,12 +1159,12 @@ Output_data_plt_i386::address_for_global(const
Symbol* gsym)
uint64_t
Output_data_plt_i386::address_for_local(const Relobj*, unsigned int)
{
- return this->address() + (this->count_ + 1) * plt_entry_size;
+ return this->address() + (this->count_ + 1) * this->get_plt_entry_size();
}
// The first entry in the PLT for an executable.
-const unsigned char
Output_data_plt_i386::exec_first_plt_entry[plt_entry_size] =
+const unsigned char
Output_data_plt_i386_exec::first_plt_entry[plt_entry_size] =
{
0xff, 0x35, // pushl contents of memory address
0, 0, 0, 0, // replaced with address of .got + 4
@@ -1022,18 +1173,36 @@ const unsigned char
Output_data_plt_i386::exec_first_plt_entry[plt_entry_size] =
0, 0, 0, 0 // unused
};
+void
+Output_data_plt_i386_exec::do_fill_first_plt_entry(
+ unsigned char* pov,
+ elfcpp::Elf_types<32>::Elf_Addr got_address)
+{
+ memcpy(pov, first_plt_entry, plt_entry_size);
+ elfcpp::Swap_unaligned<32, false>::writeval(pov + 2, got_address + 4);
+ elfcpp::Swap<32, false>::writeval(pov + 8, got_address + 8);
+}
+
// The first entry in the PLT for a shared object.
-const unsigned char Output_data_plt_i386::dyn_first_plt_entry[plt_entry_size] =
+const unsigned char Output_data_plt_i386_dyn::first_plt_entry[plt_entry_size] =
{
0xff, 0xb3, 4, 0, 0, 0, // pushl 4(%ebx)
0xff, 0xa3, 8, 0, 0, 0, // jmp *8(%ebx)
0, 0, 0, 0 // unused
};
+void
+Output_data_plt_i386_dyn::do_fill_first_plt_entry(
+ unsigned char* pov,
+ elfcpp::Elf_types<32>::Elf_Addr)
+{
+ memcpy(pov, first_plt_entry, plt_entry_size);
+}
+
// Subsequent entries in the PLT for an executable.
-const unsigned char Output_data_plt_i386::exec_plt_entry[plt_entry_size] =
+const unsigned char Output_data_plt_i386_exec::plt_entry[plt_entry_size] =
{
0xff, 0x25, // jmp indirect
0, 0, 0, 0, // replaced with address of symbol in .got
@@ -1043,9 +1212,25 @@ const unsigned char
Output_data_plt_i386::exec_plt_entry[plt_entry_size] =
0, 0, 0, 0 // replaced with offset to start of .plt
};
+unsigned int
+Output_data_plt_i386_exec::do_fill_plt_entry(
+ unsigned char* pov,
+ elfcpp::Elf_types<32>::Elf_Addr got_address,
+ unsigned int got_offset,
+ unsigned int plt_offset,
+ unsigned int plt_rel_offset)
+{
+ memcpy(pov, plt_entry, plt_entry_size);
+ elfcpp::Swap_unaligned<32, false>::writeval(pov + 2,
+ got_address + got_offset);
+ elfcpp::Swap_unaligned<32, false>::writeval(pov + 7, plt_rel_offset);
+ elfcpp::Swap<32, false>::writeval(pov + 12, - (plt_offset + 12 + 4));
+ return 6;
+}
+
// Subsequent entries in the PLT for a shared object.
-const unsigned char Output_data_plt_i386::dyn_plt_entry[plt_entry_size] =
+const unsigned char Output_data_plt_i386_dyn::plt_entry[plt_entry_size] =
{
0xff, 0xa3, // jmp *offset(%ebx)
0, 0, 0, 0, // replaced with offset of symbol in .got
@@ -1055,6 +1240,20 @@ const unsigned char
Output_data_plt_i386::dyn_plt_entry[plt_entry_size] =
0, 0, 0, 0 // replaced with offset to start of .plt
};
+unsigned int
+Output_data_plt_i386_dyn::do_fill_plt_entry(unsigned char* pov,
+ elfcpp::Elf_types<32>::Elf_Addr,
+ unsigned int got_offset,
+ unsigned int plt_offset,
+ unsigned int plt_rel_offset)
+{
+ memcpy(pov, plt_entry, plt_entry_size);
+ elfcpp::Swap_unaligned<32, false>::writeval(pov + 2, got_offset);
+ elfcpp::Swap_unaligned<32, false>::writeval(pov + 7, plt_rel_offset);
+ elfcpp::Swap<32, false>::writeval(pov + 12, - (plt_offset + 12 + 4));
+ return 6;
+}
+
// The .eh_frame unwind information for the PLT.
const unsigned char
@@ -1077,7 +1276,7 @@
Output_data_plt_i386::plt_eh_frame_cie[plt_eh_frame_cie_size] =
};
const unsigned char
-Output_data_plt_i386::plt_eh_frame_fde[plt_eh_frame_fde_size] =
+Output_data_plt_i386_standard::plt_eh_frame_fde[plt_eh_frame_fde_size] =
{
0, 0, 0, 0, // Replaced with offset to .plt.
0, 0, 0, 0, // Replaced with size of .plt.
@@ -1130,15 +1329,8 @@ Output_data_plt_i386::do_write(Output_file* of)
elfcpp::Elf_types<32>::Elf_Addr plt_address = this->address();
elfcpp::Elf_types<32>::Elf_Addr got_address = this->got_plt_->address();
- if (parameters->options().output_is_position_independent())
- memcpy(pov, dyn_first_plt_entry, plt_entry_size);
- else
- {
- memcpy(pov, exec_first_plt_entry, plt_entry_size);
- elfcpp::Swap_unaligned<32, false>::writeval(pov + 2, got_address + 4);
- elfcpp::Swap<32, false>::writeval(pov + 8, got_address + 8);
- }
- pov += plt_entry_size;
+ this->fill_first_plt_entry(pov, got_address);
+ pov += this->get_plt_entry_size();
unsigned char* got_pov = got_view;
@@ -1155,40 +1347,29 @@ Output_data_plt_i386::do_write(Output_file* of)
const int rel_size = elfcpp::Elf_sizes<32>::rel_size;
- unsigned int plt_offset = plt_entry_size;
+ unsigned int plt_offset = this->get_plt_entry_size();
unsigned int plt_rel_offset = 0;
unsigned int got_offset = 12;
const unsigned int count = this->count_ + this->irelative_count_;
for (unsigned int i = 0;
i < count;
++i,
- pov += plt_entry_size,
+ pov += this->get_plt_entry_size(),
got_pov += 4,
- plt_offset += plt_entry_size,
+ plt_offset += this->get_plt_entry_size(),
plt_rel_offset += rel_size,
got_offset += 4)
{
// Set and adjust the PLT entry itself.
-
- if (parameters->options().output_is_position_independent())
- {
- memcpy(pov, dyn_plt_entry, plt_entry_size);
- elfcpp::Swap_unaligned<32, false>::writeval(pov + 2, got_offset);
- }
- else
- {
- memcpy(pov, exec_plt_entry, plt_entry_size);
- elfcpp::Swap_unaligned<32, false>::writeval(pov + 2,
- (got_address
- + got_offset));
- }
-
- elfcpp::Swap_unaligned<32, false>::writeval(pov + 7, plt_rel_offset);
- elfcpp::Swap<32, false>::writeval(pov + 12,
- - (plt_offset + plt_entry_size));
+ unsigned int lazy_offset = this->fill_plt_entry(pov,
+ got_address,
+ got_offset,
+ plt_offset,
+ plt_rel_offset);
// Set the entry in the GOT.
- elfcpp::Swap<32, false>::writeval(got_pov, plt_address + plt_offset + 6);
+ elfcpp::Swap<32, false>::writeval(got_pov,
+ plt_address + plt_offset + lazy_offset);
}
// If any STT_GNU_IFUNC symbols have PLT entries, we need to change
@@ -1235,8 +1416,16 @@ Target_i386::make_plt_section(Symbol_table*
symtab, Layout* layout)
// Create the GOT sections first.
this->got_section(symtab, layout);
- this->plt_ = new Output_data_plt_i386(layout, this->got_plt_,
- this->got_irelative_);
+ const bool dyn = parameters->options().output_is_position_independent();
+ this->plt_ = this->make_data_plt(layout,
+ this->got_plt_,
+ this->got_irelative_,
+ dyn);
+
+ // Add unwind information if requested.
+ if (parameters->options().ld_generated_unwind_info())
+ this->plt_->add_eh_frame(layout);
+
layout->add_output_section_data(".plt", elfcpp::SHT_PROGBITS,
(elfcpp::SHF_ALLOC
| elfcpp::SHF_EXECINSTR),
@@ -1292,7 +1481,7 @@ Target_i386::plt_entry_count() const
unsigned int
Target_i386::first_plt_entry_offset() const
{
- return Output_data_plt_i386::first_plt_entry_offset();
+ return this->plt_->first_plt_entry_offset();
}
// Return the size of each PLT entry.
@@ -1300,7 +1489,7 @@ Target_i386::first_plt_entry_offset() const
unsigned int
Target_i386::plt_entry_size() const
{
- return Output_data_plt_i386::get_plt_entry_size();
+ return this->plt_->get_plt_entry_size();
}
// Get the section to use for TLS_DESC relocations.
@@ -3615,7 +3804,8 @@ Target_i386::do_calls_non_split(Relobj* object,
unsigned int shndx,
*to = "__morestack_non_split";
}
-// The selector for i386 object files.
+// The selector for i386 object files. Note this is never instantiated
+// directly. It's only used in Target_selector_i386_nacl, below.
class Target_selector_i386 : public Target_selector_freebsd
{
@@ -3631,6 +3821,327 @@ public:
{ return new Target_i386(); }
};
-Target_selector_i386 target_selector_i386;
+// NaCl variant. It uses different PLT contents.
+
+class Output_data_plt_i386_nacl : public Output_data_plt_i386
+{
+ public:
+ Output_data_plt_i386_nacl(Layout* layout,
+ Output_data_space* got_plt,
+ Output_data_space* got_irelative)
+ : Output_data_plt_i386(layout, plt_entry_size, got_plt, got_irelative)
+ { }
+
+ protected:
+ virtual unsigned int
+ do_get_plt_entry_size() const
+ { return plt_entry_size; }
+
+ virtual void
+ do_add_eh_frame(Layout* layout)
+ {
+ layout->add_eh_frame_for_plt(this, plt_eh_frame_cie, plt_eh_frame_cie_size,
+ plt_eh_frame_fde, plt_eh_frame_fde_size);
+ }
+
+ // The size of an entry in the PLT.
+ static const int plt_entry_size = 64;
+
+ // The .eh_frame unwind information for the PLT.
+ static const int plt_eh_frame_fde_size = 32;
+ static const unsigned char plt_eh_frame_fde[plt_eh_frame_fde_size];
+};
+
+class Output_data_plt_i386_nacl_exec : public Output_data_plt_i386_nacl
+{
+public:
+ Output_data_plt_i386_nacl_exec(Layout* layout,
+ Output_data_space* got_plt,
+ Output_data_space* got_irelative)
+ : Output_data_plt_i386_nacl(layout, got_plt, got_irelative)
+ { }
+
+ protected:
+ virtual void
+ do_fill_first_plt_entry(unsigned char* pov,
+ elfcpp::Elf_types<32>::Elf_Addr got_address);
+
+ virtual unsigned int
+ do_fill_plt_entry(unsigned char* pov,
+ elfcpp::Elf_types<32>::Elf_Addr got_address,
+ unsigned int got_offset,
+ unsigned int plt_offset,
+ unsigned int plt_rel_offset);
+
+ private:
+ // The first entry in the PLT for an executable.
+ static const unsigned char first_plt_entry[plt_entry_size];
+
+ // Other entries in the PLT for an executable.
+ static const unsigned char plt_entry[plt_entry_size];
+};
+
+class Output_data_plt_i386_nacl_dyn : public Output_data_plt_i386_nacl
+{
+ public:
+ Output_data_plt_i386_nacl_dyn(Layout* layout,
+ Output_data_space* got_plt,
+ Output_data_space* got_irelative)
+ : Output_data_plt_i386_nacl(layout, got_plt, got_irelative)
+ { }
+
+ protected:
+ virtual void
+ do_fill_first_plt_entry(unsigned char* pov, elfcpp::Elf_types<32>::Elf_Addr);
+
+ virtual unsigned int
+ do_fill_plt_entry(unsigned char* pov,
+ elfcpp::Elf_types<32>::Elf_Addr,
+ unsigned int got_offset,
+ unsigned int plt_offset,
+ unsigned int plt_rel_offset);
+
+ private:
+ // The first entry in the PLT for a shared object.
+ static const unsigned char first_plt_entry[plt_entry_size];
+
+ // Other entries in the PLT for a shared object.
+ static const unsigned char plt_entry[plt_entry_size];
+};
+
+class Target_i386_nacl : public Target_i386
+{
+ public:
+ Target_i386_nacl()
+ : Target_i386(&i386_nacl_info)
+ { }
+
+ protected:
+ virtual Output_data_plt_i386*
+ do_make_data_plt(Layout* layout,
+ Output_data_space* got_plt,
+ Output_data_space* got_irelative,
+ bool dyn)
+ {
+ if (dyn)
+ return new Output_data_plt_i386_nacl_dyn(layout, got_plt, got_irelative);
+ else
+ return new Output_data_plt_i386_nacl_exec(layout, got_plt,
got_irelative);
+ }
+
+ private:
+ static const Target::Target_info i386_nacl_info;
+};
+
+const Target::Target_info Target_i386_nacl::i386_nacl_info =
+{
+ 32, // size
+ false, // is_big_endian
+ elfcpp::EM_386, // machine_code
+ false, // has_make_symbol
+ false, // has_resolve
+ true, // has_code_fill
+ true, // is_default_stack_executable
+ true, // can_icf_inline_merge_sections
+ '\0', // wrap_char
+ "/lib/ld-nacl-x86-32.so.1", // dynamic_linker
+ 0x20000, // default_text_segment_address
+ 0x10000, // abi_pagesize (overridable by -z max-page-size)
+ 0x10000, // common_pagesize (overridable by -z common-page-size)
+ true, // isolate_execinstr
+ 0x10000000, // rosegment_gap
+ elfcpp::SHN_UNDEF, // small_common_shndx
+ elfcpp::SHN_UNDEF, // large_common_shndx
+ 0, // small_common_section_flags
+ 0, // large_common_section_flags
+ NULL, // attributes_section
+ NULL // attributes_vendor
+};
+
+#define NACLMASK 0xe0 // 32-byte alignment mask
+
+const unsigned char
+Output_data_plt_i386_nacl_exec::first_plt_entry[plt_entry_size] =
+{
+ 0xff, 0x35, // pushl contents of memory address
+ 0, 0, 0, 0, // replaced with address of .got + 4
+ 0x8b, 0x0d, // movl contents of address, %ecx
+ 0, 0, 0, 0, // replaced with address of .got + 8
+ 0x83, 0xe1, NACLMASK, // andl $NACLMASK, %ecx
+ 0xff, 0xe1, // jmp *%ecx
+ 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, // nops
+ 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, // nops
+ 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, // nops
+ 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, // nops
+ 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, // nops
+ 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, // nops
+ 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, // nops
+ 0x90, 0x90, 0x90, 0x90, 0x90
+};
+
+void
+Output_data_plt_i386_nacl_exec::do_fill_first_plt_entry(
+ unsigned char* pov,
+ elfcpp::Elf_types<32>::Elf_Addr got_address)
+{
+ memcpy(pov, first_plt_entry, plt_entry_size);
+ elfcpp::Swap_unaligned<32, false>::writeval(pov + 2, got_address + 4);
+ elfcpp::Swap<32, false>::writeval(pov + 8, got_address + 8);
+}
+
+// The first entry in the PLT for a shared object.
+
+const unsigned char
+Output_data_plt_i386_nacl_dyn::first_plt_entry[plt_entry_size] =
+{
+ 0xff, 0xb3, 4, 0, 0, 0, // pushl 4(%ebx)
+ 0x8b, 0x4b, 0x08, // mov 0x8(%ebx), %ecx
+ 0x83, 0xe1, NACLMASK, // andl $NACLMASK, %ecx
+ 0xff, 0xe1, // jmp *%ecx
+ 0x90, 0x90, 0x90, 0x90, 0x90, // nops
+ 0x90, 0x90, 0x90, 0x90, 0x90, // nops
+ 0x90, 0x90, 0x90, 0x90, 0x90, // nops
+ 0x90, 0x90, 0x90, 0x90, 0x90, // nops
+ 0x90, 0x90, 0x90, 0x90, 0x90, // nops
+ 0x90, 0x90, 0x90, 0x90, 0x90, // nops
+ 0x90, 0x90, 0x90, 0x90, 0x90, // nops
+ 0x90, 0x90, 0x90, 0x90, 0x90, // nops
+ 0x90, 0x90, 0x90, 0x90, 0x90, // nops
+ 0x90, 0x90, 0x90, 0x90, 0x90 // nops
+};
+
+void
+Output_data_plt_i386_nacl_dyn::do_fill_first_plt_entry(
+ unsigned char* pov,
+ elfcpp::Elf_types<32>::Elf_Addr)
+{
+ memcpy(pov, first_plt_entry, plt_entry_size);
+}
+
+// Subsequent entries in the PLT for an executable.
+
+const unsigned char
+Output_data_plt_i386_nacl_exec::plt_entry[plt_entry_size] =
+{
+ 0x8b, 0x0d, // movl contents of address, %ecx */
+ 0, 0, 0, 0, // replaced with address of symbol in .got
+ 0x83, 0xe1, NACLMASK, // andl $NACLMASK, %ecx
+ 0xff, 0xe1, // jmp *%ecx
+
+ // Pad to the next 32-byte boundary with nop instructions.
+ 0x90,
+ 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90,
+ 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90,
+
+ // Lazy GOT entries point here (32-byte aligned).
+ 0x68, // pushl immediate
+ 0, 0, 0, 0, // replaced with offset into relocation table
+ 0xe9, // jmp relative
+ 0, 0, 0, 0, // replaced with offset to start of .plt
+
+ // Pad to the next 32-byte boundary with nop instructions.
+ 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90,
+ 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90,
+ 0x90, 0x90
+};
+
+unsigned int
+Output_data_plt_i386_nacl_exec::do_fill_plt_entry(
+ unsigned char* pov,
+ elfcpp::Elf_types<32>::Elf_Addr got_address,
+ unsigned int got_offset,
+ unsigned int plt_offset,
+ unsigned int plt_rel_offset)
+{
+ memcpy(pov, plt_entry, plt_entry_size);
+ elfcpp::Swap_unaligned<32, false>::writeval(pov + 2,
+ got_address + got_offset);
+ elfcpp::Swap_unaligned<32, false>::writeval(pov + 33, plt_rel_offset);
+ elfcpp::Swap<32, false>::writeval(pov + 38, - (plt_offset + 38 + 4));
+ return 32;
+}
+
+// Subsequent entries in the PLT for a shared object.
+
+const unsigned char
+Output_data_plt_i386_nacl_dyn::plt_entry[plt_entry_size] =
+{
+ 0x8b, 0x8b, // movl offset(%ebx), %ecx
+ 0, 0, 0, 0, // replaced with offset of symbol in .got
+ 0x83, 0xe1, 0xe0, // andl $NACLMASK, %ecx
+ 0xff, 0xe1, // jmp *%ecx
+
+ // Pad to the next 32-byte boundary with nop instructions.
+ 0x90,
+ 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90,
+ 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90,
+
+ // Lazy GOT entries point here (32-byte aligned).
+ 0x68, // pushl immediate
+ 0, 0, 0, 0, // replaced with offset into relocation table.
+ 0xe9, // jmp relative
+ 0, 0, 0, 0, // replaced with offset to start of .plt.
+
+ // Pad to the next 32-byte boundary with nop instructions.
+ 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90,
+ 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90,
+ 0x90, 0x90
+};
+
+unsigned int
+Output_data_plt_i386_nacl_dyn::do_fill_plt_entry(
+ unsigned char* pov,
+ elfcpp::Elf_types<32>::Elf_Addr,
+ unsigned int got_offset,
+ unsigned int plt_offset,
+ unsigned int plt_rel_offset)
+{
+ memcpy(pov, plt_entry, plt_entry_size);
+ elfcpp::Swap_unaligned<32, false>::writeval(pov + 2, got_offset);
+ elfcpp::Swap_unaligned<32, false>::writeval(pov + 33, plt_rel_offset);
+ elfcpp::Swap<32, false>::writeval(pov + 38, - (plt_offset + 38 + 4));
+ return 32;
+}
+
+const unsigned char
+Output_data_plt_i386_nacl::plt_eh_frame_fde[plt_eh_frame_fde_size] =
+{
+ 0, 0, 0, 0, // Replaced with offset to .plt.
+ 0, 0, 0, 0, // Replaced with size of .plt.
+ 0, // Augmentation size.
+ elfcpp::DW_CFA_def_cfa_offset, 8, // DW_CFA_def_cfa_offset: 8.
+ elfcpp::DW_CFA_advance_loc + 6, // Advance 6 to __PLT__ + 6.
+ elfcpp::DW_CFA_def_cfa_offset, 12, // DW_CFA_def_cfa_offset: 12.
+ elfcpp::DW_CFA_advance_loc + 58, // Advance 58 to __PLT__ + 64.
+ elfcpp::DW_CFA_def_cfa_expression, // DW_CFA_def_cfa_expression.
+ 13, // Block length.
+ elfcpp::DW_OP_breg4, 4, // Push %esp + 4.
+ elfcpp::DW_OP_breg8, 0, // Push %eip.
+ elfcpp::DW_OP_const1u, 63, // Push 0x3f.
+ elfcpp::DW_OP_and, // & (%eip & 0x3f).
+ elfcpp::DW_OP_const1u, 37, // Push 0x25.
+ elfcpp::DW_OP_ge, // >= ((%eip & 0x3f) >= 0x25)
+ elfcpp::DW_OP_lit2, // Push 2.
+ elfcpp::DW_OP_shl, // << (((%eip & 0x3f) >= 0x25) << 2)
+ elfcpp::DW_OP_plus, // + ((((%eip&0x3f)>=0x25)<<2)+%esp+4
+ elfcpp::DW_CFA_nop, // Align to 32 bytes.
+ elfcpp::DW_CFA_nop
+};
+
+// The selector for i386-nacl object files.
+
+class Target_selector_i386_nacl
+ : public Target_selector_nacl<Target_selector_i386, Target_i386_nacl>
+{
+ public:
+ Target_selector_i386_nacl()
+ : Target_selector_nacl<Target_selector_i386,
+ Target_i386_nacl>("x86-32",
+ "elf32-i386-nacl",
+ "elf_i386_nacl")
+ { }
+};
+
+Target_selector_i386_nacl target_selector_i386;
} // End anonymous namespace.
diff --git a/gold/incremental.cc b/gold/incremental.cc
index 6436a35..9a61e77 100644
--- a/gold/incremental.cc
+++ b/gold/incremental.cc
@@ -1,6 +1,6 @@
// inremental.cc -- incremental linking support for gold
-// Copyright 2009, 2010, 2011 Free Software Foundation, Inc.
+// Copyright 2009, 2010, 2011, 2012 Free Software Foundation, Inc.
// Written by Mikolaj Zalewski <mikolajz@google.com>.
// This file is part of gold.
@@ -850,7 +850,8 @@ Incremental_binary*
make_sized_incremental_binary(Output_file* file,
const elfcpp::Ehdr<size, big_endian>& ehdr)
{
- Target* target = select_target(ehdr.get_e_machine(), size, big_endian,
+ Target* target = select_target(NULL, 0, // XXX
+ ehdr.get_e_machine(), size, big_endian,
ehdr.get_e_ident()[elfcpp::EI_OSABI],
ehdr.get_e_ident()[elfcpp::EI_ABIVERSION]);
if (target == NULL)
diff --git a/gold/layout.cc b/gold/layout.cc
index 65d1432..7155f22 100644
--- a/gold/layout.cc
+++ b/gold/layout.cc
@@ -1,6 +1,7 @@
// layout.cc -- lay out output file sections for gold
-// Copyright 2006, 2007, 2008, 2009, 2010, 2011 Free Software Foundation, Inc.
+// Copyright 2006, 2007, 2008, 2009, 2010, 2011, 2012
+// Free Software Foundation, Inc.
// Written by Ian Lance Taylor <iant@google.com>.
// This file is part of gold.
@@ -1508,7 +1509,7 @@ Layout::make_output_section(const char* name,
elfcpp::Elf_Word type,
// need to attach this one now. This happens for sections created
// directly by the linker.
if (this->sections_are_attached_)
- this->attach_section_to_segment(os);
+ this->attach_section_to_segment(¶meters->target(), os);
return os;
}
@@ -1585,12 +1586,12 @@ Layout::default_section_order(Output_section*
os, bool is_relro_local)
// seen all the input sections.
void
-Layout::attach_sections_to_segments()
+Layout::attach_sections_to_segments(const Target* target)
{
for (Section_list::iterator p = this->section_list_.begin();
p != this->section_list_.end();
++p)
- this->attach_section_to_segment(*p);
+ this->attach_section_to_segment(target, *p);
this->sections_are_attached_ = true;
}
@@ -1598,18 +1599,19 @@ Layout::attach_sections_to_segments()
// Attach an output section to a segment.
void
-Layout::attach_section_to_segment(Output_section* os)
+Layout::attach_section_to_segment(const Target* target, Output_section* os)
{
if ((os->flags() & elfcpp::SHF_ALLOC) == 0)
this->unattached_section_list_.push_back(os);
else
- this->attach_allocated_section_to_segment(os);
+ this->attach_allocated_section_to_segment(target, os);
}
// Attach an allocated output section to a segment.
void
-Layout::attach_allocated_section_to_segment(Output_section* os)
+Layout::attach_allocated_section_to_segment(const Target* target,
+ Output_section* os)
{
elfcpp::Elf_Xword flags = os->flags();
gold_assert((flags & elfcpp::SHF_ALLOC) != 0);
@@ -1649,7 +1651,7 @@
Layout::attach_allocated_section_to_segment(Output_section* os)
if (!parameters->options().omagic()
&& ((*p)->flags() & elfcpp::PF_W) != (seg_flags & elfcpp::PF_W))
continue;
- if (parameters->options().rosegment()
+ if ((target->isolate_execinstr() || parameters->options().rosegment())
&& ((*p)->flags() & elfcpp::PF_X) != (seg_flags & elfcpp::PF_X))
continue;
// If -Tbss was specified, we need to separate the data and BSS
@@ -1951,7 +1953,7 @@ Layout::define_group_signatures(Symbol_table* symtab)
// necessary.
Output_segment*
-Layout::find_first_load_seg()
+Layout::find_first_load_seg(const Target* target)
{
Output_segment* best = NULL;
for (Segment_list::const_iterator p = this->segment_list_.begin();
@@ -1961,7 +1963,9 @@ Layout::find_first_load_seg()
if ((*p)->type() == elfcpp::PT_LOAD
&& ((*p)->flags() & elfcpp::PF_R) != 0
&& (parameters->options().omagic()
- || ((*p)->flags() & elfcpp::PF_W) == 0))
+ || ((*p)->flags() & elfcpp::PF_W) == 0)
+ && (!target->isolate_execinstr()
+ || ((*p)->flags() & elfcpp::PF_X) == 0))
{
if (best == NULL || this->segment_precedes(*p, best))
best = *p;
@@ -2148,7 +2152,7 @@ Layout::relaxation_loop_body(
else if (parameters->options().relocatable())
load_seg = NULL;
else
- load_seg = this->find_first_load_seg();
+ load_seg = this->find_first_load_seg(target);
if (parameters->options().oformat_enum()
!= General_options::OBJECT_FORMAT_ELF)
@@ -3054,13 +3058,15 @@ Layout::set_segment_offsets(const Target*
target, Output_segment* load_seg,
// Find the PT_LOAD segments, and set their addresses and offsets
// and their section's addresses and offsets.
- uint64_t addr;
+ uint64_t start_addr;
if (parameters->options().user_set_Ttext())
- addr = parameters->options().Ttext();
+ start_addr = parameters->options().Ttext();
else if (parameters->options().output_is_position_independent())
- addr = 0;
+ start_addr = 0;
else
- addr = target->default_text_segment_address();
+ start_addr = target->default_text_segment_address();
+
+ uint64_t addr = start_addr;
off_t off = 0;
// If LOAD_SEG is NULL, then the file header and segment headers
@@ -3085,15 +3091,39 @@ Layout::set_segment_offsets(const Target*
target, Output_segment* load_seg,
const bool check_sections = parameters->options().check_sections();
Output_segment* last_load_segment = NULL;
+ unsigned int shndx_begin = *pshndx;
+ unsigned int shndx_load_seg = *pshndx;
+
for (Segment_list::iterator p = this->segment_list_.begin();
p != this->segment_list_.end();
++p)
{
if ((*p)->type() == elfcpp::PT_LOAD)
{
+ if (target->isolate_execinstr())
+ {
+ // When we hit the segment that should contain the
+ // file headers, reset the file offset so we place
+ // it and subsequent segments appropriately.
+ // We'll fix up the preceding segments below.
+ if (load_seg == *p)
+ {
+ if (off == 0)
+ load_seg = NULL;
+ else
+ {
+ off = 0;
+ shndx_load_seg = *pshndx;
+ }
+ }
+ }
+ else
+ {
+ // Verify that the file headers fall into the first segment.
if (load_seg != NULL && load_seg != *p)
gold_unreachable();
load_seg = NULL;
+ }
bool are_addresses_set = (*p)->are_addresses_set();
if (are_addresses_set)
@@ -3145,16 +3175,37 @@ Layout::set_segment_offsets(const Target*
target, Output_segment* load_seg,
addr = align_address(addr, (*p)->maximum_alignment());
aligned_addr = addr;
+ if (load_seg == *p)
+ {
+ // This is the segment that will contain the file
+ // headers, so its offset will have to be exactly zero.
+ gold_assert(orig_off == 0);
+
+ // If the target wants a fixed minimum distance from the
+ // text segment to the read-only segment, move up now.
+ uint64_t min_addr = start_addr + target->rosegment_gap();
+ if (addr < min_addr)
+ addr = min_addr;
+
+ // But this is not the first segment! To make its
+ // address congruent with its offset, that address better
+ // be aligned to the ABI-mandated page size.
+ addr = align_address(addr, abi_pagesize);
+ aligned_addr = addr;
+ }
+ else
+ {
if ((addr & (abi_pagesize - 1)) != 0)
addr = addr + abi_pagesize;
off = orig_off + ((addr - orig_addr) & (abi_pagesize - 1));
}
+ }
if (!parameters->options().nmagic()
&& !parameters->options().omagic())
off = align_file_offset(off, addr, abi_pagesize);
- else if (load_seg == NULL)
+ else
{
// This is -N or -n with a section script which prevents
// us from using a load segment. We need to ensure that
@@ -3239,6 +3290,38 @@ Layout::set_segment_offsets(const Target*
target, Output_segment* load_seg,
}
}
+ if (load_seg != NULL && target->isolate_execinstr())
+ {
+ // Process the early segments again, setting their file offsets
+ // so they land after the segments starting at LOAD_SEG.
+ off = align_file_offset(off, 0, target->abi_pagesize());
+
+ for (Segment_list::iterator p = this->segment_list_.begin();
+ *p != load_seg;
+ ++p)
+ {
+ if ((*p)->type() == elfcpp::PT_LOAD)
+ {
+ // We repeat the whole job of assigning addresses and
+ // offsets, but we really only want to change the offsets and
+ // must ensure that the addresses all come out the same as
+ // they did the first time through.
+ bool has_relro = false;
+ const uint64_t old_addr = (*p)->vaddr();
+ const uint64_t old_end = old_addr + (*p)->memsz();
+ uint64_t new_addr = (*p)->set_section_addresses(this, true,
+ old_addr,
+ &increase_relro,
+ &has_relro,
+ &off,
+ &shndx_begin);
+ gold_assert(new_addr == old_end);
+ }
+ }
+
+ gold_assert(shndx_begin == shndx_load_seg);
+ }
+
// Handle the non-PT_LOAD segments, setting their offsets from their
// section's offsets.
for (Segment_list::iterator p = this->segment_list_.begin();
diff --git a/gold/layout.h b/gold/layout.h
index f81ea3b..4643e32 100644
--- a/gold/layout.h
+++ b/gold/layout.h
@@ -1,6 +1,7 @@
// layout.h -- lay out output file sections for gold -*- C++ -*-
-// Copyright 2006, 2007, 2008, 2009, 2010, 2011 Free Software Foundation, Inc.
+// Copyright 2006, 2007, 2008, 2009, 2010, 2011, 2012
+// Free Software Foundation, Inc.
// Written by Ian Lance Taylor <iant@google.com>.
// This file is part of gold.
@@ -903,7 +904,7 @@ class Layout
// Attach sections to segments.
void
- attach_sections_to_segments();
+ attach_sections_to_segments(const Target*);
// For relaxation clean up, we need to know output section data created
// from a linker script.
@@ -982,7 +983,7 @@ class Layout
// Find the first read-only PT_LOAD segment, creating one if
// necessary.
Output_segment*
- find_first_load_seg();
+ find_first_load_seg(const Target*);
// Count the local symbols in the regular symbol table and the dynamic
// symbol table, and build the respective string pools.
@@ -1079,7 +1080,7 @@ class Layout
// Attach a section to a segment.
void
- attach_section_to_segment(Output_section*);
+ attach_section_to_segment(const Target*, Output_section*);
// Get section order.
Output_section_order
@@ -1087,7 +1088,7 @@ class Layout
// Attach an allocated section to a segment.
void
- attach_allocated_section_to_segment(Output_section*);
+ attach_allocated_section_to_segment(const Target*, Output_section*);
// Make the .eh_frame section.
Output_section*
diff --git a/gold/nacl.cc b/gold/nacl.cc
new file mode 100644
index 0000000..71be4e9
--- /dev/null
+++ b/gold/nacl.cc
@@ -0,0 +1,46 @@
+// nacl.cc -- Native Client support for gold
+
+// Copyright 2012 Free Software Foundation, Inc.
+
+// This file is part of gold.
+
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 3 of the License, or
+// (at your option) any later version.
+
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
+// MA 02110-1301, USA.
+
+#include "gold.h"
+
+#include <cstdio>
+
+#include "nacl.h"
+#include "elfcpp.h"
+
+namespace gold
+{
+
+// Copied from object.cc:Object::error.
+void
+Sniff_file::error(const char* format, ...) const
+{
+ va_list args;
+ va_start(args, format);
+ char* buf = NULL;
+ if (vasprintf(&buf, format, args) < 0)
+ gold_nomem();
+ va_end(args);
+ gold_error(_("%s: %s"), this->file_.filename().c_str(), buf);
+ free(buf);
+}
+
+} // end namespace gold
diff --git a/gold/nacl.h b/gold/nacl.h
new file mode 100644
index 0000000..bf5853d
--- /dev/null
+++ b/gold/nacl.h
@@ -0,0 +1,243 @@
+// nacl.h -- Native Client support for gold -*- C++ -*-
+
+// Copyright 2012 Free Software Foundation, Inc.
+
+// This file is part of gold.
+
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 3 of the License, or
+// (at your option) any later version.
+
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
+// MA 02110-1301, USA.
+
+#include "elfcpp_file.h"
+#include "fileread.h"
+#include "layout.h"
+#include "target-select.h"
+#include "target.h"
+
+#ifndef GOLD_NACL_H
+#define GOLD_NACL_H
+
+namespace gold
+{
+
+class Sniff_file
+{
+ public:
+ Sniff_file(Input_file* input_file, off_t offset)
+ : file_(input_file->file()), offset_(offset)
+ { }
+
+ class Location
+ {
+ public:
+ Location(off_t file_offset, off_t data_size)
+ : offset_(file_offset), size_(data_size)
+ { }
+
+ inline off_t offset() const
+ { return this->offset_; }
+
+ inline section_size_type size() const
+ { return this->size_; }
+
+ private:
+ off_t offset_;
+ section_size_type size_;
+ };
+
+ class View
+ {
+ public:
+ View(File_read& file, off_t file_offset, off_t data_size)
+ : data_(file.get_view(0, file_offset, data_size, false, false))
+ { }
+
+ const unsigned char* data()
+ { return this->data_; }
+
+ private:
+ const unsigned char* data_;
+ };
+
+ View view(off_t file_offset, off_t data_size)
+ {
+ return View(this->file_, this->offset_ + file_offset, data_size);
+ }
+
+ View view(Location loc)
+ {
+ return this->view(loc.offset(), loc.size());
+ }
+
+ // Report an error.
+ void
+ error(const char* format, ...) const ATTRIBUTE_PRINTF_2;
+
+ private:
+ File_read& file_;
+ off_t offset_;
+};
+
+
+template<class base_selector, class nacl_target>
+class Target_selector_nacl : public base_selector
+{
+ public:
+ Target_selector_nacl(const char* nacl_abi_name,
+ const char* bfd_name, const char* emulation)
+ : base_selector(), is_nacl_(false), nacl_abi_name_(nacl_abi_name),
+ bfd_name_(bfd_name), emulation_(emulation)
+ { }
+
+ protected:
+ virtual Target*
+ do_instantiate_target()
+ {
+ if (this->is_nacl_)
+ return new nacl_target();
+ return this->base_selector::do_instantiate_target();
+ }
+
+ virtual Target*
+ do_recognize(Input_file* file, off_t offset,
+ int machine, int osabi, int abiversion)
+ {
+ this->is_nacl_ = file != NULL && this->recognize_nacl_file(file, offset);
+ if (this->is_nacl_)
+ return this->instantiate_target();
+ return this->base_selector::do_recognize(file, offset,
+ machine, osabi, abiversion);
+ }
+
+ virtual Target*
+ do_recognize_by_bfd_name(const char* name)
+ {
+ gold_assert(this->bfd_name_ != NULL);
+ this->is_nacl_ = strcmp(name, this->bfd_name_) == 0;
+ if (this->is_nacl_)
+ return this->instantiate_target();
+ return this->base_selector::do_recognize_by_bfd_name(name);
+ }
+
+ virtual void
+ do_supported_bfd_names(std::vector<const char*>* names)
+ {
+ gold_assert(this->bfd_name_ != NULL);
+ this->base_selector::do_supported_bfd_names(names);
+ names->push_back(this->bfd_name_);
+ }
+
+ virtual void
+ do_supported_emulations(std::vector<const char*>* emulations)
+ {
+ gold_assert(this->emulation_ != NULL);
+ this->base_selector::do_supported_emulations(emulations);
+ emulations->push_back(this->emulation_);
+ }
+
+ virtual const char*
+ do_target_bfd_name(const Target* target)
+ {
+ return (!this->is_our_target(target)
+ ? NULL
+ : (this->is_nacl_
+ ? this->bfd_name_
+ : base_selector::do_target_bfd_name(target)));
+ }
+
+ private:
+ bool
+ recognize_nacl_file(Input_file* input_file, off_t offset)
+ {
+ if (this->is_big_endian())
+ {
+#if defined(HAVE_TARGET_32_BIG) || defined(HAVE_TARGET_64_BIG)
+# ifdef HAVE_TARGET_32_BIG
+ if (this->get_size() == 32)
+ return do_recognize_nacl_file<32, true>(input_file, offset);
+# endif
+# ifdef HAVE_TARGET_64_BIG
+ if (this->get_size() == 64)
+ return do_recognize_nacl_file<64, true>(input_file, offset);
+# endif
+#endif
+ gold_unreachable();
+ }
+ else
+ {
+#if defined(HAVE_TARGET_32_LITTLE) || defined(HAVE_TARGET_64_LITTLE)
+# ifdef HAVE_TARGET_32_LITTLE
+ if (this->get_size() == 32)
+ return do_recognize_nacl_file<32, false>(input_file, offset);
+# endif
+# ifdef HAVE_TARGET_64_LITTLE
+ if (this->get_size() == 64)
+ return do_recognize_nacl_file<64, false>(input_file, offset);
+# endif
+#endif
+ gold_unreachable();
+ }
+ }
+
+ template<int size, bool big_endian>
+ bool
+ do_recognize_nacl_file(Input_file* input_file, off_t offset)
+ {
+ Sniff_file file(input_file, offset);
+ elfcpp::Elf_file<size, big_endian, Sniff_file> elf_file(&file);
+ const unsigned int shnum = elf_file.shnum();
+ for (unsigned int shndx = 1; shndx < shnum; ++shndx)
+ {
+ if (elf_file.section_type(shndx) == elfcpp::SHT_NOTE)
+ {
+ Sniff_file::Location loc = elf_file.section_contents(shndx);
+ if (loc.size() < (3 * 4
+ + align_address(sizeof "NaCl", 4)
+ + align_address(nacl_abi_name_.size() + 1, 4)))
+ continue;
+ Sniff_file::View view(file.view(loc));
+ const unsigned char* note_data = view.data();
+ if ((elfcpp::Swap<32, big_endian>::readval(note_data + 0)
+ == sizeof "NaCl")
+ && (elfcpp::Swap<32, big_endian>::readval(note_data + 4)
+ == nacl_abi_name_.size() + 1)
+ && (elfcpp::Swap<32, big_endian>::readval(note_data + 8)
+ == elfcpp::NT_VERSION))
+ {
+ const unsigned char* name = note_data + 12;
+ const unsigned char* desc = (name
+ + align_address(sizeof
"NaCl", 4));
+ if (memcmp(name, "NaCl", sizeof "NaCl") == 0
+ && memcmp(desc, nacl_abi_name_.c_str(),
+ nacl_abi_name_.size() + 1) == 0)
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
+ // Whether we decided this was the NaCl target variant.
+ bool is_nacl_;
+ // The string found in the NaCl ABI note.
+ std::string nacl_abi_name_;
+ // BFD name of NaCl target, for compatibility.
+ const char* const bfd_name_;
+ // GNU linker emulation for this NaCl target, for compatibility.
+ const char* const emulation_;
+};
+
+} // end namespace gold
+
+#endif // !defined(GOLD_NACL_H)
diff --git a/gold/object.cc b/gold/object.cc
index 15e5d05..e43ffdc 100644
--- a/gold/object.cc
+++ b/gold/object.cc
@@ -1,6 +1,7 @@
// object.cc -- support for an object file for linking in gold
-// Copyright 2006, 2007, 2008, 2009, 2010, 2011 Free Software Foundation, Inc.
+// Copyright 2006, 2007, 2008, 2009, 2010, 2011, 2012
+// Free Software Foundation, Inc.
// Written by Ian Lance Taylor <iant@google.com>.
// This file is part of gold.
@@ -2934,7 +2935,8 @@ make_elf_sized_object(const std::string& name,
Input_file* input_file,
off_t offset, const elfcpp::Ehdr<size, big_endian>& ehdr,
bool* punconfigured)
{
- Target* target = select_target(ehdr.get_e_machine(), size, big_endian,
+ Target* target = select_target(input_file, offset,
+ ehdr.get_e_machine(), size, big_endian,
ehdr.get_e_ident()[elfcpp::EI_OSABI],
ehdr.get_e_ident()[elfcpp::EI_ABIVERSION]);
if (target == NULL)
diff --git a/gold/parameters.cc b/gold/parameters.cc
index 7fc5730..d69b62c 100644
--- a/gold/parameters.cc
+++ b/gold/parameters.cc
@@ -1,6 +1,7 @@
// parameters.cc -- general parameters for a link using gold
-// Copyright 2006, 2007, 2008, 2009, 2010, 2011 Free Software Foundation, Inc.
+// Copyright 2006, 2007, 2008, 2009, 2010, 2011, 2012
+// Free Software Foundation, Inc.
// Written by Ian Lance Taylor <iant@google.com>.
// This file is part of gold.
@@ -352,7 +353,8 @@ parameters_force_valid_target()
else
is_big_endian = GOLD_DEFAULT_BIG_ENDIAN;
- Target* target = select_target(elfcpp::GOLD_DEFAULT_MACHINE,
+ Target* target = select_target(NULL, 0,
+ elfcpp::GOLD_DEFAULT_MACHINE,
GOLD_DEFAULT_SIZE,
is_big_endian,
elfcpp::GOLD_DEFAULT_OSABI,
diff --git a/gold/powerpc.cc b/gold/powerpc.cc
index b443304..1bc9dfa 100644
--- a/gold/powerpc.cc
+++ b/gold/powerpc.cc
@@ -1,6 +1,6 @@
// powerpc.cc -- powerpc target support for gold.
-// Copyright 2008, 2009, 2010, 2011 Free Software Foundation, Inc.
+// Copyright 2008, 2009, 2010, 2011, 2012 Free Software Foundation, Inc.
// Written by David S. Miller <davem@davemloft.net>
// and David Edelsohn <edelsohn@gnu.org>
@@ -389,6 +389,8 @@ Target::Target_info Target_powerpc<32, true>::powerpc_info =
0x10000000, // default_text_segment_address
64 * 1024, // abi_pagesize (overridable by -z max-page-size)
4 * 1024, // common_pagesize (overridable by -z common-page-size)
+ false, // isolate_execinstr
+ 0, // rosegment_gap
elfcpp::SHN_UNDEF, // small_common_shndx
elfcpp::SHN_UNDEF, // large_common_shndx
0, // small_common_section_flags
@@ -413,6 +415,8 @@ Target::Target_info Target_powerpc<32,
false>::powerpc_info =
0x10000000, // default_text_segment_address
64 * 1024, // abi_pagesize (overridable by -z max-page-size)
4 * 1024, // common_pagesize (overridable by -z common-page-size)
+ false, // isolate_execinstr
+ 0, // rosegment_gap
elfcpp::SHN_UNDEF, // small_common_shndx
elfcpp::SHN_UNDEF, // large_common_shndx
0, // small_common_section_flags
@@ -437,6 +441,8 @@ Target::Target_info Target_powerpc<64, true>::powerpc_info =
0x10000000, // default_text_segment_address
64 * 1024, // abi_pagesize (overridable by -z max-page-size)
8 * 1024, // common_pagesize (overridable by -z common-page-size)
+ false, // isolate_execinstr
+ 0, // rosegment_gap
elfcpp::SHN_UNDEF, // small_common_shndx
elfcpp::SHN_UNDEF, // large_common_shndx
0, // small_common_section_flags
@@ -461,6 +467,8 @@ Target::Target_info Target_powerpc<64,
false>::powerpc_info =
0x10000000, // default_text_segment_address
64 * 1024, // abi_pagesize (overridable by -z max-page-size)
8 * 1024, // common_pagesize (overridable by -z common-page-size)
+ false, // isolate_execinstr
+ 0, // rosegment_gap
elfcpp::SHN_UNDEF, // small_common_shndx
elfcpp::SHN_UNDEF, // large_common_shndx
0, // small_common_section_flags
@@ -2132,7 +2140,8 @@ public:
: (big_endian ? "elf32ppc" : "elf32lppc")))
{ }
- Target* do_recognize(int machine, int, int)
+ virtual Target*
+ do_recognize(Input_file*, off_t, int machine, int, int)
{
switch (size)
{
@@ -2153,7 +2162,8 @@ public:
return this->instantiate_target();
}
- Target* do_instantiate_target()
+ virtual Target*
+ do_instantiate_target()
{ return new Target_powerpc<size, big_endian>(); }
};
diff --git a/gold/sparc.cc b/gold/sparc.cc
index a85bb81..7b78311 100644
--- a/gold/sparc.cc
+++ b/gold/sparc.cc
@@ -473,6 +473,8 @@ Target::Target_info Target_sparc<32, true>::sparc_info =
0x00010000, // default_text_segment_address
64 * 1024, // abi_pagesize (overridable by -z max-page-size)
8 * 1024, // common_pagesize (overridable by -z common-page-size)
+ false, // isolate_execinstr
+ 0, // rosegment_gap
elfcpp::SHN_UNDEF, // small_common_shndx
elfcpp::SHN_UNDEF, // large_common_shndx
0, // small_common_section_flags
@@ -497,6 +499,8 @@ Target::Target_info Target_sparc<64, true>::sparc_info =
0x100000, // default_text_segment_address
64 * 1024, // abi_pagesize (overridable by -z max-page-size)
8 * 1024, // common_pagesize (overridable by -z common-page-size)
+ false, // isolate_execinstr
+ 0, // rosegment_gap
elfcpp::SHN_UNDEF, // small_common_shndx
elfcpp::SHN_UNDEF, // large_common_shndx
0, // small_common_section_flags
@@ -4346,7 +4350,8 @@ public:
(size == 64 ? "elf64_sparc" : "elf32_sparc"))
{ }
- Target* do_recognize(int machine, int, int)
+ virtual Target*
+ do_recognize(Input_file*, off_t, int machine, int, int)
{
switch (size)
{
@@ -4368,7 +4373,8 @@ public:
return this->instantiate_target();
}
- Target* do_instantiate_target()
+ virtual Target*
+ do_instantiate_target()
{ return new Target_sparc<size, big_endian>(); }
};
diff --git a/gold/target-select.cc b/gold/target-select.cc
index 9370a87..e17cb7d 100644
--- a/gold/target-select.cc
+++ b/gold/target-select.cc
@@ -1,6 +1,7 @@
// target-select.cc -- select a target for an object file
-// Copyright 2006, 2007, 2008, 2009, 2010, 2011 Free Software Foundation, Inc.
+// Copyright 2006, 2007, 2008, 2009, 2010, 2011, 2012
+// Free Software Foundation, Inc.
// Written by Ian Lance Taylor <iant@google.com>.
// This file is part of gold.
@@ -98,8 +99,9 @@ Target_selector::do_target_bfd_name(const Target* target)
// Find the target for an ELF file.
Target*
-select_target(int machine, int size, bool is_big_endian, int osabi,
- int abiversion)
+select_target(Input_file* input_file, off_t offset,
+ int machine, int size, bool is_big_endian,
+ int osabi, int abiversion)
{
for (Target_selector* p = target_selectors; p != NULL; p = p->next())
{
@@ -108,7 +110,8 @@ select_target(int machine, int size, bool
is_big_endian, int osabi,
&& p->get_size() == size
&& (p->is_big_endian() ? is_big_endian : !is_big_endian))
{
- Target* ret = p->recognize(machine, osabi, abiversion);
+ Target* ret = p->recognize(input_file, offset,
+ machine, osabi, abiversion);
if (ret != NULL)
return ret;
}
diff --git a/gold/target-select.h b/gold/target-select.h
index 310c0b9..2e16c2a 100644
--- a/gold/target-select.h
+++ b/gold/target-select.h
@@ -1,6 +1,7 @@
// target-select.h -- select a target for an object file -*- C++ -*-
-// Copyright 2006, 2007, 2008, 2009, 2010, 2011 Free Software Foundation, Inc.
+// Copyright 2006, 2007, 2008, 2009, 2010, 2011, 2012
+// Free Software Foundation, Inc.
// Written by Ian Lance Taylor <iant@google.com>.
// This file is part of gold.
@@ -30,6 +31,7 @@
namespace gold
{
+class Input_file;
class Target;
class Target_selector;
@@ -76,8 +78,9 @@ class Target_selector
// If we can handle this target, return a pointer to a target
// structure. The size and endianness are known.
Target*
- recognize(int machine, int osabi, int abiversion)
- { return this->do_recognize(machine, osabi, abiversion); }
+ recognize(Input_file* input_file, off_t offset,
+ int machine, int osabi, int abiversion)
+ { return this->do_recognize(input_file, offset, machine, osabi,
abiversion); }
// If NAME matches the target, return a pointer to a target
// structure.
@@ -160,7 +163,7 @@ class Target_selector
// checks, or to check for multiple machine codes if the machine_
// field is EM_NONE.
virtual Target*
- do_recognize(int, int, int)
+ do_recognize(Input_file*, off_t, int, int, int)
{ return this->instantiate_target(); }
// Recognize a target by name. When this is called we already know
@@ -241,7 +244,8 @@ class Target_selector
// Select the target for an ELF file.
extern Target*
-select_target(int machine, int size, bool big_endian, int osabi,
+select_target(Input_file*, off_t,
+ int machine, int size, bool big_endian, int osabi,
int abiversion);
// Select a target using a BFD name.
diff --git a/gold/target.h b/gold/target.h
index b174058..81c8114 100644
--- a/gold/target.h
+++ b/gold/target.h
@@ -143,6 +143,16 @@ class Target
this->abi_pagesize());
}
+ // Return whether PF_X segments must contain nothing but the contents of
+ // SHF_EXECINSTR sections (no non-executable data, no headers).
+ bool
+ isolate_execinstr() const
+ { return this->pti_->isolate_execinstr; }
+
+ uint64_t
+ rosegment_gap() const
+ { return this->pti_->rosegment_gap; }
+
// If we see some object files with .note.GNU-stack sections, and
// some objects files without them, this returns whether we should
// consider the object files without them to imply that the stack
@@ -436,6 +446,11 @@ class Target
uint64_t abi_pagesize;
// The common page size used by actual implementations.
uint64_t common_pagesize;
+ // Whether PF_X segments must contain nothing but the contents of
+ // SHF_EXECINSTR sections (no non-executable data, no headers).
+ bool isolate_execinstr;
+ // If nonzero, distance from the text segment to the read-only segment.
+ uint64_t rosegment_gap;
// The special section index for small common symbols; SHN_UNDEF
// if none.
elfcpp::Elf_Half small_common_shndx;
diff --git a/gold/testsuite/testfile.cc b/gold/testsuite/testfile.cc
index 93e716a..e963d4d 100644
--- a/gold/testsuite/testfile.cc
+++ b/gold/testsuite/testfile.cc
@@ -1,6 +1,6 @@
// testfile.cc -- Dummy ELF objects for testing purposes.
-// Copyright 2006, 2007, 2008, 2009, 2011 Free Software Foundation, Inc.
+// Copyright 2006, 2007, 2008, 2009, 2011, 2012 Free Software Foundation, Inc.
// Written by Ian Lance Taylor <iant@google.com>.
// This file is part of gold.
@@ -100,6 +100,8 @@ const Target::Target_info Target_test<size,
big_endian>::test_target_info =
0x08000000, // default_text_segment_address
0x1000, // abi_pagesize
0x1000, // common_pagesize
+ false, // isolate_execinstr
+ 0, // rosegment_gap
elfcpp::SHN_UNDEF, // small_common_shndx
elfcpp::SHN_UNDEF, // large_common_shndx
0, // small_common_section_flags
@@ -154,15 +156,15 @@ class Target_selector_test : public Target_selector
: Target_selector(0xffff, size, big_endian, NULL, NULL)
{ }
- Target*
+ virtual Target*
do_instantiate_target()
{
gold_unreachable();
return NULL;
}
- Target*
- do_recognize(int, int, int)
+ virtual Target*
+ do_recognize(Input_file*, off_t, int, int, int)
{
if (size == 32)
{
@@ -198,11 +200,11 @@ class Target_selector_test : public Target_selector
return NULL;
}
- Target*
+ virtual Target*
do_recognize_by_name(const char*)
{ return NULL; }
- void
+ virtual void
do_supported_names(std::vector<const char*>*)
{ }
};
diff --git a/gold/x86_64.cc b/gold/x86_64.cc
index d67924b..1339e6f 100644
--- a/gold/x86_64.cc
+++ b/gold/x86_64.cc
@@ -40,6 +40,7 @@
#include "target-select.h"
#include "tls.h"
#include "freebsd.h"
+#include "nacl.h"
#include "gc.h"
#include "icf.h"
@@ -49,6 +50,9 @@ namespace
using namespace gold;
// A class to handle the PLT data.
+// This is an abstract base class that handles most of the linker details
+// but does not know the actual contents of PLT entries. The derived
+// classes below fill in those details.
template<int size>
class Output_data_plt_x86_64 : public Output_section_data
@@ -56,20 +60,23 @@ class Output_data_plt_x86_64 : public Output_section_data
public:
typedef Output_data_reloc<elfcpp::SHT_RELA, true, size, false> Reloc_section;
- Output_data_plt_x86_64(Layout* layout, Output_data_got<64, false>* got,
+ Output_data_plt_x86_64(Layout* layout, uint64_t addralign,
+ Output_data_got<64, false>* got,
Output_data_space* got_plt,
Output_data_space* got_irelative)
- : Output_section_data(16), layout_(layout), tlsdesc_rel_(NULL),
+ : Output_section_data(addralign), layout_(layout), tlsdesc_rel_(NULL),
irelative_rel_(NULL), got_(got), got_plt_(got_plt),
got_irelative_(got_irelative), count_(0), irelative_count_(0),
tlsdesc_got_offset_(-1U), free_list_()
{ this->init(layout); }
- Output_data_plt_x86_64(Layout* layout, Output_data_got<64, false>* got,
+ Output_data_plt_x86_64(Layout* layout, uint64_t plt_entry_size,
+ Output_data_got<64, false>* got,
Output_data_space* got_plt,
Output_data_space* got_irelative,
unsigned int plt_count)
- : Output_section_data((plt_count + 1) * plt_entry_size, 16, false),
+ : Output_section_data((plt_count + 1) * plt_entry_size,
+ plt_entry_size, false),
layout_(layout), tlsdesc_rel_(NULL), irelative_rel_(NULL), got_(got),
got_plt_(got_plt), got_irelative_(got_irelative), count_(plt_count),
irelative_count_(0), tlsdesc_got_offset_(-1U), free_list_()
@@ -118,7 +125,10 @@ class Output_data_plt_x86_64 : public Output_section_data
// Return the offset of the reserved TLSDESC_PLT entry.
unsigned int
get_tlsdesc_plt_offset() const
- { return (this->count_ + this->irelative_count_ + 1) * plt_entry_size; }
+ {
+ return ((this->count_ + this->irelative_count_ + 1)
+ * this->get_plt_entry_size());
+ }
// Return the .rela.plt section data.
Reloc_section*
@@ -145,21 +155,21 @@ class Output_data_plt_x86_64 : public Output_section_data
{ return this->count_ + this->irelative_count_; }
// Return the offset of the first non-reserved PLT entry.
- static unsigned int
+ unsigned int
first_plt_entry_offset()
- { return plt_entry_size; }
+ { return this->get_plt_entry_size(); }
// Return the size of a PLT entry.
- static unsigned int
- get_plt_entry_size()
- { return plt_entry_size; }
+ unsigned int
+ get_plt_entry_size() const
+ { return this->do_get_plt_entry_size(); }
// Reserve a slot in the PLT for an existing symbol in an incremental update.
void
reserve_slot(unsigned int plt_index)
{
- this->free_list_.remove((plt_index + 1) * plt_entry_size,
- (plt_index + 2) * plt_entry_size);
+ this->free_list_.remove((plt_index + 1) * this->get_plt_entry_size(),
+ (plt_index + 2) * this->get_plt_entry_size());
}
// Return the PLT address to use for a global symbol.
@@ -170,7 +180,74 @@ class Output_data_plt_x86_64 : public Output_section_data
uint64_t
address_for_local(const Relobj*, unsigned int symndx);
+ // Add .eh_frame information for the PLT.
+ void
+ add_eh_frame(Layout* layout)
+ { this->do_add_eh_frame(layout); }
+
protected:
+ // Fill in the first PLT entry.
+ void
+ fill_first_plt_entry(unsigned char* pov,
+ typename elfcpp::Elf_types<size>::Elf_Addr got_address,
+ typename elfcpp::Elf_types<size>::Elf_Addr plt_address)
+ { this->do_fill_first_plt_entry(pov, got_address, plt_address); }
+
+ // Fill in a normal PLT entry. Returns the offset into the entry that
+ // should be the initial GOT slot value.
+ unsigned int
+ fill_plt_entry(unsigned char* pov,
+ typename elfcpp::Elf_types<size>::Elf_Addr got_address,
+ typename elfcpp::Elf_types<size>::Elf_Addr plt_address,
+ unsigned int got_offset,
+ unsigned int plt_offset,
+ unsigned int plt_index)
+ {
+ return this->do_fill_plt_entry(pov, got_address, plt_address,
+ got_offset, plt_offset, plt_index);
+ }
+
+ // Fill in the reserved TLSDESC PLT entry.
+ void
+ fill_tlsdesc_entry(unsigned char* pov,
+ typename elfcpp::Elf_types<size>::Elf_Addr got_address,
+ typename elfcpp::Elf_types<size>::Elf_Addr plt_address,
+ typename elfcpp::Elf_types<size>::Elf_Addr got_base,
+ unsigned int tlsdesc_got_offset,
+ unsigned int plt_offset)
+ {
+ this->do_fill_tlsdesc_entry(pov, got_address, plt_address, got_base,
+ tlsdesc_got_offset, plt_offset);
+ }
+
+ virtual unsigned int
+ do_get_plt_entry_size() const = 0;
+
+ virtual void
+ do_fill_first_plt_entry(unsigned char* pov,
+ typename elfcpp::Elf_types<size>::Elf_Addr got_addr,
+ typename elfcpp::Elf_types<size>::Elf_Addr plt_addr)
+ = 0;
+
+ virtual unsigned int
+ do_fill_plt_entry(unsigned char* pov,
+ typename elfcpp::Elf_types<size>::Elf_Addr got_address,
+ typename elfcpp::Elf_types<size>::Elf_Addr plt_address,
+ unsigned int got_offset,
+ unsigned int plt_offset,
+ unsigned int plt_index) = 0;
+
+ virtual void
+ do_fill_tlsdesc_entry(unsigned char* pov,
+ typename elfcpp::Elf_types<size>::Elf_Addr got_address,
+ typename elfcpp::Elf_types<size>::Elf_Addr plt_address,
+ typename elfcpp::Elf_types<size>::Elf_Addr got_base,
+ unsigned int tlsdesc_got_offset,
+ unsigned int plt_offset) = 0;
+
+ virtual void
+ do_add_eh_frame(Layout* layout) = 0;
+
void
do_adjust_output_section(Output_section* os);
@@ -179,27 +256,11 @@ class Output_data_plt_x86_64 : public Output_section_data
do_print_to_mapfile(Mapfile* mapfile) const
{ mapfile->print_output_data(this, _("** PLT")); }
- private:
- // The size of an entry in the PLT.
- static const int plt_entry_size = 16;
-
- // The first entry in the PLT.
- // From the AMD64 ABI: "Unlike Intel386 ABI, this ABI uses the same
- // procedure linkage table for both programs and shared objects."
- static const unsigned char first_plt_entry[plt_entry_size];
-
- // Other entries in the PLT for an executable.
- static const unsigned char plt_entry[plt_entry_size];
-
- // The reserved TLSDESC entry in the PLT for an executable.
- static const unsigned char tlsdesc_plt_entry[plt_entry_size];
-
- // The .eh_frame unwind information for the PLT.
+ // The CIE of the .eh_frame unwind information for the PLT.
static const int plt_eh_frame_cie_size = 16;
- static const int plt_eh_frame_fde_size = 32;
static const unsigned char plt_eh_frame_cie[plt_eh_frame_cie_size];
- static const unsigned char plt_eh_frame_fde[plt_eh_frame_fde_size];
+ private:
// Set the final size.
void
set_final_data_size();
@@ -237,6 +298,84 @@ class Output_data_plt_x86_64 : public Output_section_data
Free_list free_list_;
};
+template<int size>
+class Output_data_plt_x86_64_standard : public Output_data_plt_x86_64<size>
+{
+ public:
+ Output_data_plt_x86_64_standard(Layout* layout,
+ Output_data_got<64, false>* got,
+ Output_data_space* got_plt,
+ Output_data_space* got_irelative)
+ : Output_data_plt_x86_64<size>(layout, plt_entry_size,
+ got, got_plt, got_irelative)
+ { }
+
+ Output_data_plt_x86_64_standard(Layout* layout,
+ Output_data_got<64, false>* got,
+ Output_data_space* got_plt,
+ Output_data_space* got_irelative,
+ unsigned int plt_count)
+ : Output_data_plt_x86_64<size>(layout, plt_entry_size,
+ got, got_plt, got_irelative,
+ plt_count)
+ { }
+
+ protected:
+ virtual unsigned int
+ do_get_plt_entry_size() const
+ { return plt_entry_size; }
+
+ virtual void
+ do_add_eh_frame(Layout* layout)
+ {
+ layout->add_eh_frame_for_plt(this,
+ this->plt_eh_frame_cie,
+ this->plt_eh_frame_cie_size,
+ plt_eh_frame_fde,
+ plt_eh_frame_fde_size);
+ }
+
+ virtual void
+ do_fill_first_plt_entry(unsigned char* pov,
+ typename elfcpp::Elf_types<size>::Elf_Addr got_addr,
+ typename elfcpp::Elf_types<size>::Elf_Addr plt_addr);
+
+ virtual unsigned int
+ do_fill_plt_entry(unsigned char* pov,
+ typename elfcpp::Elf_types<size>::Elf_Addr got_address,
+ typename elfcpp::Elf_types<size>::Elf_Addr plt_address,
+ unsigned int got_offset,
+ unsigned int plt_offset,
+ unsigned int plt_index);
+
+ virtual void
+ do_fill_tlsdesc_entry(unsigned char* pov,
+ typename elfcpp::Elf_types<size>::Elf_Addr got_address,
+ typename elfcpp::Elf_types<size>::Elf_Addr plt_address,
+ typename elfcpp::Elf_types<size>::Elf_Addr got_base,
+ unsigned int tlsdesc_got_offset,
+ unsigned int plt_offset);
+
+ private:
+ // The size of an entry in the PLT.
+ static const int plt_entry_size = 16;
+
+ // The first entry in the PLT.
+ // From the AMD64 ABI: "Unlike Intel386 ABI, this ABI uses the same
+ // procedure linkage table for both programs and shared objects."
+ static const unsigned char first_plt_entry[plt_entry_size];
+
+ // Other entries in the PLT for an executable.
+ static const unsigned char plt_entry[plt_entry_size];
+
+ // The reserved TLSDESC entry in the PLT for an executable.
+ static const unsigned char tlsdesc_plt_entry[plt_entry_size];
+
+ // The .eh_frame unwind information for the PLT.
+ static const int plt_eh_frame_fde_size = 32;
+ static const unsigned char plt_eh_frame_fde[plt_eh_frame_fde_size];
+};
+
// The x86_64 target class.
// See the ABI at
// http://www.x86-64.org/documentation/abi.pdf
@@ -252,8 +391,8 @@ class Target_x86_64 : public Sized_target<size, false>
// uses only Elf64_Rela relocation entries with explicit addends."
typedef Output_data_reloc<elfcpp::SHT_RELA, true, size, false> Reloc_section;
- Target_x86_64()
- : Sized_target<size, false>(&x86_64_info),
+ Target_x86_64(const Target::Target_info* info = &x86_64_info)
+ : Sized_target<size, false>(info),
got_(NULL), plt_(NULL), got_plt_(NULL), got_irelative_(NULL),
got_tlsdesc_(NULL), global_offset_table_(NULL), rela_dyn_(NULL),
rela_irelative_(NULL), copy_relocs_(elfcpp::R_X86_64_COPY),
@@ -477,6 +616,48 @@ class Target_x86_64 : public Sized_target<size, false>
return this->tlsdesc_reloc_info_.size() - 1;
}
+ Output_data_plt_x86_64<size>*
+ make_data_plt(Layout* layout,
+ Output_data_got<64, false>* got,
+ Output_data_space* got_plt,
+ Output_data_space* got_irelative)
+ {
+ return this->do_make_data_plt(layout, got, got_plt, got_irelative);
+ }
+
+ Output_data_plt_x86_64<size>*
+ make_data_plt(Layout* layout,
+ Output_data_got<64, false>* got,
+ Output_data_space* got_plt,
+ Output_data_space* got_irelative,
+ unsigned int plt_count)
+ {
+ return this->do_make_data_plt(layout, got, got_plt, got_irelative,
+ plt_count);
+ }
+
+ virtual Output_data_plt_x86_64<size>*
+ do_make_data_plt(Layout* layout,
+ Output_data_got<64, false>* got,
+ Output_data_space* got_plt,
+ Output_data_space* got_irelative)
+ {
+ return new Output_data_plt_x86_64_standard<size>(layout, got, got_plt,
+ got_irelative);
+ }
+
+ virtual Output_data_plt_x86_64<size>*
+ do_make_data_plt(Layout* layout,
+ Output_data_got<64, false>* got,
+ Output_data_space* got_plt,
+ Output_data_space* got_irelative,
+ unsigned int plt_count)
+ {
+ return new Output_data_plt_x86_64_standard<size>(layout, got, got_plt,
+ got_irelative,
+ plt_count);
+ }
+
private:
// The class which scans relocations.
class Scan
@@ -818,6 +999,8 @@ const Target::Target_info Target_x86_64<64>::x86_64_info =
0x400000, // default_text_segment_address
0x1000, // abi_pagesize (overridable by -z max-page-size)
0x1000, // common_pagesize (overridable by -z common-page-size)
+ false, // isolate_execinstr
+ 0, // rosegment_gap
elfcpp::SHN_UNDEF, // small_common_shndx
elfcpp::SHN_X86_64_LCOMMON, // large_common_shndx
0, // small_common_section_flags
@@ -842,6 +1025,8 @@ const Target::Target_info Target_x86_64<32>::x86_64_info =
0x400000, // default_text_segment_address
0x1000, // abi_pagesize (overridable by -z max-page-size)
0x1000, // common_pagesize (overridable by -z common-page-size)
+ false, // isolate_execinstr
+ 0, // rosegment_gap
elfcpp::SHN_UNDEF, // small_common_shndx
elfcpp::SHN_X86_64_LCOMMON, // large_common_shndx
0, // small_common_section_flags
@@ -988,18 +1173,13 @@ Output_data_plt_x86_64<size>::init(Layout* layout)
layout->add_output_section_data(".rela.plt", elfcpp::SHT_RELA,
elfcpp::SHF_ALLOC, this->rel_,
ORDER_DYNAMIC_PLT_RELOCS, false);
-
- // Add unwind information if requested.
- if (parameters->options().ld_generated_unwind_info())
- layout->add_eh_frame_for_plt(this, plt_eh_frame_cie, plt_eh_frame_cie_size,
- plt_eh_frame_fde, plt_eh_frame_fde_size);
}
template<int size>
void
Output_data_plt_x86_64<size>::do_adjust_output_section(Output_section* os)
{
- os->set_entsize(plt_entry_size);
+ os->set_entsize(this->get_plt_entry_size());
}
// Add an entry to the PLT.
@@ -1040,7 +1220,7 @@
Output_data_plt_x86_64<size>::add_entry(Symbol_table* symtab, Layout*
layout,
// Note that when setting the PLT offset for a non-IRELATIVE
// entry we skip the initial reserved PLT entry.
plt_index = *pcount + offset;
- plt_offset = plt_index * plt_entry_size;
+ plt_offset = plt_index * this->get_plt_entry_size();
++*pcount;
@@ -1057,7 +1237,8 @@
Output_data_plt_x86_64<size>::add_entry(Symbol_table* symtab, Layout*
layout,
// FIXME: This is probably not correct for IRELATIVE relocs.
// For incremental updates, find an available slot.
- plt_offset = this->free_list_.allocate(plt_entry_size,
plt_entry_size, 0);
+ plt_offset = this->free_list_.allocate(this->get_plt_entry_size(),
+ this->get_plt_entry_size(), 0);
if (plt_offset == -1)
gold_fallback(_("out of patch space (PLT);"
" relink with --incremental-full"));
@@ -1065,7 +1246,7 @@
Output_data_plt_x86_64<size>::add_entry(Symbol_table* symtab, Layout*
layout,
// The GOT and PLT entries have a 1-1 correspondance, so the GOT offset
// can be calculated from the PLT index, adjusting for the three
// reserved entries at the beginning of the GOT.
- plt_index = plt_offset / plt_entry_size - 1;
+ plt_index = plt_offset / this->get_plt_entry_size() - 1;
got_offset = (plt_index - offset + reserved) * 8;
}
@@ -1090,7 +1271,7 @@ Output_data_plt_x86_64<size>::add_local_ifunc_entry(
Sized_relobj_file<size, false>* relobj,
unsigned int local_sym_index)
{
- unsigned int plt_offset = this->irelative_count_ * plt_entry_size;
+ unsigned int plt_offset = this->irelative_count_ *
this->get_plt_entry_size();
++this->irelative_count_;
section_offset_type got_offset = this->got_irelative_->current_data_size();
@@ -1202,7 +1383,7 @@
Output_data_plt_x86_64<size>::address_for_global(const Symbol* gsym)
uint64_t offset = 0;
if (gsym->type() == elfcpp::STT_GNU_IFUNC
&& gsym->can_use_relative_reloc(false))
- offset = (this->count_ + 1) * plt_entry_size;
+ offset = (this->count_ + 1) * this->get_plt_entry_size();
return this->address() + offset;
}
@@ -1213,7 +1394,7 @@ template<int size>
uint64_t
Output_data_plt_x86_64<size>::address_for_local(const Relobj*, unsigned int)
{
- return this->address() + (this->count_ + 1) * plt_entry_size;
+ return this->address() + (this->count_ + 1) * this->get_plt_entry_size();
}
// Set the final size.
@@ -1224,14 +1405,14 @@ Output_data_plt_x86_64<size>::set_final_data_size()
unsigned int count = this->count_ + this->irelative_count_;
if (this->has_tlsdesc_entry())
++count;
- this->set_data_size((count + 1) * plt_entry_size);
+ this->set_data_size((count + 1) * this->get_plt_entry_size());
}
// The first entry in the PLT for an executable.
template<int size>
const unsigned char
-Output_data_plt_x86_64<size>::first_plt_entry[plt_entry_size] =
+Output_data_plt_x86_64_standard<size>::first_plt_entry[plt_entry_size] =
{
// From AMD64 ABI Draft 0.98, page 76
0xff, 0x35, // pushq contents of memory address
@@ -1241,11 +1422,28 @@
Output_data_plt_x86_64<size>::first_plt_entry[plt_entry_size] =
0x90, 0x90, 0x90, 0x90 // noop (x4)
};
+template<int size>
+void
+Output_data_plt_x86_64_standard<size>::do_fill_first_plt_entry(
+ unsigned char* pov,
+ typename elfcpp::Elf_types<size>::Elf_Addr got_address,
+ typename elfcpp::Elf_types<size>::Elf_Addr plt_address)
+{
+ memcpy(pov, first_plt_entry, plt_entry_size);
+ // We do a jmp relative to the PC at the end of this instruction.
+ elfcpp::Swap_unaligned<32, false>::writeval(pov + 2,
+ (got_address + 8
+ - (plt_address + 6)));
+ elfcpp::Swap<32, false>::writeval(pov + 8,
+ (got_address + 16
+ - (plt_address + 12)));
+}
+
// Subsequent entries in the PLT for an executable.
template<int size>
const unsigned char
-Output_data_plt_x86_64<size>::plt_entry[plt_entry_size] =
+Output_data_plt_x86_64_standard<size>::plt_entry[plt_entry_size] =
{
// From AMD64 ABI Draft 0.98, page 76
0xff, 0x25, // jmpq indirect
@@ -1256,11 +1454,34 @@
Output_data_plt_x86_64<size>::plt_entry[plt_entry_size] =
0, 0, 0, 0 // replaced with offset to start of .plt
};
+template<int size>
+unsigned int
+Output_data_plt_x86_64_standard<size>::do_fill_plt_entry(
+ unsigned char* pov,
+ typename elfcpp::Elf_types<size>::Elf_Addr got_address,
+ typename elfcpp::Elf_types<size>::Elf_Addr plt_address,
+ unsigned int got_offset,
+ unsigned int plt_offset,
+ unsigned int plt_index)
+{
+ memcpy(pov, plt_entry, plt_entry_size);
+ elfcpp::Swap_unaligned<32, false>::writeval(pov + 2,
+ (got_address + got_offset
+ - (plt_address + plt_offset
+ + 6)));
+
+ elfcpp::Swap_unaligned<32, false>::writeval(pov + 7, plt_index);
+ elfcpp::Swap<32, false>::writeval(pov + 12,
+ - (plt_offset + plt_entry_size));
+
+ return 6;
+}
+
// The reserved TLSDESC entry in the PLT for an executable.
template<int size>
const unsigned char
-Output_data_plt_x86_64<size>::tlsdesc_plt_entry[plt_entry_size] =
+Output_data_plt_x86_64_standard<size>::tlsdesc_plt_entry[plt_entry_size] =
{
// From Alexandre Oliva, "Thread-Local Storage Descriptors for IA32
// and AMD64/EM64T", Version 0.9.4 (2005-10-10).
@@ -1272,6 +1493,28 @@
Output_data_plt_x86_64<size>::tlsdesc_plt_entry[plt_entry_size] =
0x40, 0
};
+template<int size>
+void
+Output_data_plt_x86_64_standard<size>::do_fill_tlsdesc_entry(
+ unsigned char* pov,
+ typename elfcpp::Elf_types<size>::Elf_Addr got_address,
+ typename elfcpp::Elf_types<size>::Elf_Addr plt_address,
+ typename elfcpp::Elf_types<size>::Elf_Addr got_base,
+ unsigned int tlsdesc_got_offset,
+ unsigned int plt_offset)
+{
+ memcpy(pov, tlsdesc_plt_entry, plt_entry_size);
+ elfcpp::Swap_unaligned<32, false>::writeval(pov + 2,
+ (got_address + 8
+ - (plt_address + plt_offset
+ + 6)));
+ elfcpp::Swap_unaligned<32, false>::writeval(pov + 8,
+ (got_base
+ + tlsdesc_got_offset
+ - (plt_address + plt_offset
+ + 12)));
+}
+
// The .eh_frame unwind information for the PLT.
template<int size>
@@ -1296,7 +1539,7 @@
Output_data_plt_x86_64<size>::plt_eh_frame_cie[plt_eh_frame_cie_size]
=
template<int size>
const unsigned char
-Output_data_plt_x86_64<size>::plt_eh_frame_fde[plt_eh_frame_fde_size] =
+Output_data_plt_x86_64_standard<size>::plt_eh_frame_fde[plt_eh_frame_fde_size]
=
{
0, 0, 0, 0, // Replaced with offset to .plt.
0, 0, 0, 0, // Replaced with size of .plt.
@@ -1356,15 +1599,8 @@ Output_data_plt_x86_64<size>::do_write(Output_file* of)
typename elfcpp::Elf_types<size>::Elf_Addr got_address
= this->got_plt_->address();
- memcpy(pov, first_plt_entry, plt_entry_size);
- // We do a jmp relative to the PC at the end of this instruction.
- elfcpp::Swap_unaligned<32, false>::writeval(pov + 2,
- (got_address + 8
- - (plt_address + 6)));
- elfcpp::Swap<32, false>::writeval(pov + 8,
- (got_address + 16
- - (plt_address + 12)));
- pov += plt_entry_size;
+ this->fill_first_plt_entry(pov, got_address, plt_address);
+ pov += this->get_plt_entry_size();
unsigned char* got_pov = got_view;
@@ -1379,47 +1615,35 @@ Output_data_plt_x86_64<size>::do_write(Output_file* of)
memset(got_pov, 0, 16);
got_pov += 16;
- unsigned int plt_offset = plt_entry_size;
+ unsigned int plt_offset = this->get_plt_entry_size();
unsigned int got_offset = 24;
const unsigned int count = this->count_ + this->irelative_count_;
for (unsigned int plt_index = 0;
plt_index < count;
++plt_index,
- pov += plt_entry_size,
+ pov += this->get_plt_entry_size(),
got_pov += 8,
- plt_offset += plt_entry_size,
+ plt_offset += this->get_plt_entry_size(),
got_offset += 8)
{
// Set and adjust the PLT entry itself.
- memcpy(pov, plt_entry, plt_entry_size);
- elfcpp::Swap_unaligned<32, false>::writeval(pov + 2,
- (got_address + got_offset
- - (plt_address + plt_offset
- + 6)));
-
- elfcpp::Swap_unaligned<32, false>::writeval(pov + 7, plt_index);
- elfcpp::Swap<32, false>::writeval(pov + 12,
- - (plt_offset + plt_entry_size));
+ unsigned int lazy_offset = this->fill_plt_entry(pov,
+ got_address, plt_address,
+ got_offset, plt_offset,
+ plt_index);
// Set the entry in the GOT.
- elfcpp::Swap<64, false>::writeval(got_pov, plt_address + plt_offset + 6);
+ elfcpp::Swap<64, false>::writeval(got_pov,
+ plt_address + plt_offset + lazy_offset);
}
if (this->has_tlsdesc_entry())
{
// Set and adjust the reserved TLSDESC PLT entry.
unsigned int tlsdesc_got_offset = this->get_tlsdesc_got_offset();
- memcpy(pov, tlsdesc_plt_entry, plt_entry_size);
- elfcpp::Swap_unaligned<32, false>::writeval(pov + 2,
- (got_address + 8
- - (plt_address + plt_offset
- + 6)));
- elfcpp::Swap_unaligned<32, false>::writeval(pov + 8,
- (got_base
- + tlsdesc_got_offset
- - (plt_address + plt_offset
- + 12)));
- pov += plt_entry_size;
+ this->fill_tlsdesc_entry(pov, got_address, plt_address, got_base,
+ tlsdesc_got_offset, plt_offset);
+ pov += this->get_plt_entry_size();
}
gold_assert(static_cast<section_size_type>(pov - oview) == oview_size);
@@ -1440,9 +1664,13 @@
Target_x86_64<size>::make_plt_section(Symbol_table* symtab, Layout*
layout)
// Create the GOT sections first.
this->got_section(symtab, layout);
- this->plt_ = new Output_data_plt_x86_64<size>(layout, this->got_,
- this->got_plt_,
+ this->plt_ = this->make_data_plt(layout, this->got_, this->got_plt_,
this->got_irelative_);
+
+ // Add unwind information if requested.
+ if (parameters->options().ld_generated_unwind_info())
+ this->plt_->add_eh_frame(layout);
+
layout->add_output_section_data(".plt", elfcpp::SHT_PROGBITS,
(elfcpp::SHF_ALLOC
| elfcpp::SHF_EXECINSTR),
@@ -1515,7 +1743,7 @@ template<int size>
unsigned int
Target_x86_64<size>::first_plt_entry_offset() const
{
- return Output_data_plt_x86_64<size>::first_plt_entry_offset();
+ return this->plt_->first_plt_entry_offset();
}
// Return the size of each PLT entry.
@@ -1524,7 +1752,7 @@ template<int size>
unsigned int
Target_x86_64<size>::plt_entry_size() const
{
- return Output_data_plt_x86_64<size>::get_plt_entry_size();
+ return this->plt_->get_plt_entry_size();
}
// Create the GOT and PLT sections for an incremental update.
@@ -1581,10 +1809,15 @@
Target_x86_64<size>::init_got_plt_for_update(Symbol_table* symtab,
ORDER_NON_RELRO_FIRST, false);
// Create the PLT section.
- this->plt_ = new Output_data_plt_x86_64<size>(layout, this->got_,
+ this->plt_ = this->make_data_plt(layout, this->got_,
this->got_plt_,
this->got_irelative_,
plt_count);
+
+ // Add unwind information if requested.
+ if (parameters->options().ld_generated_unwind_info())
+ this->plt_->add_eh_frame(layout);
+
layout->add_output_section_data(".plt", elfcpp::SHT_PROGBITS,
elfcpp::SHF_ALLOC | elfcpp::SHF_EXECINSTR,
this->plt_, ORDER_PLT, false);
@@ -4187,7 +4420,8 @@ Target_x86_64<size>::do_calls_non_split(Relobj*
object, unsigned int shndx,
*to = "__morestack_non_split";
}
-// The selector for x86_64 object files.
+// The selector for x86_64 object files. Note this is never instantiated
+// directly. It's only used in Target_selector_x86_64_nacl, below.
template<int size>
class Target_selector_x86_64 : public Target_selector_freebsd
@@ -4209,7 +4443,359 @@ public:
};
-Target_selector_x86_64<64> target_selector_x86_64;
-Target_selector_x86_64<32> target_selector_x32;
+// NaCl variant. It uses different PLT contents.
+
+template<int size>
+class Output_data_plt_x86_64_nacl : public Output_data_plt_x86_64<size>
+{
+ public:
+ Output_data_plt_x86_64_nacl(Layout* layout,
+ Output_data_got<64, false>* got,
+ Output_data_space* got_plt,
+ Output_data_space* got_irelative)
+ : Output_data_plt_x86_64<size>(layout, plt_entry_size,
+ got, got_plt, got_irelative)
+ { }
+
+ Output_data_plt_x86_64_nacl(Layout* layout,
+ Output_data_got<64, false>* got,
+ Output_data_space* got_plt,
+ Output_data_space* got_irelative,
+ unsigned int plt_count)
+ : Output_data_plt_x86_64<size>(layout, plt_entry_size,
+ got, got_plt, got_irelative,
+ plt_count)
+ { }
+
+ protected:
+ virtual unsigned int
+ do_get_plt_entry_size() const
+ { return plt_entry_size; }
+
+ virtual void
+ do_add_eh_frame(Layout* layout)
+ {
+ layout->add_eh_frame_for_plt(this,
+ this->plt_eh_frame_cie,
+ this->plt_eh_frame_cie_size,
+ plt_eh_frame_fde,
+ plt_eh_frame_fde_size);
+ }
+
+ virtual void
+ do_fill_first_plt_entry(unsigned char* pov,
+ typename elfcpp::Elf_types<size>::Elf_Addr got_addr,
+ typename elfcpp::Elf_types<size>::Elf_Addr plt_addr);
+
+ virtual unsigned int
+ do_fill_plt_entry(unsigned char* pov,
+ typename elfcpp::Elf_types<size>::Elf_Addr got_address,
+ typename elfcpp::Elf_types<size>::Elf_Addr plt_address,
+ unsigned int got_offset,
+ unsigned int plt_offset,
+ unsigned int plt_index);
+
+ virtual void
+ do_fill_tlsdesc_entry(unsigned char* pov,
+ typename elfcpp::Elf_types<size>::Elf_Addr got_address,
+ typename elfcpp::Elf_types<size>::Elf_Addr plt_address,
+ typename elfcpp::Elf_types<size>::Elf_Addr got_base,
+ unsigned int tlsdesc_got_offset,
+ unsigned int plt_offset);
+
+ private:
+ // The size of an entry in the PLT.
+ static const int plt_entry_size = 64;
+
+ // The first entry in the PLT.
+ static const unsigned char first_plt_entry[plt_entry_size];
+
+ // Other entries in the PLT for an executable.
+ static const unsigned char plt_entry[plt_entry_size];
+
+ // The reserved TLSDESC entry in the PLT for an executable.
+ static const unsigned char tlsdesc_plt_entry[plt_entry_size];
+
+ // The .eh_frame unwind information for the PLT.
+ static const int plt_eh_frame_fde_size = 32;
+ static const unsigned char plt_eh_frame_fde[plt_eh_frame_fde_size];
+};
+
+template<int size>
+class Target_x86_64_nacl : public Target_x86_64<size>
+{
+ public:
+ Target_x86_64_nacl()
+ : Target_x86_64<size>(&x86_64_nacl_info)
+ { }
+
+ virtual Output_data_plt_x86_64<size>*
+ do_make_data_plt(Layout* layout,
+ Output_data_got<64, false>* got,
+ Output_data_space* got_plt,
+ Output_data_space* got_irelative)
+ {
+ return new Output_data_plt_x86_64_nacl<size>(layout, got, got_plt,
+ got_irelative);
+ }
+
+ virtual Output_data_plt_x86_64<size>*
+ do_make_data_plt(Layout* layout,
+ Output_data_got<64, false>* got,
+ Output_data_space* got_plt,
+ Output_data_space* got_irelative,
+ unsigned int plt_count)
+ {
+ return new Output_data_plt_x86_64_nacl<size>(layout, got, got_plt,
+ got_irelative,
+ plt_count);
+ }
+
+ private:
+ static const Target::Target_info x86_64_nacl_info;
+};
+
+template<>
+const Target::Target_info Target_x86_64_nacl<64>::x86_64_nacl_info =
+{
+ 64, // size
+ false, // is_big_endian
+ elfcpp::EM_X86_64, // machine_code
+ false, // has_make_symbol
+ false, // has_resolve
+ true, // has_code_fill
+ true, // is_default_stack_executable
+ true, // can_icf_inline_merge_sections
+ '\0', // wrap_char
+ "/lib64/ld-nacl-x86-64.so.1", // dynamic_linker
+ 0x20000, // default_text_segment_address
+ 0x10000, // abi_pagesize (overridable by -z max-page-size)
+ 0x10000, // common_pagesize (overridable by -z common-page-size)
+ true, // isolate_execinstr
+ 0x10000000, // rosegment_gap
+ elfcpp::SHN_UNDEF, // small_common_shndx
+ elfcpp::SHN_X86_64_LCOMMON, // large_common_shndx
+ 0, // small_common_section_flags
+ elfcpp::SHF_X86_64_LARGE, // large_common_section_flags
+ NULL, // attributes_section
+ NULL // attributes_vendor
+};
+
+template<>
+const Target::Target_info Target_x86_64_nacl<32>::x86_64_nacl_info =
+{
+ 32, // size
+ false, // is_big_endian
+ elfcpp::EM_X86_64, // machine_code
+ false, // has_make_symbol
+ false, // has_resolve
+ true, // has_code_fill
+ true, // is_default_stack_executable
+ true, // can_icf_inline_merge_sections
+ '\0', // wrap_char
+ "/lib/ld-nacl-x86-64.so.1", // dynamic_linker
+ 0x20000, // default_text_segment_address
+ 0x10000, // abi_pagesize (overridable by -z max-page-size)
+ 0x10000, // common_pagesize (overridable by -z common-page-size)
+ true, // isolate_execinstr
+ 0x10000000, // rosegment_gap
+ elfcpp::SHN_UNDEF, // small_common_shndx
+ elfcpp::SHN_X86_64_LCOMMON, // large_common_shndx
+ 0, // small_common_section_flags
+ elfcpp::SHF_X86_64_LARGE, // large_common_section_flags
+ NULL, // attributes_section
+ NULL // attributes_vendor
+};
+
+#define NACLMASK 0xe0 // 32-byte alignment mask.
+
+// The first entry in the PLT.
+
+template<int size>
+const unsigned char
+Output_data_plt_x86_64_nacl<size>::first_plt_entry[plt_entry_size] =
+{
+ 0xff, 0x35, // pushq contents of memory address
+ 0, 0, 0, 0, // replaced with address of .got + 8
+ 0x4c, 0x8b, 0x1d, // mov GOT+16(%rip), %r11
+ 0, 0, 0, 0, // replaced with address of .got + 16
+ 0x41, 0x83, 0xe3, NACLMASK, // and $-32, %r11d
+ 0x4d, 0x01, 0xfb, // add %r15, %r11
+ 0x41, 0xff, 0xe3, // jmpq *%r11
+
+ // 9-byte nop sequence to pad out to the next 32-byte boundary.
+ 0x2e, 0x0f, 0x1f, 0x84, 0, 0, 0, 0, 0, // nopl %cs:0x0(%rax,%rax,1)
+
+ // 32 bytes of nop to pad out to the standard size
+ 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, // excess data32 prefixes
+ 0x2e, 0x0f, 0x1f, 0x84, 0, 0, 0, 0, 0, // nopw %cs:0x0(%rax,%rax,1)
+ 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, // excess data32 prefixes
+ 0x2e, 0x0f, 0x1f, 0x84, 0, 0, 0, 0, 0, // nopw %cs:0x0(%rax,%rax,1)
+ 0x66, // excess data32 prefix
+ 0x90 // nop
+};
+
+template<int size>
+void
+Output_data_plt_x86_64_nacl<size>::do_fill_first_plt_entry(
+ unsigned char* pov,
+ typename elfcpp::Elf_types<size>::Elf_Addr got_address,
+ typename elfcpp::Elf_types<size>::Elf_Addr plt_address)
+{
+ memcpy(pov, first_plt_entry, plt_entry_size);
+ elfcpp::Swap_unaligned<32, false>::writeval(pov + 2,
+ (got_address + 8
+ - (plt_address + 2 + 4)));
+ elfcpp::Swap_unaligned<32, false>::writeval(pov + 9,
+ (got_address + 16
+ - (plt_address + 9 + 4)));
+}
+
+// Subsequent entries in the PLT.
+
+template<int size>
+const unsigned char
+Output_data_plt_x86_64_nacl<size>::plt_entry[plt_entry_size] =
+{
+ 0x4c, 0x8b, 0x1d, // mov name@GOTPCREL(%rip),%r11
+ 0, 0, 0, 0, // replaced with address of symbol in .got
+ 0x41, 0x83, 0xe3, NACLMASK, // and $-32, %r11d
+ 0x4d, 0x01, 0xfb, // add %r15, %r11
+ 0x41, 0xff, 0xe3, // jmpq *%r11
+
+ // 15-byte nop sequence to pad out to the next 32-byte boundary.
+ 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, // excess data32 prefixes
+ 0x2e, 0x0f, 0x1f, 0x84, 0, 0, 0, 0, 0, // nopw %cs:0x0(%rax,%rax,1)
+
+ // Lazy GOT entries point here (32-byte aligned).
+ 0x68, // pushq immediate
+ 0, 0, 0, 0, // replaced with index into relocation table
+ 0xe9, // jmp relative
+ 0, 0, 0, 0, // replaced with offset to start of .plt0
+
+ // 22 bytes of nop to pad out to the standard size.
+ 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, // excess data32 prefixes
+ 0x2e, 0x0f, 0x1f, 0x84, 0, 0, 0, 0, 0, // nopw %cs:0x0(%rax,%rax,1)
+ 0x0f, 0x1f, 0x80, 0, 0, 0, 0, // nopl 0x0(%rax)
+};
+
+template<int size>
+unsigned int
+Output_data_plt_x86_64_nacl<size>::do_fill_plt_entry(
+ unsigned char* pov,
+ typename elfcpp::Elf_types<size>::Elf_Addr got_address,
+ typename elfcpp::Elf_types<size>::Elf_Addr plt_address,
+ unsigned int got_offset,
+ unsigned int plt_offset,
+ unsigned int plt_index)
+{
+ memcpy(pov, plt_entry, plt_entry_size);
+ elfcpp::Swap_unaligned<32, false>::writeval(pov + 3,
+ (got_address + got_offset
+ - (plt_address + plt_offset
+ + 3 + 4)));
+
+ elfcpp::Swap_unaligned<32, false>::writeval(pov + 33, plt_index);
+ elfcpp::Swap_unaligned<32, false>::writeval(pov + 38,
+ - (plt_offset + 38 + 4));
+
+ return 32;
+}
+
+// The reserved TLSDESC entry in the PLT.
+
+template<int size>
+const unsigned char
+Output_data_plt_x86_64_nacl<size>::tlsdesc_plt_entry[plt_entry_size] =
+{
+ 0xff, 0x35, // pushq x(%rip)
+ 0, 0, 0, 0, // replaced with address of linkmap GOT entry (at PLTGOT + 8)
+ 0x4c, 0x8b, 0x1d, // mov y(%rip),%r11
+ 0, 0, 0, 0, // replaced with offset of reserved TLSDESC_GOT entry
+ 0x41, 0x83, 0xe3, NACLMASK, // and $-32, %r11d
+ 0x4d, 0x01, 0xfb, // add %r15, %r11
+ 0x41, 0xff, 0xe3, // jmpq *%r11
+
+ // 41 bytes of nop to pad out to the standard size.
+ 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, // excess data32 prefixes
+ 0x2e, 0x0f, 0x1f, 0x84, 0, 0, 0, 0, 0, // nopw %cs:0x0(%rax,%rax,1)
+ 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, // excess data32 prefixes
+ 0x2e, 0x0f, 0x1f, 0x84, 0, 0, 0, 0, 0, // nopw %cs:0x0(%rax,%rax,1)
+ 0x66, 0x66, // excess data32 prefixes
+ 0x2e, 0x0f, 0x1f, 0x84, 0, 0, 0, 0, 0, // nopw %cs:0x0(%rax,%rax,1)
+};
+
+template<int size>
+void
+Output_data_plt_x86_64_nacl<size>::do_fill_tlsdesc_entry(
+ unsigned char* pov,
+ typename elfcpp::Elf_types<size>::Elf_Addr got_address,
+ typename elfcpp::Elf_types<size>::Elf_Addr plt_address,
+ typename elfcpp::Elf_types<size>::Elf_Addr got_base,
+ unsigned int tlsdesc_got_offset,
+ unsigned int plt_offset)
+{
+ memcpy(pov, tlsdesc_plt_entry, plt_entry_size);
+ elfcpp::Swap_unaligned<32, false>::writeval(pov + 2,
+ (got_address + 8
+ - (plt_address + plt_offset
+ + 2 + 4)));
+ elfcpp::Swap_unaligned<32, false>::writeval(pov + 9,
+ (got_base
+ + tlsdesc_got_offset
+ - (plt_address + plt_offset
+ + 9 + 4)));
+}
+
+// The .eh_frame unwind information for the PLT.
+
+template<int size>
+const unsigned char
+Output_data_plt_x86_64_nacl<size>::plt_eh_frame_fde[plt_eh_frame_fde_size] =
+{
+ 0, 0, 0, 0, // Replaced with offset to .plt.
+ 0, 0, 0, 0, // Replaced with size of .plt.
+ 0, // Augmentation size.
+ elfcpp::DW_CFA_def_cfa_offset, 16, // DW_CFA_def_cfa_offset: 16.
+ elfcpp::DW_CFA_advance_loc + 6, // Advance 6 to __PLT__ + 6.
+ elfcpp::DW_CFA_def_cfa_offset, 24, // DW_CFA_def_cfa_offset: 24.
+ elfcpp::DW_CFA_advance_loc + 58, // Advance 58 to __PLT__ + 64.
+ elfcpp::DW_CFA_def_cfa_expression, // DW_CFA_def_cfa_expression.
+ 13, // Block length.
+ elfcpp::DW_OP_breg7, 8, // Push %rsp + 8.
+ elfcpp::DW_OP_breg16, 0, // Push %rip.
+ elfcpp::DW_OP_const1u, 63, // Push 0x3f.
+ elfcpp::DW_OP_and, // & (%rip & 0x3f).
+ elfcpp::DW_OP_const1u, 37, // Push 0x25.
+ elfcpp::DW_OP_ge, // >= ((%rip & 0x3f) >= 0x25)
+ elfcpp::DW_OP_lit3, // Push 3.
+ elfcpp::DW_OP_shl, // << (((%rip & 0x3f) >= 0x25) << 3)
+ elfcpp::DW_OP_plus, // + ((((%rip&0x3f)>=0x25)<<3)+%rsp+8
+ elfcpp::DW_CFA_nop, // Align to 32 bytes.
+ elfcpp::DW_CFA_nop
+};
+
+// The selector for x86_64-nacl object files.
+
+template<int size>
+class Target_selector_x86_64_nacl
+ : public Target_selector_nacl<Target_selector_x86_64<size>,
+ Target_x86_64_nacl<size> >
+{
+ public:
+ Target_selector_x86_64_nacl()
+ : Target_selector_nacl<Target_selector_x86_64<size>,
+ Target_x86_64_nacl<size> >("x86-64",
+ size == 64
+ ? "elf64-x86-64-nacl"
+ : "elf32-x86-64-nacl",
+ size == 64
+ ? "elf_x86_64_nacl"
+ : "elf32_x86_64_nacl")
+ { }
+};
+
+Target_selector_x86_64_nacl<64> target_selector_x86_64;
+Target_selector_x86_64_nacl<32> target_selector_x32;
} // End anonymous namespace.