[PATCH] gold: Native Client target support

Roland McGrath mcgrathr@google.com
Wed May 2 21:38:00 GMT 2012


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*>(&parameters->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(&parameters->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.



More information about the Binutils mailing list