]> git.ipfire.org Git - thirdparty/binutils-gdb.git/commitdiff
ld: entry size and merge/strings attributes propagation
authorJan Beulich <jbeulich@suse.com>
Tue, 26 Aug 2025 08:42:03 +0000 (10:42 +0200)
committerJan Beulich <jbeulich@suse.com>
Tue, 26 Aug 2025 08:42:03 +0000 (10:42 +0200)
While commit 9c0adb10c7fc ("elf: Clear entsize when clearing
SEC_MERGE|SEC_STRINGS") addressed the particular issue reported in
PR ld/33291, it didn't go quite far enough to deal with related aspects
as well:

As indicated in other recent commits, the three properties can be
largely independent (ELF generally being the target here): Entry size
doesn't require either of merge/strings, and strings also doesn't
require merge. Commit 98e6d3f5bd4e ("gas/ELF: allow specifying entity
size for arbitrary sections") uncovered issues with ld's handling.

Zap entry size when it doesn't match between input sections. In that
case SEC_MERGE and SEC_STRINGS also need to be removed, as their
underlying granularity is lost. Then deal with SEC_MERGE and
SEC_STRINGS separately.

Otoh record entry size from the first input independent of SEC_MERGE.

ld/ldlang.c

index 0bb4a17df199a1dc8a1bbf12a603796f1abcc428..54292a8dfe17ea4e0013c4642ca25dc84d4db60d 100644 (file)
@@ -2854,15 +2854,24 @@ lang_add_section (lang_statement_list_type *ptr,
       /* Only set SEC_READONLY flag on the first input section.  */
       flags &= ~ SEC_READONLY;
 
-      /* Keep SEC_MERGE and SEC_STRINGS only if they are the same.  */
-      if ((output->bfd_section->flags & (SEC_MERGE | SEC_STRINGS))
-         != (flags & (SEC_MERGE | SEC_STRINGS))
-         || ((flags & SEC_MERGE) != 0
-             && output->bfd_section->entsize != section->entsize))
+      /* Keep entry size, SEC_MERGE, and SEC_STRINGS only if entry sizes are
+        the same.  */
+      if (output->bfd_section->entsize != section->entsize)
        {
-         output->bfd_section->flags &= ~ (SEC_MERGE | SEC_STRINGS);
          output->bfd_section->entsize = 0;
-         flags &= ~ (SEC_MERGE | SEC_STRINGS);
+         flags &= ~(SEC_MERGE | SEC_STRINGS);
+       }
+
+      /* Keep SEC_MERGE and SEC_STRINGS (each) only if they are the same.  */
+      if ((output->bfd_section->flags ^ flags) & SEC_MERGE)
+       {
+         output->bfd_section->flags &= ~SEC_MERGE;
+         flags &= ~SEC_MERGE;
+       }
+      if ((output->bfd_section->flags ^ flags) & SEC_STRINGS)
+       {
+         output->bfd_section->flags &= ~SEC_STRINGS;
+         flags &= ~SEC_STRINGS;
        }
     }
   output->bfd_section->flags |= flags;
@@ -2877,8 +2886,7 @@ lang_add_section (lang_statement_list_type *ptr,
                                     link_info.output_bfd,
                                     output->bfd_section,
                                     &link_info);
-      if ((flags & SEC_MERGE) != 0)
-       output->bfd_section->entsize = section->entsize;
+      output->bfd_section->entsize = section->entsize;
     }
 
   if ((flags & SEC_TIC54X_BLOCK) != 0