include/elf/
[external/binutils.git] / bfd / elf32-cris.c
index 2f6b4d8..2037b10 100644 (file)
@@ -1,5 +1,5 @@
 /* CRIS-specific support for 32-bit ELF.
-   Copyright 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008
+   Copyright 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009
    Free Software Foundation, Inc.
    Contributed by Axis Communications AB.
    Written by Hans-Peter Nilsson, based on elf32-fr30.c
@@ -436,7 +436,8 @@ static reloc_howto_type cris_elf_howto_table [] =
   TLSHOWTO16S (R_CRIS_16_GOT_TPREL),
   TLSHOWTO32 (R_CRIS_32_TPREL),
   TLSHOWTO16S (R_CRIS_16_TPREL),
-  TLSHOWTO32 (R_CRIS_DTPMOD)
+  TLSHOWTO32 (R_CRIS_DTPMOD),
+  TLSHOWTO32 (R_CRIS_32_IE)
 };
 \f
 /* Map BFD reloc types to CRIS ELF reloc types.  */
@@ -479,7 +480,8 @@ static const struct cris_reloc_map cris_reloc_map [] =
   { BFD_RELOC_CRIS_16_GOT_TPREL, R_CRIS_16_GOT_TPREL },
   { BFD_RELOC_CRIS_32_TPREL,   R_CRIS_32_TPREL },
   { BFD_RELOC_CRIS_16_TPREL,   R_CRIS_16_TPREL },
-  { BFD_RELOC_CRIS_DTPMOD,     R_CRIS_DTPMOD }
+  { BFD_RELOC_CRIS_DTPMOD,     R_CRIS_DTPMOD },
+  { BFD_RELOC_CRIS_32_IE,      R_CRIS_32_IE }
 };
 
 static reloc_howto_type *
