[PATCH] x86: keep PLT32 relocation for local symbols instead of converting to PC32
Jan Beulich
jbeulich@suse.com
Tue Feb 17 09:04:02 GMT 2026
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).
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.
>>>>>>> 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,
>>>>>>>
>>>>>>> PR gas/25551
>>>>>>
>>>>>> It was you who reported that bug. Are you now saying that report was wrong?
>>>>>> This really needs discussing here, imo (even if it would have been someone
>>>>>> else who made that original report).
>>>>>
>>>>> The patch I submitted for gas/25551 is correct.
>>>>>
>>>>> However, the follow-up 2585b7a5ce58
>>>>> ("x86: Change PLT32 reloc against section to PC32") changed PLT32
>>>>> against a section symbol to PC32.
>>>>> This stripped the "address is insignificant" information - therefore undesired.
>>>>
>>>> Then what about PR gas/26263, which triggered this patch's creation?
>>>
>>> Thanks for the link. Timeline:
>>>
>>> * Commit 292676c15a615b5a95bede9ee91004d3f7ee7dfd adjusted both
>>> R_386_PLT32 and R_X86_64_PLT32 to section symbols if eligible.
>>> * https://sourceware.org/bugzilla/show_bug.cgi?id=26263 reported an i386 issue
>>> * https://sourceware.org/git/gitweb.cgi?p=binutils-gdb.git;h=2585b7a5ce5830e60a089aa2316a329558902f0c
>>> changed both R_386_PLT32 and R_X86_64_PLT32 against section symbols to
>>> PC32. The i386 issue was probably due to a linker bug. It's
>>> unnecessary to update x86-64.
>>> * https://sourceware.org/git/gitweb.cgi?p=binutils-gdb.git;h=ad2ce1e6457c
>>> fixed a regression for x86-64 movq $foo@PLT, %rax
>>>
>>> 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.
> 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
More information about the Binutils
mailing list