[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