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]

[PATCH, committed] Nios II CALL26 linker relaxation


The Nios II CALL and JMPI instructions take a 26-bit relocation that
encodes the low-order bits of a destination address in the same 256MB
memory segment as the source address.  Presently, the linker does
nothing but give a "relocation truncated to fit" error when such
relocations cross segment boundaries.

This patch was developed at the request of Altera to remove this restriction by having the linker add a trampoline within range of the original CALL/JMPI. The generic --relax/--no-relax linker command-line option controls generation of the trampolines (it defaults to being enabled).

There is also a new relocation added, R_NIOS2_CALL26_NOAT, which preserves the current behavior of R_NIOS2_CALL26 (no trampoline insertion). Like the assembler branch relaxations, the linker-generated trampolines use the AT register as a temporary, but it must not do this in code assembled with the .noat directive in effect, so the assembler emits the new relocation to mark non-relaxable calls for the linker. Altera has agreed to document this extension to the ABI in future revisions of the processor reference handbook.

I cut-and-pasted much of the implementation of the relaxation code from the metag backend, with some references also to ARM and other targets. The main differences compared to those other targets are that (a) the relocations are absolute rather than PC-relative, which affects the grouping strategy; and (b) when a section straddles a segment boundary, some stubs might need to be placed before the section and some after -- these are represented as different stub types in the code.

In addition to the test cases included with the patch, Altera beat on it for a while with a random test-case generator, so we're pretty confident that it's working. :-)

-Sandra

2014-01-30  Sandra Loosemore  <sandra@codesourcery.com>

	bfd/
	* bfd-in2.h: Update from reloc.c.
	* elf32-nios2.c: Include elf32-nios2.h.
	(elf_nios2_howto_table_rel): Add entry for R_NIOS2_CALL26_NOAT.
	(nios2_reloc_map): Likewise.
	(enum elf32_nios2_stub_type): Declare.
	(struct elf32_nios2_stub_hash_entry): Declare.
	(nios2_stub_hash_entry, nios2_stub_hash_lookup): New macros.
	(struct elf32_nios2_link_hash_entry): Add hsh_cache field.
	(struct elf32_nios2_link_hash_table): Add new fields bstab,
	stub_bfd, add_stub_section, layout_sections_again, stub_group,
	bfd_count, top_index, input_list, all_local_syms.
	(nios2_call26_stub_entry): New.
	(nios2_elf32_install_imm16): Move up in file.
	(nios2_elf32_install_data): Move up in file.
	(hiadj): Move up in file.
	(stub_hash_newfunc): New.
	(link_hash_newfunc): Initialize hsh_cache field.
	(STUB_SUFFIX): New.
	(nios2_stub_name): New.
	(nios2_get_stub_entry): New.
	(nios2_add_stub): New.
	(nios2_elf32_setup_section_lists): New.
	(nios2_elf32_next_input_section): New.
	(CALL26_SEGMENT): New.
	(MAX_STUB_SECTION_SIZE): New.
	(group_sections): New.
	(nios2_type_of_stub): New.
	(nios2_build_one_stub): New.
	(nios2_size_one_stub): New.
	(get_local_syms): New.
	(nios2_elf32_size_stubs): New.
	(nios2_elf32_build_stubs): New.
	(nios2_elf32_do_call26_relocate): Correct CALL26 overflow test.
	(nios2_elf32_relocate_section): Handle R_NIOS2_CALL26_NOAT.  Add
	trampolines for R_NIOS2_CALL26 stubs.
	(nios2_elf32_check_relocs): Handle R_NIOS2_CALL26_NOAT.
	(nios2_elf32_gc_sweep_hook): Likewise.
	(nios2_elf32_link_hash_table_create): Initialize the stub hash table.
	(nios2_elf32_link_hash_table_free): New.
	(bfd_elf32_bfd_link_hash_table_free): Define.
	* elf32-nios2.h: New file.
	* libbfd.h: Update from reloc.c.
	* reloc.c (BFD_RELOC_NIOS2_CALL26_NOAT): New.

	gas/
	* config/tc-nios2.c (md_apply_fix): Handle BFD_RELOC_NIOS2_CALL26_NOAT.
	(nios2_assemble_args_m): Likewise.
	(md_assemble): Likewise.

	gas/testsuite/
	* gas/nios2/call26_noat.d: New.
	* gas/nios2/call26_noat.s: New.
	* gas/nios2/call_noat.d: New.
	* gas/nios2/call_noat.s: New.

	include/elf/
	* nios2.h (elf_nios2_reloc_type): Add R_NIOS2_CALL26_NOAT.

	ld/
	* Makefile.am (enios2elf.c, enios2linux.c): Update dependencies.
	* Makefile.in: Regenerated.
	* emulparams/nios2elf.sh (EXTRA_EM_FILE): Set.
	* emulparams/nios2linux.sh (EXTRA_EM_FILE): Set.
	* emultempl/nios2elf.em: New file.
	* gen-doc.texi (NIOSII): Set.
	* ld.texinfo (NIOSII): Set.

	ld/testsuite/
	* ld-nios2/relax_call26.s: New.
	* ld-nios2/relax_call26_boundary.ld: New.
	* ld-nios2/relax_call26_boundary.s: New.
	* ld-nios2/relax_call26_boundary_c8.d: New.
	* ld-nios2/relax_call26_boundary_cc.d: New.
	* ld-nios2/relax_call26_boundary_d0.d: New.
	* ld-nios2/relax_call26_boundary_d4.d: New.
	* ld-nios2/relax_call26_boundary_d8.d: New.
	* ld-nios2/relax_call26_boundary_dc.d: New.
	* ld-nios2/relax_call26_boundary_f0.d: New.
	* ld-nios2/relax_call26_boundary_f4.d: New.
	* ld-nios2/relax_call26_boundary_f8.d: New.
	* ld-nios2/relax_call26_boundary_fc.d: New.
	* ld-nios2/relax_call26_cache.d: New.
	* ld-nios2/relax_call26_cache.ld: New.
	* ld-nios2/relax_call26_cache.s: New.
	* ld-nios2/relax_call26_multi.d: New.
	* ld-nios2/relax_call26_multi.ld: New.
	* ld-nios2/relax_call26_norelax.d: New.
	* ld-nios2/relax_call26_shared.d: New.
	* ld-nios2/relax_call26_shared.ld: New.
diff --git a/bfd/bfd-in2.h b/bfd/bfd-in2.h
index 71996db..f13467e 100644
--- a/bfd/bfd-in2.h
+++ b/bfd/bfd-in2.h
@@ -5204,6 +5204,7 @@ a matching LO8XG part.  */
   BFD_RELOC_NIOS2_JUMP_SLOT,
   BFD_RELOC_NIOS2_RELATIVE,
   BFD_RELOC_NIOS2_GOTOFF,
+  BFD_RELOC_NIOS2_CALL26_NOAT,
 
 /* IQ2000 Relocations.  */
   BFD_RELOC_IQ2000_OFFSET_16,
diff --git a/bfd/elf32-nios2.c b/bfd/elf32-nios2.c
index 82e5516..ba76898 100644
--- a/bfd/elf32-nios2.c
+++ b/bfd/elf32-nios2.c
@@ -30,6 +30,7 @@
 #include "elf-bfd.h"
 #include "elf/nios2.h"
 #include "opcode/nios2.h"
+#include "elf32-nios2.h"
 
 /* Use RELA relocations.  */
 #ifndef USE_RELA
@@ -655,6 +656,20 @@ static reloc_howto_type elf_nios2_howto_table_rel[] = {
 	 0xffffffff,
 	 FALSE),
 
+  HOWTO (R_NIOS2_CALL26_NOAT,	/* type */
+	 2,			/* rightshift */
+	 2,			/* size (0 = byte, 1 = short, 2 = long) */
+	 26,			/* bitsize */
+	 FALSE,			/* pc_relative */
+	 6,			/* bitpos */
+	 complain_overflow_dont,	/* complain on overflow */
+	 nios2_elf32_call26_relocate,	/* special function */
+	 "R_NIOS2_CALL26_NOAT",	/* name */
+	 FALSE,			/* partial_inplace */
+	 0xffffffc0,		/* src_mask */
+	 0xffffffc0,		/* dst_mask */
+	 FALSE),		/* pcrel_offset */
+
 /* Add other relocations here.  */
 };
 
@@ -732,9 +747,54 @@ static const struct elf_reloc_map nios2_reloc_map[] = {
   {BFD_RELOC_NIOS2_GLOB_DAT, R_NIOS2_GLOB_DAT},
   {BFD_RELOC_NIOS2_JUMP_SLOT, R_NIOS2_JUMP_SLOT},
   {BFD_RELOC_NIOS2_RELATIVE, R_NIOS2_RELATIVE},
-  {BFD_RELOC_NIOS2_GOTOFF, R_NIOS2_GOTOFF}
+  {BFD_RELOC_NIOS2_GOTOFF, R_NIOS2_GOTOFF},
+  {BFD_RELOC_NIOS2_CALL26_NOAT, R_NIOS2_CALL26_NOAT},
+};
+
+enum elf32_nios2_stub_type
+{
+  nios2_stub_call26_before,
+  nios2_stub_call26_after,
+  nios2_stub_none
+};
+
+struct elf32_nios2_stub_hash_entry
+{
+  /* Base hash table entry structure.  */
+  struct bfd_hash_entry bh_root;
+
+  /* The stub section.  */
+  asection *stub_sec;
+
+  /* Offset within stub_sec of the beginning of this stub.  */
+  bfd_vma stub_offset;
+
+  /* Given the symbol's value and its section we can determine its final
+     value when building the stubs (so the stub knows where to jump.  */
+  bfd_vma target_value;
+  asection *target_section;
+
+  enum elf32_nios2_stub_type stub_type;
+
+  /* The symbol table entry, if any, that this was derived from.  */
+  struct elf32_nios2_link_hash_entry *hh;
+
+  /* And the reloc addend that this was derived from.  */
+  bfd_vma addend;
+
+  /* Where this stub is being called from, or, in the case of combined
+     stub sections, the first input section in the group.  */
+  asection *id_sec;
 };
 
+#define nios2_stub_hash_entry(ent) \
+  ((struct elf32_nios2_stub_hash_entry *)(ent))
+
+#define nios2_stub_hash_lookup(table, string, create, copy) \
+  ((struct elf32_nios2_stub_hash_entry *) \
+   bfd_hash_lookup ((table), (string), (create), (copy)))
+
+
 /* The Nios II linker needs to keep track of the number of relocs that it
    decides to copy as dynamic relocs in check_relocs for each symbol.
    This is so that it can later discard them if they are found to be
@@ -761,6 +821,10 @@ struct elf32_nios2_link_hash_entry
 {
   struct elf_link_hash_entry root;
 
+  /* A pointer to the most recently used stub hash entry against this
+     symbol.  */
+  struct elf32_nios2_stub_hash_entry *hsh_cache;
+
   /* Track dynamic relocs copied for this symbol.  */
   struct elf32_nios2_dyn_relocs *dyn_relocs;
 
@@ -795,6 +859,34 @@ struct elf32_nios2_link_hash_table
     /* The main hash table.  */
     struct elf_link_hash_table root;
 
+    /* The stub hash table.  */
+    struct bfd_hash_table bstab;
+
+    /* Linker stub bfd.  */
+    bfd *stub_bfd;
+
+    /* Linker call-backs.  */
+    asection * (*add_stub_section) (const char *, asection *, bfd_boolean);
+    void (*layout_sections_again) (void);
+
+    /* Array to keep track of which stub sections have been created, and
+       information on stub grouping.  */
+    struct map_stub
+    {
+      /* These are the section to which stubs in the group will be
+	 attached.  */
+      asection *first_sec, *last_sec;
+      /* The stub sections.  There might be stubs inserted either before
+	 or after the real section.*/
+      asection *first_stub_sec, *last_stub_sec;
+    } *stub_group;
+
+    /* Assorted information used by nios2_elf32_size_stubs.  */
+    unsigned int bfd_count;
+    int top_index;
+    asection **input_list;
+    Elf_Internal_Sym **all_local_syms;
+
     /* Short-cuts to get to dynamic linker sections.  */
     asection *sdynbss;
     asection *srelbss;
@@ -865,6 +957,50 @@ static const bfd_vma nios2_so_plt0_entry[] = { /* .PLTresolve */
   0x6800683a	/* jmp r13 */
 };
 
