Move link_hash_table_free functions earlier
[deliverable/binutils-gdb.git] / bfd / elf32-nios2.c
index ba7689880798d6d130966559011aece386e365c3..10060c252230858bc510ab6b23053121def1b877 100644 (file)
@@ -1,5 +1,5 @@
 /* 32-bit ELF support for Nios II.
-   Copyright (C) 2012, 2013 Free Software Foundation, Inc.
+   Copyright (C) 2012-2014 Free Software Foundation, Inc.
    Contributed by Nigel Gray (ngray@altera.com).
    Contributed by Mentor Graphics, Inc.
 
@@ -68,8 +68,8 @@ static bfd_reloc_status_type nios2_elf32_callr_relocate
   (bfd *, arelent *, asymbol *, void *, asection *, bfd *, char **);
 
 /* Target vector.  */
-extern const bfd_target bfd_elf32_littlenios2_vec;
-extern const bfd_target bfd_elf32_bignios2_vec;
+extern const bfd_target nios2_elf32_le_vec;
+extern const bfd_target nios2_elf32_be_vec;
 
 /* Offset of tp and dtp pointers from start of TLS block.  */
 #define TP_OFFSET      0x7000
@@ -670,6 +670,62 @@ static reloc_howto_type elf_nios2_howto_table_rel[] = {
         0xffffffc0,            /* dst_mask */
         FALSE),                /* pcrel_offset */
 
+  HOWTO (R_NIOS2_GOT_LO,
+        0,
+        2,
+        16,
+        FALSE,
+        6,
+        complain_overflow_dont,
+        bfd_elf_generic_reloc,
+        "R_NIOS2_GOT_LO",
+        FALSE,
+        0x003fffc0,
+        0x003fffc0,
+        FALSE),
+
+  HOWTO (R_NIOS2_GOT_HA,
+        0,
+        2,
+        16,
+        FALSE,
+        6,
+        complain_overflow_dont,
+        bfd_elf_generic_reloc,
+        "R_NIOS2_GOT_HA",
+        FALSE,
+        0x003fffc0,
+        0x003fffc0,
+        FALSE),
+
+  HOWTO (R_NIOS2_CALL_LO,
+        0,
+        2,
+        16,
+        FALSE,
+        6,
+        complain_overflow_dont,
+        bfd_elf_generic_reloc,
+        "R_NIOS2_CALL_LO",
+        FALSE,
+        0x003fffc0,
+        0x003fffc0,
+        FALSE),
+
+  HOWTO (R_NIOS2_CALL_HA,
+        0,
+        2,
+        16,
+        FALSE,
+        6,
+        complain_overflow_dont,
+        bfd_elf_generic_reloc,
+        "R_NIOS2_CALL_HA",
+        FALSE,
+        0x003fffc0,
+        0x003fffc0,
+        FALSE),
+
 /* Add other relocations here.  */
 };
 
@@ -749,6 +805,10 @@ static const struct elf_reloc_map nios2_reloc_map[] = {
   {BFD_RELOC_NIOS2_RELATIVE, R_NIOS2_RELATIVE},
   {BFD_RELOC_NIOS2_GOTOFF, R_NIOS2_GOTOFF},
   {BFD_RELOC_NIOS2_CALL26_NOAT, R_NIOS2_CALL26_NOAT},
+  {BFD_RELOC_NIOS2_GOT_LO, R_NIOS2_GOT_LO},
+  {BFD_RELOC_NIOS2_GOT_HA, R_NIOS2_GOT_HA},
+  {BFD_RELOC_NIOS2_CALL_LO, R_NIOS2_CALL_LO},
+  {BFD_RELOC_NIOS2_CALL_HA, R_NIOS2_CALL_HA},
 };
 
 enum elf32_nios2_stub_type
@@ -839,10 +899,11 @@ struct elf32_nios2_link_hash_entry
      a dynamic GOT reloc in shared objects, only a dynamic PLT reloc.  Lazy
      linking will not work if the dynamic GOT reloc exists.
      To check for this condition efficiently, we compare got_types_used against
