This is the mail archive of the binutils@sourceware.org mailing list for the binutils project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

gold patch committed: Support for -fsplit-stack


Over in gcc land, I've been working on implementing -fsplit-stack, in
which gcc permits a discontiguous stack.  That works requires linker
support for the case where a function compiled with -fsplit-stack
calls a function compiled without -fsplit-stack.  In that case, we
need to allocate a larger contiguous stack, so that the
non-split-stack function can work.

Code compiled with -fsplit-stack will have a magic section named
.note.GNU-split-stack.  I don't particularly want to continue using
magic sections, and originally I planned to use a note.
Unfortunately, notes will be accumulated by the GNU linker, and that
is undesirable here.  Using a magic section type would be preferable,
but unfortunately gas has no general mechanism for setting the section
type, so that would require a modified gas.  Using a magic section
name is consistent with the existing use of .note.GNU-stack.
Suggestions welcome.

There is another magic section name, .note.GNU-no-split-stack, which
is used in addition to .note.GNU-split-stack when code compiled with
-fsplit-stack includes functions with the "no_split_stack" attribute.
I originally tried using a section flag on .note.GNU-split-stack, but
then gas complained.  This additional information exists so that the
linker does not complain about being unable to adjust the function.

Anyhow, this patch changes the linker so that it when it sees a
function compiled with -fsplit-stack which calls a function compiled
without -fsplit-stack, it looks for the code emitted by gcc and frobs
it to allocate a larger stack.  Specifically this is done by 1)
changing the test so that the function proglogue requires more
contiguous stack space; and 2) changing the call to __morestack
inserted by gcc to call __morestack_non_split instead.

Because I can't assume the presence of a gcc which defines
-fsplit-stack, I've included a more comprehensive set of tests than
usual.

This patch only adds support for i386 and x86_64.  This requires some
additional work on the split branch in gcc, e.g., the definition of
__morestack_non_split, which I will commit presently.

I have committed this patch to binutils mainline.

Ian


2009-10-06  Ian Lance Taylor  <iant@google.com>

	* options.h (class General_options): Define
	split_stack_adjust_size parameter.
	* object.h (class Object): Add uses_split_stack_ and
	has_no_split_stack_ fields.  Add uses_split_stack and
	has_no_split_stack accessor functions.  Declare
	handle_split_stack_section.
	(class Reloc_symbol_changes): Define.
	(class Sized_relobj): Define Function_offsets.  Declare
	split_stack_adjust, split_stack_adjust_reltype, and
	find_functions.
	* object.cc (Object::handle_split_stack_section): New function.
	(Sized_relobj::do_layout): Call handle_split_stack_section.
	* dynobj.cc (Sized_dynobj::do_layout): Call
	handle_split_stack_section.
	* reloc.cc (Sized_relobj::relocate_sections): Call
	split_stack_adjust for executable sections in split_stack
	objects.  Pass reloc_map to relocate_section.
	(Sized_relobj::split_stack_adjust): New function.
	(Sized_relobj::split_stack_adjust_reltype): New function.
	(Sized_relobj::find_functions): New function.
	* target-reloc.h: Include "object.h".
	(relocate_section): Add reloc_symbol_changes parameter.  Change
	all callers.
	* target.h (class Target): Add calls_non_split method.  Declare
	do_calls_non_split virtual method.  Declare match_view and
	set_view_to_nop.
	* target.cc: Include "elfcpp.h".
	(Target::do_calls_non_split): New function.
	(Target::match_view): New function.
	(Target::set_view_to_nop): New function.
	* gold.cc (queue_middle_tasks): Give an error if mixing
	split-stack and non-split-stack objects with -r.
	* i386.cc (Target_i386::relocate_section): Add
	reloc_symbol_changes parameter.
	(Target_i386::do_calls_non_split): New function.
	* x86_64.cc (Target_x86_64::relocate_section): Add
	reloc_symbol_changes parameter.
	(Target_x86_64::do_calls_non_split): New function.
	* arm.cc (Target_arm::relocate_section): Add reloc_symbol_changes
	parameter.
	* powerpc.cc (Target_powerpc::relocate_section): Add
	reloc_symbol_changes parameter.
	* sparc.cc (Target_sparc::relocate_section): Add
	reloc_symbol_changes parameter.
	* configure.ac: Call AM_CONDITIONAL for the default target.
	* configure: Rebuild.
	* testsuite/Makefile.am (TEST_AS): New variable.
	(check_SCRIPTS): Add split_i386.sh and split_x86_64.sh.
	(check_DATA): Add split_i386 and split_x86_64 files.
	(SPLIT_DEFSYMS): Define.
	(split_i386_[1234n].o): New targets.
	(split_i386_[124]): New targets.
	(split_i386_[1234r].stdout): New targets.
	(split_x86_64_[1234n].o): New targets.
	(split_x86_64_[124]): New targets.
	(split_x86_64_[1234r].stdout): New targets.
	(MOSTLYCLEANFILES): Add new executables.
	* testsuite/split_i386.sh: New file.
	* testsuite/split_x86_64.sh: New file.
	* testsuite/split_i386_1.s: New file.
	* testsuite/split_i386_2.s: New file.
	* testsuite/split_i386_3.s: New file.
	* testsuite/split_i386_4.s: New file.
	* testsuite/split_i386_n.s: New file.
	* testsuite/split_x86_64_1.s: New file.
	* testsuite/split_x86_64_2.s: New file.
	* testsuite/split_x86_64_3.s: New file.
	* testsuite/split_x86_64_4.s: New file.
	* testsuite/split_x86_64_n.s: New file.
	* testsuite/testfile.cc (Target_test): Update relocation_section
	function.
	* testsuite/Makefile.in: Rebuild.


Index: arm.cc
===================================================================
RCS file: /cvs/src/src/gold/arm.cc,v
retrieving revision 1.10
diff -u -u -p -r1.10 arm.cc
--- arm.cc	1 Oct 2009 00:58:38 -0000	1.10
+++ arm.cc	6 Oct 2009 22:30:56 -0000
@@ -205,7 +205,8 @@ class Target_arm : public Sized_target<3
 		   bool needs_special_offset_handling,
 		   unsigned char* view,
 		   elfcpp::Elf_types<32>::Elf_Addr view_address,
-		   section_size_type view_size);
+		   section_size_type view_size,
+		   const Reloc_symbol_changes*);
 
   // Scan the relocs during a relocatable link.
   void
@@ -1792,7 +1793,8 @@ Target_arm<big_endian>::relocate_section
     bool needs_special_offset_handling,
     unsigned char* view,
     elfcpp::Elf_types<32>::Elf_Addr address,
-    section_size_type view_size)
+    section_size_type view_size,
+    const Reloc_symbol_changes* reloc_symbol_changes)
 {
   typedef typename Target_arm<big_endian>::Relocate Arm_relocate;
   gold_assert(sh_type == elfcpp::SHT_REL);
@@ -1807,7 +1809,8 @@ Target_arm<big_endian>::relocate_section
     needs_special_offset_handling,
     view,
     address,
-    view_size);
+    view_size,
+    reloc_symbol_changes);
 }
 
 // Return the size of a relocation while scanning during a relocatable
Index: configure.ac
===================================================================
RCS file: /cvs/src/src/gold/configure.ac,v
retrieving revision 1.46
diff -u -u -p -r1.46 configure.ac
--- configure.ac	23 Jun 2009 18:10:41 -0000	1.46
+++ configure.ac	6 Oct 2009 22:30:56 -0000
@@ -151,6 +151,12 @@ for targ in $target $canon_targets; do
 	default_size=$targ_size
 	default_big_endian=$targ_big_endian
 	default_osabi=$targ_osabi
+
+	AM_CONDITIONAL(DEFAULT_TARGET_ARM, test "$targ_obj" = "arm")
+	AM_CONDITIONAL(DEFAULT_TARGET_I386, test "$targ_obj" = "i386")
+	AM_CONDITIONAL(DEFAULT_TARGET_POWERPC, test "$targ_obj" = "powerpc")
+	AM_CONDITIONAL(DEFAULT_TARGET_SPARC, test "$targ_obj" = "sparc")
+	AM_CONDITIONAL(DEFAULT_TARGET_X86_64, test "$targ_obj" = "x86_64")
       fi
     fi
   fi
Index: dynobj.cc
===================================================================
RCS file: /cvs/src/src/gold/dynobj.cc,v
retrieving revision 1.45
diff -u -u -p -r1.45 dynobj.cc
--- dynobj.cc	30 Sep 2009 22:21:13 -0000	1.45
+++ dynobj.cc	6 Oct 2009 22:30:56 -0000
@@ -408,7 +408,7 @@ Sized_dynobj<size, big_endian>::do_initi
 
 // Lay out the input sections for a dynamic object.  We don't want to
 // include sections from a dynamic object, so all that we actually do
