* elf32-sh.c (elf_sh_link_hash_entry): Replace
authorStephen Clarke <stephen.clarke@earthling.net>
Mon, 14 Oct 2002 19:29:54 +0000 (19:29 +0000)
committerStephen Clarke <stephen.clarke@earthling.net>
Mon, 14 Oct 2002 19:29:54 +0000 (19:29 +0000)
datalabel_got_offset with union of datalabel_got
offset and refcount.
(sh_elf_link_hash_newfunc): Initialize datalabel_got.refcount.
(allocate_dynrelocs): Delete unnecessary code for
STT_DATALABEL type.  Create entry in got for
datalabel version of symbol if datalabel_got.refcount > 0.
(sh_elf_relocate_section): Use datalabel_got union.
(sh_elf_gc_sweep_hook): Pull common code to initialize
h and eh out of switch statement.  Declare seen_stt_datalabel.
Initialize it.  Decrement datalabel_got.refcount for
got relocs when seen_stt_datalabel is true.
Decrement local_got_refcounts entry for datalabel got relocs
of local symbols.
(sh_elf_copy_indirect_symbol): Copy datalabel_got field over.
(sh_elf_check_relocs): Declare seen_stt_datalabel.
Initialize it.  When seen_stt_datalabel is true, increment
datalabel_got refcount rather than got.refcount.
(sh_elf_finish_dynamic_symbol): Create relocs to
initialize got entry for datalabel version of symbol.

bfd/ChangeLog
bfd/elf32-sh.c

index a063901954dc820378cb0179269ef39bf95162f1..82064f7c053372aa3c6b70d991be5328bcf20a24 100644 (file)
@@ -1,3 +1,26 @@
+2002-10-14  Stephen Clarke <stephen.clarke@superh.com>
+
+       * elf32-sh.c (elf_sh_link_hash_entry): Replace
+       datalabel_got_offset with union of datalabel_got
+       offset and refcount.
+       (sh_elf_link_hash_newfunc): Initialize datalabel_got.refcount.
+       (allocate_dynrelocs): Delete unnecessary code for
+       STT_DATALABEL type.  Create entry in got for
+       datalabel version of symbol if datalabel_got.refcount > 0.
+       (sh_elf_relocate_section): Use datalabel_got union.
+       (sh_elf_gc_sweep_hook): Pull common code to initialize
+       h and eh out of switch statement.  Declare seen_stt_datalabel.
+       Initialize it.  Decrement datalabel_got.refcount for
+       got relocs when seen_stt_datalabel is true.
+       Decrement local_got_refcounts entry for datalabel got relocs
+       of local symbols.
+       (sh_elf_copy_indirect_symbol): Copy datalabel_got field over.
+       (sh_elf_check_relocs): Declare seen_stt_datalabel.
+       Initialize it.  When seen_stt_datalabel is true, increment
+       datalabel_got refcount rather than got.refcount.
+       (sh_elf_finish_dynamic_symbol): Create relocs to
+       initialize got entry for datalabel version of symbol.
+
 2002-10-14  Alan Modra  <amodra@bigpond.net.au>
 
        * Makefile.am: Run "make dep-am".
index 53d2841e6e6f7b45f400391eb5718358dc1302a3..8da4d886c0bf55928417e6846de12a8c4f3d7fb9 100644 (file)
@@ -3505,7 +3505,11 @@ struct elf_sh_link_hash_entry
   struct elf_link_hash_entry root;
 
 #ifdef INCLUDE_SHMEDIA
-  bfd_vma datalabel_got_offset;
+  union
+  {
+    bfd_signed_vma refcount;
+    bfd_vma offset;
+  } datalabel_got;
 #endif
 
   /* Track dynamic relocs copied for this symbol.  */