+/* CALL26 stub.  */
+static const bfd_vma nios2_call26_stub_entry[] = {
+  0x00400034,	/* orhi at, r0, %hiadj(dest) */
+  0x08400004,	/* addi at, at, %lo(dest) */
+  0x0800683a	/* jmp at */
+};
+
+/* Install 16-bit immediate value VALUE at offset OFFSET into section SEC.  */
+static void
+nios2_elf32_install_imm16 (asection *sec, bfd_vma offset, bfd_vma value)
+{
+  bfd_vma word = bfd_get_32 (sec->owner, sec->contents + offset);
+
+  BFD_ASSERT(value <= 0xffff);
+
+  bfd_put_32 (sec->owner, word | ((value & 0xffff) << 6),
+	      sec->contents + offset);
+}
+
+/* Install COUNT 32-bit values DATA starting at offset OFFSET into
+   section SEC. */
+static void
+nios2_elf32_install_data (asection *sec, const bfd_vma *data, bfd_vma offset,
+			  int count)
+{
+  while (count--)
+    {
+      bfd_put_32 (sec->owner, *data, sec->contents + offset);
+      offset += 4;
+      ++data;
+    }
+}
+
+/* The usual way of loading a 32-bit constant into a Nios II register is to
+   load the high 16 bits in one instruction and then add the low 16 bits with
+   a signed add. This means that the high halfword needs to be adjusted to
+   compensate for the sign bit of the low halfword. This function returns the
+   adjusted high halfword for a given 32-bit constant.  */
+static
+bfd_vma hiadj (bfd_vma symbol_value)
+{
+  return ((symbol_value + 0x8000) >> 16) & 0xffff;
+}
+
 /* Implement elf_backend_grok_prstatus:
    Support for core dump NOTE sections.  */
 static bfd_boolean
@@ -928,6 +1064,44 @@ nios2_grok_psinfo (bfd *abfd, Elf_Internal_Note *note)
   return TRUE;
 }
 
