]> git.ipfire.org Git - thirdparty/binutils-gdb.git/commitdiff
gas: add --reloc-section-sym={all,internal,none} option for ELF
authorFangrui Song <maskray@sourceware.org>
Sun, 8 Feb 2026 19:56:49 +0000 (11:56 -0800)
committerFangrui Song <i@maskray.me>
Sun, 5 Jul 2026 15:16:40 +0000 (08:16 -0700)
When generating relocations for non-ifunc local symbols that satisfies
several conditions, GAS converts them to reference the section symbol
(STT_SECTION) instead, folding the original symbol's offset into the
addend.  This allows the original local symbol to be omitted from
.symtab, but the STT_SECTION symbol itself must be present, so the
conversion saves .symtab entries only when a section has more than one
local symbol referenced by relocations.

Add --reloc-section-sym to control this conversion:

- all (default): convert all eligible local symbols
- internal: only convert compiler-generated locals (.L prefix)
- none: never convert; keep all symbols as-is in relocations

This is useful for debugging and for tools that benefit from preserved
symbol names.

PR gas/33885

15 files changed:
gas/NEWS
gas/as.c
gas/as.h
gas/doc/as.texi
gas/testsuite/gas/elf/elf.exp
gas/testsuite/gas/elf/reloc-section-sym-all.d [new file with mode: 0644]
gas/testsuite/gas/elf/reloc-section-sym-internal.d [new file with mode: 0644]
gas/testsuite/gas/elf/reloc-section-sym-none.d [new file with mode: 0644]
gas/testsuite/gas/elf/reloc-section-sym.s [new file with mode: 0644]
gas/testsuite/gas/i386/reloc-section-sym-all.d [new file with mode: 0644]
gas/testsuite/gas/i386/reloc-section-sym-internal.d [new file with mode: 0644]
gas/testsuite/gas/i386/reloc-section-sym-none.d [new file with mode: 0644]
gas/testsuite/gas/i386/reloc-section-sym.s [new file with mode: 0644]
gas/testsuite/gas/i386/x86-64.exp
gas/write.c

index 60ab138384e21b6e092654be6e28a88c20fa532a..38928ab83ff51d84f1284d9a48c97852b6f4c64f 100644 (file)
--- a/gas/NEWS
+++ b/gas/NEWS
@@ -1,5 +1,9 @@
 -*- text -*-
 
+* New command line option --reloc-section-sym=[all|internal|none]
+  controls whether relocations referencing local binding symbols are adjusted
+  to use section symbols.
+
 * The aarch64 extensions TME and MPAMv2_VID have never been implemented in any
   products.  Arm has withdrawn them from the architecture.  The assembler will
   now warn if instructions or system registers from either extension are
index f33f6ec85cd7414b2c91096a0f34dd41a8b2c07d..b652e81286c89ee0274a3bcf02cf4cf1c6284bca 100644 (file)
--- a/gas/as.c
+++ b/gas/as.c
@@ -326,6 +326,10 @@ Options:\n\
           DEFAULT_SFRAME ? "yes" : "no");
   fprintf (stream, _("\
   --gsframe-<N>           generate SFrame version <N> information. 3 == <N>\n"));