-// here is check for .gnu.warning sections.
+// here is check for .gnu.warning and .note.GNU-split-stack sections.
 
 template<int size, bool big_endian>
 void
@@ -443,6 +443,7 @@ Sized_dynobj<size, big_endian>::do_layou
       const char* name = pnames + shdr.get_sh_name();
 
       this->handle_gnu_warning_section(name, i, symtab);
+      this->handle_split_stack_section(name);
     }
 
   delete sd->section_headers;
Index: gold.cc
===================================================================
RCS file: /cvs/src/src/gold/gold.cc,v
retrieving revision 1.68
diff -u -u -p -r1.68 gold.cc
--- gold.cc	30 Sep 2009 22:21:13 -0000	1.68
+++ gold.cc	6 Oct 2009 22:30:56 -0000
@@ -408,6 +408,23 @@ queue_middle_tasks(const General_options
     gold_fatal(_("cannot use non-ELF output format with dynamic object %s"),
 	       (*input_objects->dynobj_begin())->name().c_str());
 
+  if (parameters->options().relocatable())
+    {
+      Input_objects::Relobj_iterator p = input_objects->relobj_begin();
+      if (p != input_objects->relobj_end())
+	{
+	  bool uses_split_stack = (*p)->uses_split_stack();
+	  for (++p; p != input_objects->relobj_end(); ++p)
+	    {
+	      if ((*p)->uses_split_stack() != uses_split_stack)
+		gold_fatal(_("cannot mix split-stack '%s' and "
+			     "non-split-stack '%s' when using -r"),
+			   (*input_objects->relobj_begin())->name().c_str(),
+			   (*p)->name().c_str());
+	    }
+	}
+    }
+
   if (is_debugging_enabled(DEBUG_SCRIPT))
     layout->script_options()->print(stderr);
 
Index: i386.cc
===================================================================
RCS file: /cvs/src/src/gold/i386.cc,v
retrieving revision 1.91
diff -u -u -p -r1.91 i386.cc
--- i386.cc	6 Oct 2009 21:44:11 -0000	1.91
+++ i386.cc	6 Oct 2009 22:30:56 -0000
@@ -113,7 +113,8 @@ class Target_i386 : public Target_freebs
 		   bool needs_special_offset_handling,
 		   unsigned char* view,
 		   elfcpp::Elf_types<32>::Elf_Addr view_address,
-		   section_size_type view_size);
+		   section_size_type view_size,
+		   const Reloc_symbol_changes*);
 
   // Scan the relocs during a relocatable link.
   void
@@ -168,6 +169,13 @@ class Target_i386 : public Target_freebs
     return Target::do_is_local_label_name(name);
   }
 
+  // Adjust -fstack-split code which calls non-stack-split code.
+  void
+  do_calls_non_split(Relobj* object, unsigned int shndx,
+		     section_offset_type fnoffset, section_size_type fnsize,
+		     unsigned char* view, section_size_type view_size,
+		     std::string* from, std::string* to) const;
+
   // Return the size of the GOT section.
   section_size_type
   got_size()
@@ -2465,7 +2473,8 @@ Target_i386::relocate_section(const Relo
 			      bool needs_special_offset_handling,
 			      unsigned char* view,
 			      elfcpp::Elf_types<32>::Elf_Addr address,
-			      section_size_type view_size)
+			      section_size_type view_size,
+			      const Reloc_symbol_changes* reloc_symbol_changes)
 {
   gold_assert(sh_type == elfcpp::SHT_REL);
 
@@ -2479,7 +2488,8 @@ Target_i386::relocate_section(const Relo
     needs_special_offset_handling,
     view,
     address,
-    view_size);
+    view_size,
+    reloc_symbol_changes);
 }
 
 // Return the size of a relocation while scanning during a relocatable
@@ -2699,6 +2709,63 @@ Target_i386::do_code_fill(section_size_t
   return std::string(nops[length], length);
 }
 
+// FNOFFSET in section SHNDX in OBJECT is the start of a function
+// compiled with -fstack-split.  The function calls non-stack-split
+// code.  We have to change the function so that it always ensures
+// that it has enough stack space to run some random function.
+
+void
+Target_i386::do_calls_non_split(Relobj* object, unsigned int shndx,
+				section_offset_type fnoffset,
+				section_size_type fnsize,
+				unsigned char* view,
+				section_size_type view_size,
+				std::string* from,
+				std::string* to) const
+{
+  // The function starts with a comparison of the stack pointer and a
+  // field in the TCB.  This is followed by a jump.
+
+  // cmp %gs:NN,%esp
+  if (this->match_view(view, view_size, fnoffset, "\x65\x3b\x25", 3)
+      && fnsize > 7)
+    {
+      // We will call __morestack if the carry flag is set after this
+      // comparison.  We turn the comparison into an stc instruction
+      // and some nops.
+      view[fnoffset] = '\xf9';
+      this->set_view_to_nop(view, view_size, fnoffset + 1, 6);
+    }
+  // lea NN(%esp),%ecx
+  else if (this->match_view(view, view_size, fnoffset, "\x8d\x8c\x24", 3)
+	   && fnsize > 7)
+    {
+      // This is loading an offset from the stack pointer for a
+      // comparison.  The offset is negative, so we decrease the
+      // offset by the amount of space we need for the stack.  This
+      // means we will avoid calling __morestack if there happens to
+      // be plenty of space on the stack already.
+      unsigned char* pval = view + fnoffset + 3;
+      uint32_t val = elfcpp::Swap_unaligned<32, false>::readval(pval);
+      val -= parameters->options().split_stack_adjust_size();
+      elfcpp::Swap_unaligned<32, false>::writeval(pval, val);
+    }
+  else
+    {
+      if (!object->has_no_split_stack())
+	object->error(_("failed to match split-stack sequence at "
+			"section %u offset %0zx"),
+		      shndx, fnoffset);
+      return;
+    }
+
+  // We have to change the function so that it calls
+  // __morestack_non_split instead of __morestack.  The former will
+  // allocate additional stack space.
+  *from = "__morestack";
+  *to = "__morestack_non_split";
+}
+
 // The selector for i386 object files.
 
 class Target_selector_i386 : public Target_selector_freebsd
Index: object.cc
===================================================================
RCS file: /cvs/src/src/gold/object.cc,v
retrieving revision 1.100
diff -u -u -p -r1.100 object.cc
--- object.cc	30 Sep 2009 22:21:13 -0000	1.100
+++ object.cc	6 Oct 2009 22:30:56 -0000
@@ -231,6 +231,25 @@ Object::handle_gnu_warning_section(const
   return false;
 }
 
+// If NAME is the name of the special section which indicates that
+// this object was compiled with -fstack-split, mark it accordingly.
+
+bool
+Object::handle_split_stack_section(const char* name)
+{
+  if (strcmp(name, ".note.GNU-split-stack") == 0)
+    {
+      this->uses_split_stack_ = true;
+      return true;
+    }
+  if (strcmp(name, ".note.GNU-no-split-stack") == 0)
+    {
+      this->has_no_split_stack_ = true;
+      return true;
+    }
+  return false;
+}
+
 // Class Relobj
 
 // To copy the symbols data read from the file to a local data structure.
@@ -1109,6 +1128,16 @@ Sized_relobj<size, big_endian>::do_layou
 	      omit[i] = true;
             }
 