+/* Assorted hash table functions.  */
+
+/* Initialize an entry in the stub hash table.  */
+static struct bfd_hash_entry *
+stub_hash_newfunc (struct bfd_hash_entry *entry,
+		   struct bfd_hash_table *table,
+		   const char *string)
+{
+  /* Allocate the structure if it has not already been allocated by a
+     subclass.  */
+  if (entry == NULL)
+    {
+      entry = bfd_hash_allocate (table,
+				 sizeof (struct elf32_nios2_stub_hash_entry));
+      if (entry == NULL)
+	return entry;
+    }
+
+  /* Call the allocation method of the superclass.  */
+  entry = bfd_hash_newfunc (entry, table, string);
+  if (entry != NULL)
+    {
+      struct elf32_nios2_stub_hash_entry *hsh;
+
+      /* Initialize the local fields.  */
+      hsh = (struct elf32_nios2_stub_hash_entry *) entry;
+      hsh->stub_sec = NULL;
+      hsh->stub_offset = 0;
+      hsh->target_value = 0;
+      hsh->target_section = NULL;
+      hsh->stub_type = nios2_stub_none;
+      hsh->hh = NULL;
+      hsh->id_sec = NULL;
+    }
+
+  return entry;
+}
+
 /* Create an entry in a Nios II ELF linker hash table.  */
 static struct bfd_hash_entry *
 link_hash_newfunc (struct bfd_hash_entry *entry,
@@ -950,6 +1124,7 @@ link_hash_newfunc (struct bfd_hash_entry *entry,
       struct elf32_nios2_link_hash_entry *eh;
 
       eh = (struct elf32_nios2_link_hash_entry *) entry;
+      eh->hsh_cache = NULL;
       eh->dyn_relocs = NULL;
       eh->tls_type = GOT_UNKNOWN;
       eh->got_types_used = 0;
@@ -958,6 +1133,841 @@ link_hash_newfunc (struct bfd_hash_entry *entry,
   return entry;
 }
 
+/* Section name for stubs is the associated section name plus this
+   string.  */
+#define STUB_SUFFIX ".stub"
+
+/* Build a name for an entry in the stub hash table.  */
+static char *
+nios2_stub_name (const asection *input_section,
+		 const asection *sym_sec,
+		 const struct elf32_nios2_link_hash_entry *hh,
+		 const Elf_Internal_Rela *rel,
+		 enum elf32_nios2_stub_type stub_type)
+{
+  char *stub_name;
+  bfd_size_type len;
+  char stubpos = (stub_type == nios2_stub_call26_before) ? 'b' : 'a';
+
+  if (hh)
+    {
+      len = 8 + 1 + 1 + 1+ strlen (hh->root.root.root.string) + 1 + 8 + 1;
+      stub_name = bfd_malloc (len);
+      if (stub_name != NULL)
+	{
+	  sprintf (stub_name, "%08x_%c_%s+%x",
+		   input_section->id & 0xffffffff,
+		   stubpos,
+		   hh->root.root.root.string,
+		   (int) rel->r_addend & 0xffffffff);
+	}
+    }
+  else
+    {
+      len = 8 + 1 + 1 + 1+ 8 + 1 + 8 + 1 + 8 + 1;
+      stub_name = bfd_malloc (len);
+      if (stub_name != NULL)
+	{
+	  sprintf (stub_name, "%08x_%c_%x:%x+%x",
+		   input_section->id & 0xffffffff,
+		   stubpos,
+		   sym_sec->id & 0xffffffff,
+		   (int) ELF32_R_SYM (rel->r_info) & 0xffffffff,
+		   (int) rel->r_addend & 0xffffffff);
+	}
+    }
+  return stub_name;
+}
+
+/* Look up an entry in the stub hash.  Stub entries are cached because
+   creating the stub name takes a bit of time.  */
+static struct elf32_nios2_stub_hash_entry *
+nios2_get_stub_entry (const asection *input_section,
+		      const asection *sym_sec,
+		      struct elf32_nios2_link_hash_entry *hh,
+		      const Elf_Internal_Rela *rel,
+		      struct elf32_nios2_link_hash_table *htab,
+		      enum elf32_nios2_stub_type stub_type)
+{
+  struct elf32_nios2_stub_hash_entry *hsh;
+  const asection *id_sec;
+
+  /* If this input section is part of a group of sections sharing one
+     stub section, then use the id of the first/last section in the group,
+     depending on the stub section placement relative to the group.
+     Stub names need to include a section id, as there may well be
+     more than one stub used to reach say, printf, and we need to
+     distinguish between them.  */
+  if (stub_type == nios2_stub_call26_before)
+    id_sec = htab->stub_group[input_section->id].first_sec;
+  else
+    id_sec = htab->stub_group[input_section->id].last_sec;
+
+  if (hh != NULL && hh->hsh_cache != NULL
+      && hh->hsh_cache->hh == hh
+      && hh->hsh_cache->id_sec == id_sec
+      && hh->hsh_cache->stub_type == stub_type)
+    {
+      hsh = hh->hsh_cache;
+    }
+  else
+    {
+      char *stub_name;
+
+      stub_name = nios2_stub_name (id_sec, sym_sec, hh, rel, stub_type);
+      if (stub_name == NULL)
+	return NULL;
+
+      hsh = nios2_stub_hash_lookup (&htab->bstab,
+				    stub_name, FALSE, FALSE);
+
+      if (hh != NULL)
+	hh->hsh_cache = hsh;
+
+      free (stub_name);
+    }
+
+  return hsh;
+}
+
+/* Add a new stub entry to the stub hash.  Not all fields of the new
+   stub entry are initialised.  */
+static struct elf32_nios2_stub_hash_entry *
+nios2_add_stub (const char *stub_name,
+		asection *section,
+		struct elf32_nios2_link_hash_table *htab,
+		enum elf32_nios2_stub_type stub_type)
+{
+  asection *link_sec;
+  asection *stub_sec;
+  asection **secptr, **linkptr;
+  struct elf32_nios2_stub_hash_entry *hsh;
+  bfd_boolean afterp;
+
+  if (stub_type == nios2_stub_call26_before)
+    {
+      link_sec = htab->stub_group[section->id].first_sec;
+      secptr = &(htab->stub_group[section->id].first_stub_sec);
+      linkptr = &(htab->stub_group[link_sec->id].first_stub_sec);
+      afterp = FALSE;
+    }
+  else
+    {
+      link_sec = htab->stub_group[section->id].last_sec;
+      secptr = &(htab->stub_group[section->id].last_stub_sec);
+      linkptr = &(htab->stub_group[link_sec->id].last_stub_sec);
+      afterp = TRUE;
+    }
+  stub_sec = *secptr;
+  if (stub_sec == NULL)
+    {
+      stub_sec = *linkptr;
+      if (stub_sec == NULL)
+	{
+	  size_t namelen;
+	  bfd_size_type len;
+	  char *s_name;
+
+	  namelen = strlen (link_sec->name);
+	  len = namelen + sizeof (STUB_SUFFIX);
+	  s_name = bfd_alloc (htab->stub_bfd, len);
+	  if (s_name == NULL)
+	    return NULL;
+
+	  memcpy (s_name, link_sec->name, namelen);
+	  memcpy (s_name + namelen, STUB_SUFFIX, sizeof (STUB_SUFFIX));
+
+	  stub_sec = (*htab->add_stub_section) (s_name, link_sec, afterp);
+	  if (stub_sec == NULL)
+	    return NULL;
+	  *linkptr = stub_sec;
+	}
+      *secptr = stub_sec;
+    }
+
+  /* Enter this entry into the linker stub hash table.  */
+  hsh = nios2_stub_hash_lookup (&htab->bstab, stub_name,
+				TRUE, FALSE);
+  if (hsh == NULL)
+    {
+      (*_bfd_error_handler) (_("%B: cannot create stub entry %s"),
+			     section->owner,
+			     stub_name);
+      return NULL;
+    }
+
+  hsh->stub_sec = stub_sec;
+  hsh->stub_offset = 0;
+  hsh->id_sec = link_sec;
+  return hsh;
+}
+
+/* Set up various things so that we can make a list of input sections
+   for each output section included in the link.  Returns -1 on error,
+   0 when no stubs will be needed, and 1 on success.  */
+int
+nios2_elf32_setup_section_lists (bfd *output_bfd, struct bfd_link_info *info)
+{
+  bfd *input_bfd;
+  unsigned int bfd_count;
+  int top_id, top_index;
+  asection *section;
+  asection **input_list, **list;
+  bfd_size_type amt;
+  struct elf32_nios2_link_hash_table *htab = elf32_nios2_hash_table (info);
+
+  /* Count the number of input BFDs and find the top input section id.  */
+  for (input_bfd = info->input_bfds, bfd_count = 0, top_id = 0;
+       input_bfd != NULL;
+       input_bfd = input_bfd->link_next)
+    {
+      bfd_count += 1;
+      for (section = input_bfd->sections;
+	   section != NULL;
+	   section = section->next)
+	{
+	  if (top_id < section->id)
+	    top_id = section->id;
+	}
+    }
+
+  htab->bfd_count = bfd_count;
+
+  amt = sizeof (struct map_stub) * (top_id + 1);
+  htab->stub_group = bfd_zmalloc (amt);
+  if (htab->stub_group == NULL)
+    return -1;
+
+  /* We can't use output_bfd->section_count here to find the top output
+     section index as some sections may have been removed, and
+     strip_excluded_output_sections doesn't renumber the indices.  */
+  for (section = output_bfd->sections, top_index = 0;
+       section != NULL;
+       section = section->next)
+    {
+      if (top_index < section->index)
+	top_index = section->index;
+    }
+
+  htab->top_index = top_index;
+  amt = sizeof (asection *) * (top_index + 1);
+  input_list = bfd_malloc (amt);
+  htab->input_list = input_list;
+  if (input_list == NULL)
+    return -1;
+
+  /* For sections we aren't interested in, mark their entries with a
+     value we can check later.  */
+  list = input_list + top_index;
+  do
+    *list = bfd_abs_section_ptr;
+  while (list-- != input_list);
+
+  for (section = output_bfd->sections;
+       section != NULL;
+       section = section->next)
+    {
+      /* FIXME: This is a bit of hack. Currently our .ctors and .dtors
+       * have PC relative relocs in them but no code flag set.  */
+      if (((section->flags & SEC_CODE) != 0) ||
+	  strcmp(".ctors", section->name) ||
+	  strcmp(".dtors", section->name))
+	input_list[section->index] = NULL;
+    }
+
+  return 1;
+}
+
+/* The linker repeatedly calls this function for each input section,
+   in the order that input sections are linked into output sections.
+   Build lists of input sections to determine groupings between which
+   we may insert linker stubs.  */
+void
+nios2_elf32_next_input_section (struct bfd_link_info *info, asection *isec)
+{
+  struct elf32_nios2_link_hash_table *htab = elf32_nios2_hash_table (info);
+
+  if (isec->output_section->index <= htab->top_index)
+    {
+      asection **list = htab->input_list + isec->output_section->index;
+      if (*list != bfd_abs_section_ptr)
+	{
+	  /* Steal the last_sec pointer for our list.
+	     This happens to make the list in reverse order,
+	     which is what we want.  */
+	  htab->stub_group[isec->id].last_sec = *list;
+	  *list = isec;
+	}
+    }
+}
+
+/* Segment mask for CALL26 relocation relaxation.  */
+#define CALL26_SEGMENT(x) ((x) & 0xf0000000)
+
+/* Fudge factor for approximate maximum size of all stubs that might
+   be inserted by the linker.  This does not actually limit the number
+   of stubs that might be inserted, and only affects strategy for grouping
+   and placement of stubs.  Perhaps this should be computed based on number
+   of relocations seen, or be specifiable on the command line.  */
+#define MAX_STUB_SECTION_SIZE 0xffff
+
+/* See whether we can group stub sections together.  Grouping stub
+   sections may result in fewer stubs.  More importantly, we need to
+   put all .init* and .fini* stubs at the end of the .init or
+   .fini output sections respectively, because glibc splits the
+   _init and _fini functions into multiple parts.  Putting a stub in
+   the middle of a function is not a good idea.
+   Rather than computing groups of a maximum fixed size, for Nios II
+   CALL26 relaxation it makes more sense to compute the groups based on
+   sections that fit within a 256MB address segment.  Also do not allow
+   a group to span more than one output section, since different output
+   sections might correspond to different memory banks on a bare-metal
+   target, etc.  */
+static void
+group_sections (struct elf32_nios2_link_hash_table *htab)
+{
+  asection **list = htab->input_list + htab->top_index;
+  do
+    {
+      /* The list is in reverse order so we'll search backwards looking
+	 for the first section that begins in the same memory segment,
+	 marking sections along the way to point at the tail for this
+	 group.  */
+      asection *tail = *list;
+      if (tail == bfd_abs_section_ptr)
+	continue;
+      while (tail != NULL)
+	{
+	  bfd_vma start = tail->output_section->vma + tail->output_offset;
+	  bfd_vma end = start + tail->size;
+	  bfd_vma segment = CALL26_SEGMENT (end);
+	  asection *prev;
+
+	  if (segment != CALL26_SEGMENT (start)
+	      || segment != CALL26_SEGMENT (end + MAX_STUB_SECTION_SIZE))
+	    /* This section spans more than one memory segment, or is
+	       close enough to the end of the segment that adding stub
+	       sections before it might cause it to move so that it
+	       spans memory segments, or that stubs added at the end of
+	       this group might overflow into the next memory segment.
+	       Put it in a group by itself to localize the effects.  */
+	    {
+	      prev = htab->stub_group[tail->id].last_sec;
+	      htab->stub_group[tail->id].last_sec = tail;
+	      htab->stub_group[tail->id].first_sec = tail;
+	    }
+	  else
+	    /* Collect more sections for this group.  */
+	    {
+	      asection *curr, *first;
+	      for (curr = tail; ; curr = prev)
+		{
+		  prev = htab->stub_group[curr->id].last_sec;
+		  if (!prev
+		      || tail->output_section != prev->output_section
+		      || (CALL26_SEGMENT (prev->output_section->vma
+					  + prev->output_offset)
+			  != segment))
+		    break;
+		}
+	      first = curr;
+	      for (curr = tail; ; curr = prev)
+		{
+		  prev = htab->stub_group[curr->id].last_sec;
+		  htab->stub_group[curr->id].last_sec = tail;
+		  htab->stub_group[curr->id].first_sec = first;
+		  if (curr == first)
+		    break;
+		}
+	    }
+
+	  /* Reset tail for the next group.  */
+	  tail = prev;
+	}
+    }
+  while (list-- != htab->input_list);
+  free (htab->input_list);
+}
+
+/* Determine the type of stub needed, if any, for a call.  */
+static enum elf32_nios2_stub_type
+nios2_type_of_stub (asection *input_sec,
+		    const Elf_Internal_Rela *rel,
+		    struct elf32_nios2_link_hash_entry *hh,
+		    struct elf32_nios2_link_hash_table *htab,
+		    bfd_vma destination,
+		    struct bfd_link_info *info ATTRIBUTE_UNUSED)
+{
+  bfd_vma location, segment, start, end;
+  asection *s0, *s1, *s;
+
+  if (hh != NULL &&
+      !(hh->root.root.type == bfd_link_hash_defined
+	|| hh->root.root.type == bfd_link_hash_defweak))
+    return nios2_stub_none;
+
+  /* Determine where the call point is.  */
+  location = (input_sec->output_section->vma
+	      + input_sec->output_offset + rel->r_offset);
+  segment = CALL26_SEGMENT (location);
+
+  /* Nios II CALL and JMPI instructions can transfer control to addresses
+     within the same 256MB segment as the PC.  */
+  if (segment == CALL26_SEGMENT (destination))
+    return nios2_stub_none;
+
+  /* Find the start and end addresses of the stub group.  Also account for
+     any already-created stub sections for this group.  Note that for stubs
+     in the end section, only the first instruction of the last stub
+     (12 bytes long) needs to be within range.  */
+  s0 = htab->stub_group[input_sec->id].first_sec;
+  s = htab->stub_group[s0->id].first_stub_sec;
+  if (s != NULL && s->size > 0)
+    start = s->output_section->vma + s->output_offset;
+  else
+    start = s0->output_section->vma + s0->output_offset;
+
+  s1 = htab->stub_group[input_sec->id].last_sec;
+  s = htab->stub_group[s1->id].last_stub_sec;
+  if (s != NULL && s->size > 0)
+    end = s->output_section->vma + s->output_offset + s->size - 8;
+  else
+    end = s1->output_section->vma + s1->output_offset + s1->size;
+
+  BFD_ASSERT (start < end);
+  BFD_ASSERT (start <= location);
+  BFD_ASSERT (location < end);
+
+  /* Put stubs at the end of the group unless that is not a valid
+     location and the beginning of the group is.  It might be that
+     neither the beginning nor end works if we have an input section
+     so large that it spans multiple segment boundaries.  In that
+     case, punt; the end result will be a relocation overflow error no
+     matter what we do here.
+
+     Note that adding stubs pushes up the addresses of all subsequent
+     sections, so that stubs allocated on one pass through the
+     relaxation loop may not be valid on the next pass.  (E.g., we may
+     allocate a stub at the beginning of the section on one pass and
+     find that the call site has been bumped into the next memory
+     segment on the next pass.)  The important thing to note is that
+     we never try to reclaim the space allocated to such unused stubs,
+     so code size and section addresses can only increase with each
+     iteration.  Accounting for the start and end addresses of the
+     already-created stub sections ensures that when the algorithm
+     converges, it converges accurately, with the entire appropriate
+     stub section accessible from the call site and not just the
+     address at the start or end of the stub group proper.  */
+
+  if (segment == CALL26_SEGMENT (end))
+    return nios2_stub_call26_after;
+  else if (segment == CALL26_SEGMENT (start))
+    return nios2_stub_call26_before;
+  else
+    /* Perhaps this should be a dedicated error code.  */
+    return nios2_stub_none;
+}
+
+static bfd_boolean
+nios2_build_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg ATTRIBUTE_UNUSED)
+{
+  struct elf32_nios2_stub_hash_entry *hsh
+    = (struct elf32_nios2_stub_hash_entry *) gen_entry;
+  asection *stub_sec = hsh->stub_sec;
+  bfd_vma sym_value;
+
+  /* Make a note of the offset within the stubs for this entry.  */
+  hsh->stub_offset = stub_sec->size;
+
+  switch (hsh->stub_type)
+    {
+    case nios2_stub_call26_before:
+    case nios2_stub_call26_after:
+      /* A call26 stub looks like:
+	   orhi at, %hiadj(dest)
+	   addi at, at, %lo(dest)
+	   jmp at
+	 Note that call/jmpi instructions can't be used in PIC code
+	 so there is no reason for the stub to be PIC, either.  */
+      sym_value = (hsh->target_value
+		   + hsh->target_section->output_offset
+		   + hsh->target_section->output_section->vma
+		   + hsh->addend);
+
+      nios2_elf32_install_data (stub_sec, nios2_call26_stub_entry,
+				hsh->stub_offset, 3);
+      nios2_elf32_install_imm16 (stub_sec, hsh->stub_offset,
+				 hiadj (sym_value));
+      nios2_elf32_install_imm16 (stub_sec, hsh->stub_offset + 4,
+				 (sym_value & 0xffff));
+      stub_sec->size += 12;
+      break;
+    default:
+      BFD_FAIL ();
+      return FALSE;
+    }
+
+  return TRUE;
+}
+
+/* As above, but don't actually build the stub.  Just bump offset so
+   we know stub section sizes.  */
+static bfd_boolean
+nios2_size_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg ATTRIBUTE_UNUSED)
+{
+  struct elf32_nios2_stub_hash_entry *hsh
+    = (struct elf32_nios2_stub_hash_entry *) gen_entry;
+
+  switch (hsh->stub_type)
+    {
+    case nios2_stub_call26_before:
+    case nios2_stub_call26_after:
+      hsh->stub_sec->size += 12;
+      break;
+    default:
+      BFD_FAIL ();
+      return FALSE;
+    }
+  return TRUE;
+}
+
+/* Read in all local syms for all input bfds.
+   Returns -1 on error, 0 otherwise.  */
+
+static int
+get_local_syms (bfd *output_bfd ATTRIBUTE_UNUSED, bfd *input_bfd,
+		struct bfd_link_info *info)
+{
+  unsigned int bfd_indx;
+  Elf_Internal_Sym *local_syms, **all_local_syms;
+  struct elf32_nios2_link_hash_table *htab = elf32_nios2_hash_table (info);
+
+  /* We want to read in symbol extension records only once.  To do this
+     we need to read in the local symbols in parallel and save them for
+     later use; so hold pointers to the local symbols in an array.  */
+  bfd_size_type amt = sizeof (Elf_Internal_Sym *) * htab->bfd_count;
+  all_local_syms = bfd_zmalloc (amt);
+  htab->all_local_syms = all_local_syms;
+  if (all_local_syms == NULL)
+    return -1;
+
+  /* Walk over all the input BFDs, swapping in local symbols.  */
+  for (bfd_indx = 0;
+       input_bfd != NULL;
+       input_bfd = input_bfd->link_next, bfd_indx++)
+    {
+      Elf_Internal_Shdr *symtab_hdr;
+
+      /* We'll need the symbol table in a second.  */
+      symtab_hdr = &elf_tdata (input_bfd)->symtab_hdr;
+      if (symtab_hdr->sh_info == 0)
+	continue;
+
+      /* We need an array of the local symbols attached to the input bfd.  */
+      local_syms = (Elf_Internal_Sym *) symtab_hdr->contents;
+      if (local_syms == NULL)
+	{
+	  local_syms = bfd_elf_get_elf_syms (input_bfd, symtab_hdr,
+					     symtab_hdr->sh_info, 0,
+					     NULL, NULL, NULL);
+	  /* Cache them for elf_link_input_bfd.  */
+	  symtab_hdr->contents = (unsigned char *) local_syms;
+	}
+      if (local_syms == NULL)
+	return -1;
+
+      all_local_syms[bfd_indx] = local_syms;
+    }
+
+  return 0;
+}
+
+/* Determine and set the size of the stub section for a final link.  */
+bfd_boolean
+nios2_elf32_size_stubs (bfd *output_bfd, bfd *stub_bfd,
+			struct bfd_link_info *info,
+			asection *(*add_stub_section) (const char *,
+						       asection *, bfd_boolean),
+			void (*layout_sections_again) (void))
+{
+  bfd_boolean stub_changed = FALSE;
+  struct elf32_nios2_link_hash_table *htab = elf32_nios2_hash_table (info);
+
+  /* Stash our params away.  */
+  htab->stub_bfd = stub_bfd;
+  htab->add_stub_section = add_stub_section;
+  htab->layout_sections_again = layout_sections_again;
+
+  /* FIXME: We only compute the section groups once.  This could cause
+     problems if adding a large stub section causes following sections,
+     or parts of them, to move into another segment.  However, this seems
+     to be consistent with the way other back ends handle this....  */
+  group_sections (htab);
+
+  if (get_local_syms (output_bfd, info->input_bfds, info))
+    {
+      if (htab->all_local_syms)
+	goto error_ret_free_local;
+      return FALSE;
+    }
+
+  while (1)
+    {
+      bfd *input_bfd;
+      unsigned int bfd_indx;
+      asection *stub_sec;
+
+      for (input_bfd = info->input_bfds, bfd_indx = 0;
+	   input_bfd != NULL;
+	   input_bfd = input_bfd->link_next, bfd_indx++)
+	{
+	  Elf_Internal_Shdr *symtab_hdr;
+	  asection *section;
+	  Elf_Internal_Sym *local_syms;
+
+	  /* We'll need the symbol table in a second.  */
+	  symtab_hdr = &elf_tdata (input_bfd)->symtab_hdr;
+	  if (symtab_hdr->sh_info == 0)
+	    continue;
+
+	  local_syms = htab->all_local_syms[bfd_indx];
+
+	  /* Walk over each section attached to the input bfd.  */
+	  for (section = input_bfd->sections;
+	       section != NULL;
+	       section = section->next)
+	    {
+	      Elf_Internal_Rela *internal_relocs, *irelaend, *irela;
+
+	      /* If there aren't any relocs, then there's nothing more
+		 to do.  */
+	      if ((section->flags & SEC_RELOC) == 0
+		  || section->reloc_count == 0)
+		continue;
+
+	      /* If this section is a link-once section that will be
+		 discarded, then don't create any stubs.  */
+	      if (section->output_section == NULL
+		  || section->output_section->owner != output_bfd)
+		continue;
+
+	      /* Get the relocs.  */
+	      internal_relocs
+		= _bfd_elf_link_read_relocs (input_bfd, section, NULL, NULL,
+					     info->keep_memory);
+	      if (internal_relocs == NULL)
+		goto error_ret_free_local;
+
+	      /* Now examine each relocation.  */
+	      irela = internal_relocs;
+	      irelaend = irela + section->reloc_count;
+	      for (; irela < irelaend; irela++)
+		{
+		  unsigned int r_type, r_indx;
+		  enum elf32_nios2_stub_type stub_type;
+		  struct elf32_nios2_stub_hash_entry *hsh;
+		  asection *sym_sec;
+		  bfd_vma sym_value;
+		  bfd_vma destination;
+		  struct elf32_nios2_link_hash_entry *hh;
+		  char *stub_name;
+		  const asection *id_sec;
+
+		  r_type = ELF32_R_TYPE (irela->r_info);
+		  r_indx = ELF32_R_SYM (irela->r_info);
+
+		  if (r_type >= (unsigned int) R_NIOS2_ILLEGAL)
+		    {
+		      bfd_set_error (bfd_error_bad_value);
+		    error_ret_free_internal:
+		      if (elf_section_data (section)->relocs == NULL)
+			free (internal_relocs);
+		      goto error_ret_free_local;
+		    }
+
+		  /* Only look for stubs on CALL and JMPI instructions.  */
+		  if (r_type != (unsigned int) R_NIOS2_CALL26)
+		    continue;
+
+		  /* Now determine the call target, its name, value,
+		     section.  */
+		  sym_sec = NULL;
+		  sym_value = 0;
+		  destination = 0;
+		  hh = NULL;
+		  if (r_indx < symtab_hdr->sh_info)
+		    {
+		      /* It's a local symbol.  */
+		      Elf_Internal_Sym *sym;
+		      Elf_Internal_Shdr *hdr;
+		      unsigned int shndx;
+
+		      sym = local_syms + r_indx;
+		      if (ELF_ST_TYPE (sym->st_info) != STT_SECTION)
+			sym_value = sym->st_value;
+		      shndx = sym->st_shndx;
+		      if (shndx < elf_numsections (input_bfd))
+			{
+			  hdr = elf_elfsections (input_bfd)[shndx];
+			  sym_sec = hdr->bfd_section;
+			  destination = (sym_value + irela->r_addend
+					 + sym_sec->output_offset
+					 + sym_sec->output_section->vma);
+			}
+		    }
+		  else
+		    {
+		      /* It's an external symbol.  */
+		      int e_indx;
+
+		      e_indx = r_indx - symtab_hdr->sh_info;
+		      hh = ((struct elf32_nios2_link_hash_entry *)
+			    elf_sym_hashes (input_bfd)[e_indx]);
+
+		      while (hh->root.root.type == bfd_link_hash_indirect
+			     || hh->root.root.type == bfd_link_hash_warning)
+			hh = ((struct elf32_nios2_link_hash_entry *)
+			      hh->root.root.u.i.link);
+
+		      if (hh->root.root.type == bfd_link_hash_defined
+			  || hh->root.root.type == bfd_link_hash_defweak)
+			{
+			  sym_sec = hh->root.root.u.def.section;
+			  sym_value = hh->root.root.u.def.value;
+
+			  if (sym_sec->output_section != NULL)
+			    destination = (sym_value + irela->r_addend
+					   + sym_sec->output_offset
+					   + sym_sec->output_section->vma);
+			  else
+			    continue;
+			}
+		      else if (hh->root.root.type == bfd_link_hash_undefweak)
+			{
+			  if (! info->shared)
+			    continue;
+			}
+		      else if (hh->root.root.type == bfd_link_hash_undefined)
+			{
+			  if (! (info->unresolved_syms_in_objects == RM_IGNORE
+				 && (ELF_ST_VISIBILITY (hh->root.other)
+				     == STV_DEFAULT)))
+			    continue;
+			}
+		      else
+			{
+			  bfd_set_error (bfd_error_bad_value);
+			  goto error_ret_free_internal;
+			}
+		    }
+
+		  /* Determine what (if any) linker stub is needed.  */
+		  stub_type = nios2_type_of_stub (section, irela, hh, htab,
+						  destination, info);
+		  if (stub_type == nios2_stub_none)
+		    continue;
+
+		  /* Support for grouping stub sections.  */
+		  if (stub_type == nios2_stub_call26_before)
+		    id_sec = htab->stub_group[section->id].first_sec;
+		  else
+		    id_sec = htab->stub_group[section->id].last_sec;
+
+		  /* Get the name of this stub.  */
+		  stub_name = nios2_stub_name (id_sec, sym_sec, hh, irela,
+					       stub_type);
+		  if (!stub_name)
+		    goto error_ret_free_internal;
+
+		  hsh = nios2_stub_hash_lookup (&htab->bstab,
+						stub_name,
+						FALSE, FALSE);
+		  if (hsh != NULL)
+		    {
+		      /* The proper stub has already been created.  */
+		      free (stub_name);
+		      continue;
+		    }
+
+		  hsh = nios2_add_stub (stub_name, section, htab, stub_type);
+		  if (hsh == NULL)
+		    {
+		      free (stub_name);
+		      goto error_ret_free_internal;
+		    }
+		  hsh->target_value = sym_value;
+		  hsh->target_section = sym_sec;
+		  hsh->stub_type = stub_type;
+		  hsh->hh = hh;
+		  hsh->addend = irela->r_addend;
+		  stub_changed = TRUE;
+		}
+
+	      /* We're done with the internal relocs, free them.  */
+	      if (elf_section_data (section)->relocs == NULL)
+		free (internal_relocs);
+	    }
+	}
+
+      if (!stub_changed)
+	break;
+
+      /* OK, we've added some stubs.  Find out the new size of the
+	 stub sections.  */
+      for (stub_sec = htab->stub_bfd->sections;
+	   stub_sec != NULL;
+	   stub_sec = stub_sec->next)
+	stub_sec->size = 0;
+
+      bfd_hash_traverse (&htab->bstab, nios2_size_one_stub, htab);
+
+      /* Ask the linker to do its stuff.  */
+      (*htab->layout_sections_again) ();
+      stub_changed = FALSE;
+    }
+
+  free (htab->all_local_syms);
+  return TRUE;
+
+ error_ret_free_local:
+  free (htab->all_local_syms);
+  return FALSE;
+}
+
+/* Build all the stubs associated with the current output file.  The
+   stubs are kept in a hash table attached to the main linker hash
+   table.  This function is called via nios2elf_finish in the linker.  */
+bfd_boolean
+nios2_elf32_build_stubs (struct bfd_link_info *info)
+{
+  asection *stub_sec;
+  struct bfd_hash_table *table;
+  struct elf32_nios2_link_hash_table *htab;
+
+  htab = elf32_nios2_hash_table (info);
+
+  for (stub_sec = htab->stub_bfd->sections;
+       stub_sec != NULL;
+       stub_sec = stub_sec->next)
+    {
+      bfd_size_type size;
+
+      /* Allocate memory to hold the linker stubs.  */
+      size = stub_sec->size;
+      stub_sec->contents = bfd_zalloc (htab->stub_bfd, size);
+      if (stub_sec->contents == NULL && size != 0)
+	return FALSE;
+      stub_sec->size = 0;
+    }
+
+  /* Build the stubs as directed by the stub hash table.  */
+  table = &htab->bstab;
+  bfd_hash_traverse (table, nios2_build_one_stub, info);
+
+  return TRUE;
+}
+
+
 /* Implement bfd_elf32_bfd_reloc_type_lookup:
    Given a BFD reloc type, return a howto structure.  */
 static reloc_howto_type *
