Nios II CALL26 linker relaxation
authorSandra Loosemore <sandra@codesourcery.com>
Fri, 31 Jan 2014 01:47:07 +0000 (17:47 -0800)
committerSandra Loosemore <sandra@codesourcery.com>
Fri, 31 Jan 2014 01:47:07 +0000 (17:47 -0800)
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.

45 files changed:
bfd/ChangeLog
bfd/bfd-in2.h
bfd/elf32-nios2.c
bfd/elf32-nios2.h [new file with mode: 0644]
bfd/libbfd.h
bfd/reloc.c
gas/ChangeLog
gas/config/tc-nios2.c
gas/testsuite/ChangeLog
gas/testsuite/gas/nios2/call26_noat.d [new file with mode: 0644]
gas/testsuite/gas/nios2/call26_noat.s [new file with mode: 0644]
gas/testsuite/gas/nios2/call_noat.d [new file with mode: 0644]
gas/testsuite/gas/nios2/call_noat.s [new file with mode: 0644]
include/elf/ChangeLog
include/elf/nios2.h
ld/ChangeLog
ld/Makefile.am
ld/Makefile.in
ld/emulparams/nios2elf.sh
ld/emulparams/nios2linux.sh
ld/emultempl/nios2elf.em [new file with mode: 0644]
ld/gen-doc.texi
ld/ld.texinfo
ld/testsuite/ChangeLog
ld/testsuite/ld-nios2/relax_call26.s [new file with mode: 0644]
ld/testsuite/ld-nios2/relax_call26_boundary.ld [new file with mode: 0644]
ld/testsuite/ld-nios2/relax_call26_boundary.s [new file with mode: 0644]
ld/testsuite/ld-nios2/relax_call26_boundary_c8.d [new file with mode: 0644]
ld/testsuite/ld-nios2/relax_call26_boundary_cc.d [new file with mode: 0644]
ld/testsuite/ld-nios2/relax_call26_boundary_d0.d [new file with mode: 0644]
ld/testsuite/ld-nios2/relax_call26_boundary_d4.d [new file with mode: 0644]
ld/testsuite/ld-nios2/relax_call26_boundary_d8.d [new file with mode: 0644]
ld/testsuite/ld-nios2/relax_call26_boundary_dc.d [new file with mode: 0644]
ld/testsuite/ld-nios2/relax_call26_boundary_f0.d [new file with mode: 0644]
ld/testsuite/ld-nios2/relax_call26_boundary_f4.d [new file with mode: 0644]
ld/testsuite/ld-nios2/relax_call26_boundary_f8.d [new file with mode: 0644]
ld/testsuite/ld-nios2/relax_call26_boundary_fc.d [new file with mode: 0644]
ld/testsuite/ld-nios2/relax_call26_cache.d [new file with mode: 0644]
ld/testsuite/ld-nios2/relax_call26_cache.ld [new file with mode: 0644]
ld/testsuite/ld-nios2/relax_call26_cache.s [new file with mode: 0644]
ld/testsuite/ld-nios2/relax_call26_multi.d [new file with mode: 0644]
ld/testsuite/ld-nios2/relax_call26_multi.ld [new file with mode: 0644]
ld/testsuite/ld-nios2/relax_call26_norelax.d [new file with mode: 0644]
ld/testsuite/ld-nios2/relax_call26_shared.d [new file with mode: 0644]
ld/testsuite/ld-nios2/relax_call26_shared.ld [new file with mode: 0644]

index ec39127ed9586f1f37094378fad49369c5b871a8..a77013ec0f91c674695970a5e9bccd9f34267101 100644 (file)
@@ -1,3 +1,49 @@
+2014-01-30  Sandra Loosemore  <sandra@codesourcery.com>
+
+       * 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.
+
 2014-01-29  Nick Clifton  <nickc@redhat.com>
 
        PR binutils/16318
index b5aeb406a64ac8005cc151160d0d63b29ce2ea4b..73e2332f25e14f516cc6fe97c3a2f8496dbb6896 100644 (file)
@@ -5225,6 +5225,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,
index 82e55164c8b9d71c3c194961787028c43d68b969..ba7689880798d6d130966559011aece386e365c3 100644 (file)
@@ -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 (file)
index 0000000..e6e0920
--- /dev/null
@@ -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 */
index 87605b964df1395841b0be4ae97fded808f3e9c2..9711e171bd5aab0179ed8c37320d0ce0462b55fb 100644 (file)
@@ -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",
index 0d191f194c212ce5e7ed4e6aa88a600996933bfc..3d1256d7ef837b8d2a30871dd22981d75828f951 100644 (file)
@@ -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.
 
index 99bc518e1f40dfcb5324318f1919804216eb7721..a3f0f03ca5436487ec811d42275a4cd758203eb6 100644 (file)
@@ -1,3 +1,9 @@
+2014-01-30  Sandra Loosemore  <sandra@codesourcery.com>
+
+       * config/tc-nios2.c (md_apply_fix): Handle BFD_RELOC_NIOS2_CALL26_NOAT.
+       (nios2_assemble_args_m): Likewise.
+       (md_assemble): Likewise.
+
 2014-01-24  DJ Delorie  <dj@redhat.com>
 
        * config/tc-msp430.c (msp430_section): Always flag data sections,