@@ -3616,13 +3620,10 @@ sh_elf_link_hash_newfunc (entry, table, string)
                                     table, string));
   if (ret != (struct elf_sh_link_hash_entry *) NULL)
     {
-      struct elf_sh_link_hash_entry *eh;
-
-      eh = (struct elf_sh_link_hash_entry *) ret;
-      eh->dyn_relocs = NULL;
-      eh->gotplt_refcount = 0;
+      ret->dyn_relocs = NULL;
+      ret->gotplt_refcount = 0;
 #ifdef INCLUDE_SHMEDIA
-      ret->datalabel_got_offset = (bfd_vma) -1;
+      ret->datalabel_got.refcount = ret->root.got.refcount;
 #endif
       ret->tls_type = GOT_UNKNOWN;
       ret->tls_tpoff32 = false;
@@ -4127,20 +4128,7 @@ allocate_dynrelocs (h, inf)
        }
 
       s = htab->sgot;
-#ifdef INCLUDE_SHMEDIA
-      if (h->type == STT_DATALABEL)
-       {
-         struct elf_sh_link_hash_entry *hsh;
-
-         h = (struct elf_link_hash_entry *) h->root.u.i.link;
-         hsh = (struct elf_sh_link_hash_entry *)h;
-         hsh->datalabel_got_offset = s->_raw_size;
-       }
-      else
-       h->got.offset = s->_raw_size;
-#else
       h->got.offset = s->_raw_size;
-#endif
       s->_raw_size += 4;
       /* R_SH_TLS_GD needs 2 consecutive GOT slots.  */
       if (tls_type == GOT_TLS_GD)
@@ -4159,6 +4147,32 @@ allocate_dynrelocs (h, inf)
   else
     h->got.offset = (bfd_vma) -1;
 
+#ifdef INCLUDE_SHMEDIA
+  if (eh->datalabel_got.refcount > 0)
+    {
+      asection *s;
+      boolean dyn;
+
+      /* Make sure this symbol is output as a dynamic symbol.
+        Undefined weak syms won't yet be marked as dynamic.  */
+      if (h->dynindx == -1
+         && (h->elf_link_hash_flags & ELF_LINK_FORCED_LOCAL) == 0)
+       {
+         if (! bfd_elf32_link_record_dynamic_symbol (info, h))
+           return false;
+       }
+
+      s = htab->sgot;
+      eh->datalabel_got.offset = s->_raw_size;
+      s->_raw_size += 4;
+      dyn = htab->root.dynamic_sections_created;
+      if (WILL_CALL_FINISH_DYNAMIC_SYMBOL (dyn, info, h))
+       htab->srelgot->_raw_size += sizeof (Elf32_External_Rela);
+    }
+  else
+    eh->datalabel_got.offset = (bfd_vma) -1;
+#endif
+
   if (eh->dyn_relocs == NULL)
     return true;
 
@@ -4999,7 +5013,7 @@ sh_elf_relocate_section (output_bfd, info, input_bfd, input_section,
                  struct elf_sh_link_hash_entry *hsh;
 
                  hsh = (struct elf_sh_link_hash_entry *)h;
-                 off = hsh->datalabel_got_offset;
+                 off = hsh->datalabel_got.offset;
                }
 #endif
              BFD_ASSERT (off != (bfd_vma) -1);
@@ -5035,7 +5049,7 @@ sh_elf_relocate_section (output_bfd, info, input_bfd, input_section,
                          struct elf_sh_link_hash_entry *hsh;
 
                          hsh = (struct elf_sh_link_hash_entry *)h;
-                         hsh->datalabel_got_offset |= 1;
+                         hsh->datalabel_got.offset |= 1;
                        }
                      else
 #endif
@@ -5893,128 +5907,170 @@ sh_elf_gc_sweep_hook (abfd, info, sec, relocs)
 
   relend = relocs + sec->reloc_count;
   for (rel = relocs; rel < relend; rel++)