+	  // The .note.GNU-split-stack section is also special.  It
+	  // indicates that the object was compiled with
+	  // -fsplit-stack.
+	  if (this->handle_split_stack_section(name))
+	    {
+	      if (!parameters->options().relocatable()
+		  && !parameters->options().shared())
+		omit[i] = true;
+	    }
+
           bool discard = omit[i];
           if (!discard)
             {
Index: object.h
===================================================================
RCS file: /cvs/src/src/gold/object.h,v
retrieving revision 1.79
diff -u -u -p -r1.79 object.h
--- object.h	30 Sep 2009 22:21:13 -0000	1.79
+++ object.h	6 Oct 2009 22:30:56 -0000
@@ -195,7 +195,8 @@ class Object
   Object(const std::string& name, Input_file* input_file, bool is_dynamic,
 	 off_t offset = 0)
     : name_(name), input_file_(input_file), offset_(offset), shnum_(-1U),
-      is_dynamic_(is_dynamic), xindex_(NULL), no_export_(false)
+      is_dynamic_(is_dynamic), uses_split_stack_(false),
+      has_no_split_stack_(false), xindex_(NULL), no_export_(false)
   { input_file->file().add_object(); }
 
   virtual ~Object()
@@ -216,6 +217,17 @@ class Object
   is_dynamic() const
   { return this->is_dynamic_; }
 
+  // Return whether this object was compiled with -fsplit-stack.
+  bool
+  uses_split_stack() const
+  { return this->uses_split_stack_; }
+
+  // Return whether this object contains any functions compiled with
+  // the no_split_stack attribute.
+  bool
+  has_no_split_stack() const
+  { return this->has_no_split_stack_; }
+
   // Returns NULL for Objects that are not plugin objects.  This method
   // is overridden in the Pluginobj class.
   Pluginobj*
@@ -556,6 +568,12 @@ class Object
   handle_gnu_warning_section(const char* name, unsigned int shndx,
 			     Symbol_table*);
 
+  // If NAME is the name of the special section which indicates that
+  // this object was compiled with -fstack-split, mark it accordingly,
+  // and return true.  Otherwise return false.
+  bool
+  handle_split_stack_section(const char* name);
+
  private:
   // This class may not be copied.
   Object(const Object&);
@@ -572,6 +590,11 @@ class Object
   unsigned int shnum_;
   // Whether this is a dynamic object.
   bool is_dynamic_;
+  // Whether this object was compiled with -fsplit-stack.
+  bool uses_split_stack_;
+  // Whether this object contains any functions compiled with the
+  // no_split_stack attribute.
+  bool has_no_split_stack_;
   // Many sections for objects with more than SHN_LORESERVE sections.
   Xindex* xindex_;
   // True if exclude this object from automatic symbol export.
@@ -1252,6 +1275,30 @@ class Got_offset_list
   Got_offset_list* got_next_;
 };
 
+// This type is used to modify relocations for -fsplit-stack.  It is
+// indexed by relocation index, and means that the relocation at that
+// index should use the symbol from the vector, rather than the one
+// indicated by the relocation.
+
+class Reloc_symbol_changes
+{
+ public:
+  Reloc_symbol_changes(size_t count)
+    : vec_(count, NULL)
+  { }
+
+  void
+  set(size_t i, Symbol* sym)
+  { this->vec_[i] = sym; }
+
+  const Symbol*
+  operator[](size_t i) const
+  { return this->vec_[i]; }
+
+ private:
+  std::vector<Symbol*> vec_;
+};
+
 // A regular object file.  This is size and endian specific.
 
 template<int size, bool big_endian>
@@ -1671,6 +1718,30 @@ class Sized_relobj : public Relobj
 		      unsigned char* reloc_view,
 		      section_size_type reloc_view_size);
 
+  // A type shared by split_stack_adjust_reltype and find_functions.
+  typedef std::map<section_offset_type, section_size_type> Function_offsets;
+
+  // Check for -fsplit-stack routines calling non-split-stack routines.
+  void
+  split_stack_adjust(const Symbol_table*, const unsigned char* pshdrs,
+		     unsigned int sh_type, unsigned int shndx,
+		     const unsigned char* prelocs, size_t reloc_count,
+		     unsigned char* view, section_size_type view_size,
+		     Reloc_symbol_changes** reloc_map);
+
+  template<int sh_type>
+  void
+  split_stack_adjust_reltype(const Symbol_table*, const unsigned char* pshdrs,
+			     unsigned int shndx, const unsigned char* prelocs,
+			     size_t reloc_count, unsigned char* view,
+			     section_size_type view_size,
+			     Reloc_symbol_changes** reloc_map);
+
+  // Find all functions in a section.
+  void
+  find_functions(const unsigned char* pshdrs, unsigned int shndx,
+		 Function_offsets*);
+
   // Initialize input to output maps for section symbols in merged
   // sections.
   void
Index: options.h
===================================================================
RCS file: /cvs/src/src/gold/options.h,v
retrieving revision 1.108
diff -u -u -p -r1.108 options.h
--- options.h	1 Oct 2009 00:58:38 -0000	1.108
+++ options.h	6 Oct 2009 22:30:56 -0000
@@ -812,6 +812,10 @@ class General_options
   DEFINE_bool(Bshareable, options::ONE_DASH, '\0', false,
               N_("Generate shared library"), NULL);
 
+  DEFINE_uint(split_stack_adjust_size, options::TWO_DASHES, '\0', 0x4000,
+	      N_("Stack size when -fsplit-stack function calls non-split"),
+	      N_("SIZE"));
+
   // This is not actually special in any way, but I need to give it
   // a non-standard accessor-function name because 'static' is a keyword.
   DEFINE_special(static, options::ONE_DASH, '\0',
Index: powerpc.cc
===================================================================
RCS file: /cvs/src/src/gold/powerpc.cc,v
retrieving revision 1.14
diff -u -u -p -r1.14 powerpc.cc
--- powerpc.cc	1 Oct 2009 00:58:38 -0000	1.14
+++ powerpc.cc	6 Oct 2009 22:30:56 -0000
@@ -110,7 +110,8 @@ class Target_powerpc : public Sized_targ
 		   bool needs_special_offset_handling,
 		   unsigned char* view,
 		   typename elfcpp::Elf_types<size>::Elf_Addr view_address,
-		   section_size_type view_size);
+		   section_size_type view_size,
+		   const Reloc_symbol_changes*);
 
   // Scan the relocs during a relocatable link.
   void
@@ -1854,7 +1855,8 @@ Target_powerpc<size, big_endian>::reloca
 			bool needs_special_offset_handling,
 			unsigned char* view,
 			typename elfcpp::Elf_types<size>::Elf_Addr address,
-			section_size_type view_size)
+			section_size_type view_size,
+			const Reloc_symbol_changes* reloc_symbol_changes)
 {
   typedef Target_powerpc<size, big_endian> Powerpc;
   typedef typename Target_powerpc<size, big_endian>::Relocate Powerpc_relocate;
@@ -1871,7 +1873,8 @@ Target_powerpc<size, big_endian>::reloca
     needs_special_offset_handling,
     view,
     address,
-    view_size);
+    view_size,
+    reloc_symbol_changes);
 }
 
 // Return the size of a relocation while scanning during a relocatable
Index: reloc.cc
===================================================================
RCS file: /cvs/src/src/gold/reloc.cc,v
retrieving revision 1.45
diff -u -u -p -r1.45 reloc.cc
--- reloc.cc	30 Sep 2009 22:21:13 -0000	1.45
+++ reloc.cc	6 Oct 2009 22:30:56 -0000
@@ -888,39 +888,36 @@ Sized_relobj<size, big_endian>::relocate
 
       relinfo.reloc_shndx = i;
       relinfo.data_shndx = index;
+      unsigned char* view = (*pviews)[index].view;
+      Address address = (*pviews)[index].address;
+      section_size_type view_size = (*pviews)[index].view_size;
+
+      Reloc_symbol_changes* reloc_map = NULL;
+      if (this->uses_split_stack() && output_offset != invalid_address)
+	{
+	  typename This::Shdr data_shdr(pshdrs + index * This::shdr_size);
+	  if ((data_shdr.get_sh_flags() & elfcpp::SHF_EXECINSTR) != 0)
+	    this->split_stack_adjust(symtab, pshdrs, sh_type, index,
+				     prelocs, reloc_count, view, view_size,
+				     &reloc_map);
+	}
+
       if (!parameters->options().relocatable())
 	{
-	  target->relocate_section(&relinfo,
-				   sh_type,
-				   prelocs,
-				   reloc_count,
-				   os,
+	  target->relocate_section(&relinfo, sh_type, prelocs, reloc_count, os,
 				   output_offset == invalid_address,
-				   (*pviews)[index].view,
-				   (*pviews)[index].address,
-				   (*pviews)[index].view_size);
+				   view, address, view_size, reloc_map);
 	  if (parameters->options().emit_relocs())
 	    this->emit_relocs(&relinfo, i, sh_type, prelocs, reloc_count,
-			      os, output_offset,
-			      (*pviews)[index].view,
-			      (*pviews)[index].address,
-			      (*pviews)[index].view_size,
-			      (*pviews)[i].view,
-			      (*pviews)[i].view_size);
+			      os, output_offset, view, address, view_size,
+			      (*pviews)[i].view, (*pviews)[i].view_size);
 	}
       else
 	{
 	  Relocatable_relocs* rr = this->relocatable_relocs(i);
-	  target->relocate_for_relocatable(&relinfo,
-					   sh_type,
-					   prelocs,
-					   reloc_count,
-					   os,
-					   output_offset,
-					   rr,
-					   (*pviews)[index].view,
-					   (*pviews)[index].address,
-					   (*pviews)[index].view_size,
+	  target->relocate_for_relocatable(&relinfo, sh_type, prelocs,
+					   reloc_count, os, output_offset, rr,
+					   view, address, view_size,
 					   (*pviews)[i].view,
 					   (*pviews)[i].view_size);
 	}
@@ -1025,6 +1022,244 @@ Sized_relobj<size, big_endian>::free_inp
     }
 }
 