+  fprintf (stream, _("\
+  --reloc-section-sym=[all|internal|none]\n\
+                          adjust eligible relocations to use section symbols\n\
+                          (default: all)\n"));
 # if defined (TARGET_USE_SCFI) && defined (TARGET_USE_GINSN)
   fprintf (stream, _("\
   --scfi=experimental     Synthesize DWARF CFI for hand-written asm\n\
@@ -523,7 +527,8 @@ parse_args (int * pargc, char *** pargv)
       OPTION_SFRAME_3,
       OPTION_SCFI,
       OPTION_INFO,
-      OPTION_NOINFO
+      OPTION_NOINFO,
+      OPTION_RELOC_SECTION_SYM
     /* When you add options here, check that they do
        not collide with OPTION_MD_BASE.  See as.h.  */
     };
@@ -556,6 +561,7 @@ parse_args (int * pargc, char *** pargv)
     ,{"generate-missing-build-notes", required_argument, NULL, OPTION_ELF_BUILD_NOTES}
     ,{"gsframe", optional_argument, NULL, OPTION_SFRAME}
     ,{"gsframe-3", no_argument, NULL, OPTION_SFRAME_3}
+    ,{"reloc-section-sym", required_argument, NULL, OPTION_RELOC_SECTION_SYM}
 # if defined (TARGET_USE_SCFI) && defined (TARGET_USE_GINSN)
     ,{"scfi", required_argument, NULL, OPTION_SCFI}
 # endif
@@ -1043,6 +1049,18 @@ This program has absolutely no warranty.\n"));
          flag_sectname_subst = 1;
          break;
 
+       case OPTION_RELOC_SECTION_SYM:
+         if (strcasecmp (optarg, "all") == 0)
+           flag_reloc_section_sym = reloc_section_sym_all;
+         else if (strcasecmp (optarg, "internal") == 0)
+           flag_reloc_section_sym = reloc_section_sym_internal;
+         else if (strcasecmp (optarg, "none") == 0)
+           flag_reloc_section_sym = reloc_section_sym_none;
+         else
+           as_fatal (_("Invalid --reloc-section-sym= option: `%s'"),
+                     optarg);
+         break;
+
        case OPTION_ELF_BUILD_NOTES:
          if (strcasecmp (optarg, "no") == 0)
            flag_generate_build_notes = false;
index 94bc816be1e7dbd1ad919feead7daadc87a6a0ba..2fe0a48a225a1b9f57457288adada916e64473b9 100644 (file)
--- a/gas/as.h
+++ b/gas/as.h
@@ -405,6 +405,16 @@ enum multibyte_input_handling
 };
 COMMON enum multibyte_input_handling multibyte_handling;
 
+/* Controls whether relocations referencing local symbols are converted
+   to use section symbols.  */
+enum reloc_section_sym_type
+{
+  reloc_section_sym_all = 0,
+  reloc_section_sym_internal,
+  reloc_section_sym_none
+};
+COMMON enum reloc_section_sym_type flag_reloc_section_sym;
+
 /* TRUE if we should produce a listing.  */
 extern int listing;
 
index 3c4d20bd7d4e12ed0d2219dd2f3e066b5fb99106..5d7772d62d3bca0cf5078e8e6e3773c8613e6f94 100644 (file)
@@ -257,6 +257,7 @@ gcc(1), ld(1), and the Info entries for @file{binutils} and @file{ld}.
  [@b{--multibyte-handling=[allow|warn|warn-sym-only]}]
  [@b{--no-pad-sections}]
  [@b{-o} @var{objfile}] [@b{-R}]
+ [@b{--reloc-section-sym=[all|internal|none]}]
  [@b{--scfi=experimental}]
  [@b{--sectname-subst}]
  [@b{--size-check=[error|warning]}]
@@ -956,6 +957,16 @@ Ignored.  Supported for compatibility with tools that pass the same option to
 both the assembler and the linker.
 
 @ifset ELF
+@item --reloc-section-sym=all
+@itemx --reloc-section-sym=internal
+@itemx --reloc-section-sym=none
+Control whether relocations referencing local binding symbols are adjusted to
+use section symbols instead.  With @code{all} (the default), relocations
+against all eligible local binding symbols are converted.  With
+@code{internal}, only relocations against internal labels (symbols matching the
+@code{.L} prefix) are converted.  With @code{none}, no such conversions are
+performed.
+
 @item --scfi=experimental
 This option controls whether the assembler should synthesize CFI for
 hand-written input.  If the input already contains some synthesizable CFI
index 2232e2d58d9986146b52bf36684d9be3ef70e588..5580c494c543871db1d0b51e04377adf90f7ef6e 100644 (file)
@@ -188,15 +188,18 @@ if { [is_elf_format] } then {
        rx-*-* { }
        loongarch*-*-* { }
        default {
-           # The next test can fail if the target does not convert fixups
+           # The following tests can fail if the target does not convert fixups
            # against ordinary symbols into relocations against section symbols.
-           # This is usually revealed by the error message:
-           #  symbol `sym' required but not present
            setup_xfail "m681*-*-*" "m68hc*-*-*" "xgate-*-*" "vax-*-*" "avr-*-*"
            run_dump_test redef
            run_dump_test equ-reloc
+           setup_xfail "m681*-*-*" "m68hc*-*-*" "xgate-*-*" "vax-*-*" "avr-*-*"
+           run_dump_test "reloc-section-sym-all"
+           setup_xfail "m681*-*-*" "m68hc*-*-*" "xgate-*-*" "avr-*-*"
+           run_dump_test "reloc-section-sym-internal"
        }
     }
