older ld converts push with GOTPCRELX into call - is a local guard ok?

Sam James sam@gentoo.org
Thu Jul 9 19:32:21 GMT 2026


"Dora, Sunil Kumar via Binutils" <binutils@sourceware.org> writes:

> Hi,
>
> I was debugging rustc segfaults and traced them to GOTPCRELX handling
> in older ld.
>
> Since commit 11c2852449825 (binutils 2.45), gas emits
> R_X86_64_GOTPCRELX for "push foo@GOTPCREL(%rip)". Older ld's
> elf_x86_64_convert_load_reloc() only checks modrm 0x25 (jmp) in the
> 0xff case and treats everything else as call, so a push (modrm 0x35)
> gets silently rewritten to "addr32 call foo". In our case foo is a
> read-only LLVM table statically linked into librustc_driver.so, so
> rustc calls into .rodata and crashes.
>
> Reproducer (two installs on purpose - that mismatch is the bug):
>
>     $ cat repro.s
>         .text
>         .globl  func
>     func:
>         push    tbl@GOTPCREL(%rip)
>         add     $8, %rsp
>         ret
>         .section .rodata
>         .globl  tbl
>         .hidden tbl
>     tbl:
>         .zero   576
>
>     $ as --version | head -1 
>     GNU assembler (GNU Binutils) 2.46.1
>     $ as -o repro.o repro.s
>     $ readelf -rW repro.o | grep tbl
>     0000000000000002  0000000300000029 R_X86_64_GOTPCRELX  0000000000000000 tbl - 4
>
>     $ ld --version | head -1
>     GNU ld (GNU Binutils for Ubuntu) 2.38
>     $ ld -shared -o bad.so repro.o
>     $ objdump -d bad.so | grep -A1 '<func>:'
>     0000000000001000 <func>:
>         1000:       67 e8 fa 0f 00 00       addr32 call 2000 <tbl>
>
>     ld 2.46.1 on the same repro.o keeps "ff 35" (push through GOT).
>     gas 2.38 emits plain GOTPCREL for this source, so only new-gas
>     objects with old ld are affected.
>
> Old branches are closed, I know - but some of our build hosts must
> stay on distro binutils for a while, so we plan to carry this locally
> (skip conversion for anything that isn't call/jmp, matching what newer
> ld does for push in a shared library):

Older branches are not closed. Like glibc, we keep older branches alive
for obvious trivial fixes for as long as people are willing to maintian
them (within reason).

But in fact, not only are they not closed, H.J. already backported fixes
for your exact problem a year ago.

> [...]
>
> 1. Is this guard safe, or can modrm be something other than
>    0x15/0x25/0x35 here that needs different handling?

Use H.J.'s patch?

>
> 2. Worth documenting this incompatibility (PR or release notes)?
>    Every ld before 2.45 silently produces bad code from such objects,
>    and tracing the crash back to the linker was not easy.

There's already https://sourceware.org/PR32991.

>
> Thanks,
> Sunil Dora

sam
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 418 bytes
Desc: not available
URL: <https://sourceware.org/pipermail/binutils/attachments/20260709/08b95d68/attachment.sig>


More information about the Binutils mailing list