@@ -1122,17 +2132,6 @@ nios2_elf_final_gp (bfd *output_bfd, asymbol *symbol, bfd_boolean relocatable,
   return bfd_reloc_ok;
 }
 
-/* The usual way of loading a 32-bit constant into a Nios II register is to
-   load the high 16 bits in one instruction and then add the low 16 bits with
-   a signed add. This means that the high halfword needs to be adjusted to
-   compensate for the sign bit of the low halfword. This function returns the
-   adjusted high halfword for a given 32-bit constant.  */
-static
-bfd_vma hiadj (bfd_vma symbol_value)
-{
-  return ((symbol_value + 0x8000) >> 16) & 0xffff;
-}
-
 /* Do the relocations that require special handling.  */
 static bfd_reloc_status_type
 nios2_elf32_do_hi16_relocate (bfd *abfd, reloc_howto_type *howto, 
@@ -1223,8 +2222,10 @@ nios2_elf32_do_call26_relocate (bfd *abfd, reloc_howto_type *howto,
 				bfd_vma symbol_value, bfd_vma addend)
 {
   /* Check that the relocation is in the same page as the current address.  */
-  if (((symbol_value + addend) & 0xf0000000)
-      != ((input_section->output_section->vma + offset) & 0xf0000000))
+  if (CALL26_SEGMENT (symbol_value + addend) 
+      != CALL26_SEGMENT (input_section->output_section->vma
+			 + input_section->output_offset
+			 + offset))
     return bfd_reloc_overflow;
 
   return _bfd_final_link_relocate (howto, abfd, input_section,
@@ -1840,6 +2841,7 @@ nios2_elf32_relocate_section (bfd *output_bfd,
 						 rel->r_addend);
 	      break;
 	    case R_NIOS2_CALL26:
+	    case R_NIOS2_CALL26_NOAT:
 	      /* If we have a call to an undefined weak symbol, we just want
 		 to stuff a zero in the bits of the call instruction and
 		 bypass the normal call26 relocation handling, because it'll
@@ -1873,6 +2875,46 @@ nios2_elf32_relocate_section (bfd *output_bfd,
 
 		  unresolved_reloc = FALSE;
 		}
+	      /* Detect R_NIOS2_CALL26 relocations that would overflow the
+		 256MB segment.  Replace the target with a reference to a
+		 trampoline instead.
+		 Note that htab->stub_group is null if relaxation has been
+		 disabled by the --no-relax linker command-line option, so
+		 we can use that to skip this processing entirely.  */
+	      if (howto->type == R_NIOS2_CALL26 && htab->stub_group)
+		{
+		  bfd_vma dest = relocation + rel->r_addend;
+		  enum elf32_nios2_stub_type stub_type;
+
+		  eh = (struct elf32_nios2_link_hash_entry *)h;
+		  stub_type = nios2_type_of_stub (input_section, rel, eh,
+						  htab, dest, NULL);
+
+		  if (stub_type != nios2_stub_none)
+		    {
+		      struct elf32_nios2_stub_hash_entry *hsh;
+
+		      hsh = nios2_get_stub_entry (input_section, sec,
+						  eh, rel, htab, stub_type);
+		      if (hsh == NULL)
+			{
+			  r = bfd_reloc_undefined;
+			  break;
+			}
+
+		      dest = (hsh->stub_offset
+			      + hsh->stub_sec->output_offset
+			      + hsh->stub_sec->output_section->vma);
+		      r = nios2_elf32_do_call26_relocate (input_bfd, howto,
+							  input_section,
+							  contents,
+							  rel->r_offset,
+							  dest, 0);
+		      break;
+		    }
+		}
+
+	      /* Normal case.  */
 	      r = nios2_elf32_do_call26_relocate (input_bfd, howto,
 						  input_section, contents,
 						  rel->r_offset, relocation,
@@ -2739,6 +3781,7 @@ nios2_elf32_check_relocs (bfd *abfd, struct bfd_link_info *info,
 
 	case R_NIOS2_BFD_RELOC_32:
 	case R_NIOS2_CALL26:
+	case R_NIOS2_CALL26_NOAT:
 	case R_NIOS2_HIADJ16:
 	case R_NIOS2_LO16:
 
@@ -2757,7 +3800,7 @@ nios2_elf32_check_relocs (bfd *abfd, struct bfd_link_info *info,
 		 turns out to be a function defined by a dynamic object.  */
 	      h->plt.refcount++;
 
-	      if (r_type == R_NIOS2_CALL26)
+	      if (r_type == R_NIOS2_CALL26 || r_type == R_NIOS2_CALL26_NOAT)
 		h->needs_plt = 1;
 	    }
 
@@ -2920,6 +3963,7 @@ nios2_elf32_gc_sweep_hook (bfd *abfd,
 	case R_NIOS2_PCREL_HA:
 	case R_NIOS2_BFD_RELOC_32:
 	case R_NIOS2_CALL26:
+	case R_NIOS2_CALL26_NOAT:
 	  if (h != NULL)
 	    {
 	      struct elf32_nios2_link_hash_entry *eh;
@@ -2955,32 +3999,6 @@ nios2_elf32_gc_sweep_hook (bfd *abfd,
   return TRUE;
 }
 
-/* Install 16-bit immediate value VALUE at offset OFFSET into section SEC.  */
-static void
-nios2_elf32_install_imm16 (asection *sec, bfd_vma offset, bfd_vma value)
-{
-  bfd_vma word = bfd_get_32 (sec->owner, sec->contents + offset);
-
-  BFD_ASSERT(value <= 0xffff);
-
-  bfd_put_32 (sec->owner, word | ((value & 0xffff) << 6),
-	      sec->contents + offset);
-}
-
-/* Install COUNT 32-bit values DATA starting at offset OFFSET into
-   section SEC. */
-static void
-nios2_elf32_install_data (asection *sec, const bfd_vma *data, bfd_vma offset,
-			  int count)
-{
-  while (count--)
-    {
-      bfd_put_32 (sec->owner, *data, sec->contents + offset);
-      offset += 4;
-      ++data;
-    }
-}
-
 /* Implement elf_backend_finish_dynamic_symbols:
    Finish up dynamic symbol handling.  We set the contents of various
    dynamic sections here.  */
@@ -3969,9 +4987,25 @@ nios2_elf32_link_hash_table_create (bfd *abfd)
       return NULL;
     }
 
+  /* Init the stub hash table too.  */
+  if (!bfd_hash_table_init (&ret->bstab, stub_hash_newfunc,
+			    sizeof (struct elf32_nios2_stub_hash_entry)))
+    return NULL;
+
   return &ret->root.root;
 }
 
+/* Free the derived linker hash table.  */
+static void
+nios2_elf32_link_hash_table_free (struct bfd_link_hash_table *btab)
+{
+  struct elf32_nios2_link_hash_table *htab
+    = (struct elf32_nios2_link_hash_table *) btab;
+
+  bfd_hash_table_free (&htab->bstab);
+  _bfd_elf_link_hash_table_free (btab);
+}
+
 /* Implement elf_backend_reloc_type_class.  */
 static enum elf_reloc_type_class
 nios2_elf32_reloc_type_class (const struct bfd_link_info *info ATTRIBUTE_UNUSED,
@@ -4078,6 +5112,8 @@ const struct bfd_elf_special_section elf32_nios2_special_sections[] =
 
 #define bfd_elf32_bfd_link_hash_table_create \
 					  nios2_elf32_link_hash_table_create
+#define bfd_elf32_bfd_link_hash_table_free \
+					  nios2_elf32_link_hash_table_free
 
 /* Relocation table lookup macros.  */
 
diff --git a/bfd/elf32-nios2.h b/bfd/elf32-nios2.h
new file mode 100644
index 0000000..e6e0920
--- /dev/null
+++ b/bfd/elf32-nios2.h
@@ -0,0 +1,38 @@
+/* Nios II support for 32-bit ELF
+   Copyright (C) 2013, 2014 Free Software Foundation, Inc.
+   Contributed by Mentor Graphics
+
+   This file is part of BFD, the Binary File Descriptor library.
+
+   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.  */
+
+#ifndef _ELF32_NIOS2_H
+#define _ELF32_NIOS2_H
+
+extern int nios2_elf32_setup_section_lists
+  (bfd *, struct bfd_link_info *);
+
+extern void nios2_elf32_next_input_section
+  (struct bfd_link_info *, asection *);
+
+extern bfd_boolean nios2_elf32_size_stubs
+  (bfd *, bfd *, struct bfd_link_info *, 
+   asection * (*) (const char *, asection *, bfd_boolean), void (*) (void));
+
+extern bfd_boolean nios2_elf32_build_stubs
+  (struct bfd_link_info *);
+
+#endif  /* _ELF32_NIOS2_H */
diff --git a/bfd/libbfd.h b/bfd/libbfd.h
index 87605b9..9711e17 100644
--- a/bfd/libbfd.h
+++ b/bfd/libbfd.h
@@ -2532,6 +2532,7 @@ static const char *const bfd_reloc_code_real_names[] = { "@@uninitialized@@",
   "BFD_RELOC_NIOS2_JUMP_SLOT",
   "BFD_RELOC_NIOS2_RELATIVE",
   "BFD_RELOC_NIOS2_GOTOFF",
+  "BFD_RELOC_NIOS2_CALL26_NOAT",
   "BFD_RELOC_IQ2000_OFFSET_16",
   "BFD_RELOC_IQ2000_OFFSET_21",
   "BFD_RELOC_IQ2000_UHI16",
diff --git a/bfd/reloc.c b/bfd/reloc.c
index 0d191f1..3d1256d 100644
--- a/bfd/reloc.c
+++ b/bfd/reloc.c
@@ -6065,6 +6065,8 @@ ENUMX
   BFD_RELOC_NIOS2_RELATIVE
 ENUMX
   BFD_RELOC_NIOS2_GOTOFF
+ENUMX
+  BFD_RELOC_NIOS2_CALL26_NOAT
 ENUMDOC
   Relocations used by the Altera Nios II core.
 
diff --git a/gas/config/tc-nios2.c b/gas/config/tc-nios2.c
index 08b7aec..eb81b35 100644
--- a/gas/config/tc-nios2.c
+++ b/gas/config/tc-nios2.c
@@ -1139,6 +1139,7 @@ md_apply_fix (fixS *fixP, valueT *valP, segT seg ATTRIBUTE_UNUSED)
 		  || fixP->fx_r_type == BFD_RELOC_NIOS2_U16
 		  || fixP->fx_r_type == BFD_RELOC_16_PCREL
 		  || fixP->fx_r_type == BFD_RELOC_NIOS2_CALL26
+		  || fixP->fx_r_type == BFD_RELOC_NIOS2_CALL26_NOAT
 		  || fixP->fx_r_type == BFD_RELOC_NIOS2_IMM5
 		  || fixP->fx_r_type == BFD_RELOC_NIOS2_CACHE_OPX
 		  || fixP->fx_r_type == BFD_RELOC_NIOS2_IMM6
@@ -1595,7 +1596,10 @@ nios2_assemble_args_m (nios2_insn_infoS *insn_info)
       unsigned long immed
 	= nios2_assemble_expression (insn_info->insn_tokens[1], insn_info,
 				     insn_info->insn_reloc,
-				     BFD_RELOC_NIOS2_CALL26, 0);
+				     (nios2_as_options.noat
+				      ? BFD_RELOC_NIOS2_CALL26_NOAT
+				      : BFD_RELOC_NIOS2_CALL26),
+				     0);
 
       SET_INSN_FIELD (IMM26, insn_info->insn_code, immed);
       nios2_check_assembly (insn_info->insn_code, insn_info->insn_tokens[2]);
@@ -2728,7 +2732,10 @@ md_assemble (char *op_str)
 		   && !nios2_as_options.noat
 		   && insn->insn_nios2_opcode->pinfo & NIOS2_INSN_CALL
 		   && insn->insn_reloc
-		   && insn->insn_reloc->reloc_type == BFD_RELOC_NIOS2_CALL26)
+		   && ((insn->insn_reloc->reloc_type
+			== BFD_RELOC_NIOS2_CALL26)
+		       || (insn->insn_reloc->reloc_type
+			   == BFD_RELOC_NIOS2_CALL26_NOAT)))
 	    output_call (insn);
 	  else if (insn->insn_nios2_opcode->pinfo & NIOS2_INSN_ANDI)
 	    output_andi (insn);
diff --git a/gas/testsuite/gas/nios2/call26_noat.d b/gas/testsuite/gas/nios2/call26_noat.d
new file mode 100644
index 0000000..34bfe4e
--- /dev/null
+++ b/gas/testsuite/gas/nios2/call26_noat.d
@@ -0,0 +1,76 @@
+#objdump: -dr --prefix-addresses --show-raw-insn
+#name: NIOS2 nios2-reloc-r-nios2-call26-noat
+
+# Test the branch instructions.
+.*: +file format elf32-littlenios2
+
+Disassembly of section .text:
+[	]*\.\.\.
+[	]*0: R_NIOS2_CALL26_NOAT	.text\+0x100
+[	]*4: R_NIOS2_CALL26_NOAT	globalfunc
+0+0008 <[^>]*> 0001883a 	nop
+0+000c <[^>]*> 0001883a 	nop
+0+0010 <[^>]*> 0001883a 	nop
+0+0014 <[^>]*> 0001883a 	nop
+0+0018 <[^>]*> 0001883a 	nop
+0+001c <[^>]*> 0001883a 	nop
+0+0020 <[^>]*> 0001883a 	nop
+0+0024 <[^>]*> 0001883a 	nop
+0+0028 <[^>]*> 0001883a 	nop
+0+002c <[^>]*> 0001883a 	nop
+0+0030 <[^>]*> 0001883a 	nop
+0+0034 <[^>]*> 0001883a 	nop
+0+0038 <[^>]*> 0001883a 	nop
+0+003c <[^>]*> 0001883a 	nop
+0+0040 <[^>]*> 0001883a 	nop
+0+0044 <[^>]*> 0001883a 	nop
+0+0048 <[^>]*> 0001883a 	nop
+0+004c <[^>]*> 0001883a 	nop
+0+0050 <[^>]*> 0001883a 	nop
+0+0054 <[^>]*> 0001883a 	nop
+0+0058 <[^>]*> 0001883a 	nop
+0+005c <[^>]*> 0001883a 	nop
+0+0060 <[^>]*> 0001883a 	nop
+0+0064 <[^>]*> 0001883a 	nop
+0+0068 <[^>]*> 0001883a 	nop
+0+006c <[^>]*> 0001883a 	nop
+0+0070 <[^>]*> 0001883a 	nop
+0+0074 <[^>]*> 0001883a 	nop
+0+0078 <[^>]*> 0001883a 	nop
+0+007c <[^>]*> 0001883a 	nop
+0+0080 <[^>]*> 0001883a 	nop
+0+0084 <[^>]*> 0001883a 	nop
+0+0088 <[^>]*> 0001883a 	nop
+0+008c <[^>]*> 0001883a 	nop
+0+0090 <[^>]*> 0001883a 	nop
+0+0094 <[^>]*> 0001883a 	nop
+0+0098 <[^>]*> 0001883a 	nop
+0+009c <[^>]*> 0001883a 	nop
+0+00a0 <[^>]*> 0001883a 	nop
+0+00a4 <[^>]*> 0001883a 	nop
+0+00a8 <[^>]*> 0001883a 	nop
+0+00ac <[^>]*> 0001883a 	nop
+0+00b0 <[^>]*> 0001883a 	nop
+0+00b4 <[^>]*> 0001883a 	nop
+0+00b8 <[^>]*> 0001883a 	nop
+0+00bc <[^>]*> 0001883a 	nop
+0+00c0 <[^>]*> 0001883a 	nop
+0+00c4 <[^>]*> 0001883a 	nop
+0+00c8 <[^>]*> 0001883a 	nop
+0+00cc <[^>]*> 0001883a 	nop
+0+00d0 <[^>]*> 0001883a 	nop
+0+00d4 <[^>]*> 0001883a 	nop
+0+00d8 <[^>]*> 0001883a 	nop
+0+00dc <[^>]*> 0001883a 	nop
+0+00e0 <[^>]*> 0001883a 	nop
+0+00e4 <[^>]*> 0001883a 	nop
+0+00e8 <[^>]*> 0001883a 	nop
+0+00ec <[^>]*> 0001883a 	nop
+0+00f0 <[^>]*> 0001883a 	nop
+0+00f4 <[^>]*> 0001883a 	nop
+0+00f8 <[^>]*> 0001883a 	nop
+0+00fc <[^>]*> 0001883a 	nop
+0+0100 <[^>]*> 0001883a 	nop
+	...
+
+
diff --git a/gas/testsuite/gas/nios2/call26_noat.s b/gas/testsuite/gas/nios2/call26_noat.s
new file mode 100644
index 0000000..f0a93e7
--- /dev/null
+++ b/gas/testsuite/gas/nios2/call26_noat.s
@@ -0,0 +1,13 @@
+# Test for Nios II 32-bit relocations
+
+.global globalfunc
+.text
+.set norelax
+.set noat
+start:
+	call localfunc
+	call globalfunc
+
+.align 8	
+localfunc:
+	nop
diff --git a/gas/testsuite/gas/nios2/call_noat.d b/gas/testsuite/gas/nios2/call_noat.d
new file mode 100644
index 0000000..03aadb5
--- /dev/null
+++ b/gas/testsuite/gas/nios2/call_noat.d
@@ -0,0 +1,11 @@
+# objdump: -dr --prefix-addresses --show-raw-insn
+#name: NIOS2 call noat
+
+.*: +file format elf32-littlenios2
+
+Disassembly of section .text:
+0+0000 <[^>]*> 00000000 	call	00000000 <[^>]*>
+[	]*0: R_NIOS2_CALL26_NOAT	.text\+0xc
+0+0004 <[^>]*> 503ee83a 	callr	r10
+0+0008 <[^>]*> 00000000 	call	00000000 <[^>]*>
+[	]*8: R_NIOS2_CALL26_NOAT	external
diff --git a/gas/testsuite/gas/nios2/call_noat.s b/gas/testsuite/gas/nios2/call_noat.s
new file mode 100644
index 0000000..67613b7
--- /dev/null
+++ b/gas/testsuite/gas/nios2/call_noat.s
@@ -0,0 +1,14 @@
+# Source file used to test the call and callr instructions
+.text
+.set norelax
+.set noat
+foo:
+	call	func1
+	callr	r10
+# use external symbol
+	.global external
+	call	external
+func1:
+	
+
+
diff --git a/include/elf/nios2.h b/include/elf/nios2.h
index ff5947b..7686350 100644
--- a/include/elf/nios2.h
+++ b/include/elf/nios2.h
@@ -75,7 +75,8 @@ START_RELOC_NUMBERS (elf_nios2_reloc_type)
   RELOC_NUMBER (R_NIOS2_JUMP_SLOT, 38)
   RELOC_NUMBER (R_NIOS2_RELATIVE, 39)
   RELOC_NUMBER (R_NIOS2_GOTOFF, 40)
-  RELOC_NUMBER (R_NIOS2_ILLEGAL, 41)
+  RELOC_NUMBER (R_NIOS2_CALL26_NOAT,  41)
+  RELOC_NUMBER (R_NIOS2_ILLEGAL, 42)
 END_RELOC_NUMBERS (R_NIOS2_maxext)
 
 /* Processor-specific section flags.  */
diff --git a/ld/Makefile.am b/ld/Makefile.am
index 3499e72..5968668 100644
--- a/ld/Makefile.am
+++ b/ld/Makefile.am
@@ -1497,10 +1497,12 @@ enews.c: $(srcdir)/emulparams/news.sh \
   $(srcdir)/emultempl/generic.em $(srcdir)/scripttempl/aout.sc ${GEN_DEPENDS}
 	${GENSCRIPTS} news "$(tdir_news)"
 enios2elf.c: $(srcdir)/emulparams/nios2elf.sh \
-  $(ELF_DEPS) $(srcdir)/scripttempl/elf.sc ${GEN_DEPENDS}
+  $(srcdir)/emultempl/elf32.em $(srcdir)/emultempl/nios2elf.em \
+  $(srcdir)/scripttempl/elf.sc ${GEN_DEPENDS}
 	${GENSCRIPTS} nios2elf "$(tdir_nios2elf)"
 enios2linux.c: $(srcdir)/emulparams/nios2linux.sh \
-  $(ELF_DEPS) $(srcdir)/scripttempl/elf.sc ${GEN_DEPENDS}
+  $(srcdir)/emultempl/elf32.em $(srcdir)/emultempl/nios2elf.em \
+  $(srcdir)/scripttempl/elf.sc ${GEN_DEPENDS}
 	${GENSCRIPTS} nios2linux "$(tdir_nios2linux)"
 ens32knbsd.c:	$(srcdir)/emulparams/ns32knbsd.sh \
   $(srcdir)/emultempl/generic.em $(srcdir)/emultempl/netbsd.em \
diff --git a/ld/Makefile.in b/ld/Makefile.in
index 0119a74..59cba73 100644
--- a/ld/Makefile.in
+++ b/ld/Makefile.in
@@ -2929,10 +2929,12 @@ enews.c: $(srcdir)/emulparams/news.sh \
   $(srcdir)/emultempl/generic.em $(srcdir)/scripttempl/aout.sc ${GEN_DEPENDS}
 	${GENSCRIPTS} news "$(tdir_news)"
 enios2elf.c: $(srcdir)/emulparams/nios2elf.sh \
-  $(ELF_DEPS) $(srcdir)/scripttempl/elf.sc ${GEN_DEPENDS}
+  $(srcdir)/emultempl/elf32.em $(srcdir)/emultempl/nios2elf.em \
+  $(srcdir)/scripttempl/elf.sc ${GEN_DEPENDS}
 	${GENSCRIPTS} nios2elf "$(tdir_nios2elf)"
 enios2linux.c: $(srcdir)/emulparams/nios2linux.sh \
-  $(ELF_DEPS) $(srcdir)/scripttempl/elf.sc ${GEN_DEPENDS}
+  $(srcdir)/emultempl/elf32.em $(srcdir)/emultempl/nios2elf.em \
+  $(srcdir)/scripttempl/elf.sc ${GEN_DEPENDS}
 	${GENSCRIPTS} nios2linux "$(tdir_nios2linux)"
 ens32knbsd.c:	$(srcdir)/emulparams/ns32knbsd.sh \
   $(srcdir)/emultempl/generic.em $(srcdir)/emultempl/netbsd.em \
diff --git a/ld/emulparams/nios2elf.sh b/ld/emulparams/nios2elf.sh
index 767f3de..7ccde97 100644
--- a/ld/emulparams/nios2elf.sh
+++ b/ld/emulparams/nios2elf.sh
@@ -1,6 +1,6 @@
 SCRIPT_NAME=elf
 TEMPLATE_NAME=elf32
-EXTRA_EM_FILE=
+EXTRA_EM_FILE=nios2elf
 OUTPUT_FORMAT="elf32-littlenios2"
 LITTLE_OUTPUT_FORMAT="elf32-littlenios2"
 BIG_OUTPUT_FORMAT="elf32-bignios2"
diff --git a/ld/emulparams/nios2linux.sh b/ld/emulparams/nios2linux.sh
index aa409a9..f215177 100644
--- a/ld/emulparams/nios2linux.sh
+++ b/ld/emulparams/nios2linux.sh
@@ -1,6 +1,6 @@
 SCRIPT_NAME=elf
 TEMPLATE_NAME=elf32
-EXTRA_EM_FILE=
+EXTRA_EM_FILE="nios2elf"
 OUTPUT_FORMAT="elf32-littlenios2"
 LITTLE_OUTPUT_FORMAT="elf32-littlenios2"
 BIG_OUTPUT_FORMAT="elf32-bignios2"
diff --git a/ld/emultempl/nios2elf.em b/ld/emultempl/nios2elf.em
new file mode 100644
index 0000000..c86eba1
--- /dev/null
+++ b/ld/emultempl/nios2elf.em
@@ -0,0 +1,317 @@
+# This shell script emits a C file. -*- C -*-
+#   Copyright (C) 2013, 2014 Free Software Foundation, Inc.
+#
+# This file is part of GNU Binutils.
+#
+# 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.
+#
+
+# This file is sourced from elf32.em, and defines extra Nios II ELF
+# specific routines. Taken from metagelf.em.
+#
+fragment <<EOF
+
+#include "ldctor.h"
+#include "elf32-nios2.h"
+
+
+/* Fake input file for stubs.  */
+static lang_input_statement_type *stub_file;
+
+/* Whether we need to call nios2_layout_sections_again.  */
+static int need_laying_out = 0;
+
+
+/* This is called before the input files are opened.  We create a new
+   fake input file to hold the stub sections.  */
+
+static void
+nios2elf_create_output_section_statements (void)
+{
+  extern const bfd_target bfd_elf32_littlenios2_vec, bfd_elf32_bignios2_vec;
+
+  if (link_info.output_bfd->xvec != &bfd_elf32_littlenios2_vec
+      && link_info.output_bfd->xvec != &bfd_elf32_bignios2_vec)
+    return;
+
+  /* If --no-relax was not explicitly specified by the user, enable
+     relaxation.  If it's not enabled (either explicitly or by default),
+     we're done, as we won't need to create any stubs.  */
+  if (!link_info.relocatable && RELAXATION_DISABLED_BY_DEFAULT)
+    ENABLE_RELAXATION;
+  if (!RELAXATION_ENABLED)
+    return;
+
+  stub_file = lang_add_input_file ("linker stubs",
+				   lang_input_file_is_fake_enum,
+				   NULL);
+  stub_file->the_bfd = bfd_create ("linker stubs", link_info.output_bfd);
+  if (stub_file->the_bfd == NULL
+      || ! bfd_set_arch_mach (stub_file->the_bfd,
+			      bfd_get_arch (link_info.output_bfd),
+			      bfd_get_mach (link_info.output_bfd)))
+    {
+      einfo ("%X%P: can not create BFD %E\n");
+      return;
+    }
+
+  stub_file->the_bfd->flags |= BFD_LINKER_CREATED;
+  ldlang_add_file (stub_file);
+}
+
+
+struct hook_stub_info
+{
+  lang_statement_list_type add;
+  asection *input_section;
+};
+
+/* Traverse the linker tree to find the spot where the stub goes.  */
+
+static bfd_boolean
+hook_in_stub (struct hook_stub_info *info, lang_statement_union_type **lp,
+	      bfd_boolean afterp)
+{
+  lang_statement_union_type *l;
+  bfd_boolean ret;
+
+  for (; (l = *lp) != NULL; lp = &l->header.next)
+    {
+      switch (l->header.type)
+	{
+	case lang_constructors_statement_enum:
+	  ret = hook_in_stub (info, &constructor_list.head, afterp);
+	  if (ret)
+	    return ret;
+	  break;
+
+	case lang_output_section_statement_enum:
+	  ret = hook_in_stub (info,
+			      &l->output_section_statement.children.head,
+			      afterp);
+	  if (ret)
+	    return ret;
+	  break;
+
+	case lang_wild_statement_enum:
+	  ret = hook_in_stub (info, &l->wild_statement.children.head, afterp);
+	  if (ret)
+	    return ret;
+	  break;
+
+	case lang_group_statement_enum:
+	  ret = hook_in_stub (info, &l->group_statement.children.head, afterp);
+	  if (ret)
+	    return ret;
+	  break;
+
+	case lang_input_section_enum:
+	  if (l->input_section.section == info->input_section)
+	    {
+	      /* We've found our section.  Insert the stub immediately
+		 before or after its associated input section.  */
+	      if (afterp)
+		{
+		  *(info->add.tail) = l->header.next;
+		  l->header.next = info->add.head;
+		}
+	      else
+		{
+		  *lp = info->add.head;
+		  *(info->add.tail) = l;
+		}
+	      return TRUE;
+	    }
+	  break;
+
+	case lang_data_statement_enum:
+	case lang_reloc_statement_enum:
+	case lang_object_symbols_statement_enum:
+	case lang_output_statement_enum:
+	case lang_target_statement_enum:
+	case lang_input_statement_enum:
+	case lang_assignment_statement_enum:
+	case lang_padding_statement_enum:
+	case lang_address_statement_enum:
+	case lang_fill_statement_enum:
+	  break;
+
+	default:
+	  FAIL ();
+	  break;
+	}
+    }
+  return FALSE;
+}
+
+/* Call-back for elf32_nios2_size_stubs.  */
+
+/* Create a new stub section, and arrange for it to be linked
+   immediately before or after INPUT_SECTION, according to AFTERP.  */
+
+static asection *
+nios2elf_add_stub_section (const char *stub_sec_name, asection *input_section,
+			   bfd_boolean afterp)
+{
+  asection *stub_sec;
+  flagword flags;
+  asection *output_section;
+  const char *secname;
+  lang_output_section_statement_type *os;
+  struct hook_stub_info info;
+
+  flags = (SEC_ALLOC | SEC_LOAD | SEC_READONLY | SEC_CODE
+	   | SEC_HAS_CONTENTS | SEC_RELOC | SEC_IN_MEMORY | SEC_KEEP);
+  stub_sec = bfd_make_section_anyway_with_flags (stub_file->the_bfd,
+						 stub_sec_name, flags);
+  if (stub_sec == NULL)
+    goto err_ret;
+
+  output_section = input_section->output_section;
+  secname = bfd_get_section_name (output_section->owner, output_section);
+  os = lang_output_section_find (secname);
+
+  info.input_section = input_section;
+  lang_list_init (&info.add);
+  lang_add_section (&info.add, stub_sec, NULL, os);
+
+  if (info.add.head == NULL)
+    goto err_ret;
+
+  if (hook_in_stub (&info, &os->children.head, afterp))
+    return stub_sec;
+
+ err_ret:
+  einfo ("%X%P: can not make stub section: %E\n");
+  return NULL;
+}
+
+
+/* Another call-back for elf32_nios2_size_stubs.  */
+
+static void
+nios2elf_layout_sections_again (void)
+{
+  /* If we have changed sizes of the stub sections, then we need
+     to recalculate all the section offsets.  This may mean we need to
+     add even more stubs.  */
+  gld${EMULATION_NAME}_map_segments (TRUE);
+  need_laying_out = -1;
+}
+
+
+static void
+build_section_lists (lang_statement_union_type *statement)
+{
+  if (statement->header.type == lang_input_section_enum)
+    {
+      asection *i = statement->input_section.section;
+
+      if (i->sec_info_type != SEC_INFO_TYPE_JUST_SYMS
+	  && (i->flags & SEC_EXCLUDE) == 0
+	  && i->output_section != NULL
+	  && i->output_section->owner == link_info.output_bfd)
+	{
+	  nios2_elf32_next_input_section (&link_info, i);
+	}
+    }
+}
+
+
+/* For Nios II we use this opportunity to build linker stubs.  */
+
+static void
+gld${EMULATION_NAME}_after_allocation (void)
+{
+  /* bfd_elf_discard_info just plays with data and debugging sections,
+     ie. doesn't affect code size, so we can delay resizing the
+     sections.  It's likely we'll resize everything in the process of
+     adding stubs.  */
+  if (bfd_elf_discard_info (link_info.output_bfd, &link_info))
+    need_laying_out = 1;
+
+  /* If generating a relocatable output file, then we don't
+     have to examine the relocs.  */
+  if (stub_file != NULL && !link_info.relocatable && RELAXATION_ENABLED)
+    {
+      int ret = nios2_elf32_setup_section_lists (link_info.output_bfd,
+						 &link_info);
+
+      if (ret != 0)
+	{
+	  if (ret < 0)
+	    {
+	      einfo ("%X%P: can not size stub section: %E\n");
+	      return;
+	    }
+
+	  lang_for_each_statement (build_section_lists);
+
+	  /* Call into the BFD backend to do the real work.  */
+	  if (! nios2_elf32_size_stubs (link_info.output_bfd,
+					stub_file->the_bfd,
+					&link_info,
+					&nios2elf_add_stub_section,
+					&nios2elf_layout_sections_again))
+	    {
+	      einfo ("%X%P: can not size stub section: %E\n");
+	      return;
+	    }
+	}
+    }
+
+  if (need_laying_out != -1)
+    gld${EMULATION_NAME}_map_segments (need_laying_out);
+
+  if (!link_info.relocatable && RELAXATION_ENABLED)
+    {
+      /* Now build the linker stubs.  */
+      if (stub_file != NULL && stub_file->the_bfd->sections != NULL)
+	{
+	  if (! nios2_elf32_build_stubs (&link_info))
+	    einfo ("%X%P: can not build stubs: %E\n");
+	}
+    }
+}
+
+
+/* Avoid processing the fake stub_file in vercheck, stat_needed and
+   check_needed routines.  */
+
+static void (*real_func) (lang_input_statement_type *);
+
+static void nios2_for_each_input_file_wrapper (lang_input_statement_type *l)
+{
+  if (l != stub_file)
+    (*real_func) (l);
+}
+
+static void
+nios2_lang_for_each_input_file (void (*func) (lang_input_statement_type *))
+{
+  real_func = func;
+  lang_for_each_input_file (&nios2_for_each_input_file_wrapper);
+}
+
+#define lang_for_each_input_file nios2_lang_for_each_input_file
+
+EOF
+
+
+# Put these extra nios2elf routines in ld_${EMULATION_NAME}_emulation
+#
+LDEMUL_AFTER_ALLOCATION=gld${EMULATION_NAME}_after_allocation
+LDEMUL_CREATE_OUTPUT_SECTION_STATEMENTS=nios2elf_create_output_section_statements
diff --git a/ld/gen-doc.texi b/ld/gen-doc.texi
index acc6c57..ede1e08 100644
--- a/ld/gen-doc.texi
+++ b/ld/gen-doc.texi
@@ -18,6 +18,7 @@
 @set MMIX
 @set MSP430
 @set NDS32
+@set NIOSII
 @set POWERPC
 @set POWERPC64
 @set Renesas
diff --git a/ld/ld.texinfo b/ld/ld.texinfo
index a8e5ea6..1287a6c 100644
--- a/ld/ld.texinfo
+++ b/ld/ld.texinfo
@@ -30,6 +30,7 @@
 @set MMIX
 @set MSP430
 @set NDS32
+@set NIOSII
 @set POWERPC
 @set POWERPC64
 @set Renesas
@@ -1605,6 +1606,9 @@ This option is only supported on a few targets.
 @ifset M68HC11
 @xref{M68HC11/68HC12,,@command{ld} and the 68HC11 and 68HC12}.
 @end ifset
+@ifset NIOSII
+@xref{Nios II,,@command{ld} and the Altera Nios II}.
+@end ifset
 @ifset POWERPC
 @xref{PowerPC ELF32,,@command{ld} and PowerPC 32-bit ELF Support}.
 @end ifset
@@ -6105,6 +6109,9 @@ functionality are not listed.
 @ifset NDS32
 * NDS32::			@command{ld} and NDS32
 @end ifset
+@ifset NIOSII
+* Nios II::			@command{ld} and the Altera Nios II
+@end ifset
 @ifset POWERPC
 * PowerPC ELF32::		@command{ld} and PowerPC 32-bit ELF Support
 @end ifset
@@ -6743,6 +6750,43 @@ Avoid generating the IFC instruction inside the loop.
 @end ifclear
 @end ifset
 
+@ifset NIOSII
+@ifclear GENERIC
+@raisesections
+@end ifclear
+
+@node Nios II
+@section @command{ld} and the Altera Nios II
+@cindex Nios II call relaxation
+@kindex --relax on Nios II
+
+Call and immediate jump instructions on Nios II processors are limited to
+transferring control to addresses in the same 256MB memory segment,
+which may result in @command{ld} giving
+@samp{relocation truncated to fit} errors with very large programs.
+The command-line option @option{--relax} enables the generation of
+trampolines that can access the entire 32-bit address space for calls
+outside the normal @code{call} and @code{jmpi} address range.  These
+trampolines are inserted at section boundaries, so may not themselves
+be reachable if an input section and its associated call trampolines are
+larger than 256MB.
+
+The @option{--relax} option is enabled by default unless @option{-r}
+is also specified.  You can disable trampoline generation by using the
+@option{--no-relax} linker option.  You can also disable this optimization
+locally by using the @samp{set .noat} directive in assembly-language
+source files, as the linker-inserted trampolines use the @code{at}
+register as a temporary.
+
+Note that the linker @option{--relax} option is independent of assembler
+relaxation options, and that using the GNU assembler's @option{-relax-all}
+option interferes with the linker's more selective call instruction relaxation.
+
+@ifclear GENERIC
+@lowersections
+@end ifclear
+@end ifset
+
 @ifset POWERPC
 @ifclear GENERIC
 @raisesections
diff --git a/ld/testsuite/ld-nios2/relax_call26.s b/ld/testsuite/ld-nios2/relax_call26.s
new file mode 100644
index 0000000..b3b28df
--- /dev/null
+++ b/ld/testsuite/ld-nios2/relax_call26.s
@@ -0,0 +1,27 @@
+# test for call26 relaxation via linker stubs
+
+.globl text0
+.section text0, "ax", @progbits
+	call func0	# in same section
+	call func1	# in nearby section
+	call func2a	# in distant section
+	jmpi func2b	# also in distant section
+
+func0:
+	ret
+
+.section text1, "ax", @progbits
+func1:
+	nop
+	nop
+	call func2a	# in distant section
+	ret
+
+.section text2, "ax", @progbits
+func2a:
+	nop
+	nop
+	nop
+	ret
+func2b:
+	nop
diff --git a/ld/testsuite/ld-nios2/relax_call26_boundary.ld b/ld/testsuite/ld-nios2/relax_call26_boundary.ld
new file mode 100644
index 0000000..313ef8c
--- /dev/null
+++ b/ld/testsuite/ld-nios2/relax_call26_boundary.ld
@@ -0,0 +1,14 @@
+/* Simple script for testing call26 relaxation via linker stubs.
+   This script is used for a bunch of tests that vary the placement of
+   section text0 near a 256 memory segment boundary, by using
+   --section-start command-line options.  */
+
+OUTPUT_FORMAT("elf32-littlenios2", "elf32-littlenios2", "elf32-littlenios2")
+OUTPUT_ARCH(nios2)
+ENTRY(_start)
+SECTIONS
+{
+	_start = .;
+	text0 : { *(text0) *(text1) }
+	text2 0x40000000 : { *(text2) }
+}
diff --git a/ld/testsuite/ld-nios2/relax_call26_boundary.s b/ld/testsuite/ld-nios2/relax_call26_boundary.s
new file mode 100644
index 0000000..ce79ebd
--- /dev/null
+++ b/ld/testsuite/ld-nios2/relax_call26_boundary.s
@@ -0,0 +1,29 @@
+# Test for call26 relaxation via linker stubs.
+# This .s file is used with several different linker scripts that vary the
+# placement of the sections in the output.
+# Section text0 is 32 bytes long and requires at least 2 linker stubs
+# (12 bytes each) to reach the call destinations in text2.  Another stub
+# may be required to reach func0 if the section is laid out so that it crosses 
+# a 256MB memory segment boundary.
+
+.globl text0
+.section text0, "ax", @progbits
+	call func0	# in same section
+	call func2a	# in distant section
+	nop
+	nop
+	nop
+	nop
+	jmpi func2b	# in distant section
+
+func0:
+	ret
+
+.section text2, "ax", @progbits
+func2a:
+	nop
+	nop
+	nop
+	ret
+func2b:
+	nop
diff --git a/ld/testsuite/ld-nios2/relax_call26_boundary_c8.d b/ld/testsuite/ld-nios2/relax_call26_boundary_c8.d
new file mode 100644
index 0000000..61fd858
--- /dev/null
+++ b/ld/testsuite/ld-nios2/relax_call26_boundary_c8.d
@@ -0,0 +1,9 @@
+#name: NIOS2 relax_call26_boundary_c8
+#ld: --relax -Trelax_call26_boundary.ld --section-start=text0=0x0fffffc8
+#source: relax_call26_boundary.s
+#objdump: -dr --prefix-addresses 
+# Test relaxation of call26 relocations via linker stubs.  We don't need to
+# check the exact layout of stubs for this test, only verify that it
+# links without "relocation truncated to fit" errors.
+
+#pass
diff --git a/ld/testsuite/ld-nios2/relax_call26_boundary_cc.d b/ld/testsuite/ld-nios2/relax_call26_boundary_cc.d
new file mode 100644
index 0000000..c3a571a
--- /dev/null
+++ b/ld/testsuite/ld-nios2/relax_call26_boundary_cc.d
@@ -0,0 +1,9 @@
+#name: NIOS2 relax_call26_boundary_cc
+#ld: --relax -Trelax_call26_boundary.ld --section-start=text0=0x0fffffcc
+#source: relax_call26_boundary.s
+#objdump: -dr --prefix-addresses 
+# Test relaxation of call26 relocations via linker stubs.  We don't need to
+# check the exact layout of stubs for this test, only verify that it
+# links without "relocation truncated to fit" errors.
+
+#pass
diff --git a/ld/testsuite/ld-nios2/relax_call26_boundary_d0.d b/ld/testsuite/ld-nios2/relax_call26_boundary_d0.d
new file mode 100644
index 0000000..67f28ce
--- /dev/null
+++ b/ld/testsuite/ld-nios2/relax_call26_boundary_d0.d
@@ -0,0 +1,9 @@
+#name: NIOS2 relax_call26_boundary_d0
+#ld: --relax -Trelax_call26_boundary.ld --section-start=text0=0x0fffffd0
+#source: relax_call26_boundary.s
+#objdump: -dr --prefix-addresses 
+# Test relaxation of call26 relocations via linker stubs.  We don't need to
+# check the exact layout of stubs for this test, only verify that it
+# links without "relocation truncated to fit" errors.
+
+#pass
diff --git a/ld/testsuite/ld-nios2/relax_call26_boundary_d4.d b/ld/testsuite/ld-nios2/relax_call26_boundary_d4.d
new file mode 100644
index 0000000..9ffdf0e
--- /dev/null
+++ b/ld/testsuite/ld-nios2/relax_call26_boundary_d4.d
@@ -0,0 +1,9 @@
+#name: NIOS2 relax_call26_boundary_d4
+#ld: --relax -Trelax_call26_boundary.ld --section-start=text0=0x0fffffd4
+#source: relax_call26_boundary.s
+#objdump: -dr --prefix-addresses 
+# Test relaxation of call26 relocations via linker stubs.  We don't need to
+# check the exact layout of stubs for this test, only verify that it
+# links without "relocation truncated to fit" errors.
+
+#pass
diff --git a/ld/testsuite/ld-nios2/relax_call26_boundary_d8.d b/ld/testsuite/ld-nios2/relax_call26_boundary_d8.d
new file mode 100644
index 0000000..168d532
--- /dev/null
+++ b/ld/testsuite/ld-nios2/relax_call26_boundary_d8.d
@@ -0,0 +1,9 @@
+#name: NIOS2 relax_call26_boundary_d8
+#ld: --relax -Trelax_call26_boundary.ld --section-start=text0=0x0fffffd8
+#source: relax_call26_boundary.s
+#objdump: -dr --prefix-addresses 
+# Test relaxation of call26 relocations via linker stubs.  We don't need to
+# check the exact layout of stubs for this test, only verify that it
+# links without "relocation truncated to fit" errors.
+
+#pass
diff --git a/ld/testsuite/ld-nios2/relax_call26_boundary_dc.d b/ld/testsuite/ld-nios2/relax_call26_boundary_dc.d
new file mode 100644
index 0000000..539051e
--- /dev/null
+++ b/ld/testsuite/ld-nios2/relax_call26_boundary_dc.d
@@ -0,0 +1,9 @@
+#name: NIOS2 relax_call26_boundary_dc
+#ld: --relax -Trelax_call26_boundary.ld --section-start=text0=0x0fffffdc
+#source: relax_call26_boundary.s
+#objdump: -dr --prefix-addresses 
+# Test relaxation of call26 relocations via linker stubs.  We don't need to
+# check the exact layout of stubs for this test, only verify that it
+# links without "relocation truncated to fit" errors.
+
+#pass
diff --git a/ld/testsuite/ld-nios2/relax_call26_boundary_f0.d b/ld/testsuite/ld-nios2/relax_call26_boundary_f0.d
new file mode 100644
index 0000000..fe83151
--- /dev/null
+++ b/ld/testsuite/ld-nios2/relax_call26_boundary_f0.d
@@ -0,0 +1,9 @@
+#name: NIOS2 relax_call26_boundary_f0
+#ld: --relax -Trelax_call26_boundary.ld --section-start=text0=0x0ffffff0
+#source: relax_call26_boundary.s
+#objdump: -dr --prefix-addresses 
+# Test relaxation of call26 relocations via linker stubs.  We don't need to
+# check the exact layout of stubs for this test, only verify that it
+# links without "relocation truncated to fit" errors.
+
+#pass
diff --git a/ld/testsuite/ld-nios2/relax_call26_boundary_f4.d b/ld/testsuite/ld-nios2/relax_call26_boundary_f4.d
new file mode 100644
index 0000000..4006ff2
--- /dev/null
+++ b/ld/testsuite/ld-nios2/relax_call26_boundary_f4.d
@@ -0,0 +1,9 @@
+#name: NIOS2 relax_call26_boundary_f4
+#ld: --relax -Trelax_call26_boundary.ld --section-start=text0=0x0ffffff4
+#source: relax_call26_boundary.s
+#objdump: -dr --prefix-addresses 
+# Test relaxation of call26 relocations via linker stubs.  We don't need to
+# check the exact layout of stubs for this test, only verify that it
+# links without "relocation truncated to fit" errors.
+
+#pass
diff --git a/ld/testsuite/ld-nios2/relax_call26_boundary_f8.d b/ld/testsuite/ld-nios2/relax_call26_boundary_f8.d
new file mode 100644
index 0000000..10eb654
--- /dev/null
+++ b/ld/testsuite/ld-nios2/relax_call26_boundary_f8.d
@@ -0,0 +1,9 @@
+#name: NIOS2 relax_call26_boundary_f8
+#ld: --relax -Trelax_call26_boundary.ld --section-start=text0=0x0ffffff8
+#source: relax_call26_boundary.s
+#objdump: -dr --prefix-addresses 
+# Test relaxation of call26 relocations via linker stubs.  We don't need to
+# check the exact layout of stubs for this test, only verify that it
+# links without "relocation truncated to fit" errors.
+
+#pass
diff --git a/ld/testsuite/ld-nios2/relax_call26_boundary_fc.d b/ld/testsuite/ld-nios2/relax_call26_boundary_fc.d
new file mode 100644
index 0000000..cf93b5a
--- /dev/null
+++ b/ld/testsuite/ld-nios2/relax_call26_boundary_fc.d
@@ -0,0 +1,9 @@
+#name: NIOS2 relax_call26_boundary_fc
+#ld: --relax -Trelax_call26_boundary.ld --section-start=text0=0x0ffffffc
+#source: relax_call26_boundary.s
+#objdump: -dr --prefix-addresses 
+# Test relaxation of call26 relocations via linker stubs.  We don't need to
+# check the exact layout of stubs for this test, only verify that it
+# links without "relocation truncated to fit" errors.
+
+#pass
diff --git a/ld/testsuite/ld-nios2/relax_call26_cache.d b/ld/testsuite/ld-nios2/relax_call26_cache.d
new file mode 100644
index 0000000..43121c0
--- /dev/null
+++ b/ld/testsuite/ld-nios2/relax_call26_cache.d
@@ -0,0 +1,9 @@
+#name: NIOS2 relax_call26_cache
+#ld: --relax -Trelax_call26_cache.ld
+#source: relax_call26_cache.s
+#objdump: -dr --prefix-addresses 
+# Test relaxation of call26 relocations via linker stubs.  We don't need to
+# check the exact layout of stubs for this test, only verify that it
+# links without "relocation truncated to fit" errors.
+
+#pass
diff --git a/ld/testsuite/ld-nios2/relax_call26_cache.ld b/ld/testsuite/ld-nios2/relax_call26_cache.ld
new file mode 100644
index 0000000..d3c4307
--- /dev/null
+++ b/ld/testsuite/ld-nios2/relax_call26_cache.ld
@@ -0,0 +1,13 @@
+/* Simple script for testing call26 relaxation via linker stubs.
+   In this case, input sections text0 and text1 are placed in the
+   same output section in the same 256MB segment, so they can share stubs.  */
+
+OUTPUT_FORMAT("elf32-littlenios2", "elf32-littlenios2", "elf32-littlenios2")
+OUTPUT_ARCH(nios2)
+ENTRY(_start)
+SECTIONS
+{
+	_start = .;
+	text0 0x0fffffe0 : { *(text0) *(text1) }
+	text2 0x40000000 : { *(text2) }
+}
diff --git a/ld/testsuite/ld-nios2/relax_call26_cache.s b/ld/testsuite/ld-nios2/relax_call26_cache.s
new file mode 100644
index 0000000..3712853
--- /dev/null
+++ b/ld/testsuite/ld-nios2/relax_call26_cache.s
@@ -0,0 +1,28 @@
+# test for call26 relaxation via linker stubs
+#
+# The purpose of this test is to ensure that, when section text0 straddles
+# a 256MB memory segment boundary with calls to the same function on either
+# side, the stub caching doesn't get confused and incorrectly use a stub
+# on the wrong side.
+
+.globl text0
+.section text0, "ax", @progbits
+	call func2a	# in distant section
+	call func2a	# in distant section
+	nop
+	nop
+	nop
+	nop
+	nop
+	nop
+	nop
+	nop
+	nop
+	nop
+	call func2a	# in distant section
+	call func2a	# in distant section
+
+.section text2, "ax", @progbits
+.globl func2a
+func2a:
+	ret
diff --git a/ld/testsuite/ld-nios2/relax_call26_multi.d b/ld/testsuite/ld-nios2/relax_call26_multi.d
new file mode 100644
index 0000000..28279ef
--- /dev/null
+++ b/ld/testsuite/ld-nios2/relax_call26_multi.d
@@ -0,0 +1,36 @@
+#name: NIOS2 relax_call26_multi
+#ld: --relax -Trelax_call26_multi.ld
+#source: relax_call26.s
+#objdump: -dr --prefix-addresses 
+# Test relaxation of call26 relocations via linker stubs
+
+.*: +file format elf32-littlenios2
+
+Disassembly of section text0:
+00000000 <_start> call	00000010 <func0>
+00000004 <[^>]*> call	0000002c <func1>
+00000008 <[^>]*> call	00000020 <[^>]*>
+0000000c <[^>]*> jmpi	00000014 <[^>]*>
+00000010 <func0> ret
+00000014 <[^>]*> movhi	at,16384
+00000018 <[^>]*> addi	at,at,16
+0000001c <[^>]*> jmp	at
+00000020 <[^>]*> movhi	at,16384
+00000024 <[^>]*> addi	at,at,0
+00000028 <[^>]*> jmp	at
+
+Disassembly of section text1:
+0000002c <func1> nop
+00000030 <[^>]*> nop
+00000034 <[^>]*> call	0000003c <[^>]*>
+00000038 <[^>]*> ret
+0000003c <[^>]*> movhi	at,16384
+00000040 <[^>]*> addi	at,at,0
+00000044 <[^>]*> jmp	at
+
+Disassembly of section text2:
+40000000 <func2a> nop
+40000004 <[^>]*> nop
+40000008 <[^>]*> nop
+4000000c <[^>]*> ret
+40000010 <func2b> nop
diff --git a/ld/testsuite/ld-nios2/relax_call26_multi.ld b/ld/testsuite/ld-nios2/relax_call26_multi.ld
new file mode 100644
index 0000000..750f747
--- /dev/null
+++ b/ld/testsuite/ld-nios2/relax_call26_multi.ld
@@ -0,0 +1,14 @@
+/* Simple script for testing call26 relaxation via linker stubs.
+   In this case, input sections text0 and text1 cannot share stubs
+   because they are in different output sections.  */
+
+OUTPUT_FORMAT("elf32-littlenios2", "elf32-littlenios2", "elf32-littlenios2")
+OUTPUT_ARCH(nios2)
+ENTRY(_start)
+SECTIONS
+{
+	_start = .;
+	text0 0 : { *(text0) }
+	text1 : { *(text1) }
+	text2 0x40000000 : { *(text2) }
+}
diff --git a/ld/testsuite/ld-nios2/relax_call26_norelax.d b/ld/testsuite/ld-nios2/relax_call26_norelax.d
new file mode 100644
index 0000000..7c7371c
--- /dev/null
+++ b/ld/testsuite/ld-nios2/relax_call26_norelax.d
@@ -0,0 +1,5 @@
+#name: NIOS2 relax_call26_norelax
+#ld: --no-relax -Trelax_call26_multi.ld
+#source: relax_call26.s
+#error: .*relocation truncated to fit: R_NIOS2_CALL26.*
+# Test relaxation of call26 relocations via linker stubs
diff --git a/ld/testsuite/ld-nios2/relax_call26_shared.d b/ld/testsuite/ld-nios2/relax_call26_shared.d
new file mode 100644
index 0000000..75ccbca
--- /dev/null
+++ b/ld/testsuite/ld-nios2/relax_call26_shared.d
@@ -0,0 +1,31 @@
+#name: NIOS2 relax_call26_shared
+#ld: --relax -Trelax_call26_shared.ld
+#source: relax_call26.s
+#objdump: -dr --prefix-addresses 
+# Test relaxation of call26 relocations via linker stubs
+
+.*: +file format elf32-littlenios2
+
+Disassembly of section text0:
+00000000 <_start> call	00000010 <func0>
+00000004 <[^>]*> call	00000014 <func1>
+00000008 <[^>]*> call	00000030 <[^>]*>
+0000000c <[^>]*> jmpi	00000024 <[^>]*>
+00000010 <func0> ret
+00000014 <func1> nop
+00000018 <[^>]*> nop
+0000001c <[^>]*> call	00000030 <[^>]*>
+00000020 <[^>]*> ret
+00000024 <[^>]*> movhi	at,16384
+00000028 <[^>]*> addi	at,at,16
+0000002c <[^>]*> jmp	at
+00000030 <[^>]*> movhi	at,16384
+00000034 <[^>]*> addi	at,at,0
+00000038 <[^>]*> jmp	at
+
+Disassembly of section text2:
+40000000 <func2a> nop
+40000004 <[^>]*> nop
+40000008 <[^>]*> nop
+4000000c <[^>]*> ret
+40000010 <func2b> nop
diff --git a/ld/testsuite/ld-nios2/relax_call26_shared.ld b/ld/testsuite/ld-nios2/relax_call26_shared.ld
new file mode 100644
index 0000000..6e6fd44
--- /dev/null
+++ b/ld/testsuite/ld-nios2/relax_call26_shared.ld
@@ -0,0 +1,13 @@
+/* Simple script for testing call26 relaxation via linker stubs.
+   In this case, input sections text0 and text1 are placed in the
+   same output section in the same 256MB segment, so they can share stubs.  */
+
+OUTPUT_FORMAT("elf32-littlenios2", "elf32-littlenios2", "elf32-littlenios2")
+OUTPUT_ARCH(nios2)
+ENTRY(_start)
+SECTIONS
+{
+	_start = .;
+	text0 0 : { *(text0) *(text1) }
+	text2 0x40000000 : { *(text2) }
+}

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