-     CALL16_USED, meaning
-     (got_types_used & (GOT16_USED | CALL16_USED)) == CALL16_USED.  */
-#define GOT16_USED     1
-#define CALL16_USED    2
+     CALL_USED, meaning
+     (got_types_used & (GOT_USED | CALL_USED)) == CALL_USED.
+  */
+#define GOT_USED       1
+#define CALL_USED      2
   unsigned char got_types_used;
 };
 
@@ -892,6 +953,9 @@ struct elf32_nios2_link_hash_table
     asection *srelbss;
     asection *sbss;
 
+    /* GOT pointer symbol _gp_got.  */
+    struct elf_link_hash_entry *h_gp_got;
+
     union {
       bfd_signed_vma refcount;
       bfd_vma offset;
@@ -1319,7 +1383,7 @@ nios2_elf32_setup_section_lists (bfd *output_bfd, struct bfd_link_info *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)
+       input_bfd = input_bfd->link.next)
     {
       bfd_count += 1;
       for (section = input_bfd->sections;
@@ -1654,7 +1718,7 @@ get_local_syms (bfd *output_bfd ATTRIBUTE_UNUSED, bfd *input_bfd,
   /* 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++)
+       input_bfd = input_bfd->link.next, bfd_indx++)
     {
       Elf_Internal_Shdr *symtab_hdr;
 
@@ -1719,7 +1783,7 @@ nios2_elf32_size_stubs (bfd *output_bfd, bfd *stub_bfd,
 
       for (input_bfd = info->input_bfds, bfd_indx = 0;
           input_bfd != NULL;
-          input_bfd = input_bfd->link_next, bfd_indx++)
+          input_bfd = input_bfd->link.next, bfd_indx++)
        {
          Elf_Internal_Shdr *symtab_hdr;
          asection *section;
@@ -1949,16 +2013,21 @@ nios2_elf32_build_stubs (struct bfd_link_info *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;
-    }
+    /* The stub_bfd may contain non-stub sections if it is also the
+       dynobj.  Any such non-stub sections are created with the
+       SEC_LINKER_CREATED flag set, while stub sections do not
+       have that flag.  Ignore any non-stub sections here.  */
+    if ((stub_sec->flags & SEC_LINKER_CREATED) == 0)
+      {  
+       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;
@@ -2671,6 +2740,7 @@ nios2_elf32_relocate_section (bfd *output_bfd,
   asection *splt;
   asection *sreloc = NULL;
   bfd_vma *local_got_offsets;
+  bfd_vma got_base;
 
   symtab_hdr = &elf_tdata (input_bfd)->symtab_hdr;
   sym_hashes = elf_sym_hashes (input_bfd);
@@ -2681,6 +2751,11 @@ nios2_elf32_relocate_section (bfd *output_bfd,
   splt = htab->root.splt;
   local_got_offsets = elf_local_got_offsets (input_bfd);
 
+  if (elf32_nios2_hash_table (info)->h_gp_got == NULL)
+    got_base = 0;
+  else
+    got_base = elf32_nios2_hash_table (info)->h_gp_got->root.u.def.value;
+
   for (rel = relocs; rel < relend; rel++)
     {
       reloc_howto_type *howto;
@@ -2933,6 +3008,10 @@ nios2_elf32_relocate_section (bfd *output_bfd,
 
            case R_NIOS2_GOT16:
            case R_NIOS2_CALL16:
+           case R_NIOS2_GOT_LO:
+           case R_NIOS2_GOT_HA:
+           case R_NIOS2_CALL_LO:
+           case R_NIOS2_CALL_HA:
              /* Relocation is to the entry for this symbol in the
                 global offset table.  */
              if (sgot == NULL)
@@ -2948,7 +3027,7 @@ nios2_elf32_relocate_section (bfd *output_bfd,
                  bfd_boolean dyn;
 
                  eh = (struct elf32_nios2_link_hash_entry *)h;
-                 use_plt = (eh->got_types_used == CALL16_USED
+                 use_plt = (eh->got_types_used == CALL_USED
                             && h->plt.offset != (bfd_vma) -1);
 
                  off = h->got.offset;
@@ -3026,24 +3105,45 @@ nios2_elf32_relocate_section (bfd *output_bfd,
              if (use_plt && info->shared)
                {
                  off = ((h->plt.offset - 24) / 12 + 3) * 4;
-                 relocation = htab->root.sgotplt->output_offset + off;
+                 relocation = (htab->root.sgotplt->output_offset + off
+                               - got_base);
                }
              else
-               relocation = sgot->output_offset + off;
+               relocation = sgot->output_offset + off - got_base;
 
              /* This relocation does not use the addend.  */
              rel->r_addend = 0;
 
-             r = _bfd_final_link_relocate (howto, input_bfd, input_section,
-                                           contents, rel->r_offset,
-                                           relocation, rel->r_addend);
+             switch (howto->type)
+               {
+               case R_NIOS2_GOT_LO:
+               case R_NIOS2_CALL_LO:
+                 r = nios2_elf32_do_lo16_relocate (input_bfd, howto,
+                                                   input_section, contents,
+                                                   rel->r_offset, relocation,
+                                                   rel->r_addend);
+                 break;
+               case R_NIOS2_GOT_HA:
+               case R_NIOS2_CALL_HA:
+                 r = nios2_elf32_do_hiadj16_relocate (input_bfd, howto,
+                                                      input_section, contents,
+                                                      rel->r_offset,
+                                                      relocation,
+                                                      rel->r_addend);
+                 break;
+               default:
+                 r = _bfd_final_link_relocate (howto, input_bfd,
+                                               input_section, contents,
+                                               rel->r_offset, relocation,
+                                               rel->r_addend);
+                 break;
+               }
              break;
 
            case R_NIOS2_GOTOFF_LO:
            case R_NIOS2_GOTOFF_HA:
            case R_NIOS2_GOTOFF:
-             /* Relocation is relative to the start of the
-                global offset table.  */
+             /* Relocation is relative to the global offset table pointer.  */
 
              BFD_ASSERT (sgot != NULL);
              if (sgot == NULL)
@@ -3053,11 +3153,13 @@ nios2_elf32_relocate_section (bfd *output_bfd,
                }
 
              /* Note that sgot->output_offset is not involved in this
-                calculation.  We always want the start of .got.  If we
-                define _GLOBAL_OFFSET_TABLE in a different way, as is
-                permitted by the ABI, we might have to change this
-                calculation.  */
+                calculation.  We always want the start of .got.  */
              relocation -= sgot->output_section->vma;
+
+             /* Now we adjust the relocation to be relative to the GOT pointer
+                (the _gp_got symbol), which possibly contains the 0x8000 bias.  */
+             relocation -= got_base;
+
              switch (howto->type)
                {
                case R_NIOS2_GOTOFF_LO:
@@ -3127,7 +3229,7 @@ nios2_elf32_relocate_section (bfd *output_bfd,
                  htab->tls_ldm_got.offset |= 1;
                }
 
-             relocation = (htab->root.sgot->output_offset + off);
+             relocation = htab->root.sgot->output_offset + off - got_base;
 
              r = _bfd_final_link_relocate (howto, input_bfd, input_section,
                                            contents, rel->r_offset,
@@ -3284,7 +3386,7 @@ nios2_elf32_relocate_section (bfd *output_bfd,
 
                if ((tls_type & GOT_TLS_GD) && r_type != R_NIOS2_TLS_GD16)
                  off += 8;
-               relocation = (htab->root.sgot->output_offset + off);
+               relocation = htab->root.sgot->output_offset + off - got_base;
 
                r = _bfd_final_link_relocate (howto, input_bfd, input_section,
                                              contents, rel->r_offset,
@@ -3489,6 +3591,7 @@ static bfd_boolean
 create_got_section (bfd *dynobj, struct bfd_link_info *info)
 {
   struct elf32_nios2_link_hash_table *htab;
+  struct elf_link_hash_entry *h;
 
   htab = elf32_nios2_hash_table (info);
 
@@ -3500,6 +3603,16 @@ create_got_section (bfd *dynobj, struct bfd_link_info *info)
   if (!bfd_set_section_alignment (dynobj, htab->root.sgotplt, 4))
     return FALSE;
 
+  /* The Nios II ABI specifies that GOT-relative relocations are relative
+     to the linker-created symbol _gp_got, rather than using
+     _GLOBAL_OFFSET_TABLE_ directly.  In particular, the latter always
+     points to the base of the GOT while _gp_got may include a bias.  */
+  h = _bfd_elf_define_linkage_sym (dynobj, info, htab->root.sgotplt,
+                                  "_gp_got");
+  elf32_nios2_hash_table (info)->h_gp_got = h;
+  if (h == NULL)
+    return FALSE;
+
   return TRUE;
 }
 
@@ -3653,7 +3766,11 @@ nios2_elf32_check_relocs (bfd *abfd, struct bfd_link_info *info,
       switch (r_type)
        {
        case R_NIOS2_GOT16:
+       case R_NIOS2_GOT_LO:
+       case R_NIOS2_GOT_HA:
        case R_NIOS2_CALL16:
+       case R_NIOS2_CALL_LO:
+       case R_NIOS2_CALL_HA:
        case R_NIOS2_TLS_GD16:
        case R_NIOS2_TLS_IE16:
          /* This symbol requires a global offset table entry.  */
@@ -3664,7 +3781,11 @@ nios2_elf32_check_relocs (bfd *abfd, struct bfd_link_info *info,
              {
              default:
              case R_NIOS2_GOT16:
+             case R_NIOS2_GOT_LO:
+             case R_NIOS2_GOT_HA:
              case R_NIOS2_CALL16:
+             case R_NIOS2_CALL_LO:
+             case R_NIOS2_CALL_HA:
                tls_type = GOT_NORMAL;
                break;
              case R_NIOS2_TLS_GD16:
@@ -3701,7 +3822,9 @@ nios2_elf32_check_relocs (bfd *abfd, struct bfd_link_info *info,
                  = (struct elf32_nios2_link_hash_entry *)h;
                h->got.refcount++;
                old_tls_type = elf32_nios2_hash_entry(h)->tls_type;
-               if (r_type == R_NIOS2_CALL16)
+               if (r_type == R_NIOS2_CALL16
+                   || r_type == R_NIOS2_CALL_LO
+                   || r_type == R_NIOS2_CALL_HA)
                  {
                    /* Make sure a plt entry is created for this symbol if
                       it turns out to be a function defined by a dynamic
@@ -3709,10 +3832,10 @@ nios2_elf32_check_relocs (bfd *abfd, struct bfd_link_info *info,
                    h->plt.refcount++;
                    h->needs_plt = 1;
                    h->type = STT_FUNC;
-                   eh->got_types_used |= CALL16_USED;
+                   eh->got_types_used |= CALL_USED;
                  }
                else
-                 eh->got_types_used |= GOT16_USED;
+                 eh->got_types_used |= GOT_USED;
              }
            else
              {
@@ -3946,7 +4069,11 @@ nios2_elf32_gc_sweep_hook (bfd *abfd,
       switch (r_type)
        {
        case R_NIOS2_GOT16:
+       case R_NIOS2_GOT_LO:
+       case R_NIOS2_GOT_HA:
        case R_NIOS2_CALL16:
+       case R_NIOS2_CALL_LO:
+       case R_NIOS2_CALL_HA:
          if (h != NULL)
            {
              if (h->got.refcount > 0)
@@ -4096,7 +4223,7 @@ nios2_elf32_finish_dynamic_symbol (bfd *output_bfd,
        }
     }
 
-  use_plt = (eh->got_types_used == CALL16_USED
+  use_plt = (eh->got_types_used == CALL_USED
             && h->plt.offset != (bfd_vma) -1);
 
   if (!use_plt && h->got.offset != (bfd_vma) -1
@@ -4178,9 +4305,10 @@ nios2_elf32_finish_dynamic_symbol (bfd *output_bfd,
       bfd_elf32_swap_reloca_out (output_bfd, &rela, loc);
     }
 
-  /* Mark _DYNAMIC and _GLOBAL_OFFSET_TABLE_ as absolute.  */
+  /* Mark _DYNAMIC, _GLOBAL_OFFSET_TABLE_, and _gp_got as absolute.  */
   if (strcmp (h->root.root.string, "_DYNAMIC") == 0
-      || h == elf_hash_table (info)->hgot)
+      || h == elf_hash_table (info)->hgot
+      || h == elf32_nios2_hash_table (info)->h_gp_got)
     sym->st_shndx = SHN_ABS;
 
   return TRUE;
@@ -4568,7 +4696,7 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, PTR inf)
     }
 
   eh = (struct elf32_nios2_link_hash_entry *) h;
-  use_plt = (eh->got_types_used == CALL16_USED
+  use_plt = (eh->got_types_used == CALL_USED
             && h->plt.offset != (bfd_vma) -1);
 
   if (h->got.refcount > 0)
@@ -4763,7 +4891,7 @@ nios2_elf32_size_dynamic_sections (bfd *output_bfd ATTRIBUTE_UNUSED,
 
   /* Set up .got offsets for local syms, and space for local dynamic
      relocs.  */
-  for (ibfd = info->input_bfds; ibfd != NULL; ibfd = ibfd->link_next)
+  for (ibfd = info->input_bfds; ibfd != NULL; ibfd = ibfd->link.next)
     {
       bfd_signed_vma *local_got;
       bfd_signed_vma *end_local_got;
@@ -4846,6 +4974,16 @@ nios2_elf32_size_dynamic_sections (bfd *output_bfd ATTRIBUTE_UNUSED,
      sym dynamic relocs.  */
   elf_link_hash_traverse (& htab->root, allocate_dynrelocs, info);
 
+  if (elf_hash_table (info)->dynamic_sections_created)
+    {
+      /* If the .got section is more than 0x8000 bytes, we add
+        0x8000 to the value of _gp_got, so that 16-bit relocations
+        have a greater chance of working. */
+      if (htab->root.sgot->size >= 0x8000
+         && elf32_nios2_hash_table (info)->h_gp_got->root.u.def.value == 0)
+       elf32_nios2_hash_table (info)->h_gp_got->root.u.def.value = 0x8000;
+    }
+
   /* The check_relocs and adjust_dynamic_symbol entry points have
      determined the sizes of the various dynamic sections.  Allocate
      memory for them.  */
@@ -4966,6 +5104,17 @@ nios2_elf32_size_dynamic_sections (bfd *output_bfd ATTRIBUTE_UNUSED,
   return TRUE;
 }
 
+/* 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 bfd_elf32_bfd_link_hash_table_create.  */
 static struct bfd_link_hash_table *
 nios2_elf32_link_hash_table_create (bfd *abfd)
@@ -4995,17 +5144,6 @@ nios2_elf32_link_hash_table_create (bfd *abfd)
   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,
@@ -5029,8 +5167,8 @@ nios2_elf32_reloc_type_class (const struct bfd_link_info *info ATTRIBUTE_UNUSED,
 static bfd_boolean
 is_nios2_elf_target (const struct bfd_target *targ)
 {
-  return (targ == &bfd_elf32_littlenios2_vec
-         || targ == &bfd_elf32_bignios2_vec);
+  return (targ == &nios2_elf32_le_vec
+         || targ == &nios2_elf32_be_vec);
 }
 
 /* Implement elf_backend_add_symbol_hook.
@@ -5161,9 +5299,9 @@ const struct bfd_elf_special_section elf32_nios2_special_sections[] =
 
 #define elf_backend_special_sections     elf32_nios2_special_sections
 
-#define TARGET_LITTLE_SYM              bfd_elf32_littlenios2_vec
+#define TARGET_LITTLE_SYM              nios2_elf32_le_vec
 #define TARGET_LITTLE_NAME             "elf32-littlenios2"
-#define TARGET_BIG_SYM                 bfd_elf32_bignios2_vec
+#define TARGET_BIG_SYM                 nios2_elf32_be_vec
 #define TARGET_BIG_NAME                        "elf32-bignios2"
 
 #define elf_backend_got_header_size    12
This page took 0.03108 seconds and 4 git commands to generate.