+// If an object was compiled with -fsplit-stack, this is called to
+// check whether any relocations refer to functions defined in objects
+// which were not compiled with -fsplit-stack.  If they were, then we
+// need to apply some target-specific adjustments to request
+// additional stack space.
+
+template<int size, bool big_endian>
+void
+Sized_relobj<size, big_endian>::split_stack_adjust(
+    const Symbol_table* symtab,
+    const unsigned char* pshdrs,
+    unsigned int sh_type,
+    unsigned int shndx,
+    const unsigned char* prelocs,
+    size_t reloc_count,
+    unsigned char* view,
+    section_size_type view_size,
+    Reloc_symbol_changes** reloc_map)
+{
+  if (sh_type == elfcpp::SHT_REL)
+    this->split_stack_adjust_reltype<elfcpp::SHT_REL>(symtab, pshdrs, shndx,
+						      prelocs, reloc_count,
+						      view, view_size,
+						      reloc_map);
+  else
+    {
+      gold_assert(sh_type == elfcpp::SHT_RELA);
+      this->split_stack_adjust_reltype<elfcpp::SHT_RELA>(symtab, pshdrs, shndx,
+							 prelocs, reloc_count,
+							 view, view_size,
+							 reloc_map);
+    }
+}
+
+// Adjust for -fsplit-stack, templatized on the type of the relocation
+// section.
+
+template<int size, bool big_endian>
+template<int sh_type>
+void
+Sized_relobj<size, big_endian>::split_stack_adjust_reltype(
+    const Symbol_table* symtab,
+    const unsigned char* pshdrs,
+    unsigned int shndx,
+    const unsigned char* prelocs,
+    size_t reloc_count,
+    unsigned char* view,
+    section_size_type view_size,
+    Reloc_symbol_changes** reloc_map)
+{
+  typedef typename Reloc_types<sh_type, size, big_endian>::Reloc Reltype;
+  const int reloc_size = Reloc_types<sh_type, size, big_endian>::reloc_size;
+
+  size_t local_count = this->local_symbol_count();
+
+  std::vector<section_offset_type> non_split_refs;
+
+  const unsigned char* pr = prelocs;
+  for (size_t i = 0; i < reloc_count; ++i, pr += reloc_size)
+    {
+      Reltype reloc(pr);
+
+      typename elfcpp::Elf_types<size>::Elf_WXword r_info = reloc.get_r_info();
+      unsigned int r_sym = elfcpp::elf_r_sym<size>(r_info);
+      if (r_sym < local_count)
+	continue;
+
+      const Symbol* gsym = this->global_symbol(r_sym);
+      gold_assert(gsym != NULL);
+      if (gsym->is_forwarder())
+	gsym = symtab->resolve_forwards(gsym);
+
+      // See if this relocation refers to a function defined in an
+      // object compiled without -fsplit-stack.  Note that we don't
+      // care about the type of relocation--this means that in some
+      // cases we will ask for a large stack unnecessarily, but this
+      // is not fatal.  FIXME: Some targets have symbols which are
+      // functions but are not type STT_FUNC, e.g., STT_ARM_TFUNC.
+      if (gsym->type() == elfcpp::STT_FUNC
+	  && !gsym->is_undefined()
+	  && gsym->source() == Symbol::FROM_OBJECT
+	  && !gsym->object()->uses_split_stack())
+	{
+	  section_offset_type offset =
+	    convert_to_section_size_type(reloc.get_r_offset());
+	  non_split_refs.push_back(offset);
+	}
+    }
+
+  if (non_split_refs.empty())
+    return;
+
+  // At this point, every entry in NON_SPLIT_REFS indicates a
+  // relocation which refers to a function in an object compiled
+  // without -fsplit-stack.  We now have to convert that list into a
+  // set of offsets to functions.  First, we find all the functions.
+
+  Function_offsets function_offsets;
+  this->find_functions(pshdrs, shndx, &function_offsets);
+  if (function_offsets.empty())
+    return;
+
+  // Now get a list of the function with references to non split-stack
+  // code.
+
+  Function_offsets calls_non_split;
+  for (std::vector<section_offset_type>::const_iterator p
+	 = non_split_refs.begin();
+       p != non_split_refs.end();
+       ++p)
+    {
+      Function_offsets::const_iterator low = function_offsets.lower_bound(*p);
+      if (low == function_offsets.end())
+	--low;
+      else if (low->first == *p)
+	;
+      else if (low == function_offsets.begin())
+	continue;
+      else
+	--low;
+
+      calls_non_split.insert(*low);
+    }
+  if (calls_non_split.empty())
+    return;
+
+  // Now we have a set of functions to adjust.  The adjustments are
+  // target specific.  Besides changing the output section view
+  // however, it likes, the target may request a relocation change
+  // from one global symbol name to another.
+
+  for (Function_offsets::const_iterator p = calls_non_split.begin();
+       p != calls_non_split.end();
+       ++p)
+    {
+      std::string from;
+      std::string to;
+      parameters->target().calls_non_split(this, shndx, p->first, p->second,
+					   view, view_size, &from, &to);
+      if (!from.empty())
+	{
+	  gold_assert(!to.empty());
+	  Symbol* tosym = NULL;
+
+	  // Find relocations in the relevant function which are for
+	  // FROM.
+	  pr = prelocs;
+	  for (size_t i = 0; i < reloc_count; ++i, pr += reloc_size)
+	    {
+	      Reltype reloc(pr);
+
+	      typename elfcpp::Elf_types<size>::Elf_WXword r_info =
+		reloc.get_r_info();
+	      unsigned int r_sym = elfcpp::elf_r_sym<size>(r_info);
+	      if (r_sym < local_count)
+		continue;
+
+	      section_offset_type offset =
+		convert_to_section_size_type(reloc.get_r_offset());
+	      if (offset < p->first
+		  || (offset
+		      >= (p->first
+			  + static_cast<section_offset_type>(p->second))))
+		continue;
+
+	      const Symbol* gsym = this->global_symbol(r_sym);
+	      if (from == gsym->name())
+		{
+		  if (tosym == NULL)
+		    {
+		      tosym = symtab->lookup(to.c_str());
+		      if (tosym == NULL)
+			{
+			  this->error(_("could not convert call "
+					"to '%s' to '%s'"),
+				      from.c_str(), to.c_str());
+			  break;
+			}
+		    }
+
+		  if (*reloc_map == NULL)
+		    *reloc_map = new Reloc_symbol_changes(reloc_count);
+		  (*reloc_map)->set(i, tosym);
+		}
+	    }
+	}
+    }
+}
+
+// Find all the function in this object defined in section SHNDX.
+// Store their offsets in the section in FUNCTION_OFFSETS.
+
+template<int size, bool big_endian>
+void
+Sized_relobj<size, big_endian>::find_functions(
+    const unsigned char* pshdrs,
+    unsigned int shndx,
+    Sized_relobj<size, big_endian>::Function_offsets* function_offsets)
+{
+  // We need to read the symbols to find the functions.  If we wanted
+  // to, we could cache reading the symbols across all sections in the
+  // object.
+  const unsigned int symtab_shndx = this->symtab_shndx_;
+  typename This::Shdr symtabshdr(pshdrs + symtab_shndx * This::shdr_size);
+  gold_assert(symtabshdr.get_sh_type() == elfcpp::SHT_SYMTAB);
+
+  typename elfcpp::Elf_types<size>::Elf_WXword sh_size =
+    symtabshdr.get_sh_size();
+  const unsigned char* psyms = this->get_view(symtabshdr.get_sh_offset(),
+					      sh_size, true, true);
+
+  const int sym_size = This::sym_size;
+  const unsigned int symcount = sh_size / sym_size;
+  for (unsigned int i = 0; i < symcount; ++i, psyms += sym_size)
+    {
+      typename elfcpp::Sym<size, big_endian> isym(psyms);
+
+      // FIXME: Some targets can have functions which do not have type
+      // STT_FUNC, e.g., STT_ARM_TFUNC.
+      if (isym.get_st_type() != elfcpp::STT_FUNC
+	  || isym.get_st_size() == 0)
+	continue;
+
+      bool is_ordinary;
+      unsigned int sym_shndx = this->adjust_sym_shndx(i, isym.get_st_shndx(),
+						      &is_ordinary);
+      if (!is_ordinary || sym_shndx != shndx)
+	continue;
+
+      section_offset_type value =
+	convert_to_section_size_type(isym.get_st_value());
+      section_size_type fnsize =
+	convert_to_section_size_type(isym.get_st_size());
+
+      (*function_offsets)[value] = fnsize;
+    }
+}
+
 // Class Merged_symbol_value.
 
 template<int size>