+    run_dump_test "reloc-section-sym-none"
     run_dump_test "pseudo"
     run_dump_test "text-prev" $dump_opts
     run_dump_test "text-subsect" $dump_opts
diff --git a/gas/testsuite/gas/elf/reloc-section-sym-all.d b/gas/testsuite/gas/elf/reloc-section-sym-all.d
new file mode 100644 (file)
index 0000000..b4da309
--- /dev/null
@@ -0,0 +1,12 @@
+#source: reloc-section-sym.s
+#as: --reloc-section-sym=all
+#objdump: -rsj .data
+#name: reloc-section-sym=all
+
+.*: +file format .*
+
+RELOCATION RECORDS FOR \[\.data\]:
+OFFSET +TYPE +VALUE
+0*0 [^ ]+ +\.bss.*
+0*4 [^ ]+ +\.bss.*
+#pass
diff --git a/gas/testsuite/gas/elf/reloc-section-sym-internal.d b/gas/testsuite/gas/elf/reloc-section-sym-internal.d
new file mode 100644 (file)
index 0000000..0c0f464
--- /dev/null
@@ -0,0 +1,12 @@
+#source: reloc-section-sym.s
+#as: --reloc-section-sym=internal
+#objdump: -rsj .data
+#name: reloc-section-sym=internal
+
+.*: +file format .*
+
+RELOCATION RECORDS FOR \[\.data\]:
+OFFSET +TYPE +VALUE
+0*0 [^ ]+ +local.*
+0*4 [^ ]+ +\.bss.*
+#pass
diff --git a/gas/testsuite/gas/elf/reloc-section-sym-none.d b/gas/testsuite/gas/elf/reloc-section-sym-none.d
new file mode 100644 (file)
index 0000000..557728b
--- /dev/null
@@ -0,0 +1,12 @@
+#source: reloc-section-sym.s
+#as: --reloc-section-sym=none
+#objdump: -rsj .data
+#name: reloc-section-sym=none
+
+.*: +file format .*
+
+RELOCATION RECORDS FOR \[\.data\]:
+OFFSET +TYPE +VALUE
+0*0 [^ ]+ +local.*
+0*4 [^ ]+ +\.Ltemp.*
+#pass
diff --git a/gas/testsuite/gas/elf/reloc-section-sym.s b/gas/testsuite/gas/elf/reloc-section-sym.s
new file mode 100644 (file)
index 0000000..37f1258
--- /dev/null
@@ -0,0 +1,9 @@
+       .section .bss
+local:
+       .zero 1
+.Ltemp:
+       .zero 1
+
+       .data
+       .long local + 16
+       .long .Ltemp + 16
diff --git a/gas/testsuite/gas/i386/reloc-section-sym-all.d b/gas/testsuite/gas/i386/reloc-section-sym-all.d
new file mode 100644 (file)
index 0000000..2c8fd57
--- /dev/null
@@ -0,0 +1,23 @@
+#source: reloc-section-sym.s
+#as: --reloc-section-sym=all
+#objdump: -rsj .data -j .text1
+#name: reloc-section-sym=all
+
+.*:     file format .*
+
+RELOCATION RECORDS FOR \[\.data\]:
+OFFSET +TYPE +VALUE
+0+0 R_X86_64_64 +\.text\+0x0+11
+0+8 R_X86_64_64 +\.text\+0x0+12
+
+
+RELOCATION RECORDS FOR \[\.text1\]:
+OFFSET +TYPE +VALUE
+0+1 R_X86_64_PC32 +\.text-0x0+3
+0+6 R_X86_64_PC32 +\.text-0x0+2
+
+
+Contents of section \.data:
+ 0000 00000000 00000000 00000000 00000000  \.+
+Contents of section \.text1:
+ 0000 e8000000 00e80000 0000 +.*
diff --git a/gas/testsuite/gas/i386/reloc-section-sym-internal.d b/gas/testsuite/gas/i386/reloc-section-sym-internal.d
new file mode 100644 (file)
index 0000000..2387fab
--- /dev/null
@@ -0,0 +1,23 @@
+#source: reloc-section-sym.s
+#as: --reloc-section-sym=internal
+#objdump: -rsj .data -j .text1
+#name: reloc-section-sym=internal
+
+.*:     file format .*
+
+RELOCATION RECORDS FOR \[\.data\]:
+OFFSET +TYPE +VALUE
+0+0 R_X86_64_64 +named_local\+0x0+10
+0+8 R_X86_64_64 +\.text\+0x0+12
+
+
+RELOCATION RECORDS FOR \[\.text1\]:
+OFFSET +TYPE +VALUE
+0+1 R_X86_64_PC32 +named_local-0x0+4
+0+6 R_X86_64_PC32 +\.text-0x0+2
+
+
+Contents of section \.data:
+ 0000 00000000 00000000 00000000 00000000  \.+
+Contents of section \.text1:
+ 0000 e8000000 00e80000 0000 +.*
diff --git a/gas/testsuite/gas/i386/reloc-section-sym-none.d b/gas/testsuite/gas/i386/reloc-section-sym-none.d
new file mode 100644 (file)
index 0000000..8f7fe3f
--- /dev/null
@@ -0,0 +1,23 @@
+#source: reloc-section-sym.s
+#as: --reloc-section-sym=none
+#objdump: -rsj .data -j .text1
+#name: reloc-section-sym=none
+
+.*:     file format .*
+
+RELOCATION RECORDS FOR \[\.data\]:
+OFFSET +TYPE +VALUE
+0+0 R_X86_64_64 +named_local\+0x0+10
+0+8 R_X86_64_64 +\.Ltemp\+0x0+10
+
+
+RELOCATION RECORDS FOR \[\.text1\]:
+OFFSET +TYPE +VALUE
+0+1 R_X86_64_PC32 +named_local-0x0+4
+0+6 R_X86_64_PC32 +\.Ltemp-0x0+4
+
+
+Contents of section \.data:
+ 0000 00000000 00000000 00000000 00000000  \.+
+Contents of section \.text1:
+ 0000 e8000000 00e80000 0000 +.*
diff --git a/gas/testsuite/gas/i386/reloc-section-sym.s b/gas/testsuite/gas/i386/reloc-section-sym.s
new file mode 100644 (file)
index 0000000..dcb25d3
--- /dev/null
@@ -0,0 +1,14 @@
+       .text
+       nop
+named_local:
+       .byte 0
+.Ltemp:
+       nop
+
+.section .text1,"ax"
+       call named_local
+       call .Ltemp
+
+.data
+       .quad named_local + 16
+       .quad .Ltemp + 16
index 8ddf05481a5a1ebc36a31764718ad90cd7038384..3e5ffd8d13f6bc3f843a1abed869df642ba06b93 100644 (file)
@@ -775,6 +775,10 @@ if [is_elf_format] then {
        run_dump_test "x86-64-align-branch-3"
     }
     run_dump_test ehinterp
+
+    run_dump_test "reloc-section-sym-all"
+    run_dump_test "reloc-section-sym-internal"
+    run_dump_test "reloc-section-sym-none"
 }
 run_dump_test pr27198
 run_dump_test pr29483
index 9514c3df42e9f90ecf28825cef767cf30de79c95..cd02d8c7fb837ab314535a589e30f17f0a55498f 100644 (file)
@@ -909,6 +909,14 @@ adjust_reloc_syms (bfd *abfd ATTRIBUTE_UNUSED,
        if ((symsec->flags & SEC_THREAD_LOCAL) != 0)
          continue;
 
+       /* With --reloc-section-sym=none, skip adjustment.
+          With --reloc-section-sym=internal, only adjust relocs against
+          internal labels (e.g. .L prefix symbols in ELF).  */
+       if (flag_reloc_section_sym == reloc_section_sym_none
+           || (flag_reloc_section_sym == reloc_section_sym_internal
+               && !bfd_is_local_label (stdoutput, symbol_get_bfdsym (sym))))
+         continue;
+
        val = S_GET_VALUE (sym);
 
 #if defined(TC_AARCH64) && defined(OBJ_COFF)