[PATCH v4] gas: add --reloc-section-sym={all, internal, none} option for ELF

Fangrui Song <[email protected]>
Newsgroups gmane.comp.gnu.binutils
Message-ID <[email protected]>
From: Fangrui Song <[email protected]>

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
---
 gas/NEWS                                      |  4 ++++
 gas/as.c                                      | 20 +++++++++++++++-
 gas/as.h                                      | 10 ++++++++
 gas/doc/as.texi                               | 11 +++++++++
 gas/testsuite/gas/elf/elf.exp                 |  9 +++++---
 gas/testsuite/gas/elf/reloc-section-sym-all.d | 12 ++++++++++
 .../gas/elf/reloc-section-sym-internal.d      | 12 ++++++++++
 .../gas/elf/reloc-section-sym-none.d          | 12 ++++++++++
 gas/testsuite/gas/elf/reloc-section-sym.s     |  9 ++++++++
 .../gas/i386/reloc-section-sym-all.d          | 23 +++++++++++++++++++
 .../gas/i386/reloc-section-sym-internal.d     | 23 +++++++++++++++++++
 .../gas/i386/reloc-section-sym-none.d         | 23 +++++++++++++++++++
 gas/testsuite/gas/i386/reloc-section-sym.s    | 14 +++++++++++
 gas/testsuite/gas/i386/x86-64.exp             |  4 ++++
 gas/write.c                                   |  8 +++++++
 15 files changed, 190 insertions(+), 4 deletions(-)
 create mode 100644 gas/testsuite/gas/elf/reloc-section-sym-all.d
 create mode 100644 gas/testsuite/gas/elf/reloc-section-sym-internal.d
 create mode 100644 gas/testsuite/gas/elf/reloc-section-sym-none.d
 create mode 100644 gas/testsuite/gas/elf/reloc-section-sym.s
 create mode 100644 gas/testsuite/gas/i386/reloc-section-sym-all.d
 create mode 100644 gas/testsuite/gas/i386/reloc-section-sym-internal.d
 create mode 100644 gas/testsuite/gas/i386/reloc-section-sym-none.d
 create mode 100644 gas/testsuite/gas/i386/reloc-section-sym.s

diff --git a/gas/NEWS b/gas/NEWS
index b36bcb5cf3d..ffc9a0f06be 100644
--- 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 legacy .vtable_entry and .vtable_inherit directives that were
   needed for versions of GCC prior to gcc-3.0 (when the generic C++
   ABI was adopted) are now considered obsolete.  They are now deprecated
diff --git a/gas/as.c b/gas/as.c
index f33f6ec85cd..b652e81286c 100644
--- 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;
diff --git a/gas/as.h b/gas/as.h
index 94bc816be1e..2fe0a48a225 100644
--- 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;
 
diff --git a/gas/doc/as.texi b/gas/doc/as.texi
index 3c4d20bd7d4..5d7772d62d3 100644
--- a/gas/doc/as.texi
+++ b/gas/doc/as.texi
@@ -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
diff --git a/gas/testsuite/gas/elf/elf.exp b/gas/testsuite/gas/elf/elf.exp
index 2232e2d58d9..5580c494c54 100644
--- a/gas/testsuite/gas/elf/elf.exp
+++ b/gas/testsuite/gas/elf/elf.exp
@@ -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
index 00000000000..b4da309c062
--- /dev/null
+++ b/gas/testsuite/gas/elf/reloc-section-sym-all.d
@@ -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
index 00000000000..0c0f464472a
--- /dev/null
+++ b/gas/testsuite/gas/elf/reloc-section-sym-internal.d
@@ -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
index 00000000000..557728b1ee3
--- /dev/null
+++ b/gas/testsuite/gas/elf/reloc-section-sym-none.d
@@ -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
index 00000000000..37f1258f102
--- /dev/null
+++ b/gas/testsuite/gas/elf/reloc-section-sym.s
@@ -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
index 00000000000..2c8fd576ab5
--- /dev/null
+++ b/gas/testsuite/gas/i386/reloc-section-sym-all.d
@@ -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
index 00000000000..2387fab9e56
--- /dev/null
+++ b/gas/testsuite/gas/i386/reloc-section-sym-internal.d
@@ -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
index 00000000000..8f7fe3f2a52
--- /dev/null
+++ b/gas/testsuite/gas/i386/reloc-section-sym-none.d
@@ -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
index 00000000000..dcb25d3b6ab
--- /dev/null
+++ b/gas/testsuite/gas/i386/reloc-section-sym.s
@@ -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
diff --git a/gas/testsuite/gas/i386/x86-64.exp b/gas/testsuite/gas/i386/x86-64.exp
index 8ddf05481a5..3e5ffd8d13f 100644
--- a/gas/testsuite/gas/i386/x86-64.exp
+++ b/gas/testsuite/gas/i386/x86-64.exp
@@ -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
diff --git a/gas/write.c b/gas/write.c
index 9514c3df42e..cd02d8c7fb8 100644
--- a/gas/write.c
+++ b/gas/write.c
@@ -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)
-- 
2.43.0
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.