-    switch (sh_elf_optimized_tls_reloc (info, ELF32_R_TYPE (rel->r_info),
-                                  ELF32_R_SYM (rel->r_info)
-                                  >= symtab_hdr->sh_info))
-      {
-      case R_SH_TLS_LD_32:
-       if (sh_elf_hash_table (info)->tls_ldm_got.refcount > 0)
-         sh_elf_hash_table (info)->tls_ldm_got.refcount -= 1;
-       break;
+    {
+#ifdef INCLUDE_SHMEDIA
+      int seen_stt_datalabel = 0;
+#endif
 
-      case R_SH_GOT32:
-      case R_SH_GOTOFF:
-      case R_SH_GOTPC:
+      r_symndx = ELF32_R_SYM (rel->r_info);
+      if (r_symndx < symtab_hdr->sh_info)
+       h = NULL;
+      else
+       {
+         h = sym_hashes[r_symndx - symtab_hdr->sh_info];
 #ifdef INCLUDE_SHMEDIA
-      case R_SH_GOT_LOW16:
-      case R_SH_GOT_MEDLOW16:
-      case R_SH_GOT_MEDHI16:
-      case R_SH_GOT_HI16:
-      case R_SH_GOT10BY4:
-      case R_SH_GOT10BY8:
-      case R_SH_GOTOFF_LOW16:
-      case R_SH_GOTOFF_MEDLOW16:
-      case R_SH_GOTOFF_MEDHI16:
-      case R_SH_GOTOFF_HI16:
-      case R_SH_GOTPC_LOW16:
-      case R_SH_GOTPC_MEDLOW16:
-      case R_SH_GOTPC_MEDHI16:
-      case R_SH_GOTPC_HI16:
+         while (h->root.type == bfd_link_hash_indirect
+                || h->root.type == bfd_link_hash_warning)
+           {
+             seen_stt_datalabel |= h->type == STT_DATALABEL;
+             h = (struct elf_link_hash_entry *) h->root.u.i.link;
+           }
 #endif
-      case R_SH_TLS_GD_32:
-      case R_SH_TLS_IE_32:
-       r_symndx = ELF32_R_SYM (rel->r_info);
-       if (r_symndx >= symtab_hdr->sh_info)
-         {
-           h = sym_hashes[r_symndx - symtab_hdr->sh_info];
-           if (h->got.refcount > 0)
-             h->got.refcount -= 1;
-         }
-       else if (local_got_refcounts != NULL)
-         {
-           if (local_got_refcounts[r_symndx] > 0)
-             local_got_refcounts[r_symndx] -= 1;
-         }
-       break;
+       }
+      eh = (struct elf_sh_link_hash_entry *) h;
 
-      case R_SH_DIR32:
-      case R_SH_REL32:
-       r_symndx = ELF32_R_SYM (rel->r_info);
-       if (r_symndx >= symtab_hdr->sh_info)
-         {
-           struct elf_sh_link_hash_entry *eh;
-           struct elf_sh_dyn_relocs **pp;
-           struct elf_sh_dyn_relocs *p;
+      switch (sh_elf_optimized_tls_reloc (info, ELF32_R_TYPE (rel->r_info),
+                                         ELF32_R_SYM (rel->r_info)
+                                         >= symtab_hdr->sh_info))
+       {
+       case R_SH_TLS_LD_32:
+         if (sh_elf_hash_table (info)->tls_ldm_got.refcount > 0)
+           sh_elf_hash_table (info)->tls_ldm_got.refcount -= 1;
+         break;
+
+       case R_SH_GOT32:
+       case R_SH_GOTOFF:
+       case R_SH_GOTPC:
+#ifdef INCLUDE_SHMEDIA
+       case R_SH_GOT_LOW16:
+       case R_SH_GOT_MEDLOW16:
+       case R_SH_GOT_MEDHI16:
+       case R_SH_GOT_HI16:
+       case R_SH_GOT10BY4:
+       case R_SH_GOT10BY8:
+       case R_SH_GOTOFF_LOW16:
+       case R_SH_GOTOFF_MEDLOW16:
+       case R_SH_GOTOFF_MEDHI16:
+       case R_SH_GOTOFF_HI16:
+       case R_SH_GOTPC_LOW16:
+       case R_SH_GOTPC_MEDLOW16:
+       case R_SH_GOTPC_MEDHI16:
+       case R_SH_GOTPC_HI16:
+#endif
+       case R_SH_TLS_GD_32:
+       case R_SH_TLS_IE_32:
+         if (h != NULL)
+           {
+#ifdef INCLUDE_SHMEDIA
+             if (seen_stt_datalabel)
+               {
+                 if (eh->datalabel_got.refcount > 0)
+                   eh->datalabel_got.refcount -= 1;
+               }
+             else
+#endif
+               if (h->got.refcount > 0)
+                 h->got.refcount -= 1;
+           }
+         else if (local_got_refcounts != NULL)
+           {
+#ifdef INCLUDE_SHMEDIA
+             if (rel->r_addend & 1)
+               {
+                 if (local_got_refcounts[symtab_hdr->sh_info + r_symndx] > 0)
+                   local_got_refcounts[symtab_hdr->sh_info + r_symndx] -= 1;
+               }
+             else
+#endif
+               if (local_got_refcounts[r_symndx] > 0)
+                 local_got_refcounts[r_symndx] -= 1;
+           }
+         break;
+
+       case R_SH_DIR32:
+       case R_SH_REL32:
+         if (h != NULL)
+           {
+             struct elf_sh_dyn_relocs **pp;
+             struct elf_sh_dyn_relocs *p;
 
-           h = sym_hashes[r_symndx - symtab_hdr->sh_info];
 
-           if (!info->shared && h->plt.refcount > 0)
-             h->plt.refcount -= 1;
+             if (!info->shared && h->plt.refcount > 0)
+               h->plt.refcount -= 1;
 
-           eh = (struct elf_sh_link_hash_entry *) h;
+             for (pp = &eh->dyn_relocs; (p = *pp) != NULL; pp = &p->next)
+               if (p->sec == sec)
+                 {
+                   if (ELF32_R_TYPE (rel->r_info) == R_SH_REL32)
+                     p->pc_count -= 1;
+                   p->count -= 1;
+                   if (p->count == 0)
+                     *pp = p->next;
+                   break;
+                 }
+           }
+         break;
+
+       case R_SH_PLT32:
+#ifdef INCLUDE_SHMEDIA
+       case R_SH_PLT_LOW16:
+       case R_SH_PLT_MEDLOW16:
+       case R_SH_PLT_MEDHI16:
+       case R_SH_PLT_HI16:
+#endif
+         if (h != NULL)
+           {
+             if (h->plt.refcount > 0)
+               h->plt.refcount -= 1;
+           }
+         break;
 
-           for (pp = &eh->dyn_relocs; (p = *pp) != NULL; pp = &p->next)
-             if (p->sec == sec)
+       case R_SH_GOTPLT32:
+#ifdef INCLUDE_SHMEDIA
+       case R_SH_GOTPLT_LOW16:
+       case R_SH_GOTPLT_MEDLOW16:
+       case R_SH_GOTPLT_MEDHI16:
+       case R_SH_GOTPLT_HI16:
+       case R_SH_GOTPLT10BY4:
+       case R_SH_GOTPLT10BY8:
+#endif
+         if (h != NULL)
+           {
+             if (eh->gotplt_refcount > 0)
                {
-                 if (ELF32_R_TYPE (rel->r_info) == R_SH_REL32)
-                   p->pc_count -= 1;
-                 p->count -= 1;
-                 if (p->count == 0)
-                   *pp = p->next;
-                 break;
+                 eh->gotplt_refcount -= 1;
+                 if (h->plt.refcount > 0)
+                   h->plt.refcount -= 1;
                }
-         }
-       break;
-
-      case R_SH_PLT32:
 #ifdef INCLUDE_SHMEDIA
-      case R_SH_PLT_LOW16:
-      case R_SH_PLT_MEDLOW16:
-      case R_SH_PLT_MEDHI16:
-      case R_SH_PLT_HI16:
+             else if (seen_stt_datalabel)
+               {
+                 if (eh->datalabel_got.refcount > 0)
+                   eh->datalabel_got.refcount -= 1;
+               }
 #endif
-       r_symndx = ELF32_R_SYM (rel->r_info);
-       if (r_symndx >= symtab_hdr->sh_info)
-         {
-           h = sym_hashes[r_symndx - symtab_hdr->sh_info];
-           if (h->plt.refcount > 0)
-             h->plt.refcount -= 1;
-         }
-       break;
-
-      case R_SH_GOTPLT32:
+             else if (h->got.refcount > 0)
+               h->got.refcount -= 1;
+           }
+         else if (local_got_refcounts != NULL)
+           {
 #ifdef INCLUDE_SHMEDIA
-      case R_SH_GOTPLT_LOW16:
-      case R_SH_GOTPLT_MEDLOW16:
-      case R_SH_GOTPLT_MEDHI16:
-      case R_SH_GOTPLT_HI16:
-      case R_SH_GOTPLT10BY4:
-      case R_SH_GOTPLT10BY8:
+             if (rel->r_addend & 1)
+               {
+                 if (local_got_refcounts[symtab_hdr->sh_info + r_symndx] > 0)
+                   local_got_refcounts[symtab_hdr->sh_info + r_symndx] -= 1;
+               }
+             else
 #endif
-       r_symndx = ELF32_R_SYM (rel->r_info);
-       if (r_symndx >= symtab_hdr->sh_info)
-         {
-           h = sym_hashes[r_symndx - symtab_hdr->sh_info];
-           eh = (struct elf_sh_link_hash_entry *) h;
-           if (eh->gotplt_refcount > 0)
-             {
-               eh->gotplt_refcount -= 1;
-               if (h->plt.refcount > 0)
-                 h->plt.refcount -= 1;
-             }
-           else if (h->got.refcount > 0)
-             h->got.refcount -= 1;
-         }
-       else if (local_got_refcounts != NULL)
-         {
-           if (local_got_refcounts[r_symndx] > 0)
-             local_got_refcounts[r_symndx] -= 1;
-         }
-       break;
+               if (local_got_refcounts[r_symndx] > 0)
+                 local_got_refcounts[r_symndx] -= 1;
+           }
+         break;
 
-      default:
-       break;
-      }
+       default:
+         break;
+       }
+    }
 
   return true;
 }
