[PATCH] x86: keep PLT32 relocation for local symbols instead of converting to PC32
Fangrui Song
i@maskray.me
Wed Feb 18 18:05:28 GMT 2026
On Wed, Feb 18, 2026 at 1:36 AM Jan Beulich <jbeulich@suse.com> wrote:
>
> On 17.02.2026 19:12, Fangrui Song wrote:
> > 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.
>
> You're again resorting to an example where there is no talk of PLT in the
> source. In that case the assembler (appropriately or not) using PLT32
> kind of implies that the linker do its best to avoid creating a PLT entry.
> For "call foo@plt", otoh, it is an optimization, which in principle users
> should opt in to.
The point is that PLT32 never guarantees a PLT entry - not in any linker.
As mentioned, if `foo` is non-preemptible, the linker resolves `foo` directly.
This is not an optional optimization - if `foo` has hidden visibility
(or localized by version script local:, or defined &
-Bsymbolic-functions), it will not be in the dynamic symbol table and
a JUMP_SLOT dynamic relocation cannot be used at all.
The most constrained visibility rule means that a compiler generating
`call foo@plt` cannot ensure other translation units won't set the
visibility to hidden.
> > 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.
>
> Effectively what you're suggesting is that we deprecate @plt, properly
> documenting that its absence on CALL/JMP operands still means PLT32 will be
> used as relocation. That'll need properly spelling out in the doc then.
> Which may be not as easy as it sounds, as it looks as if none of the @...
> operand modifiers were documented anywhere.
I agree that the @plt behavior on x86-64 deserves documentation. One
choice is for the x86-64 psABI to document @plt .
Alternatively, x86-64 could have a convention doc like RISC-V's
https://github.com/riscv-non-isa/riscv-toolchain-conventions
> >>>>> This patch disables PLT32->PC32 conversion. If there is still
> >>>>> uncertainty regarding the i386 linker bug, I can leave the i386
> >>>>> behavior unchanged.
> >>>>
> >>>> This would imo be worse. There shouldn't be differences in handing like
> >>>> this, except when the psABI-s really differ in certain aspects. I don't
> >>>> think they do here. (There are other differences which I don't really
> >>>> understand. One of them I explicitly called out in [1], but sadly no-one
> >>>> cared to clarify this.)
> >>>
> >>> The patch applies the same policy to both i386 and x86-64: both keep
> >>> PLT32 against section symbols, both remove the PLT32-to-PC32
> >>> conversion in i386_validate_fix, both use the same
> >>> tc_i386_fix_adjustable change. The handling is identical.
> >>
> >> Just to clarify - my earlier response was to "I can leave the i386
> >> behavior unchanged", i.e. you suggesting to make the behavior further
> >> different.
> >
> > 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.
>
> Yes, that bug I have on my list to address. Certainly nice if it gets addressed
> by other means.
>
> Jan
More information about the Binutils
mailing list