[PATCH] x86: keep PLT32 relocation for local symbols instead of converting to PC32

Fangrui Song i@maskray.me
Wed Feb 18 04:02:44 GMT 2026


Apologies to Jan and H.J for the duplicate message. I should not use
`@sourceware.org` as a sender since the email address is "receive
only". https://sourceware.org/bugzilla/show_bug.cgi?id=33906

Resend to ensure the message goes to binutils@sourceware.org

On Tue, Feb 17, 2026 at 1:04 AM Jan Beulich <jbeulich@suse.com> wrote:
>
> On 16.02.2026 22:54, Fangrui Song wrote:
> > On Tue, Feb 10, 2026 at 12:24 AM Jan Beulich <jbeulich@suse.com> wrote:
> >> On 10.02.2026 06:16, Fangrui Song wrote:
> >>> On Mon, Feb 9, 2026 at 1:03 AM Jan Beulich <jbeulich@suse.com> wrote:
> >>>> On 09.02.2026 09:46, Fangrui Song wrote:
> >>>>> On Mon, Feb 9, 2026 at 12:23 AM Jan Beulich <jbeulich@suse.com> wrote:
> >>>>>> On 09.02.2026 00:26, Fangrui Song wrote:
> >>>>>>> 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).
> >>>>>>
> >>>>>> I fear I don't understand this wording: The (ultimate) symbol address is
> >>>>>> very much relevant, or else the wrong contents will be put in the PLT?
> >>>>>
> >>>>> The x86-64 PLT32 relocation type is a branch relocation type, which
> >>>>> can be used to make a function call but not by taking the address
> >>>>> (pointer escape).
> >>>>> The name is a misnomer (therefore on arm/aarch64/ppc they are not
> >>>>> called "R_*_PLT*") - if the target symbol is non-preemptible, the
> >>>>> linker resolves the relocation as a direct PC-relative one.
> >>>>
> >>>> Taking Arm64 as example, can you even compare with that? I couldn't spot
> >>>> any relocation using L in the "Operation" column.
> >>>
> >>> While its Operation column contains
> >>>
> >>> R_<CLS>_JUMP26  S+A-P
> >>> R_<CLS>_CALL26  S+A-P
> >>>
> >>> There is some information at
> >>> https://github.com/ARM-software/abi-aa/blob/main/aaelf64/aaelf64.rst#577call-and-jump-relocations
> >>>
> >>>> A linker may use a veneer (a sequence of instructions) to implement a relocated branch if the relocation is either
> >>>>
> >>>> R_<CLS>_CALL26, R_<CLS>_JUMP26 or R_<CLS>_PLT32 and:
> >>>>
> >>>> The target symbol has type STT_FUNC.
> >>>> Or, the target symbol and relocated place are in separate sections input to the linker.
> >>>> Or, the target symbol is undefined (external to the link unit).         <----------- this is the PLT case
> >>
> >> Is it, really? Nothing is said (afaics) that such veneers then need to live
> >> in a construct named PLT. They could be scattered around, and there's not
> >> even a requirement to allocate a PLT entry.
> >
> > Right - no PLT needs to be allocated.
> > The relocation type tells the linker to "transfer control there by any means".
> > The linker may resolve it directly (if non-preemptible (STB_LOCAL,
> > hidden/protected visibility, defined in executable of -Bsymbolic
> > shared objects, etc)),
> > route it through a PLT entry, or insert a veneer (arm,aarch64,powerpc,etc).
> >
> > This is why I said R_X86_64_PLT32 was a misnomer. It functions as a
> > generic call relocation.
> > It would have been clearer if we had named it R_X86_64_CALL32.
>
> It could have been done that way, but we need to live with what we've got.
> Which mandates the setting up of a PLT entry, omitting of which is only
> an optimization (which should be possible to suppress, especially if
> someone actively used @plt in assembly, in the expectation to have a PLT
> entry allocated no matter what).

Hi Jan, I don't think omitting a PLT entry is an optional optimization.
`.globl foo: call foo` in assembly, used in static linking builds, is
expected to resolve the PLT32 directly without creating a PLT entry.

Actually, GNU ld, gold, lld/ELF, and mold resolve PLT32 directly for
non-preemptible symbols.

We should accept that the @plt notation in assembly and the PLT32
relocation type names are misleading. They suggest that a PLT entry is
involved, but that is often not the case.

> We could consider introducing CALL32 (maybe better BRANCH32, to make
> clear that use with JMP is equally okay), yet introduction of a new reloc
> type comes with its own price.

We could rename R_X86_64_PLT32 to CALL32, though the need to rename it
has likely passed.

My recommendation for future architectures:

    https://maskray.me/blog/2026-02-16-call-relocation-types#recommendation-for-future-architectures
    For a specific instruction or pseudo instruction for function
calls and tail calls, use a single call relocation type—no "PLT" vs.
"non-PLT" distinction. The assembler should emit the same relocation,
and the linker, which knows whether the symbol is preemptible, decides
whether a PLT stub or range extension thunk is needed. AArch64's
R_AARCH64_CALL26 and PowerPC64 ELFv2's R_PPC64_REL24 demonstrate this
approach well.
    This discussion does not apply to intra-function branches, which
target local labels.
Well, the patch applies the same change to both i386 and x86-64: both
keep PLT32 against section symbols. No behavioral divergence.

Without this patch `call .text1@plt` and `local: call local@plt` generate PC32.
Just a reminder: If a symbol is non-preemptible, ld won't generate a
PLT anyway - and there aren't any options to change that.

> > The only difference is that `call foo` generates a PLT32 for x86-64
> > but a PC32 for i386, while `call foo@plt` generates a PLT32 for both
> > i386 and x86-64.
> >
> > I have a note why we don't change `call foo` to PLT32 for i386
> >
> >   There are two issues disallowing the switch from R_386_PC32 to
> > R_386_PLT32 https://sourceware.org/bugzilla/show_bug.cgi?id=27169.
> > First is that one can do something like:
> >
> >   gcc -m32 -fno-pic -shared -z notext a.c -o a.so
> >
> >   The linker will produce a R_386_PC32 dynamic relocation. According
> > to H.J., some shared objects intentionally do this for optimization.
> > This is a dark art leveraging text relocations for an unusual
> > PC-relative relocation type.
>
> Yes, games like this can be played on i386. Technically they should
> be possible to also play on x32, I would think. Why are we not
> concerned of that?
>
> Jan

x32 uses x86-64 relocation types. If a user wants to have PC32 instead
of PLT32, use a .reloc directive

% cat g.s
.reloc ., R_X86_64_PC32, .text
call .+1        # +1 can be omitted with SHT_RELA/SHT_CREL


More information about the Binutils mailing list