Index: sparc.cc
===================================================================
RCS file: /cvs/src/src/gold/sparc.cc,v
retrieving revision 1.18
diff -u -u -p -r1.18 sparc.cc
--- sparc.cc	1 Oct 2009 00:58:38 -0000	1.18
+++ sparc.cc	6 Oct 2009 22:30:56 -0000
@@ -112,7 +112,8 @@ class Target_sparc : public Sized_target
 		   bool needs_special_offset_handling,
 		   unsigned char* view,
 		   typename elfcpp::Elf_types<size>::Elf_Addr view_address,
-		   section_size_type view_size);
+		   section_size_type view_size,
+		   const Reloc_symbol_changes*);
 
   // Scan the relocs during a relocatable link.
   void
@@ -3106,7 +3107,8 @@ Target_sparc<size, big_endian>::relocate
 			bool needs_special_offset_handling,
 			unsigned char* view,
 			typename elfcpp::Elf_types<size>::Elf_Addr address,
-			section_size_type view_size)
+			section_size_type view_size,
+			const Reloc_symbol_changes* reloc_symbol_changes)
 {
   typedef Target_sparc<size, big_endian> Sparc;
   typedef typename Target_sparc<size, big_endian>::Relocate Sparc_relocate;
@@ -3123,7 +3125,8 @@ Target_sparc<size, big_endian>::relocate
     needs_special_offset_handling,
     view,
     address,
-    view_size);
+    view_size,
+    reloc_symbol_changes);
 }
 
 // Return the size of a relocation while scanning during a relocatable
Index: target-reloc.h
===================================================================
RCS file: /cvs/src/src/gold/target-reloc.h,v
retrieving revision 1.34
diff -u -u -p -r1.34 target-reloc.h
--- target-reloc.h	5 Aug 2009 20:51:56 -0000	1.34
+++ target-reloc.h	6 Oct 2009 22:30:56 -0000
@@ -25,6 +25,7 @@
 
 #include "elfcpp.h"
 #include "symtab.h"
+#include "object.h"
 #include "reloc.h"
 #include "reloc-types.h"
 
@@ -163,6 +164,12 @@ get_comdat_behavior(const char* name)
 // NEEDS_SPECIAL_OFFSET_HANDLING is true, in which case they refer to
 // the output section.
 
+// RELOC_SYMBOL_CHANGES is used for -fsplit-stack support.  If it is
+// not NULL, it is a vector indexed by relocation index.  If that
+// entry is not NULL, it points to a global symbol which used as the
+// symbol for the relocation, ignoring the symbol index in the
+// relocation.
+
 template<int size, bool big_endian, typename Target_type, int sh_type,
 	 typename Relocate>
 inline void
@@ -175,7 +182,8 @@ relocate_section(
     bool needs_special_offset_handling,
     unsigned char* view,
     typename elfcpp::Elf_types<size>::Elf_Addr view_address,
-    section_size_type view_size)
+    section_size_type view_size,
+    const Reloc_symbol_changes* reloc_symbol_changes)
 {
   typedef typename Reloc_types<sh_type, size, big_endian>::Reloc Reltype;
   const int reloc_size = Reloc_types<sh_type, size, big_endian>::reloc_size;
@@ -210,7 +218,9 @@ relocate_section(
 
       Symbol_value<size> symval;
       const Symbol_value<size> *psymval;
-      if (r_sym < local_count)
+      if (r_sym < local_count
+	  && (reloc_symbol_changes == NULL
+	      || (*reloc_symbol_changes)[i] == NULL))
 	{
 	  sym = NULL;
 	  psymval = object->local_symbol(r_sym);
@@ -246,7 +256,7 @@ relocate_section(
 	        {
 	          if (comdat_behavior == CB_WARNING)
                     gold_warning_at_location(relinfo, i, offset,
-                                             _("Relocation refers to discarded "
+                                             _("relocation refers to discarded "
                                                "comdat section"));
                   symval.set_output_value(0);
 	        }
@@ -256,10 +266,17 @@ relocate_section(
 	}
       else
 	{
-	  const Symbol* gsym = object->global_symbol(r_sym);
-	  gold_assert(gsym != NULL);
-	  if (gsym->is_forwarder())
-	    gsym = relinfo->symtab->resolve_forwards(gsym);
+	  const Symbol* gsym;
+	  if (reloc_symbol_changes != NULL
+	      && (*reloc_symbol_changes)[i] != NULL)
+	    gsym = (*reloc_symbol_changes)[i];
+	  else
+	    {
+	      gsym = object->global_symbol(r_sym);
+	      gold_assert(gsym != NULL);
+	      if (gsym->is_forwarder())
+		gsym = relinfo->symtab->resolve_forwards(gsym);
+	    }
 
 	  sym = static_cast<const Sized_symbol<size>*>(gsym);
 	  if (sym->has_symtab_index())
Index: target.cc
===================================================================
RCS file: /cvs/src/src/gold/target.cc,v
retrieving revision 1.3
diff -u -u -p -r1.3 target.cc
--- target.cc	30 Sep 2009 22:21:13 -0000	1.3
+++ target.cc	6 Oct 2009 22:30:56 -0000
@@ -23,6 +23,7 @@
 #include "gold.h"
 #include "target.h"
 #include "dynobj.h"
+#include "elfcpp.h"
 
 namespace gold
 {
@@ -135,4 +136,50 @@ Target::do_make_elf_object(const std::st
 }
 #endif
 
+// Default conversion for -fsplit-stack is to give an error.
+
+void
+Target::do_calls_non_split(Relobj* object, unsigned int, section_offset_type,
+			   section_size_type, unsigned char*, section_size_type,
+			   std::string*, std::string*) const
+{
+  static bool warned;
+  if (!warned)
+    {
+      gold_error(_("linker does not include stack split support "
+		   "required by %s"),
+		 object->name().c_str());
+      warned = true;
+    }
+}
+
+//  Return whether BYTES/LEN matches VIEW/VIEW_SIZE at OFFSET.
+
+bool
+Target::match_view(const unsigned char* view, section_size_type view_size,
+		   section_offset_type offset, const char* bytes,
+		   size_t len) const
+{
+  if (offset + len > view_size)
+    return false;
+  return memcmp(view + offset, bytes, len) == 0;
+}
+
+// Set the contents of a VIEW/VIEW_SIZE to nops starting at OFFSET
+// for LEN bytes.
+
+void
+Target::set_view_to_nop(unsigned char* view, section_size_type view_size,
+			section_offset_type offset, size_t len) const
+{
+  gold_assert(offset >= 0 && offset + len <= view_size);
+  if (!this->has_code_fill())
+    memset(view + offset, 0, len);
+  else
+    {
+      std::string fill = this->code_fill(len);
+      memcpy(view + offset, fill.data(), len);
+    }
+}
+
 } // End namespace gold.
Index: target.h
===================================================================
RCS file: /cvs/src/src/gold/target.h,v
retrieving revision 1.36
diff -u -u -p -r1.36 target.h
--- target.h	18 Sep 2009 01:10:38 -0000	1.36
+++ target.h	6 Oct 2009 22:30:56 -0000
@@ -43,11 +43,13 @@ namespace gold
 
 class General_options;
 class Object;
+class Relobj;
 template<int size, bool big_endian>
 class Sized_relobj;
 class Relocatable_relocs;
 template<int size, bool big_endian>
 class Relocate_info;
+class Reloc_symbol_changes;
 class Symbol;
 template<int size>
 class Sized_symbol;
@@ -217,6 +219,22 @@ class Target
   is_local_label_name(const char* name) const
   { return this->do_is_local_label_name(name); }
 
+  // A function starts at OFFSET in section SHNDX in OBJECT.  That
+  // function was compiled with -fsplit-stack, but it refers to a
+  // function which was compiled without -fsplit-stack.  VIEW is a
+  // modifiable view of the section; VIEW_SIZE is the size of the
+  // view.  The target has to adjust the function so that it allocates
+  // enough stack.
+  void
+  calls_non_split(Relobj* object, unsigned int shndx,
+		  section_offset_type fnoffset, section_size_type fnsize,
+		  unsigned char* view, section_size_type view_size,
+		  std::string* from, std::string* to) const
+  {
+    this->do_calls_non_split(object, shndx, fnoffset, fnsize, view, view_size,
+			     from, to);
+  }
+
   // Make an ELF object.
   template<int size, bool big_endian>
   Object*
@@ -244,7 +262,7 @@ class Target
       return pass < 2;
 
     return this->do_relax(pass);
-  } 
+  }
 
  protected:
   // This struct holds the constant information for a child class.  We
@@ -331,9 +349,15 @@ class Target
   virtual bool
   do_is_local_label_name(const char*) const;
 
+  // Virtual function which may be overridden by the child class.
+  virtual void
+  do_calls_non_split(Relobj* object, unsigned int, section_offset_type,
+		     section_size_type, unsigned char*, section_size_type,
+		     std::string*, std::string*) const;
+
   // make_elf_object hooks.  There are four versions of these for
   // different address sizes and endianities.
-  
+
 #ifdef HAVE_TARGET_32_LITTLE
   // Virtual functions which may be overriden by the child class.
   virtual Object*
@@ -372,6 +396,18 @@ class Target
   do_relax(int)
   { return false; }
 
+  // A function for targets to call.  Return whether BYTES/LEN matches
+  // VIEW/VIEW_SIZE at OFFSET.
+  bool
+  match_view(const unsigned char* view, section_size_type view_size,
+	     section_offset_type offset, const char* bytes, size_t len) const;
+
+  // Set the contents of a VIEW/VIEW_SIZE to nops starting at OFFSET
+  // for LEN bytes.
+  void
+  set_view_to_nop(unsigned char* view, section_size_type view_size,
+		  section_offset_type offset, size_t len) const;
+
  private:
   // The implementations of the four do_make_elf_object virtual functions are
   // almost identical except for their sizes and endianity.  We use a template.
@@ -478,7 +514,8 @@ class Sized_target : public Target
 		   bool needs_special_offset_handling,
 		   unsigned char* view,
 		   typename elfcpp::Elf_types<size>::Elf_Addr view_address,
-		   section_size_type view_size) = 0;
+		   section_size_type view_size,
+		   const Reloc_symbol_changes*) = 0;
 
   // Scan the relocs during a relocatable link.  The parameters are
   // like scan_relocs, with an additional Relocatable_relocs
Index: x86_64.cc
===================================================================
RCS file: /cvs/src/src/gold/x86_64.cc,v
retrieving revision 1.86
diff -u -u -p -r1.86 x86_64.cc
--- x86_64.cc	1 Oct 2009 00:58:38 -0000	1.86
+++ x86_64.cc	6 Oct 2009 22:30:56 -0000
@@ -120,7 +120,8 @@ class Target_x86_64 : public Target_free
 		   bool needs_special_offset_handling,
 		   unsigned char* view,
 		   elfcpp::Elf_types<64>::Elf_Addr view_address,
-		   section_size_type view_size);
+		   section_size_type view_size,
+		   const Reloc_symbol_changes*);
 
   // Scan the relocs during a relocatable link.
   void
