]> git.ipfire.org Git - thirdparty/binutils-gdb.git/commitdiff
bfd: generalize _bfd_elf_merge_sections()
authorJan Beulich <jbeulich@suse.com>
Fri, 24 Oct 2025 13:11:11 +0000 (15:11 +0200)
committerJan Beulich <jbeulich@suse.com>
Fri, 24 Oct 2025 13:11:11 +0000 (15:11 +0200)
Except for the ELF class check, which isn't needed anymore when the
generic linker knows how to deal with SEC_MERGE sections, there isn't
anything substantially ELF-specific left in the function.

This also eliminates the need for the "remove_hook" callback.

As a result, section merging itself now works for mixed-class ELF input
objects (issues with dropping of symbols and relocations that were there
before for such cases remain present, though), i.e. the PR ld/19013
testcases need adjusting accordingly: Both now expect identical .rodata
contents. While making the change, add another line of expected output,
to properly match after "#...". Else a mismatch on the important line
isn't properly visible in ld.log.

In set_symbol_from_hash() additionally set BSF_GLOBAL when dealing with a
defined symbol. Without that the if() body ahead of the one being added to
default_indirect_link_order() would not be entered once previously
undefined symbols become defined (suggesting that there is a pre-existing
issue there).

12 files changed:
bfd/bfd-in2.h
bfd/elf-bfd.h
bfd/elflink.c
bfd/elfxx-target.h
bfd/libbfd-in.h
bfd/libbfd.h
bfd/linker.c
bfd/merge.c
bfd/reloc.c
bfd/syms.c
ld/testsuite/ld-x86-64/pr19013-x32.d
ld/testsuite/ld-x86-64/pr19013.d

index ad6077f093ac4a268fc0a3d23f994a62f7c29ac1..8f3b0f7c255d81b54692a29adb6336c05f873cb0 100644 (file)
@@ -1190,6 +1190,9 @@ typedef struct bfd_symbol
   /* This section symbol should be included in the symbol table.  */
 #define BSF_SECTION_SYM_USED    (1 << 24)
 
+  /* This symbol underwent section merge resolution.  */
+#define BSF_MERGE_RESOLVED      (1 << 25)
+
   flagword flags;
 
   /* A pointer to the section to which this symbol is
index 4ed71095ea6dd2755508fc4a714f2f8bc1a635e9..850a86fda253873e6f908bf6b7d5064b739d2f68 100644 (file)
@@ -2363,8 +2363,6 @@ extern bool _bfd_elf_link_hash_table_init
    unsigned int);
 extern bool _bfd_elf_slurp_version_tables
   (bfd *, bool);
-extern bool _bfd_elf_merge_sections
-  (bfd *, struct bfd_link_info *);
 extern bool _bfd_elf_match_sections_by_type
   (bfd *, const asection *, bfd *, const asection *);
 extern bool bfd_elf_is_group_section
index 2dd121de4a7412a44287265a762e1190f6de227a..fd0e549eb1063f887b4c64aed5e0cfba9b3ca579 100644 (file)
@@ -8158,46 +8158,6 @@ bfd_elf_size_dynsym_hash_dynstr (bfd *output_bfd, struct bfd_link_info *info)
   return true;
 }
 \f
-/* Make sure sec_info_type is cleared if sec_info is cleared too.  */
-
-static void
-merge_sections_remove_hook (bfd *abfd ATTRIBUTE_UNUSED,
-                           asection *sec)
-{
-  BFD_ASSERT (sec->sec_info_type == SEC_INFO_TYPE_MERGE);
-  sec->sec_info_type = SEC_INFO_TYPE_NONE;
-}
-
-/* Finish SHF_MERGE section merging.  */
-
-bool
-_bfd_elf_merge_sections (bfd *obfd, struct bfd_link_info *info)
-{
-  bfd *ibfd;
-  asection *sec;
-
-  if (ENABLE_CHECKING && !is_elf_hash_table (info->hash))
-    abort ();
-
-  for (ibfd = info->input_bfds; ibfd != NULL; ibfd = ibfd->link.next)
-    if ((ibfd->flags & DYNAMIC) == 0
-       && bfd_get_flavour (ibfd) == bfd_target_elf_flavour
-       && (elf_elfheader (ibfd)->e_ident[EI_CLASS]
-           == get_elf_backend_data (obfd)->s->elfclass))
-      for (sec = ibfd->sections; sec != NULL; sec = sec->next)
-       if ((sec->flags & SEC_MERGE) != 0
-           && !bfd_is_abs_section (sec->output_section)
-           && !_bfd_add_merge_section (obfd,
-                                       &info->hash->merge_info,
-                                       sec))
-             return false;
-
-  if (info->hash->merge_info != NULL)
-    return _bfd_merge_sections (obfd, info, info->hash->merge_info,
-                               merge_sections_remove_hook);
-  return true;
-}
-
 /* Create an entry in an ELF linker hash table.  */
 
 struct bfd_hash_entry *
