* elf64-alpha.c (ALPHA_ELF_GOT_ENTRY_RELOCS_XLATED): Defined.
authorJakub Jelinek <jakub@redhat.com>
Wed, 28 Nov 2001 19:15:14 +0000 (19:15 +0000)
committerJakub Jelinek <jakub@redhat.com>
Wed, 28 Nov 2001 19:15:14 +0000 (19:15 +0000)
(elf64_alpha_relocate_section): Translate local_got_entries
for STT_SECTION symbol to SHF_MERGE section the first time
we see it.
* elfxx-ia64.c (struct elfNN_ia64_local_hash_entry): Add
sec_merge_done.
(get_local_sym_hash): New, extracted from get_dyn_sym_info.
(get_dyn_sym_info): Use it.
(elfNN_ia64_relocate_section): Translate local dyn entries
for STT_SECTION symbol to SHF_MERGE section the first time
we see it.

        * write.c (adjust_reloc_syms): Mark SEC_MERGE symbols as used
        in reloc if it has non-zero addend.
        * config/tc-alpha.c (tc_gen_reloc): Reinstall SEC_MERGE check.
        * config/tc-sparc.c (md_apply_fix3): Likewise.

bfd/ChangeLog
bfd/elf64-alpha.c
bfd/elfxx-ia64.c
gas/ChangeLog
gas/config/tc-alpha.c
gas/config/tc-sparc.c
gas/write.c

index 9a4c51672775984587b3f43573fe3e08821cebad..b126fd7ff7d20676a5ac9e1e670510a3e64b6de6 100644 (file)
@@ -1,3 +1,17 @@
+2001-11-28  Jakub Jelinek  <jakub@redhat.com>
+
+       * elf64-alpha.c (ALPHA_ELF_GOT_ENTRY_RELOCS_XLATED): Defined.
+       (elf64_alpha_relocate_section): Translate local_got_entries
+       for STT_SECTION symbol to SHF_MERGE section the first time
+       we see it.
+       * elfxx-ia64.c (struct elfNN_ia64_local_hash_entry): Add
+       sec_merge_done.
+       (get_local_sym_hash): New, extracted from get_dyn_sym_info.
+       (get_dyn_sym_info): Use it.
+       (elfNN_ia64_relocate_section): Translate local dyn entries
+       for STT_SECTION symbol to SHF_MERGE section the first time
+       we see it.
+
 2001-11-27  H.J. Lu <hjl@gnu.org>
 
        * elflink.h (elf_bfd_discard_info): Skip if the input bfd isn't
index 783f01030805b9d9dc304805258d2955c089e0b5..950d051bf565c9135097b3f6eba5104fbbfce373 100644 (file)
@@ -170,8 +170,9 @@ struct alpha_elf_link_hash_entry
 
     int flags;
 
-    /* An additional flag.  */
+    /* Additional flags.  */
 #define ALPHA_ELF_GOT_ENTRY_RELOCS_DONE 0x10
+#define ALPHA_ELF_GOT_ENTRY_RELOCS_XLATED 0x20
 
     int use_count;
   } *got_entries;
@@ -3400,6 +3401,37 @@ elf64_alpha_relocate_section (output_bfd, info, input_bfd, input_section,
                gotent = (alpha_elf_tdata(input_bfd)->
                          local_got_entries[r_symndx]);
                dynamic_symbol = false;
+
+               /* Need to adjust local GOT entries' addends for SEC_MERGE
+                  unless it has been done already.  */
+               if ((sec->flags & SEC_MERGE)
+                   && ELF_ST_TYPE (sym->st_info) == STT_SECTION
+                   && elf_section_data (sec)->merge_info
+                   && (gotent->flags & ALPHA_ELF_GOT_ENTRY_RELOCS_XLATED) == 0)
+                 {
+                   struct alpha_elf_got_entry *ent;
+                   asection *msec;
+
+                   for (ent = gotent; ent; ent = ent->next)
+                     {
+                       ent->flags |= ALPHA_ELF_GOT_ENTRY_RELOCS_XLATED;
+                       if (ent->use_count == 0)
+                         continue;
+                       msec = sec;
+                       ent->addend =
+                         _bfd_merged_section_offset (output_bfd, &msec,
+                                                     elf_section_data (sec)->
+                                                     merge_info,
+                                                     sym->st_value
+                                                     + ent->addend,
+                                                     (bfd_vma) 0);
+                       ent->addend -= sym->st_value;
+                       ent->addend += msec->output_section->vma
+                                      + msec->output_offset
+                                      - sec->output_section->vma
+                                      - sec->output_offset;
+                     }
+                 }
              }
 
            BFD_ASSERT(gotent != NULL);
