<table border="1" cellspacing="0" cellpadding="8">
<tr>
<th>Issue</th>
<td>
<a href=https://github.com/llvm/llvm-project/issues/202189>202189</a>
</td>
</tr>
<tr>
<th>Summary</th>
<td>
[RISC-V][lld] ld.lld PLT GOTPLT out of range wrong success
</td>
</tr>
<tr>
<th>Labels</th>
<td>
</td>
</tr>
<tr>
<th>Assignees</th>
<td>
</td>
</tr>
<tr>
<th>Reporter</th>
<td>
XiaobingHou1219
</td>
</tr>
</table>
<pre>
I ran into this while reducing a RISC-V linker testcase. The reproducer is small, and I have been seeing the same result consistently across three reruns.
### Summary
ld.lld 22.1.0 links successfully with no diagnostic, emits `.rela.plt R_RISCV_JUMP_SLOT ext` at `.got.plt+0x10`, but the synthesized PLT header and `ext@plt` entry address `0xffffffff90000000` and `0xffffffff90000010` rather than the real `.got.plt` VMA `0x0000000090000000` and slot `0x0000000090000010`. The negative over-range control likewise links and addresses `0x100010000`/`0x100010010` instead of `.got.plt` at `0x10000`/`0x10010`. In-range positive and negative controls target the correct `.got.plt` addresses.
### Expected behavior
Link a valid RV64 RISC-V shared object that needs a PLT entry for an undefined function while a linker script places `.plt` at `0x10000` and `.got.plt` at `0x90000000`, outside the RV64 AUIPC+load PC-relative range used by the ordinary PLT sequence. The linker must not silently emit PLT code whose load address is not the actual `.got.plt` or `.got.plt` entry.
### Environment
- linker route: GNU as 2.45 input, current ld.lld 22.1.0 under `-shared -melf64lriscv -T`, with GNU ld.bfd 2.45 showing the same semantic failure and in-range linker-script controls for both linkers
- march: rv64gc
- mabi: lp64
- first failing stage: link
- local stability check: True
### Reduced testcase
These are the reduced input files from the minimized reproducer I used locally:
#### `caller.s`
```asm
.text
.globl caller
.type caller,@function
caller:
call ext
ret
```
#### `in-pos-control.ld`
```ld
PHDRS
{
text PT_LOAD FLAGS(5);
data PT_LOAD FLAGS(6);
dynamic PT_DYNAMIC FLAGS(6);
}
SECTIONS
{
. = 0xffc0;
.text : { *(.text .text.*) } :text
. = 0x10000;
.plt : { *(.plt) *(.iplt) } :text
.rela.dyn : { *(.rela.dyn) } :text
.rela.plt : { *(.rela.plt) } :text
.dynsym : { *(.dynsym) } :text
.dynstr : { *(.dynstr) } :text
.hash : { *(.hash) } :text
.gnu.hash : { *(.gnu.hash) } :text
. = 0x7fff0000;
.got.plt : AT(0x30000) { *(.got.plt) } :data
.got : AT(0x30100) { *(.got) } :data
.dynamic : AT(0x30200) { *(.dynamic) } :data :dynamic
}
```
#### `over-pos.ld`
```ld
PHDRS
{
text PT_LOAD FLAGS(5);
data PT_LOAD FLAGS(6);
dynamic PT_DYNAMIC FLAGS(6);
}
SECTIONS
{
. = 0xffc0;
.text : { *(.text .text.*) } :text
. = 0x10000;
.plt : { *(.plt) *(.iplt) } :text
.rela.dyn : { *(.rela.dyn) } :text
.rela.plt : { *(.rela.plt) } :text
.dynsym : { *(.dynsym) } :text
.dynstr : { *(.dynstr) } :text
.hash : { *(.hash) } :text
.gnu.hash : { *(.gnu.hash) } :text
. = 0x90000000;
.got.plt : AT(0x30000) { *(.got.plt) } :data
.got : AT(0x30100) { *(.got) } :data
.dynamic : AT(0x30200) { *(.dynamic) } :data :dynamic
}
```
### Reproduction notes
- This packaged root does not have a single canonical `run.ps1` wrapper.
- Use the reduced inputs under `case/` and follow the commands documented in `case/README.md`.
- Stable witness outputs, when present, are preserved under `verify/run1..run3/`.
### What I checked
- Reduced inputs are preserved under case/.
- Stable witness outputs are preserved under verify/run1..run3/.
- The strict recheck says stable normalized run signatures across three runs: True.
- Tracker guidance link: https://llvm.org/docs/HowToSubmitABug.html
- evidence summary: 3 clean reproductions under hunt/verify/riscv_plt_gotplt_out_of_range_wrong_success/run1..run3` show stable GNU-as assembly success and stable ld.lld classifications: each run has 2 ld.lld in-range controls classified `ok` and 2 ld.lld over-range links classified `wrong_plt_target`. Representative run1 `normal.over_pos.lld.so` has `.plt` at `0x10000`, `.got.plt` at `0x90000000`, `.rela.plt R_RISCV_JUMP_SLOT ext` at `0x90000010`, and disassembly `auipc t2,0x8fff0; ld t3,0(t2)` plus `auipc t3,0x8fff0; ld t3,-16(t3)`, which decodes on RV64 to `0xffffffff90000000` and `0xffffffff90000010`. The in-range control at `.got.plt=0x7fff0000` decodes to the actual `.got.plt`. Local records had PLT initial-value and PLT32 support coverage but no PLT/GOTPLT code-range root. Current LLVM source writes PLT header/entry displacements through `uint32_t offset = ...` and then emits HI20/LO12 pieces, explaining the RV64 truncation/sign-extension behavior. Web searches over LLVM GitHub issues, Sourceware Bugzilla/lists, and broader web queries for RISC-V PLT, `.got.plt`, out-of-range, `writePltHeader`, and `riscv_make_plt_header` found no direct current report.
### Notes
RISC-V psABI GOT-load text documents AUIPC+load PC-relative addressing and a +-2GiB range for the analogous GOT sequence: https://riscv-non-isa.github.io/riscv-elf-psabi-doc/ ; current LLVM `RISCV::writePltHeader`/`writePlt` source uses 32-bit offsets for `.got.plt` PLT addressing: https://github.com/llvm/llvm-project/blob/main/lld/ELF/Arch/RISCV.cpp#L2633-L2688 ; cross-linker/source contrast: https://gnu.googlesource.com/binutils-gdb/+/refs/heads/gdb-15-branch/bfd/elfnn-riscv.c#269 .
Root key: `lld.riscv.plt_gotplt_out_of_range_wrong_success`
Case id: `20260605-lld-riscv-plt-gotplt-out-of-range-wrong-success`
</pre>
<img width="1" height="1" alt="" src="http://email.email.llvm.org/o/eJzsGV1P40jy15iXki3HgZA88BBgwnBiZhAws3dPqO0u2720u739Ecj--lN12yGEsF-nW-mkGyEy6a6vru8qmLWiUYhnycl5cnJ5xLxrtTn7p2C6FKr5rP2kmCyOSs03Z9dgmAKhnAbXCgvPrZAIBrmvhGqAwd31_UX6A6RQT2jAoXUVs5jBQ0tgvdHcV2hAWLAdkzIpLoApDtfQsjVCiajAIhIt1yJY1hGa9dJBpZUV1qFycgOsMtpacK1BAjBe2SzJL5N8OfwupvEH7n3XMbOJx5JnUnIoimyS5UFIC9ZXFVpbeyk38CxcC0oDF6xR2jpRkYTYCWchmeWZQcmyXjq4e6SX_nj8x_cvt4_3N98eAF9cMsuBuQDYaEdwSXGev0zyZJYTndK7-KyNci1a8StyuL15gBYZRxMUkcxyInScE_IsB1TObIBxbtAGEfKXevi3yOO_wDWi7l8GzmCYa8kYLVOBvUEm3wg5y-HHl2UkMBDN96lbqd0hiMAi2ldhw5xYI-g1mtQw1SBZzRktQYonfBYWB6UTxeFRODxrEohFjkmx2j2LzxDKOmQcdL0vPHOvJPbQB_Gu1SBPr60IMpIEW4EHKS04ZhqMRqq0MVi5d7xGqT_wt08vPVYOOZTYsrXQJgLcCPUEDNZMCg53P2bHY6TYlhnkoMufiZlrmQOFyC2w4BrR_rUm7wCvONZCIYfaq8oJrYYAZGPA2cqI3kEvWRX1-pGKRo85pMYd05PXau-s4BiUEiRffr--vUiKc6kZh9uLlIIiqDGq2Ft6_SbAa8OFYmYT3mLxF4-qGrLBIHHnrQOlHVghY2xTtAX4SnOE51aT1xCrMQqEDQhEn1XOv3dmbfZPgho_sphaC6NVh8rFq3SUzWjvMJku4errd2AWiuz4BITqvSO9VN4YVA7eJhWyUWCfDpZNO5T17FgaYas1pA-DVkOmIbqSZ2XNI23b6uc3uc9ix5QTFdRMSG-i24rRmaOY6WD0rROTt5TatcO9HV_VMVO19Byznh031etxKehU9rPj8awWxrrAlMSxjjVBD0RwqyNdMUlXpZDCbaBqsXoioAfj8bCm76hOIN-WhXj_0KJFYAaH5BRhgpqhFhIt1EZ34bITSnQhbe7UkuvocUEeuUmmy4PMiX8yywkGTWbJChFglscfZrt4AgCQOcrCr18bqUsJEXkXatPjeFpcJMf5GJcRZrgZJSIUOoI3tA26PUl-S36h0l7bdLB1Jvn7h0geD24_X97dD3en5yNDehjcPjzefFtewupmeXWfFPOTpFgk0xGGM8fegczegADfKNaJisAu__V1-eX64jBkcnoZ_3P_6eLh-tvX9wJlkEwvgSpXle8wCBYA8qfk9BySYpkU83gWfmfhZAHJ6SUB7ZprJBhT3Q5Fqtt7BEOJXozfxPj1HdFY-PlG7RMYzz-SZdswHML7kB0QSbvp9rHi6W_hOHMIx5mPcFpm230MOvsIvlH-IM54_js2Oa3ret8sQ5oOFJcPSTHPX6YBJpB65TB2VFsG5Ke7VN5SmByi8BH26M5vKBTvKAxge1TC53Dz1un_UEiHbqnX9r8TzH9vNP9dwfyfxPJfDea_MZb_F0J52yX-P5RDaxP7kdCUK-1w23U90Jzcs-qJNdS3aO2Aa4wtbBh6GVihGkmNhNJKVLGfNV5lvZ1Q8_psWN-jyUaK3-2BVsm-dp6htQojUGgXay2lfh5mmq5jilvguvLU8AbsHZy7T8vLL5-yjjLRlt-9Y6VE6lgVtd_aO-IXmtgWFfQGLfXONMobjF_NGvmrQGs0ot4kxcp4Ncky49U0yvdBR_4TTUHXsaNEPopx9_a5h3gNr_gdyQ-iHpYxe7UignVGVA4MBsHAso0N_a9EUNp0TMbO1CuwolHMeYN2b1PhlR1b5FfShlU0bTRecKaq2NYTVOtcT-Ckq2Il5brLtGmSYsV1ZZNi9Vk_P-h7X3bCLc99k7WukyNRXAtOsxbYYf8xXcIUKolMbXtn8tXRbVpPFly9aoGmlcdeusdGO_rQ3j3q-jEMHo_PRqvmcdicvNXZLA9TzKiYq6_fU2aBWYtdKTfjtiWuFCLIMD9VklkralGxIBcJjKxqgz5bGr5GwO34sx14RlQMI61-Gj1_i7KzkIj7h7cY8Tn0yjj_h5UBRXRw7GG29WpCsNHSGVF8DEVb8sxq4khC_sbETfHxxwbuP7NoGpG3OyZ6Nxd2q3CabLzoK3BFUlzkL3PqwJLpOUgObkpHSTGnuwUR7aW3OyjTwyjpZEZI04gUE4GoWuBII7sFreKiwOm_trGKC4J9O--v1qaXO_3kLN9yD7vJD1YDGdyEsdVgpQ230LK4gRNKOMFkumbSxyH79uZhWoD1fa8NzdZrNKzBsMJTmm6TYnX17WHcUwyiUnrP4GLYDNzc_PgCVntTITwb4dDurPuSYhWXO1zYsK-hfBwShfZNS3J7ody0eHSg69qiC3U3y7JRe46Sb1xNfr4u8qRY3XybFNALrDBkZ3zpJRNqXChEkxivYoQlxYrSVIovDpWlsjVurDL4CUuwyEzVkjXXaOJTroT77EsQ1vrI4T687Zny6blvfhVSMspUwsbyQFKWRofl5jOW8ItHIzAuKIb1V1DkfmAMW6dU11GtA0RQ4a10n6P-Xv2dymXIVx17whDH7QgCtfaKx5VuWOeNWxuDZNgPCtDX1wI-yNnb5fk1XH17SMMqKvSuYxG1H2_EhpVV2I0rDgyS4jwtrsT5sCsjTQRnVUzqRntLLLaLsvdFIDwzVVqlwrKsEa71ZSb09gZlnfaWlSLlukqKFVDYVrvumMzykFCI5HR5QKWrHU2HbB7911u0MC3SUoz-GO24l9LIv18f_f4Bg8iV7oaSNnykvdE_Y0U1qJS6TIpVx4QKlzwpVp9uCHlpqpaaFJI_q_o-KaY3xWw6TW-K2Xwe30rVNo2LL_LwKHzIIMy6A_IonzVaNxIj6CBZKZR3Qtq04WUAPCcVY03FjnyLPhteppOTtDRMBbHKmiRFWSuVBmtkVVJMi9kC3njZHXWATxgqMg14kmcR-o8V27EBvWAWQfCBSpEXs3yWn6RS8sg87aVLI7l0N5bSQC7dJ3fEz6Z8MV2wIzybnM7z-XS2OJ0ctWfHZZUjq-qaF-VkgRyL05NFdcpns_yE8fn8SJwNzE8nxclsMsn49OR0XvJ5OSvyfL5YJMc5dkzIbOxgjkICIbTJfHEkWYnSjn98MmfBG0rf2OQ4D5nkFc8JJ8OfqWJQJieXyck5OcjJ5Vjpyf-GtKw9eeoQaOHVY_dx5I08-9N-Oaa91SD4-qz4dwAAAP__x10zhA">