[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