index 4cf02bbedd7e5270fa83f28ab3badb73f9d5b5d1..839555647b049bc032a414a0b6307dc6c9b08250 100644 (file)
 #define bfd_elfNN_bfd_final_link       bfd_elf_final_link
 #endif
 #ifndef bfd_elfNN_bfd_merge_sections
-#define bfd_elfNN_bfd_merge_sections   _bfd_elf_merge_sections
+#define bfd_elfNN_bfd_merge_sections   _bfd_merge_sections
 #endif
 #else /* ! defined (elf_backend_relocate_section) */
 /* If no backend relocate_section routine, use the generic linker.
index 5a0a6696b51c8955a878119a760b4e2e30b87687..8caec1c76a6ec3ef7e30d244a5c7d878a44f4b4e 100644 (file)
@@ -688,16 +688,10 @@ extern bfd_reloc_status_type _bfd_relocate_contents
 extern bfd_reloc_status_type _bfd_clear_contents
   (reloc_howto_type *, bfd *, asection *, bfd_byte *, bfd_vma) ATTRIBUTE_HIDDEN;
 
-/* Register a SEC_MERGE section as a candidate for merging.  */
-
-extern bool _bfd_add_merge_section
-  (bfd *, void **, asection *) ATTRIBUTE_HIDDEN;
-
 /* Attempt to merge SEC_MERGE sections.  */
 
 extern bool _bfd_merge_sections
-  (bfd *, struct bfd_link_info *, void *, void (*) (bfd *, asection *))
-  ATTRIBUTE_HIDDEN;
+  (bfd *, struct bfd_link_info *) ATTRIBUTE_HIDDEN;
 
 /* Write out a merged section.  */
 
index 9c3c98e04cbab383946c48eda34b0b9834118bb3..617df41924e2944f6b242998e458bd72de579d26 100644 (file)
@@ -694,16 +694,10 @@ extern bfd_reloc_status_type _bfd_relocate_contents
 extern bfd_reloc_status_type _bfd_clear_contents
   (reloc_howto_type *, bfd *, asection *, bfd_byte *, bfd_vma) ATTRIBUTE_HIDDEN;
 
-/* Register a SEC_MERGE section as a candidate for merging.  */
-
-extern bool _bfd_add_merge_section
-  (bfd *, void **, asection *) ATTRIBUTE_HIDDEN;
-
 /* Attempt to merge SEC_MERGE sections.  */
 
 extern bool _bfd_merge_sections
-  (bfd *, struct bfd_link_info *, void *, void (*) (bfd *, asection *))
-  ATTRIBUTE_HIDDEN;
+  (bfd *, struct bfd_link_info *) ATTRIBUTE_HIDDEN;
 
 /* Write out a merged section.  */
 