index 08b7aecec8f3a6a347bb64148003d95dffa96372..eb81b352d82dadc0fef112838f4fe60d74d77e8a 100644 (file)
@@ -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);
index 8538da20913083dbc5077c71329cd0ae2047f7c7..c45f647d46778dd083a5bd9d79e0f18951045b85 100644 (file)
@@ -1,3 +1,10 @@
+2014-01-30  Sandra Loosemore  <sandra@codesourcery.com>
+
+       * gas/nios2/call26_noat.d: New.
+       * gas/nios2/call26_noat.s: New.
+       * gas/nios2/call_noat.d: New.
+       * gas/nios2/call_noat.s: New.
+
 2014-01-30  Michael Zolotukhin  <michael.v.zolotukhin@gmail.com>
            Jan Beulich  <jbeulich@suse.com>
 
diff --git a/gas/testsuite/gas/nios2/call26_noat.d b/gas/testsuite/gas/nios2/call26_noat.d
new file mode 100644 (file)
index 0000000..34bfe4e
--- /dev/null
@@ -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 (file)
index 0000000..f0a93e7
--- /dev/null
@@ -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 (file)
index 0000000..03aadb5
--- /dev/null
@@ -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 (file)
index 0000000..67613b7
--- /dev/null
@@ -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:
+       
+
+
index b9127b4c84e0f7f612b52216c4f2489f9d11c4cc..28272d8338716e88861916aa5f64217e06797d8e 100644 (file)
@@ -1,3 +1,7 @@
+2014-01-30  Sandra Loosemore  <sandra@codesourcery.com>
+
+       * nios2.h (elf_nios2_reloc_type): Add R_NIOS2_CALL26_NOAT.
+
 2014-01-30  Ulrich Weigand  <uweigand@de.ibm.com>
 
        * common.h (AT_HWCAP2): Define.
index ff5947bf77b7e9c8142852509157300d27e2222a..76863508bfd90b04fe2a2117348ff5718fcce61c 100644 (file)
@@ -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.  */
index b072ff9477f49d71a10caa76bec5a15fbf06f17a..e765743feb798fa09a440f87a656afa2c1d2fc16 100644 (file)
@@ -1,3 +1,13 @@
+2014-01-30  Sandra Loosemore  <sandra@codesourcery.com>
+
+       * 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.
+
 2014-01-28  Nick Clifton  <nickc@redhat.com>
 
        * Makefile.am: Remove obsolete MSP430 emulations.
index 3499e727a6480da072e8dc60fa67e81719aab3ff..5968668c42e7915ffb65cc9f2587285bfa3e45a5 100644 (file)
@@ -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 \
index 0119a74fcc4d1f6993354175a7060f8601326fdd..59cba73cd649c2ddac8b5405fd22b3877f488ec3 100644 (file)
@@ -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 \
index 767f3decd67b2cfd8a191204a7c6efba4f15f75b..7ccde9773b49fb144a743778515c3837e28b08d9 100644 (file)
@@ -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"
index aa409a9ec700f7bc5c0c6cbdad158ac2a454ccab..f21517799640ccecf21bee4f3bdff90d77559eb5 100644 (file)
@@ -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 (file)
index 0000000..c86eba1
--- /dev/null
@@ -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
index acc6c57e763292de407a27f68603779026ccb56e..ede1e08957faceba09766501f7d34561d656c086 100644 (file)
@@ -18,6 +18,7 @@
 @set MMIX
 @set MSP430
 @set NDS32
+@set NIOSII
 @set POWERPC
 @set POWERPC64
 @set Renesas
index a8e5ea69a7aa3b51169a354e7b2eba948eb88deb..1287a6cc180368ce3d6856527e91de09a845fc12 100644 (file)
@@ -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
index 3cd19305ee4f97462be59f74e311a33fb08d725f..a46d25caa292bcd68bced9223e4b94d50b190744 100644 (file)
@@ -1,3 +1,27 @@
+2014-01-30  Sandra Loosemore  <sandra@codesourcery.com>
+
+       * 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.
+
 2014-01-29  H.J. Lu  <hongjiu.lu@intel.com>
 
        * ld-elf/rdynamic-1.c: New file.
diff --git a/ld/testsuite/ld-nios2/relax_call26.s b/ld/testsuite/ld-nios2/relax_call26.s
new file mode 100644 (file)
index 0000000..b3b28df
--- /dev/null
@@ -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 (file)
index 0000000..313ef8c
--- /dev/null
@@ -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 (file)
index 0000000..ce79ebd
--- /dev/null
@@ -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 (file)
index 0000000..61fd858
--- /dev/null
@@ -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 (file)
index 0000000..c3a571a
--- /dev/null
@@ -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 (file)
index 0000000..67f28ce
--- /dev/null
@@ -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 (file)
index 0000000..9ffdf0e
--- /dev/null
@@ -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 (file)
index 0000000..168d532
--- /dev/null
@@ -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 (file)
index 0000000..539051e
--- /dev/null
@@ -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 (file)
index 0000000..fe83151
--- /dev/null
@@ -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 (file)
index 0000000..4006ff2
--- /dev/null
@@ -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 (file)
index 0000000..10eb654
--- /dev/null
@@ -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 (file)
index 0000000..cf93b5a
--- /dev/null
@@ -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 (file)
index 0000000..43121c0
--- /dev/null
@@ -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 (file)
index 0000000..d3c4307
--- /dev/null
@@ -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 (file)
index 0000000..3712853
--- /dev/null
@@ -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 (file)
index 0000000..28279ef
--- /dev/null
@@ -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 (file)
index 0000000..750f747
--- /dev/null
@@ -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 (file)
index 0000000..7c7371c
--- /dev/null
@@ -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 (file)
index 0000000..75ccbca
--- /dev/null
@@ -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 (file)
index 0000000..6e6fd44
--- /dev/null
@@ -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) }
+}
This page took 0.065117 seconds and 4 git commands to generate.