index ed06f546440cc09470969ee2f3169c6d44ade362..2e34a3071c6fcd465fb63b167222cd6b7c621944 100644 (file)
@@ -111,6 +111,10 @@ struct elfNN_ia64_local_hash_entry
 {
   struct bfd_hash_entry root;
   struct elfNN_ia64_dyn_sym_info *info;
+
+  /* True if this hash entry's addends was translated for
+     SHF_MERGE optimization.  */
+  unsigned sec_merge_done : 1;
 };
 
 struct elfNN_ia64_local_hash_table
@@ -216,6 +220,9 @@ static void elfNN_ia64_dyn_sym_traverse
           PTR info));
 static boolean elfNN_ia64_create_dynamic_sections
   PARAMS ((bfd *abfd, struct bfd_link_info *info));
+static struct elfNN_ia64_local_hash_entry * get_local_sym_hash
+  PARAMS ((struct elfNN_ia64_link_hash_table *ia64_info,
+          bfd *abfd, const Elf_Internal_Rela *rel, boolean create));
 static struct elfNN_ia64_dyn_sym_info * get_dyn_sym_info
   PARAMS ((struct elfNN_ia64_link_hash_table *ia64_info,
           struct elf_link_hash_entry *h,
@@ -1719,6 +1726,32 @@ elfNN_ia64_create_dynamic_sections (abfd, info)
   return true;
 }
 
+/* Find and/or create a hash entry for local symbol.  */
+static struct elfNN_ia64_local_hash_entry *
+get_local_sym_hash (ia64_info, abfd, rel, create)
+     struct elfNN_ia64_link_hash_table *ia64_info;
+     bfd *abfd;
+     const Elf_Internal_Rela *rel;
+     boolean create;
+{
+  char *addr_name;
+  size_t len;
+
+  /* Construct a string for use in the elfNN_ia64_local_hash_table.
+     name describes what was once anonymous memory.  */
+
+  len = sizeof (void*)*2 + 1 + sizeof (bfd_vma)*4 + 1 + 1;
+  len += 10;   /* %p slop */
+
+  addr_name = alloca (len);
+  sprintf (addr_name, "%p:%lx",
+          (void *) abfd, (unsigned long) ELFNN_R_SYM (rel->r_info));
+
+  /* Collect the canonical entry data for this address.  */
+  return elfNN_ia64_local_hash_lookup (&ia64_info->loc_hash_table,
+                                      addr_name, create, create);
+}
+
 /* Find and/or create a descriptor for dynamic symbol info.  This will
    vary based on global or local symbol, and the addend to the reloc.  */
 
@@ -1739,22 +1772,8 @@ get_dyn_sym_info (ia64_info, h, abfd, rel, create)
   else
     {
       struct elfNN_ia64_local_hash_entry *loc_h;
-      char *addr_name;
-      size_t len;
-
-      /* Construct a string for use in the elfNN_ia64_local_hash_table.
-         The name describes what was once anonymous memory.  */
-
-      len = sizeof (void*)*2 + 1 + sizeof (bfd_vma)*4 + 1 + 1;
-      len += 10;       /* %p slop */
-
-      addr_name = alloca (len);
-      sprintf (addr_name, "%p:%lx",
-              (void *) abfd, (unsigned long) ELFNN_R_SYM (rel->r_info));
 
-      /* Collect the canonical entry data for this address.  */
-      loc_h = elfNN_ia64_local_hash_lookup (&ia64_info->loc_hash_table,
-                                           addr_name, create, create);
+      loc_h = get_local_sym_hash (ia64_info, abfd, rel, create);
       BFD_ASSERT (loc_h);
 
       pp = &loc_h->info;
@@ -3482,6 +3501,37 @@ elfNN_ia64_relocate_section (output_bfd, info, input_bfd, input_section,
          sym = local_syms + r_symndx;
          sym_sec = local_sections[r_symndx];
          value = _bfd_elf_rela_local_sym (output_bfd, sym, sym_sec, rel);
+         if ((sym_sec->flags & SEC_MERGE)
+             && ELF_ST_TYPE (sym->st_info) == STT_SECTION
+             && elf_section_data (sym_sec)->merge_info)
+           {
+             struct elfNN_ia64_local_hash_entry *loc_h;
+      
+             loc_h = get_local_sym_hash (ia64_info, input_bfd, rel, false);
+             if (loc_h && ! loc_h->sec_merge_done)
+               {
+                 struct elfNN_ia64_dyn_sym_info *dynent;
+                 asection *msec;
+
+                 for (dynent = loc_h->info; dynent; dynent = dynent->next)
+                   {
+                     msec = sym_sec;
+                     dynent->addend =
+                       _bfd_merged_section_offset (output_bfd, &msec,
+                                                   elf_section_data (msec)->
+                                                   merge_info,
+                                                   sym->st_value
+                                                   + dynent->addend,
+                                                   (bfd_vma) 0);
+                     dynent->addend -= sym->st_value;
+                     dynent->addend += msec->output_section->vma
+                                       + msec->output_offset
+                                       - sym_sec->output_section->vma
+                                       - sym_sec->output_offset;
+                   }
+                 loc_h->sec_merge_done = 1;
+               }
+           }
        }
       else
        {
index 261ce4d0249c399b83c0aac58c902a42b60cb295..b07bb46dc5b38e7cd7119cf956a776aba9054ae2 100644 (file)
@@ -1,3 +1,10 @@
+2001-11-28  Jakub Jelinek  <jakub@redhat.com>
+
+       * write.c (adjust_reloc_syms): Mark SEC_MERGE symbols as used
+       in reloc if it has non-zero addend.
+       * config/tc-alpha.c (tc_gen_reloc): Reinstall SEC_MERGE check.
+       * config/tc-sparc.c (md_apply_fix3): Likewise.
+
 2001-11-28  Andreas Schwab  <schwab@suse.de>
 
        * as.c (parse_args): Call md_after_parse_args if defined.
index f9908e7924ac1553383bf27080efe6770d7e49ad..f73c8628e477229e1a591b86009105b2c9705fa9 100644 (file)
@@ -1507,7 +1507,8 @@ tc_gen_reloc (sec, fixp)
        * at assembly time.  bfd_perform_reloc doesn't know about this sort
        * of thing, and as a result we need to fake it out here.
        */
-      if ((S_IS_EXTERN (fixp->fx_addsy) || S_IS_WEAK (fixp->fx_addsy))
+      if ((S_IS_EXTERN (fixp->fx_addsy) || S_IS_WEAK (fixp->fx_addsy)
+          || (S_GET_SEGMENT (fixp->fx_addsy)->flags & SEC_MERGE))
          && !S_IS_COMMON (fixp->fx_addsy))
        reloc->addend -= symbol_get_bfdsym (fixp->fx_addsy)->value;
 #endif
index f1639a3f1666685f1b1098416a87e7311e0c50db..2db2bac12ba7f5980851c8262ee7259d1b33ccbf 100644 (file)
@@ -2909,12 +2909,7 @@ md_apply_fix3 (fixP, valP, segment)
       if (symbol_used_in_reloc_p (sym)
          && (S_IS_EXTERNAL (sym)
              || S_IS_WEAK (sym)
-#if 0 /* Although fixups against local symbols in SEC_MERGE sections
-        should be treated as if they were against external symbols
-        write.c:fixup_segment() will not have included the value of
-        the symbol under these particular cicumstances.  */
              || (seg->flags & SEC_MERGE)
-#endif
              || (sparc_pic_code && ! fixP->fx_pcrel)
              || (seg != segment
                  && (((bfd_get_section_flags (stdoutput, seg) & SEC_LINK_ONCE) != 0)
index 5397aa09949dc4d28d1b7b68cfaccb856b8e8a99..55db85a7ec91e30f1f861021f3f65c86512d965a 100644 (file)
@@ -873,6 +873,14 @@ adjust_reloc_syms (abfd, sec, xxx)
            symbol_mark_used_in_reloc (fixp->fx_addsy);
            goto done;
          }
+
+       /* Never adjust a reloc against local symbol in a merge section
+          with non-zero addend.  */
+       if ((symsec->flags & SEC_MERGE) && fixp->fx_offset)
+         {
+           symbol_mark_used_in_reloc (fixp->fx_addsy);
+           goto done;
+         }
 #endif
 
        /* Is there some other reason we can't adjust this one?  (E.g.,