index ae44ec3f2d2923e389c27d48caea1e1c6da27852..6e2ef059b52e4dbb9a8151bccc80fe817e99f3c8 100644 (file)
@@ -2310,7 +2310,9 @@ _bfd_generic_link_output_symbols (bfd *output_bfd,
    hash table entry.  */
 
 static void
-set_symbol_from_hash (asymbol *sym, struct bfd_link_hash_entry *h)
+set_symbol_from_hash (bfd *output_bfd,
+                     asymbol *sym,
+                     struct bfd_link_hash_entry *h)
 {
   switch (h->type)
     {
@@ -2341,13 +2343,26 @@ set_symbol_from_hash (asymbol *sym, struct bfd_link_hash_entry *h)
       sym->flags |= BSF_WEAK;
       break;
     case bfd_link_hash_defined:
+      sym->flags |= BSF_GLOBAL;
       sym->section = h->u.def.section;
       sym->value = h->u.def.value;
+      if (sym->section->sec_info_type == SEC_INFO_TYPE_MERGE)
+       {
+         sym->value =
+           _bfd_merged_section_offset (output_bfd, &sym->section, sym->value);
+         sym->flags |= BSF_MERGE_RESOLVED;
+       }
       break;
     case bfd_link_hash_defweak:
       sym->flags |= BSF_WEAK;
       sym->section = h->u.def.section;
       sym->value = h->u.def.value;
+      if (sym->section->sec_info_type == SEC_INFO_TYPE_MERGE)
+       {
+         sym->value =
+           _bfd_merged_section_offset (output_bfd, &sym->section, sym->value);
+         sym->flags |= BSF_MERGE_RESOLVED;
+       }
       break;
     case bfd_link_hash_common:
       sym->value = h->u.c.size;
@@ -2402,7 +2417,7 @@ _bfd_generic_link_write_global_symbol (struct generic_link_hash_entry *h,
       sym->flags = 0;
     }
 
-  set_symbol_from_hash (sym, &h->root);
+  set_symbol_from_hash (wginfo->output_bfd, sym, &h->root);
 
   sym->flags |= BSF_GLOBAL;
 
@@ -2690,7 +2705,7 @@ default_indirect_link_order (bfd *output_bfd,
       for (; sympp < symppend; sympp++)
        {
          asymbol *sym;
-         struct bfd_link_hash_entry *h;
+         struct bfd_link_hash_entry *h = NULL;
 
          sym = *sympp;
 
@@ -2716,9 +2731,22 @@ default_indirect_link_order (bfd *output_bfd,
                                          bfd_asymbol_name (sym),
                                          false, false, true);
              if (h != NULL)
-               set_symbol_from_hash (sym, h);
+               set_symbol_from_hash (output_bfd, sym, h);
+           }
+
+         if (h == NULL
+             && sym->section->sec_info_type == SEC_INFO_TYPE_MERGE
+             && !(sym->flags & (BSF_SECTION_SYM | BSF_MERGE_RESOLVED)))
+           {
+             sym->value = _bfd_merged_section_offset (output_bfd,
+                                                      &sym->section,
+                                                      sym->value);
+             sym->flags |= BSF_MERGE_RESOLVED;
            }
        }
+
+      if (input_section->sec_info_type == SEC_INFO_TYPE_MERGE)
+       return _bfd_write_merged_section (output_bfd, input_section);
     }
 
   if ((output_section->flags & (SEC_GROUP | SEC_LINKER_CREATED)) == SEC_GROUP
index 6f068b6117b9cdbae06c91b6480b45ebfaa1387d..d89f4800f8a51a08a82264a0c02710929a5a90f5 100644 (file)
@@ -608,7 +608,7 @@ sec_merge_emit (bfd *abfd, struct sec_merge_sec_info *secinfo,
 /* Register a SEC_MERGE section as a candidate for merging.
    This function is called for all non-dynamic SEC_MERGE input sections.  */
 
-bool
+static bool
 _bfd_add_merge_section (bfd *abfd, void **psinfo, asection *sec)
 {
   struct sec_merge_info *sinfo;
@@ -973,11 +973,10 @@ merge_strings (struct sec_merge_info *sinfo)
 /* This function is called once after all SEC_MERGE sections are registered
    with _bfd_merge_section.  */
 
-bool
-_bfd_merge_sections (bfd *abfd,
-                    struct bfd_link_info *info ATTRIBUTE_UNUSED,
-                    void *xsinfo,
-                    void (*remove_hook) (bfd *, asection *))
+static bool
+merge_sections (bfd *abfd,
+               struct bfd_link_info *info ATTRIBUTE_UNUSED,
+               void *xsinfo)
 {
   struct sec_merge_info *sinfo;
 
@@ -995,9 +994,9 @@ _bfd_merge_sections (bfd *abfd,
        if (secinfo->sec->flags & SEC_EXCLUDE
            || !record_section (sinfo, secinfo))
          {
+           BFD_ASSERT (secinfo->sec->sec_info_type == SEC_INFO_TYPE_MERGE);
            secinfo->sec->sec_info = NULL;
-           if (remove_hook)
-             (*remove_hook) (abfd, secinfo->sec);
+           secinfo->sec->sec_info_type = SEC_INFO_TYPE_NONE;
          }
        else if (align)
          {
@@ -1056,6 +1055,30 @@ _bfd_merge_sections (bfd *abfd,
   return true;
 }
 
+/* Finish SEC_MERGE section merging.  */
+
+bool
+_bfd_merge_sections (bfd *obfd, struct bfd_link_info *info)
+{
+  const bfd *ibfd;
+  asection *sec;
+
+  for (ibfd = info->input_bfds; ibfd != NULL; ibfd = ibfd->link.next)
+    if ((ibfd->flags & DYNAMIC) == 0)
+      for (sec = ibfd->sections; sec != NULL; sec = sec->next)
+       if ((sec->flags & SEC_MERGE) != 0
+           && !bfd_is_abs_section (sec->output_section)
+           && !_bfd_add_merge_section (obfd,
+                                       &info->hash->merge_info,
+                                       sec))
+             return false;
+
+  if (info->hash->merge_info == NULL)
+    return true;
+
+  return merge_sections (obfd, info, info->hash->merge_info);
+}
+
 /* Write out the merged section.  */
 
 bool
index c9d53bb9e11b93d5394bd7e0bbd511a9852d550a..aa69a3c2dc93b3f5ca987a5a5571b70f4ae756cf 100644 (file)
@@ -8554,12 +8554,30 @@ bfd_generic_get_relocated_section_contents (bfd *abfd,
              r = bfd_reloc_ok;
            }
          else
-           r = bfd_perform_relocation (input_bfd,
-                                       *parent,
-                                       data,
-                                       input_section,
-                                       relocatable ? abfd : NULL,
-                                       &error_message);
+           {
+             if ((symbol->flags & BSF_SECTION_SYM)
+                 && symbol->section->sec_info_type == SEC_INFO_TYPE_MERGE
+                 /* This, while apparently necessary, feels bogus.  */
+                 && !(symbol->section->flags & SEC_DEBUGGING))
+               {
+                 asection *sec = symbol->section;
+
+                 (*parent)->addend =
+                   _bfd_merged_section_offset (abfd, &sec, (*parent)->addend);
+                 /* We may not change symbol->section, so the output_offset
+                    adjustment done in bfd_perform_relocation() needs taking
+                    care of (and compensating) here.  */
+                 (*parent)->addend +=
+                   sec->output_offset - symbol->section->output_offset;
+               }
+
+             r = bfd_perform_relocation (input_bfd,
+                                         *parent,
+                                         data,
+                                         input_section,
+                                         relocatable ? abfd : NULL,
+                                         &error_message);
+           }
 
          if (relocatable)
            {
index df2229b3fa3f7485d5944c20fe8d5afaa4cf2de7..b8f21c5fc0c4c1b63c59c223bdd1c41036c6c58a 100644 (file)
@@ -303,6 +303,9 @@ CODE_FRAGMENT
 .  {* This section symbol should be included in the symbol table.  *}
 .#define BSF_SECTION_SYM_USED    (1 << 24)
 .
+.  {* This symbol underwent section merge resolution.  *}
+.#define BSF_MERGE_RESOLVED      (1 << 25)
+.
 .  flagword flags;
 .
 .  {* A pointer to the section to which this symbol is
index 5634b87f7c821293ab0d36c44b142eb55ecd3ae3..60f0be0b59e713dc299a6825181bf54dc9cf881f 100644 (file)
@@ -2,7 +2,4 @@
 #as: --x32
 #ld: --oformat elf32-i386 -m elf32_x86_64
 #objdump: -s -j .rodata
-
-#...
- [0-9a-f]+ 02030041 42434400 +...ABCD. +
-#pass
+#dump: pr19013.d
index 97137a793e1fbf45b9d865facbd6acc8e31582ac..2a1fe9b3e6fa380b7ff8b3b65113b1a621c3d320 100644 (file)
@@ -3,5 +3,6 @@
 #objdump: -s -j .rodata
 
 #...
- [0-9a-f]+ 00000203 00414243 4400 +.....ABCD. +
+Contents of section \.rodata:
+ [0-9a-f]+ 02030041 42434400 +...ABCD. +
 #pass