@@ -162,6 +163,13 @@ class Target_x86_64 : public Target_free
   do_is_defined_by_abi(const Symbol* sym) const
   { return strcmp(sym->name(), "__tls_get_addr") == 0; }
 
+  // Adjust -fstack-split code which calls non-stack-split code.
+  void
+  do_calls_non_split(Relobj* object, unsigned int shndx,
+		     section_offset_type fnoffset, section_size_type fnsize,
+		     unsigned char* view, section_size_type view_size,
+		     std::string* from, std::string* to) const;
+
   // Return the size of the GOT section.
   section_size_type
   got_size()
@@ -2417,15 +2425,17 @@ Target_x86_64::Relocate::tls_ie_to_le(co
 // Relocate section data.
 
 void
-Target_x86_64::relocate_section(const Relocate_info<64, false>* relinfo,
-                                unsigned int sh_type,
-                                const unsigned char* prelocs,
-                                size_t reloc_count,
-				Output_section* output_section,
-				bool needs_special_offset_handling,
-                                unsigned char* view,
-                                elfcpp::Elf_types<64>::Elf_Addr address,
-                                section_size_type view_size)
+Target_x86_64::relocate_section(
+    const Relocate_info<64, false>* relinfo,
+    unsigned int sh_type,
+    const unsigned char* prelocs,
+    size_t reloc_count,
+    Output_section* output_section,
+    bool needs_special_offset_handling,
+    unsigned char* view,
+    elfcpp::Elf_types<64>::Elf_Addr address,
+    section_size_type view_size,
+    const Reloc_symbol_changes* reloc_symbol_changes)
 {
   gold_assert(sh_type == elfcpp::SHT_RELA);
 
@@ -2439,7 +2449,8 @@ Target_x86_64::relocate_section(const Re
     needs_special_offset_handling,
     view,
     address,
-    view_size);
+    view_size,
+    reloc_symbol_changes);
 }
 
 // Return the size of a relocation while scanning during a relocatable
@@ -2657,6 +2668,63 @@ Target_x86_64::do_code_fill(section_size
   return std::string(nops[length], length);
 }
 
+// FNOFFSET in section SHNDX in OBJECT is the start of a function
+// compiled with -fstack-split.  The function calls non-stack-split
+// code.  We have to change the function so that it always ensures
+// that it has enough stack space to run some random function.
+
+void
+Target_x86_64::do_calls_non_split(Relobj* object, unsigned int shndx,
+				  section_offset_type fnoffset,
+				  section_size_type fnsize,
+				  unsigned char* view,
+				  section_size_type view_size,
+				  std::string* from,
+				  std::string* to) const
+{
+  // The function starts with a comparison of the stack pointer and a
+  // field in the TCB.  This is followed by a jump.
+
+  // cmp %fs:NN,%rsp
+  if (this->match_view(view, view_size, fnoffset, "\x64\x48\x3b\x24\x25", 5)
+      && fnsize > 9)
+    {
+      // We will call __morestack if the carry flag is set after this
+      // comparison.  We turn the comparison into an stc instruction
+      // and some nops.
+      view[fnoffset] = '\xf9';
+      this->set_view_to_nop(view, view_size, fnoffset + 1, 8);
+    }
+  // lea NN(%rsp),%r10
+  else if (this->match_view(view, view_size, fnoffset, "\x4c\x8d\x94\x24", 4)
+	   && fnsize > 8)
+    {
+      // This is loading an offset from the stack pointer for a
+      // comparison.  The offset is negative, so we decrease the
+      // offset by the amount of space we need for the stack.  This
+      // means we will avoid calling __morestack if there happens to
+      // be plenty of space on the stack already.
+      unsigned char* pval = view + fnoffset + 4;
+      uint32_t val = elfcpp::Swap_unaligned<32, false>::readval(pval);
+      val -= parameters->options().split_stack_adjust_size();
+      elfcpp::Swap_unaligned<32, false>::writeval(pval, val);
+    }
+  else
+    {
+      if (!object->has_no_split_stack())
+	object->error(_("failed to match split-stack sequence at "
+			"section %u offset %0zx"),
+		      shndx, fnoffset);
+      return;
+    }
+
+  // We have to change the function so that it calls
+  // __morestack_non_split instead of __morestack.  The former will
+  // allocate additional stack space.
+  *from = "__morestack";
+  *to = "__morestack_non_split";
+}
+
 // The selector for x86_64 object files.
 
 class Target_selector_x86_64 : public Target_selector_freebsd
Index: testsuite/Makefile.am
===================================================================
RCS file: /cvs/src/src/gold/testsuite/Makefile.am,v
retrieving revision 1.103
diff -u -u -p -r1.103 Makefile.am
--- testsuite/Makefile.am	18 Sep 2009 20:02:21 -0000	1.103
+++ testsuite/Makefile.am	6 Oct 2009 22:30:56 -0000
@@ -25,6 +25,7 @@ TEST_CXXFILT = $(top_builddir)/../binuti
 TEST_STRIP = $(top_builddir)/../binutils/strip-new
 TEST_AR = $(top_builddir)/../binutils/ar
 TEST_NM = $(top_builddir)/../binutils/nm-new
+TEST_AS = $(top_builddir)/../gas/as-new
 
 if PLUGINS
 LIBDL = -ldl
@@ -1182,3 +1183,79 @@ permission_test: basic_test.o gcctestdir
 
 endif GCC
 endif NATIVE_LINKER