@@ -6027,6 +6083,9 @@ sh_elf_copy_indirect_symbol (bed, dir, ind)
      struct elf_link_hash_entry *dir, *ind;
 {
   struct elf_sh_link_hash_entry *edir, *eind;
+#ifdef INCLUDE_SHMEDIA
+  bfd_signed_vma tmp;
+#endif
 
   edir = (struct elf_sh_link_hash_entry *) dir;
   eind = (struct elf_sh_link_hash_entry *) ind;
@@ -6065,6 +6124,16 @@ sh_elf_copy_indirect_symbol (bed, dir, ind)
     }
   edir->gotplt_refcount = eind->gotplt_refcount;
   eind->gotplt_refcount = 0;
+#ifdef INCLUDE_SHMEDIA
+  tmp = edir->datalabel_got.refcount;
+  if (tmp < 1)
+    {
+      edir->datalabel_got.refcount = eind->datalabel_got.refcount;
+      eind->datalabel_got.refcount = tmp;
+    }
+  else
+    BFD_ASSERT (eind->datalabel_got.refcount < 1);
+#endif
 
   if (ind->root.type == bfd_link_hash_indirect
       && dir->got.refcount <= 0)
@@ -6145,6 +6214,9 @@ sh_elf_check_relocs (abfd, info, sec, relocs)
     {
       struct elf_link_hash_entry *h;
       unsigned long r_symndx;
+#ifdef INCLUDE_SHMEDIA
+      int seen_stt_datalabel = 0;
+#endif
 
       r_symndx = ELF32_R_SYM (rel->r_info);
       r_type = ELF32_R_TYPE (rel->r_info);
@@ -6152,7 +6224,17 @@ sh_elf_check_relocs (abfd, info, sec, relocs)
       if (r_symndx < symtab_hdr->sh_info)
        h = NULL;
       else
-       h = sym_hashes[r_symndx - symtab_hdr->sh_info];
+       {
+         h = sym_hashes[r_symndx - symtab_hdr->sh_info];
+#ifdef INCLUDE_SHMEDIA
+         while (h->root.type == bfd_link_hash_indirect
+                || h->root.type == bfd_link_hash_warning)
+           {
+             seen_stt_datalabel |= h->type == STT_DATALABEL;
+             h = (struct elf_link_hash_entry *) h->root.u.i.link;
+           }
+#endif
+       }
 
       r_type = sh_elf_optimized_tls_reloc (info, r_type, h == NULL);
       if (! info->shared
@@ -6256,7 +6338,17 @@ sh_elf_check_relocs (abfd, info, sec, relocs)
 
          if (h != NULL)
            {
-             h->got.refcount += 1;
+#ifdef INCLUDE_SHMEDIA
+             if (seen_stt_datalabel)
+               {
+                 struct elf_sh_link_hash_entry *eh = 
+                   (struct elf_sh_link_hash_entry *)h;
+
+                 eh->datalabel_got.refcount += 1;
+               }
+             else
+#endif
+               h->got.refcount += 1;
              old_tls_type = sh_elf_hash_entry (h)->tls_type;
            }
          else
@@ -6293,7 +6385,12 @@ sh_elf_check_relocs (abfd, info, sec, relocs)
                    = (char *) (local_got_refcounts + symtab_hdr->sh_info);
 #endif
                }
-             local_got_refcounts[r_symndx] += 1;
+#ifdef INCLUDE_SHMEDIA
+             if (rel->r_addend & 1)
+               local_got_refcounts[symtab_hdr->sh_info + r_symndx] += 1;
+             else
+#endif
+               local_got_refcounts[r_symndx] += 1;
              old_tls_type = sh_elf_local_got_tls_type (abfd) [r_symndx];
            }
 
