[lld] [ELF] Don't relax PLT32 for branches from small into large code on x86-64 (PR #216409)
Farid Zakaria via llvm-commits
llvm-commits at lists.llvm.org
Mon Aug 17 10:28:57 PDT 2026
================
@@ -757,8 +757,15 @@ static void addPltEntry(Ctx &ctx, PltSection &plt, GotPltSection &gotPlt,
return;
}
gotPlt.addEntry(sym);
- rel.addReloc(
- {type, &gotPlt, sym.getGotPltOffset(ctx), isPreemptible, sym, 0, expr});
----------------
fzakaria wrote:
AI helped me identify this bug:
We always need a matching 1:1 pair for plt and `.rela.plt` -- the reason for this is the index provided to the dynamic linker is then looked to search for the mathing relocation to resolve the symbol.
(This is a constraint that probably needs to be better handled with an API contract)
The early exit you do here makes this no longer true and will break for dynamically linked objects.
Looks like this is not caught in the tests because there is no dynamically linked object test -- let's add one!
A regression test needs a dynamic link with a preemptible PLT entry after a range-kept one, ideally with an execution check.
note: - -z nowpasses even with the bug, so it's a useful contrast case documenting why it survives (eager binding walks .rela.plt as an array and never executes the pushq).
```asm
# REQUIRES: x86
## A lazy PLT entry pushes its .plt index, which _dl_fixup() uses as an index
## into .rela.plt. Keeping a PLT entry for a non-preemptible symbol must not
## desynchronize the two arrays: .plt entry N must still describe .rela.plt
## entry N, or every subsequent lazily bound call resolves to the wrong symbol.
# RUN: rm -rf %t && split-file %s %t && cd %t
# RUN: llvm-mc -filetype=obj -triple=x86_64 a.s -o a.o
# RUN: llvm-mc -filetype=obj -triple=x86_64 b.s -o b.o
# RUN: ld.lld -shared b.o -o b.so
# RUN: ld.lld a.o b.so -o a
# RUN: llvm-objdump -d --no-show-raw-insn a | FileCheck %s --check-prefix=LAZY
# RUN: llvm-readelf -rW a | FileCheck %s --check-prefix=RELAPLT
# RUN: ld.lld -pie a.o b.so -o a.pie
# RUN: llvm-objdump -d --no-show-raw-insn a.pie | FileCheck %s --check-prefix=LAZY
# RUN: llvm-readelf -rW a.pie | FileCheck %s --check-prefix=RELAPLT
## The index each lazy entry pushes must match its position in .rela.plt below.
# LAZY: <foo at plt>:
# LAZY-NEXT: jmpq
# LAZY-NEXT: pushq $0x0
# LAZY: <bar at plt>:
# LAZY-NEXT: jmpq
# LAZY-NEXT: pushq $0x1
## .rela.plt holds only the preemptible symbols, in PLT entry order. A
## non-preemptible symbol has no dynsym entry and must not consume an index.
# RELAPLT: Relocation section '.rela.plt'{{.*}} contains 2 entries:
# RELAPLT: R_X86_64_JUMP_SLOT {{.*}} foo + 0
# RELAPLT-NEXT: R_X86_64_JUMP_SLOT {{.*}} bar + 0
# RELAPLT-NOT: R_X86_64_JUMP_SLOT
#--- a.s
.section .ltext,"axl", at progbits
.globl large
.type large, @function
large:
retq
.text
.globl _start
.type _start, @function
_start:
call large
call foo
call bar
retq
#--- b.s
.globl foo
.type foo, @function
foo:
retq
.globl bar
.type bar, @function
bar:
retq
```
https://github.com/llvm/llvm-project/pull/216409
More information about the llvm-commits
mailing list