[lld] e2572b8 - [LLD][RISCV][Zicfilp] Generate unlabeled landing pad-style PLT (#145461)
via llvm-commits
llvm-commits at lists.llvm.org
Mon Jul 20 00:12:19 PDT 2026
Author: Ming-Yi Lai
Date: 2026-07-20T15:12:15+08:00
New Revision: e2572b883f0b2bc7a7a3808e484039f9382aa898
URL: https://github.com/llvm/llvm-project/commit/e2572b883f0b2bc7a7a3808e484039f9382aa898
DIFF: https://github.com/llvm/llvm-project/commit/e2572b883f0b2bc7a7a3808e484039f9382aa898.diff
LOG: [LLD][RISCV][Zicfilp] Generate unlabeled landing pad-style PLT (#145461)
To support dynamic linking when Zicfilp is enabled, lpad insns are
inserted into PLTs. This patch generates the unlabeled landing pad-style
PLT, in which all the lpads have label `0`, when ZICFILP-unlabeled is
enabled:
--- PLT Header:
```
1: auipc t3, %pcrel_hi(.got.plt)
sub t1, t1, t2
l[w|d] t2, %pcrel_lo(1b)(t3)
addi t1, t1, -(hdr size + 16)
addi t0, t3, %pcrel_lo(1b)
srli t1, t1, log2(16/PTRSIZE)
l[w|d] t0, PTRSIZE(t0)
jr t2
```
--- PLT Entry:
```
lpad 0
1: auipc t2, %pcrel_hi(function at .got.plt)
l[w|d] t2, %pcrel_lo(1b)(t2)
jalr t1, t2
```
(The PLT format is specified in the psABI draft at
<https://github.com/riscv-non-isa/riscv-elf-psabi-doc/pull/417>)
---------
Co-authored-by: Piyou Chen <piyou.chen at sifive.com>
Co-authored-by: Kito Cheng <npickito at gmail.com>
Added:
Modified:
lld/ELF/Arch/RISCV.cpp
lld/test/ELF/riscv-feature-zicfilp-unlabeled.s
Removed:
################################################################################
diff --git a/lld/ELF/Arch/RISCV.cpp b/lld/ELF/Arch/RISCV.cpp
index b88136326f449..49c41ff9ebe84 100644
--- a/lld/ELF/Arch/RISCV.cpp
+++ b/lld/ELF/Arch/RISCV.cpp
@@ -240,37 +240,73 @@ void RISCV::writeIgotPlt(uint8_t *buf, const Symbol &s) const {
}
void RISCV::writePltHeader(uint8_t *buf) const {
- // 1: auipc t2, %pcrel_hi(.got.plt)
- // sub t1, t1, t3
- // l[wd] t3, %pcrel_lo(1b)(t2); t3 = _dl_runtime_resolve
- // addi t1, t1, -pltHeaderSize-12; t1 = &.plt[i] - &.plt[0]
- // addi t0, t2, %pcrel_lo(1b)
- // srli t1, t1, (rv64?1:2); t1 = &.got.plt[i] - &.got.plt[0]
- // l[wd] t0, Wordsize(t0); t0 = link_map
- // jr t3
+ // If using lpad (CFI):
+ //
+ // 1: auipc t3, %pcrel_hi(.got.plt)
+ // sub t1, t1, t2
+ // l[w|d] t2, %pcrel_lo(1b)(t3)
+ // addi t1, t1, -(hdr size + 16)
+ // addi t0, t3, %pcrel_lo(1b)
+ // srli t1, t1, log2(16/PTRSIZE)
+ // l[w|d] t0, PTRSIZE(t0)
+ // jr t2
+ //
+ // If not using lpad:
+ //
+ // 1: auipc t2, %pcrel_hi(.got.plt)
+ // sub t1, t1, t3
+ // l[w|d] t3, %pcrel_lo(1b)(t2) ; t3 = _dl_runtime_resolve
+ // addi t1, t1, -pltHeaderSize-12 ; t1 = &.plt[i] - &.plt[0]
+ // addi t0, t2, %pcrel_lo(1b)
+ // srli t1, t1, (rv64?1:2) ; t1 = &.got.plt[i] - &.got.plt[0]
+ // l[w|d] t0, Wordsize(t0) ; t0 = link_map
+ // jr t3
+ bool lpad =
+ ctx.arg.andFeatures & GNU_PROPERTY_RISCV_FEATURE_1_CFI_LP_UNLABELED;
uint32_t offset = ctx.in.gotPlt->getVA() - ctx.in.plt->getVA();
uint32_t load = ctx.arg.is64 ? LD : LW;
- write32le(buf + 0, utype(AUIPC, X_T2, hi20(offset)));
- write32le(buf + 4, rtype(SUB, X_T1, X_T1, X_T3));
- write32le(buf + 8, itype(load, X_T3, X_T2, lo12(offset)));
- write32le(buf + 12, itype(ADDI, X_T1, X_T1, -ctx.target->pltHeaderSize - 12));
- write32le(buf + 16, itype(ADDI, X_T0, X_T2, lo12(offset)));
+ uint32_t auipcReg = lpad ? X_T3 : X_T2;
+ uint32_t workReg = lpad ? X_T2 : X_T3;
+
+ write32le(buf + 0, utype(AUIPC, auipcReg, hi20(offset)));
+ write32le(buf + 4, rtype(SUB, X_T1, X_T1, workReg));
+ write32le(buf + 8, itype(load, workReg, auipcReg, lo12(offset)));
+ write32le(buf + 12, itype(ADDI, X_T1, X_T1,
+ -ctx.target->pltHeaderSize - (lpad ? 16 : 12)));
+ write32le(buf + 16, itype(ADDI, X_T0, auipcReg, lo12(offset)));
write32le(buf + 20, itype(SRLI, X_T1, X_T1, ctx.arg.is64 ? 1 : 2));
write32le(buf + 24, itype(load, X_T0, X_T0, ctx.arg.wordsize));
- write32le(buf + 28, itype(JALR, 0, X_T3, 0));
+ write32le(buf + 28, itype(JALR, X_X0, workReg, 0));
}
void RISCV::writePlt(uint8_t *buf, const Symbol &sym,
uint64_t pltEntryAddr) const {
- // 1: auipc t3, %pcrel_hi(f at .got.plt)
- // l[wd] t3, %pcrel_lo(1b)(t3)
- // jalr t1, t3
- // nop
- uint32_t offset = sym.getGotPltVA(ctx) - pltEntryAddr;
- write32le(buf + 0, utype(AUIPC, X_T3, hi20(offset)));
- write32le(buf + 4, itype(ctx.arg.is64 ? LD : LW, X_T3, X_T3, lo12(offset)));
- write32le(buf + 8, itype(JALR, X_T1, X_T3, 0));
- write32le(buf + 12, itype(ADDI, 0, 0, 0));
+ // If using lpad:
+ //
+ // lpad 0
+ // 1: auipc t2, %pcrel_hi(function at .got.plt)
+ // l[w|d] t2, %pcrel_lo(1b)(t2)
+ // jalr t1, t2
+ //
+ // If not using lpad:
+ //
+ // 1: auipc t3, %pcrel_hi(f at .got.plt)
+ // l[w|d] t3, %pcrel_lo(1b)(t3)
+ // jalr t1, t3
+ // nop
+ bool lpad =
+ ctx.arg.andFeatures & GNU_PROPERTY_RISCV_FEATURE_1_CFI_LP_UNLABELED;
+ uint32_t auipcOffset = lpad * 4;
+ uint32_t offset = sym.getGotPltVA(ctx) - pltEntryAddr - auipcOffset;
+ uint32_t rd = lpad ? X_T2 : X_T3;
+ if (lpad)
+ write32le(buf + 0, utype(AUIPC, X_X0, 0)); // lpad 0
+ write32le(buf + 0 + auipcOffset, utype(AUIPC, rd, hi20(offset)));
+ write32le(buf + 4 + auipcOffset,
+ itype(ctx.arg.is64 ? LD : LW, rd, rd, lo12(offset)));
+ write32le(buf + 8 + auipcOffset, itype(JALR, X_T1, rd, 0));
+ if (!lpad)
+ write32le(buf + 12, itype(ADDI, X_X0, X_X0, 0));
}
RelType RISCV::getDynRel(RelType type) const {
diff --git a/lld/test/ELF/riscv-feature-zicfilp-unlabeled.s b/lld/test/ELF/riscv-feature-zicfilp-unlabeled.s
index 20491f057c8ed..1ed28c1c26a3b 100644
--- a/lld/test/ELF/riscv-feature-zicfilp-unlabeled.s
+++ b/lld/test/ELF/riscv-feature-zicfilp-unlabeled.s
@@ -25,6 +25,12 @@
# RUN: llvm-readelf -n out | FileCheck --check-prefix=ZICFILP %s
# RUN: ld.lld f1-s.o f3-s.o --shared -o out.so --fatal-warnings
# RUN: llvm-readelf -n out.so | FileCheck --check-prefix=ZICFILP %s
+
+## Check the unlabeled landing pad-style PLT. f1's `call f2` references the
+## undefined f2, which becomes a preemptible PLT entry in a shared object.
+# RUN: ld.lld rv32-f1-s.o --shared -o out.rv32.so --fatal-warnings
+# RUN: llvm-objdump -h -d --no-show-raw-insn --mattr=+experimental-zicfilp out.rv32.so | FileCheck --check-prefixes=PLT-DIS,PLT-DIS32 %s
+# RUN: llvm-objdump -h -d --no-show-raw-insn --mattr=+experimental-zicfilp out.so | FileCheck --check-prefixes=PLT-DIS,PLT-DIS64 %s
# RUN: ld.lld f1-s.o f2.o f3-s.o -o out.force -z zicfilp=unlabeled --fatal-warnings
# RUN: llvm-readelf -n out.force | FileCheck --check-prefix=ZICFILP %s
# RUN: ld.lld f2-s.o f3.o --shared -o out.force.so -z zicfilp=never -z zicfilp=unlabeled --fatal-warnings
@@ -68,6 +74,32 @@
# RUN: llvm-readelf -n out.override | FileCheck --check-prefixes=ZICFILP,OVERRIDE %s
# OVERRIDE-NOT: ZICFILP-func-sig
+# PLT-DIS32: .plt 00000030 00001220 TEXT
+# PLT-DIS32: .got.plt 0000000c 000032a8 DATA
+# PLT-DIS64: .plt 00000030 0000000000001370 TEXT
+# PLT-DIS64: .got.plt 00000018 0000000000003450 DATA
+
+# PLT-DIS: Disassembly of section .plt:
+# PLT-DIS: <.plt>:
+# PLT-DIS-NEXT: auipc t3, 0x2
+# PLT-DIS-NEXT: sub t1, t1, t2
+# PLT-DIS32-NEXT: lw t2, 0x88(t3)
+# PLT-DIS64-NEXT: ld t2, 0xe0(t3)
+# PLT-DIS-NEXT: addi t1, t1, -0x30
+# PLT-DIS32-NEXT: addi t0, t3, 0x88
+# PLT-DIS64-NEXT: addi t0, t3, 0xe0
+# PLT-DIS32-NEXT: srli t1, t1, 0x2
+# PLT-DIS64-NEXT: srli t1, t1, 0x1
+# PLT-DIS32-NEXT: lw t0, 0x4(t0)
+# PLT-DIS64-NEXT: ld t0, 0x8(t0)
+# PLT-DIS-NEXT: jr t2
+
+# PLT-DIS: lpad 0x0
+# PLT-DIS-NEXT: auipc t2, 0x2
+# PLT-DIS32-NEXT: lw t2, 0x6c(t2)
+# PLT-DIS64-NEXT: ld t2, 0xcc(t2)
+# PLT-DIS-NEXT: jalr t1, t2
+
#--- rv32-f1-s.s
.section ".note.gnu.property", "a"
.balign 4
More information about the llvm-commits
mailing list