From: Fangrui Song Date: Sun, 8 Feb 2026 19:56:49 +0000 (-0800) Subject: gas: add --reloc-section-sym={all,internal,none} option for ELF X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=eec25cabd2d004cfc2a9898b1ec93cbdef2fcd77;p=thirdparty%2Fbinutils-gdb.git gas: add --reloc-section-sym={all,internal,none} option for ELF 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 --- diff --git a/gas/NEWS b/gas/NEWS index 60ab138384e..38928ab83ff 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 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 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- generate SFrame version information. 3 == \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)