@@ -6948,6 +7045,60 @@ sh_elf_finish_dynamic_symbol (output_bfd, info, h, sym)
       ++srel->reloc_count;
     }
 
+#ifdef INCLUDE_SHMEDIA
+  {
+    struct elf_sh_link_hash_entry *eh;
+
+    eh = (struct elf_sh_link_hash_entry *) h;
+    if (eh->datalabel_got.offset != (bfd_vma) -1)
+      {
+       asection *sgot;
+       asection *srel;
+       Elf_Internal_Rela rel;
+
+       /* This symbol has a datalabel entry in the global offset table.
+          Set it up.  */
+
+       sgot = htab->sgot;
+       srel = htab->srelgot;
+       BFD_ASSERT (sgot != NULL && srel != NULL);
+
+       rel.r_offset = (sgot->output_section->vma
+                       + sgot->output_offset
+                       + (eh->datalabel_got.offset &~ (bfd_vma) 1));
+
+       /* If this is a static link, or it is a -Bsymbolic link and the
+          symbol is defined locally or was forced to be local because
+          of a version file, we just want to emit a RELATIVE reloc.
+          The entry in the global offset table will already have been
+          initialized in the relocate_section function.  */
+       if (info->shared
+           && (info->symbolic
+               || h->dynindx == -1
+               || (h->elf_link_hash_flags & ELF_LINK_FORCED_LOCAL))
+           && (h->elf_link_hash_flags & ELF_LINK_HASH_DEF_REGULAR))
+         {
+           rel.r_info = ELF32_R_INFO (0, R_SH_RELATIVE);
+           rel.r_addend = (h->root.u.def.value
+                           + h->root.u.def.section->output_section->vma
+                           + h->root.u.def.section->output_offset);
+         }
+       else
+         {
+           bfd_put_32 (output_bfd, (bfd_vma) 0, sgot->contents
+                       + eh->datalabel_got.offset);
+           rel.r_info = ELF32_R_INFO (h->dynindx, R_SH_GLOB_DAT);
+           rel.r_addend = 0;
+         }
+
+       bfd_elf32_swap_reloca_out (output_bfd, &rel,
+                                  ((Elf32_External_Rela *) srel->contents
+                                   + srel->reloc_count));
+       ++srel->reloc_count;
+      }
+  }
+#endif
+
   if ((h->elf_link_hash_flags & ELF_LINK_HASH_NEEDS_COPY) != 0)
     {
       asection *s;