[PATCH v2] x86: keep PLT32 relocation for local symbols instead of converting to PC32
Fangrui Song
maskray@sourceware.org
Mon Feb 16 08:46:22 GMT 2026
Revert the PLT32-to-PC32 conversions introduced by commits 2585b7a5ce58
("x86: Change PLT32 reloc against section to PC32") and ad2ce1e6457c
("x86: Turn PLT32 to PC32 only for PC-relative relocations").
PLT32 is a branch relocation type where the symbol address is
insignificant (similar to R_AARCH64_CALL26 and R_PPC64_REL24).
Converting it to PC32 makes the symbol address significant, which
prevents the linker from making certain transforms (e.g.
a relocation-based identical code folding feature might
disallow folding a section if it defines symbols with significant
addresses.)
With this change, PLT32 relocations against local symbols (including .L
local labels) are adjusted to reference the section symbol (via
adjust_reloc_syms), matching the longstanding behavior of LLVM
integrated assembler. PLT32 relocations referencing section symbols are
well supported by ld.
Fix the root cause of PR gas/26263: for i386 REL relocations,
md_apply_fix wrote the correct implicit addend -4 for R_386_PLT32, but
bfd_install_relocation (partial_inplace, pcrel_offset) then subtracted
reloc_entry->address, corrupting it to e.g. -5. The 2020 workaround
converted PLT32 to PC32 to avoid the issue. Fix this properly by adding
BFD_RELOC_386_PLT32 to the bfd_install_relocation pre-compensation hack
in md_apply_fix (matching the existing handling for BFD_RELOC_32_PCREL),
and limiting the value = -4 override to the RELA case where
bfd_install_relocation does not modify instruction bytes.
PR gas/26263
PR gas/32196
---
gas/config/tc-i386.c | 26 ++++++-------------------
gas/testsuite/gas/i386/relax-5.d | 2 +-
gas/testsuite/gas/i386/reloc32.d | 2 +-
gas/testsuite/gas/i386/reloc64.d | 2 +-
gas/testsuite/gas/i386/x86-64-relax-4.d | 2 +-
5 files changed, 10 insertions(+), 24 deletions(-)
diff --git a/gas/config/tc-i386.c b/gas/config/tc-i386.c
index ca4523fe2cd..38b0b3ed2a4 100644
--- a/gas/config/tc-i386.c
+++ b/gas/config/tc-i386.c
@@ -4137,11 +4137,6 @@ tc_i386_fix_adjustable (fixS *fixP)
|| fixP->fx_r_type == BFD_RELOC_VTABLE_INHERIT
|| fixP->fx_r_type == BFD_RELOC_VTABLE_ENTRY)
return 0;
- /* Resolve PLT32 relocation against local symbol to section only for
- PC-relative relocations. */
- if (fixP->fx_r_type == BFD_RELOC_386_PLT32
- || fixP->fx_r_type == BFD_RELOC_32_PLT_PCREL)
- return fixP->fx_pcrel;
return 1;
}
#endif
@@ -16658,7 +16653,8 @@ md_apply_fix (fixS *fixP, valueT *valP, segT seg ATTRIBUTE_UNUSED)
&& (fixP->fx_r_type == BFD_RELOC_32_PCREL
|| fixP->fx_r_type == BFD_RELOC_64_PCREL
|| fixP->fx_r_type == BFD_RELOC_16_PCREL
- || fixP->fx_r_type == BFD_RELOC_8_PCREL)
+ || fixP->fx_r_type == BFD_RELOC_8_PCREL
+ || fixP->fx_r_type == BFD_RELOC_386_PLT32)
&& !use_rela_relocations)
{
/* This is a hack. There should be a better way to handle this.
@@ -16721,8 +16717,10 @@ md_apply_fix (fixS *fixP, valueT *valP, segT seg ATTRIBUTE_UNUSED)
case BFD_RELOC_32_PLT_PCREL:
/* Make the jump instruction point to the address of the operand.
At runtime we merely add the offset to the actual PLT entry.
- NB: Subtract the offset size only for jump instructions. */
- if (fixP->fx_pcrel)
+ NB: Subtract the offset size only for jump instructions.
+ For i386 REL relocations, the bfd_install_relocation
+ compensation above handles this. */
+ if (fixP->fx_pcrel && use_rela_relocations)
value = -4;
break;
@@ -18428,18 +18426,6 @@ i386_validate_fix (fixS *fixp)
#ifdef OBJ_ELF
else
{
- /* NB: Commit 292676c1 resolved PLT32 reloc aganst local symbol
- to section. Since PLT32 relocation must be against symbols,
- turn such PLT32 relocation into PC32 relocation. NB: We can
- turn PLT32 relocation into PC32 relocation only for PC-relative
- relocations since non-PC-relative relocations need PLT entries.
- */
- if (fixp->fx_addsy
- && fixp->fx_pcrel
- && (fixp->fx_r_type == BFD_RELOC_386_PLT32
- || fixp->fx_r_type == BFD_RELOC_32_PLT_PCREL)
- && symbol_section_p (fixp->fx_addsy))
- fixp->fx_r_type = BFD_RELOC_32_PCREL;
if (!object_64bit)
{
if (fixp->fx_r_type == BFD_RELOC_386_GOT32
diff --git a/gas/testsuite/gas/i386/relax-5.d b/gas/testsuite/gas/i386/relax-5.d
index 5fcd7f64752..002780913c8 100644
--- a/gas/testsuite/gas/i386/relax-5.d
+++ b/gas/testsuite/gas/i386/relax-5.d
@@ -10,6 +10,6 @@ Disassembly of section .text:
Disassembly of section .init.text:
0+ <foo>:
- +[a-f0-9]+: e8 fc ff ff ff call 1 <foo\+0x1> 1: R_386_PC32 .text
+ +[a-f0-9]+: e8 fc ff ff ff call 1 <foo\+0x1> 1: R_386_PLT32 .text
+[a-f0-9]+: e8 fc ff ff ff call 6 <foo\+0x6> 6: R_386_PC32 .text
#pass
diff --git a/gas/testsuite/gas/i386/reloc32.d b/gas/testsuite/gas/i386/reloc32.d
index ebac545b200..c3b43e1ac9f 100644
--- a/gas/testsuite/gas/i386/reloc32.d
+++ b/gas/testsuite/gas/i386/reloc32.d
@@ -43,7 +43,7 @@ Disassembly of section \.text:
.*[ ]+R_386_TLS_LE[ ]+xtrn
.*[ ]+R_386_TLS_LE_32[ ]+xtrn
.*[ ]+R_386_TLS_LE_32[ ]+xtrn
-.*[ ]+R_386_PLT32[ ]+ptr
+.*[ ]+R_386_PLT32[ ]+\.data(\+0x[0-9a-f]+)?
Disassembly of section \.data:
#...
.*[ ]+R_386_32[ ]+xtrn
diff --git a/gas/testsuite/gas/i386/reloc64.d b/gas/testsuite/gas/i386/reloc64.d
index 5fee029e56a..f7ca9e85ba6 100644
--- a/gas/testsuite/gas/i386/reloc64.d
+++ b/gas/testsuite/gas/i386/reloc64.d
@@ -59,7 +59,7 @@ Disassembly of section \.text:
.*[ ]+R_X86_64_32[ ]+xtrn
.*[ ]+R_X86_64_GOT64[ ]+ptr
.*[ ]+R_X86_64_GOTOFF64[ ]+Ldst
-.*[ ]+R_X86_64_PLT32[ ]+ptr
+.*[ ]+R_X86_64_PLT32[ ]+\.data(\+0x[0-9a-f]+)?
Disassembly of section \.data:
#...
.*[ ]+R_X86_64_64[ ]+xtrn
diff --git a/gas/testsuite/gas/i386/x86-64-relax-4.d b/gas/testsuite/gas/i386/x86-64-relax-4.d
index a5d65973412..3148534620d 100644
--- a/gas/testsuite/gas/i386/x86-64-relax-4.d
+++ b/gas/testsuite/gas/i386/x86-64-relax-4.d
@@ -12,6 +12,6 @@ Disassembly of section .text:
Disassembly of section .init.text:
0+ <foo>:
- +[a-f0-9]+: e8 00 00 00 00 call 5 <foo\+0x5> 1: R_X86_64_PC32 .text-0x4
+ +[a-f0-9]+: e8 00 00 00 00 call 5 <foo\+0x5> 1: R_X86_64_PLT32 .text-0x4
+[a-f0-9]+: 48 8d 05 00 00 00 00 lea 0x0\(%rip\),%rax # c <foo\+0xc> 8: R_X86_64_PC32 .text-0x4
#pass
--
2.43.0
More information about the Binutils
mailing list