@@ -1494,7 +1496,7 @@ cris_elf_relocate_section (output_bfd, info, input_bfd, input_section,
                   && r_type != R_CRIS_16_PCREL
                   && r_type != R_CRIS_32_PCREL)
                  || (!info->symbolic
-                     || !h->def_regular)))
+                     || (h != NULL && !h->def_regular))))
            {
              Elf_Internal_Rela outrel;
              bfd_byte *loc;
@@ -1526,7 +1528,16 @@ cris_elf_relocate_section (output_bfd, info, input_bfd, input_section,
                                         rel->r_offset);
              if (outrel.r_offset == (bfd_vma) -1)
                skip = TRUE;
-             else if (outrel.r_offset == (bfd_vma) -2)
+             else if (outrel.r_offset == (bfd_vma) -2
+                      /* For now, undefined weak symbols with non-default
+                         visibility (yielding 0), like exception info for
+                         discarded sections, will get a R_CRIS_NONE
+                         relocation rather than no relocation, because we
+                         notice too late that the symbol doesn't need a
+                         relocation.  */
+                      || (h != NULL
+                          && h->root.type == bfd_link_hash_undefweak
+                          && ELF_ST_VISIBILITY (h->other) != STV_DEFAULT))
                skip = TRUE, relocate = TRUE;
              outrel.r_offset += (input_section->output_section->vma
                                  + input_section->output_offset);
@@ -1604,10 +1615,12 @@ cris_elf_relocate_section (output_bfd, info, input_bfd, input_section,
        case R_CRIS_16_DTPREL:
        case R_CRIS_32_DTPREL:
          /* This relocation must only be performed against local
-            symbols.  It's also ok when we link a program and the
-            symbol is defined in an ordinary (non-DSO) object (if
-            it's undefined there, we've already seen an error).  */
+            symbols, or to sections that are not loadable.  It's also
+            ok when we link a program and the symbol is defined in an
+            ordinary (non-DSO) object (if it's undefined there, we've
+            already seen an error).  */
          if (h != NULL
+             && (input_section->flags & SEC_ALLOC) != 0
              && ELF_ST_VISIBILITY (h->other) == STV_DEFAULT
              && (info->shared
                  || (!h->def_regular
@@ -1630,14 +1643,16 @@ cris_elf_relocate_section (output_bfd, info, input_bfd, input_section,
              return FALSE;
            }
 
-         BFD_ASSERT (elf_cris_hash_table (info)->dtpmod_refcount != 0);
+         BFD_ASSERT ((input_section->flags & SEC_ALLOC) == 0
+                     || elf_cris_hash_table (info)->dtpmod_refcount != 0);
 
          /* Fill in a R_CRIS_DTPMOD reloc at offset 3 if we haven't
             already done so.  Note that we do this in .got.plt, not
             in .got, as .got.plt contains the first part, still the
             reloc is against .got, because the linker script directs
             (is required to direct) them both into .got.  */
-         if (elf_cris_hash_table (info)->dtpmod_refcount > 0)
+         if (elf_cris_hash_table (info)->dtpmod_refcount > 0
+             && (input_section->flags & SEC_ALLOC) != 0)
            {
              asection *sgotplt = bfd_get_section_by_name (dynobj, ".got.plt");
              BFD_ASSERT (sgotplt != NULL);
@@ -1676,9 +1691,14 @@ cris_elf_relocate_section (output_bfd, info, input_bfd, input_section,
            }
 
          /* The thread-based offset to the local symbol is the
-            relocation.  */
+            relocation.
+            For the executable, TLS data begins at the thread pointer plus
+            the negative size of the TLS data.  For a DSO, that's part of
+            the module TLS offset.  */
          relocation -= elf_hash_table (info)->tls_sec == NULL
-           ? 0 : elf_hash_table (info)->tls_sec->vma;
+           ? 0 : (elf_hash_table (info)->tls_sec->vma
+                  + (info->shared
+                     ? 0 : elf_hash_table (info)->tls_size));
          break;
 
        case R_CRIS_32_GD:
@@ -1713,7 +1733,8 @@ cris_elf_relocate_section (output_bfd, info, input_bfd, input_section,
              return FALSE;
            }
 
-         if (!info->shared && (h == NULL || h->def_regular))
+         if (!info->shared
+             && (h == NULL || h->def_regular || ELF_COMMON_DEF_P (h)))
            {
              /* Known contents of the GOT.  */
              bfd_vma off;
@@ -1832,6 +1853,17 @@ cris_elf_relocate_section (output_bfd, info, input_bfd, input_section,
             the GOT entry.  */
          break;
 
+       case R_CRIS_32_IE:
+         if (info->shared)
+           {
+             bfd_set_error (bfd_error_invalid_operation);
+
+             /* We've already informed in cris_elf_check_relocs that
+                this is an error.  */
+             return FALSE;
+           }
+         /* Fall through.  */
+
        case R_CRIS_32_GOT_TPREL:
        case R_CRIS_16_GOT_TPREL:
          if (rel->r_addend != 0)
@@ -1859,8 +1891,9 @@ cris_elf_relocate_section (output_bfd, info, input_bfd, input_section,
              bfd_vma off;
 
              /* The symbol is defined in the program, so just write
-                the known_tpoffset into the GOT.  */
+                the -prog_tls_size+known_tpoffset into the GOT.  */
              relocation -= elf_hash_table (info)->tls_sec->vma;
+             relocation -= elf_hash_table (info)->tls_size;
 
              if (h != NULL)
                off = h->got.offset;
@@ -1884,7 +1917,8 @@ cris_elf_relocate_section (output_bfd, info, input_bfd, input_section,
              else
                off &= ~3;
 
-             relocation = sgot->output_offset + off;
+             relocation = sgot->output_offset + off
+               + (r_type == R_CRIS_32_IE ? sgot->output_section->vma : 0);
            }
          else
            {
@@ -1944,10 +1978,12 @@ cris_elf_relocate_section (output_bfd, info, input_bfd, input_section,
              else
                off &= ~3;
 
-             relocation = sgot->output_offset + off;
+             relocation = sgot->output_offset + off
+               + (r_type == R_CRIS_32_IE ? sgot->output_section->vma : 0);
            }
 
-         /* The GOT-relative offset to the GOT entry is the relocation.  */
+         /* The GOT-relative offset to the GOT entry is the relocation,
+            or for R_CRIS_32_GD, the actual address of the GOT entry.  */
          break;
 
        case R_CRIS_16_TPREL:
@@ -1965,7 +2001,7 @@ cris_elf_relocate_section (output_bfd, info, input_bfd, input_section,
 
          if (h != NULL
              && ELF_ST_VISIBILITY (h->other) == STV_DEFAULT
-             && !h->def_regular
+             && !(h->def_regular || ELF_COMMON_DEF_P (h))
              /* If it's undefined, then an error message has already
                 been emitted.  */
              && h->root.type != bfd_link_hash_undefined)
@@ -1985,7 +2021,9 @@ cris_elf_relocate_section (output_bfd, info, input_bfd, input_section,
 
          /* NULL if we had an error.  */
          relocation -= elf_hash_table (info)->tls_sec == NULL
-           ? 0 : elf_hash_table (info)->tls_sec->vma;
+           ? 0
+           : (elf_hash_table (info)->tls_sec->vma
+              + elf_hash_table (info)->tls_size);
 
          /* The TLS-relative offset is the relocation.  */
          break;
@@ -2130,13 +2168,19 @@ elf_cris_finish_dynamic_symbol (output_bfd, info, h, sym)
       bfd_byte *loc;
       bfd_boolean has_gotplt = gotplt_offset != 0;
 
-      /* Get the index in the procedure linkage table which
-        corresponds to this symbol.  This is the index of this symbol
-        in all the symbols for which we are making plt entries.  The
-        first entry in the procedure linkage table is reserved.  */
-      /* We have to count backwards here, and the result is only valid as
-        an index into .got.plt and its relocations.  FIXME: Constants...  */
-      bfd_vma gotplt_index = gotplt_offset/4 - 3;
+      /* Get the index in the .rela.plt relocations for the .got.plt
+        entry that corresponds to this symbol.
+        We have to count backwards here, and the result is only valid
+        as an index into .rela.plt.  We also have to undo the effect
+        of the R_CRIS_DTPMOD entry at .got index 3 (offset 12 into
+        .got.plt) for which gotplt_offset is adjusted, because while
+        that entry goes into .got.plt, its relocation goes into
+        .rela.got, not .rela.plt.  (It's not PLT-specific; not to be
+        processed as part of the runtime lazy .rela.plt relocation).
+        FIXME: There be literal constants here...  */
+      bfd_vma rela_plt_index
+       = (elf_cris_hash_table (info)->dtpmod_refcount != 0
+          ? gotplt_offset/4 - 2 - 3 : gotplt_offset/4 - 3);
 
       /* Get the offset into the .got table of the entry that corresponds
         to this function.  Note that we embed knowledge that "incoming"
@@ -2186,7 +2230,7 @@ elf_cris_finish_dynamic_symbol (output_bfd, info, h, sym)
        {
          /* Fill in the offset to the reloc table.  */
          bfd_put_32 (output_bfd,
-                     gotplt_index * sizeof (Elf32_External_Rela),
+                     rela_plt_index * sizeof (Elf32_External_Rela),
                      splt->contents + h->plt.offset + plt_off2);
 
          /* Fill in the offset to the first PLT entry, where to "jump".  */
@@ -2209,7 +2253,7 @@ elf_cris_finish_dynamic_symbol (output_bfd, info, h, sym)
                           + got_offset);
          rela.r_info = ELF32_R_INFO (h->dynindx, R_CRIS_JUMP_SLOT);
          rela.r_addend = 0;
-         loc = srela->contents + gotplt_index * sizeof (Elf32_External_Rela);
+         loc = srela->contents + rela_plt_index * sizeof (Elf32_External_Rela);
          bfd_elf32_swap_reloca_out (output_bfd, &rela, loc);
        }
 
@@ -2559,6 +2603,7 @@ cris_elf_gc_sweep_hook (bfd *abfd,
            : &local_got_refcounts[LGOT_DTP_NDX (r_symndx)];
          break;
 
+       case R_CRIS_32_IE:
        case R_CRIS_16_GOT_TPREL:
        case R_CRIS_32_GOT_TPREL:
          specific_refcount = h != NULL
@@ -2572,6 +2617,7 @@ cris_elf_gc_sweep_hook (bfd *abfd,
 
       switch (r_type)
        {
+       case R_CRIS_32_IE:
        case R_CRIS_32_GD:
        case R_CRIS_16_GOT_TPREL:
        case R_CRIS_32_GOT_TPREL:
@@ -2643,6 +2689,10 @@ cris_elf_gc_sweep_hook (bfd *abfd,
          break;
 
        case R_CRIS_32_DTPREL:
+         /* This'd be a .dtpreld entry in e.g. debug info.  */
+         if ((sec->flags & SEC_ALLOC) == 0)
+           break;
+         /* Fall through.  */
        case R_CRIS_16_DTPREL:
          elf_cris_hash_table (info)->dtpmod_refcount--;
          if (elf_cris_hash_table (info)->dtpmod_refcount == 0)
@@ -3027,7 +3077,11 @@ elf_cris_copy_indirect_symbol (struct bfd_link_info *info,
   /* Only indirect symbols are replaced; we're not interested in
      updating any of EIND's fields for other symbols.  */
   if (eind->root.root.type != bfd_link_hash_indirect)
-    return;
+    {
+      /* Still, we need to copy flags for e.g. weak definitions.  */
+      _bfd_elf_link_hash_copy_indirect (info, dir, ind);
+      return;
+    }
 
   BFD_ASSERT (edir->pcrel_relocs_copied == NULL);
   BFD_ASSERT (edir->gotplt_offset == 0 || eind->gotplt_offset == 0);
@@ -3106,8 +3160,17 @@ cris_elf_check_relocs (abfd, info, sec, relocs)
         on the first input bfd we found that contained dynamic relocs.  */
       switch (r_type)
        {
-       case R_CRIS_16_DTPREL:
        case R_CRIS_32_DTPREL:
+         if ((sec->flags & SEC_ALLOC) == 0)
+           /* This'd be a .dtpreld entry in e.g. debug info.  We have
+              several different switch statements below, but none of
+              that is needed; we need no preparations for resolving
+              R_CRIS_32_DTPREL into a non-allocated section (debug
+              info), so let's just move on to the next
+              relocation.  */
+           continue;
+         /* Fall through.  */
+       case R_CRIS_16_DTPREL:
          /* The first .got.plt entry is right after the R_CRIS_DTPMOD
             entry at index 3. */
          if (elf_cris_hash_table (info)->dtpmod_refcount == 0)
@@ -3115,6 +3178,7 @@ cris_elf_check_relocs (abfd, info, sec, relocs)
          elf_cris_hash_table (info)->dtpmod_refcount++;
          /* Fall through.  */
 
+       case R_CRIS_32_IE:
        case R_CRIS_32_GD:
        case R_CRIS_16_GOT_GD:
        case R_CRIS_32_GOT_GD:
@@ -3188,6 +3252,7 @@ cris_elf_check_relocs (abfd, info, sec, relocs)
            break;
          /* Fall through.  */
 
+       case R_CRIS_32_IE:
        case R_CRIS_32_GD:
        case R_CRIS_16_GOT_GD:
        case R_CRIS_32_GOT_GD:
@@ -3234,6 +3299,7 @@ cris_elf_check_relocs (abfd, info, sec, relocs)
       /* Warn and error for invalid input.  */
       switch (r_type)
        {
+       case R_CRIS_32_IE:
        case R_CRIS_32_TPREL:
        case R_CRIS_16_TPREL:
        case R_CRIS_32_GD:
@@ -3271,11 +3337,12 @@ cris_elf_check_relocs (abfd, info, sec, relocs)
             elsewhere.  */
          break;
 
+       case R_CRIS_32_IE:
        case R_CRIS_32_GOT_TPREL:
        case R_CRIS_16_GOT_TPREL:
          r_symndx_lgot = LGOT_TPREL_NDX (r_symndx);
 
-         /* Those two relocs also require that a DSO is of type
+         /* Those relocs also require that a DSO is of type
             Initial Exec.  Like other targets, we don't reset this
             flag even if the relocs are GC:ed away.  */
          if (info->shared)
@@ -3306,6 +3373,7 @@ cris_elf_check_relocs (abfd, info, sec, relocs)
             GOT entry for it, so handle it like a GOT reloc.  */
          /* Fall through.  */
 
+       case R_CRIS_32_IE:
        case R_CRIS_32_GD:
        case R_CRIS_16_GOT_GD:
        case R_CRIS_32_GOT_GD:
@@ -3356,6 +3424,7 @@ cris_elf_check_relocs (abfd, info, sec, relocs)
                  elf_cris_hash_entry (h)->dtp_refcount++;
                  break;
 
+               case R_CRIS_32_IE:
                case R_CRIS_32_GOT_TPREL:
                case R_CRIS_16_GOT_TPREL:
                  if (elf_cris_hash_entry (h)->tprel_refcount == 0)