+
+# These tests work with cross linkers.
+
+if DEFAULT_TARGET_I386
+
+check_SCRIPTS += split_i386.sh
+check_DATA += split_i386_1.stdout split_i386_2.stdout \
+	split_i386_3.stdout split_i386_4.stdout split_i386_r.stdout
+SPLIT_DEFSYMS = --defsym __morestack=0x100 --defsym __morestack_non_split=0x200
+split_i386_1.o: split_i386_1.s
+	$(TEST_AS) -o $@ $<
+split_i386_2.o: split_i386_2.s
+	$(TEST_AS) -o $@ $<
+split_i386_3.o: split_i386_3.s
+	$(TEST_AS) -o $@ $<
+split_i386_4.o: split_i386_4.s
+	$(TEST_AS) -o $@ $<
+split_i386_n.o: split_i386_n.s
+	$(TEST_AS) -o $@ $<
+split_i386_1: split_i386_1.o split_i386_n.o ../ld-new
+	../ld-new $(SPLIT_DEFSYMS) -o $@ split_i386_1.o split_i386_n.o
+split_i386_1.stdout: split_i386_1
+	$(TEST_OBJDUMP) -d $< > $@
+split_i386_2: split_i386_2.o split_i386_n.o ../ld-new
+	../ld-new $(SPLIT_DEFSYMS) -o $@ split_i386_2.o split_i386_n.o
+split_i386_2.stdout: split_i386_2
+	$(TEST_OBJDUMP) -d $< > $@
+split_i386_3.stdout: split_i386_3.o split_i386_n.o ../ld-new
+	../ld-new $(SPLIT_DEFSYMS) -o split_i386_3 split_i386_3.o split_i386_n.o > $@ 2>&1 || exit 0
+split_i386_4: split_i386_4.o split_i386_n.o ../ld-new
+	../ld-new $(SPLIT_DEFSYMS) -o $@ split_i386_4.o split_i386_n.o
+split_i386_4.stdout: split_i386_4
+	$(TEST_OBJDUMP) -d $< > $@
+split_i386_r.stdout: split_i386_1.o split_i386_n.o ../ld-new
+	../ld-new -r split_i386_1.o split_i386_n.o -o split_i386_r > $@ 2>&1 || exit 0
+MOSTLYCLEANFILES += split_i386_1 split_i386_2 split_i386_3 \
+	split_i386_4 split_i386_r
+
+endif DEFAULT_TARGET_I386
+
+if DEFAULT_TARGET_X86_64
+
+check_SCRIPTS += split_x86_64.sh
+check_DATA += split_x86_64_1.stdout split_x86_64_2.stdout \
+	split_x86_64_3.stdout split_x86_64_4.stdout split_x86_64_r.stdout
+SPLIT_DEFSYMS = --defsym __morestack=0x100 --defsym __morestack_non_split=0x200
+split_x86_64_1.o: split_x86_64_1.s
+	$(TEST_AS) -o $@ $<
+split_x86_64_2.o: split_x86_64_2.s
+	$(TEST_AS) -o $@ $<
+split_x86_64_3.o: split_x86_64_3.s
+	$(TEST_AS) -o $@ $<
+split_x86_64_4.o: split_x86_64_4.s
+	$(TEST_AS) -o $@ $<
+split_x86_64_n.o: split_x86_64_n.s
+	$(TEST_AS) -o $@ $<
+split_x86_64_1: split_x86_64_1.o split_x86_64_n.o ../ld-new
+	../ld-new $(SPLIT_DEFSYMS) -o $@ split_x86_64_1.o split_x86_64_n.o
+split_x86_64_1.stdout: split_x86_64_1
+	$(TEST_OBJDUMP) -d $< > $@
+split_x86_64_2: split_x86_64_2.o split_x86_64_n.o ../ld-new
+	../ld-new $(SPLIT_DEFSYMS) -o $@ split_x86_64_2.o split_x86_64_n.o
+split_x86_64_2.stdout: split_x86_64_2
+	$(TEST_OBJDUMP) -d $< > $@
+split_x86_64_3.stdout: split_x86_64_3.o split_x86_64_n.o ../ld-new
+	../ld-new $(SPLIT_DEFSYMS) -o split_x86_64_3 split_x86_64_3.o split_x86_64_n.o > $@ 2>&1 || exit 0
+split_x86_64_4: split_x86_64_4.o split_x86_64_n.o ../ld-new
+	../ld-new $(SPLIT_DEFSYMS) -o $@ split_x86_64_4.o split_x86_64_n.o
+split_x86_64_4.stdout: split_x86_64_4
+	$(TEST_OBJDUMP) -d $< > $@
+split_x86_64_r.stdout: split_x86_64_1.o split_x86_64_n.o ../ld-new
+	../ld-new -r split_x86_64_1.o split_x86_64_n.o -o split_x86_64_r > $@ 2>&1 || exit 0
+MOSTLYCLEANFILES += split_x86_64_1 split_x86_64_2 split_x86_64_3 \
+	split_x86_64_4 split_x86_64_r
+
+endif DEFAULT_TARGET_X86_64
Index: testsuite/split_i386.sh
===================================================================
RCS file: testsuite/split_i386.sh
diff -N testsuite/split_i386.sh
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ testsuite/split_i386.sh	6 Oct 2009 22:30:56 -0000
@@ -0,0 +1,54 @@
+#!/bin/sh
+
+# split_i386.sh -- test -fstack-split for i386
+
+# Copyright 2009 Free Software Foundation, Inc.
+# Written by Ian Lance Taylor <iant@google.com>.
+
+# 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.
+
+match()
+{
+  if ! egrep "$1" "$2" >/dev/null 2>&1; then
+    echo 1>&2 "could not find '$1' in $2"
+    exit 1
+  fi
+}
+
+nomatch()
+{
+  if egrep "$1" "$2" >/dev/null 2>&1; then
+    echo 1>&2 "found unexpected '$1' in $2"
+    exit 1
+  fi
+}
+
+match 'cmp.*+%gs:[^,]*,%esp' split_i386_1.stdout
+match 'call.*__morestack>?$' split_i386_1.stdout
+match 'lea.*-0x200\(%esp\),' split_i386_1.stdout
+
+match 'stc' split_i386_2.stdout
+match 'call.*__morestack_non_split>?$' split_i386_2.stdout
+nomatch 'call.*__morestack>?$' split_i386_2.stdout
+match 'lea.*-0x4200\(%esp\),' split_i386_2.stdout
+
+match 'failed to match' split_i386_3.stdout
+
+match 'call.*__morestack>?$' split_i386_4.stdout
+
+match 'cannot mix' split_i386_r.stdout
Index: testsuite/split_i386_1.s
===================================================================
RCS file: testsuite/split_i386_1.s
diff -N testsuite/split_i386_1.s
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ testsuite/split_i386_1.s	6 Oct 2009 22:30:56 -0000
@@ -0,0 +1,33 @@
+# split_i386_1.s: i386 specific test case for -fsplit-stack.
+
+	.text
+
+	.global	fn1
+	.type	fn1,@function
+fn1:
+	cmp	%gs:0x30,%esp
+	jae	1f
+	call	__morestack
+	ret
+1:
+	call	fn2
+	ret
+
+	.size	fn1,. - fn1
+
+	.global	fn2
+	.type	fn2,@function
+fn2:
+	lea	-0x200(%esp),%ecx
+	cmp	%gs:0x30,%ecx
+	jae	1f
+	call	__morestack
+	ret
+1:
+	call	fn1
+	ret
+
+	.size	fn2,. - fn2
+
+	.section	.note.GNU-stack,"",@progbits
+	.section	.note.GNU-split-stack,"",@progbits
Index: testsuite/split_i386_2.s
===================================================================
RCS file: testsuite/split_i386_2.s
diff -N testsuite/split_i386_2.s
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ testsuite/split_i386_2.s	6 Oct 2009 22:30:56 -0000
@@ -0,0 +1,33 @@
+# split_i386_2.s: i386 specific, -fsplit-stack calling non-split
+
+	.text
+
+	.global	fn1
+	.type	fn1,@function
+fn1:
+	cmp	%gs:0x30,%esp
+	jae	1f
+	call	__morestack
+	ret
+1:
+	call	fn3
+	ret
+
+	.size	fn1,. - fn1
+
+	.global	fn2
+	.type	fn2,@function
+fn2:
+	lea	-0x200(%esp),%ecx
+	cmp	%gs:0x30,%ecx
+	jae	1f
+	call	__morestack
+	ret
+1:
+	call	fn3
+	ret
+
+	.size	fn2,. - fn2
+
+	.section	.note.GNU-stack,"",@progbits
+	.section	.note.GNU-split-stack,"",@progbits
Index: testsuite/split_i386_3.s
===================================================================
RCS file: testsuite/split_i386_3.s
diff -N testsuite/split_i386_3.s
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ testsuite/split_i386_3.s	6 Oct 2009 22:30:56 -0000
@@ -0,0 +1,22 @@
+# split_i386_3.s: i386 specific, adjustment failure
+
+	.text
+
+	.global	fn1
+	.type	fn1,@function
+fn1:
+	push	%ebp
+	mov	%esp,%ebp
+	cmp	%gs:0x30,%esp
+	jae	1f
+	call	__morestack
+	ret
+1:
+	call	fn3
+	leave
+	ret
+
+	.size	fn1,. - fn1
+
+	.section	.note.GNU-stack,"",@progbits
+	.section	.note.GNU-split-stack,"",@progbits
Index: testsuite/split_i386_4.s
===================================================================
RCS file: testsuite/split_i386_4.s
diff -N testsuite/split_i386_4.s
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ testsuite/split_i386_4.s	6 Oct 2009 22:30:56 -0000
@@ -0,0 +1,23 @@
+# split_i386_4.s: i386 specific, permitted adjustment failure
+
+	.text
+
+	.global	fn1
+	.type	fn1,@function
+fn1:
+	push	%ebp
+	mov	%esp,%ebp
+	cmp	%gs:0x30,%esp
+	jae	1f
+	call	__morestack
+	ret
+1:
+	call	fn3
+	leave
+	ret
+
+	.size	fn1,. - fn1
+
+	.section	.note.GNU-stack,"",@progbits
+	.section	.note.GNU-split-stack,"",@progbits
+	.section	.note.GNU-no-split-stack,"",@progbits
Index: testsuite/split_i386_n.s
===================================================================
RCS file: testsuite/split_i386_n.s
diff -N testsuite/split_i386_n.s
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ testsuite/split_i386_n.s	6 Oct 2009 22:30:56 -0000
@@ -0,0 +1,12 @@
+# split_i386_n.s: i386 specific, -fsplit-stack calling non-split
+
+	.text
+
+	.global	fn3
+	.type	fn3,@function
+fn3:
+	ret
+
+	.size	fn3,. - fn3
+
+	.section	.note.GNU-stack,"",@progbits
Index: testsuite/split_x86_64.sh
===================================================================
RCS file: testsuite/split_x86_64.sh
diff -N testsuite/split_x86_64.sh
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ testsuite/split_x86_64.sh	6 Oct 2009 22:30:56 -0000
@@ -0,0 +1,54 @@
+#!/bin/sh
+
+# split_x86_64.sh -- test -fstack-split for x86_64
+
+# Copyright 2009 Free Software Foundation, Inc.
+# Written by Ian Lance Taylor <iant@google.com>.
+
+# 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.
+
+match()
+{
+  if ! egrep "$1" "$2" >/dev/null 2>&1; then
+    echo 1>&2 "could not find '$1' in $2"
+    exit 1
+  fi
+}
+
+nomatch()
+{
+  if egrep "$1" "$2" >/dev/null 2>&1; then
+    echo 1>&2 "found unexpected '$1' in $2"
+    exit 1
+  fi
+}
+
+match 'cmp.*+%fs:[^,]*,%rsp' split_x86_64_1.stdout
+match 'callq.*__morestack>?$' split_x86_64_1.stdout
+match 'lea.*-0x200\(%rsp\),' split_x86_64_1.stdout
+
+match 'stc' split_x86_64_2.stdout
+match 'callq.*__morestack_non_split>?$' split_x86_64_2.stdout
+nomatch 'callq.*__morestack>?$' split_x86_64_2.stdout
+match 'lea.*-0x4200\(%rsp\),' split_x86_64_2.stdout
+
+match 'failed to match' split_x86_64_3.stdout
+
+match 'callq.*__morestack>?$' split_x86_64_4.stdout
+
+match 'cannot mix' split_x86_64_r.stdout
Index: testsuite/split_x86_64_1.s
===================================================================
RCS file: testsuite/split_x86_64_1.s
diff -N testsuite/split_x86_64_1.s
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ testsuite/split_x86_64_1.s	6 Oct 2009 22:30:56 -0000
@@ -0,0 +1,33 @@
+# split_x86_64_1.s: x86_64 specific test case for -fsplit-stack.
+
+	.text
+
+	.global	fn1
+	.type	fn1,@function
+fn1:
+	cmp	%fs:0x70,%rsp
+	jae	1f
+	callq	__morestack
+	retq
+1:
+	callq	fn2
+	retq
+
+	.size	fn1,. - fn1
+
+	.global	fn2
+	.type	fn2,@function
+fn2:
+	lea	-0x200(%rsp),%r10
+	cmp	%fs:0x70,%r10
+	jae	1f
+	callq	__morestack
+	retq
+1:
+	callq	fn1
+	retq
+
+	.size	fn2,. - fn2
+
+	.section	.note.GNU-stack,"",@progbits
+	.section	.note.GNU-split-stack,"",@progbits
Index: testsuite/split_x86_64_2.s
===================================================================
RCS file: testsuite/split_x86_64_2.s
diff -N testsuite/split_x86_64_2.s
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ testsuite/split_x86_64_2.s	6 Oct 2009 22:30:56 -0000
@@ -0,0 +1,33 @@
+# split_x86_64_2.s: x86_64 specific, -fsplit-stack calling non-split
+
+	.text
+
+	.global	fn1
+	.type	fn1,@function
+fn1:
+	cmp	%fs:0x70,%rsp
+	jae	1f
+	callq	__morestack
+	retq
+1:
+	callq	fn3
+	retq
+
+	.size	fn1,. - fn1
+
+	.global	fn2
+	.type	fn2,@function
+fn2:
+	lea	-0x200(%rsp),%r10
+	cmp	%fs:0x70,%r10
+	jae	1f
+	callq	__morestack
+	retq
+1:
+	callq	fn3
+	retq
+
+	.size	fn2,. - fn2
+
+	.section	.note.GNU-stack,"",@progbits
+	.section	.note.GNU-split-stack,"",@progbits
Index: testsuite/split_x86_64_3.s
===================================================================
RCS file: testsuite/split_x86_64_3.s
diff -N testsuite/split_x86_64_3.s
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ testsuite/split_x86_64_3.s	6 Oct 2009 22:30:56 -0000
@@ -0,0 +1,22 @@
+# split_x86_64_3.s: x86_64 specific, adjustment failure
+
+	.text
+
+	.global	fn1
+	.type	fn1,@function
+fn1:
+	push	%rbp
+	mov	%rsp,%rbp
+	cmp	%fs:0x70,%rsp
+	jae	1f
+	callq	__morestack
+	retq
+1:
+	callq	fn3
+	leaveq
+	retq
+
+	.size	fn1,. - fn1
+
+	.section	.note.GNU-stack,"",@progbits
+	.section	.note.GNU-split-stack,"",@progbits
Index: testsuite/split_x86_64_4.s
===================================================================
RCS file: testsuite/split_x86_64_4.s
diff -N testsuite/split_x86_64_4.s
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ testsuite/split_x86_64_4.s	6 Oct 2009 22:30:56 -0000
@@ -0,0 +1,23 @@
+# split_x86_64_4.s: x86_64 specific, permitted adjustment failure
+
+	.text
+
+	.global	fn1
+	.type	fn1,@function
+fn1:
+	push	%rbp
+	mov	%rsp,%rbp
+	cmp	%fs:0x70,%rsp
+	jae	1f
+	callq	__morestack
+	retq
+1:
+	callq	fn3
+	leaveq
+	retq
+
+	.size	fn1,. - fn1
+
+	.section	.note.GNU-stack,"",@progbits
+	.section	.note.GNU-split-stack,"",@progbits
+	.section	.note.GNU-no-split-stack,"",@progbits
Index: testsuite/split_x86_64_n.s
===================================================================
RCS file: testsuite/split_x86_64_n.s
diff -N testsuite/split_x86_64_n.s
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ testsuite/split_x86_64_n.s	6 Oct 2009 22:30:56 -0000
@@ -0,0 +1,12 @@
+# split_x86_64_n.s: x86_64 specific, -fsplit-stack calling non-split
+
+	.text
+
+	.global	fn3
+	.type	fn3,@function
+fn3:
+	retq
+
+	.size	fn3,. - fn3
+
+	.section	.note.GNU-stack,"",@progbits
Index: testsuite/testfile.cc
===================================================================
RCS file: /cvs/src/src/gold/testsuite/testfile.cc,v
retrieving revision 1.15
diff -u -u -p -r1.15 testfile.cc
--- testsuite/testfile.cc	22 Jun 2009 06:51:53 -0000	1.15
+++ testsuite/testfile.cc	6 Oct 2009 22:30:56 -0000
@@ -61,7 +61,7 @@ class Target_test : public Sized_target<
   relocate_section(const Relocate_info<size, big_endian>*, unsigned int,
 		   const unsigned char*, size_t, Output_section*, bool,
 		   unsigned char*, typename elfcpp::Elf_types<size>::Elf_Addr,
-		   section_size_type)
+		   section_size_type, const Reloc_symbol_changes*)
   { ERROR("call to Target_test::relocate_section"); }
 
   void

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]