[lld] [LLD][RISCV][Zicfilp] Generate unlabeled landing pad-style PLT (PR #145461)

via llvm-commits llvm-commits at lists.llvm.org
Mon Jun 23 22:41:54 PDT 2025


llvmbot wrote:


<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-lld-elf

Author: Ming-Yi Lai (mylai-mtk)

<details>
<summary>Changes</summary>

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:

```
    lpad 0
1:  auipc  t2, %pcrel_hi(.got.plt)
    sub    t1, t1, t3               # shifted .got.plt offset + hdr size + 16
    l[w|d] t3, %pcrel_lo(1b)(t2)    # _dl_runtime_resolve
    addi   t1, t1, -(hdr size + 16) # shifted .got.plt offset
    addi   t0, t2, %pcrel_lo(1b)    # &.got.plt
    srli   t1, t1, log2(16/PTRSIZE) # .got.plt offset
    l[w|d] t0, PTRSIZE(t0)          # link map
    jr     t3
    nop
    nop
    nop
```

--- PLT Entry:

```
    lpad 0
1:  auipc   t3, %pcrel_hi(function at .got.plt)
    l[w|d]  t3, %pcrel_lo(1b)(t3)
    jalr    t1, t3
```

(The PLT format is specified in the psABI draft at <https://github.com/riscv-non-isa/riscv-elf-psabi-doc/pull/417>)

---
Full diff: https://github.com/llvm/llvm-project/pull/145461.diff


2 Files Affected:

- (modified) lld/ELF/Arch/RISCV.cpp (+70-2) 
- (added) lld/test/ELF/riscv-plt-cfi-lp-unlabeled.s (+135) 


``````````diff
diff --git a/lld/ELF/Arch/RISCV.cpp b/lld/ELF/Arch/RISCV.cpp
index 72d83159ad8ac..33d3fdcc60ff8 100644
--- a/lld/ELF/Arch/RISCV.cpp
+++ b/lld/ELF/Arch/RISCV.cpp
@@ -27,7 +27,7 @@ using namespace lld::elf;
 
 namespace {
 
-class RISCV final : public TargetInfo {
+class RISCV : public TargetInfo {
 public:
   RISCV(Ctx &);
   uint32_t calcEFlags() const override;
@@ -1065,6 +1065,66 @@ void RISCV::finalizeRelax(int passes) const {
   }
 }
 
+namespace {
+
+class RISCVCfiLpUnlabeledPLT final : public RISCV {
+public:
+  RISCVCfiLpUnlabeledPLT(Ctx &ctx);
+  void writePltHeader(uint8_t *buf) const override;
+  void writePlt(uint8_t *buf, const Symbol &sym,
+                uint64_t pltEntryAddr) const override;
+};
+
+} // namespace
+
+RISCVCfiLpUnlabeledPLT::RISCVCfiLpUnlabeledPLT(Ctx &ctx) : RISCV(ctx) {
+  pltHeaderSize = 48;
+}
+
+void RISCVCfiLpUnlabeledPLT::writePltHeader(uint8_t *buf) const {
+  // lpad 0
+  // 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-16; 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
+  // nop
+  // nop
+  // nop
+  const uint32_t offset =
+      ctx.in.gotPlt->getVA() - (ctx.in.plt->getVA() + 4 /* offset for lpad */);
+  const uint32_t load = ctx.arg.is64 ? LD : LW;
+  write32le(buf + 0, utype(AUIPC, 0, 0)); // lpad 0
+  write32le(buf + 4, utype(AUIPC, X_T2, hi20(offset)));
+  write32le(buf + 8, rtype(SUB, X_T1, X_T1, X_T3));
+  write32le(buf + 12, itype(load, X_T3, X_T2, lo12(offset)));
+  write32le(buf + 16, itype(ADDI, X_T1, X_T1, -ctx.target->pltHeaderSize - 16));
+  write32le(buf + 20, itype(ADDI, X_T0, X_T2, lo12(offset)));
+  write32le(buf + 24, itype(SRLI, X_T1, X_T1, ctx.arg.is64 ? 1 : 2));
+  write32le(buf + 28, itype(load, X_T0, X_T0, ctx.arg.wordsize));
+  write32le(buf + 32, itype(JALR, 0, X_T3, 0));
+  write32le(buf + 36, itype(ADDI, 0, 0, 0)); // nop
+  write32le(buf + 40, itype(ADDI, 0, 0, 0)); // nop
+  write32le(buf + 44, itype(ADDI, 0, 0, 0)); // nop
+}
+
+void RISCVCfiLpUnlabeledPLT::writePlt(uint8_t *buf, const Symbol &sym,
+                                      uint64_t pltEntryAddr) const {
+  // lpad 0
+  // 1: auipc t3, %pcrel_hi(f at .got.plt)
+  // l[wd] t3, %pcrel_lo(1b)(t3)
+  // jalr t1, t3
+  const uint32_t offset =
+      sym.getGotPltVA(ctx) - (pltEntryAddr + 4 /* offset for lpad */);
+  write32le(buf + 0, utype(AUIPC, 0, 0)); // lpad 0
+  write32le(buf + 4, utype(AUIPC, X_T3, hi20(offset)));
+  write32le(buf + 8, itype(ctx.arg.is64 ? LD : LW, X_T3, X_T3, lo12(offset)));
+  write32le(buf + 12, itype(JALR, X_T1, X_T3, 0));
+}
+
 namespace {
 // Representation of the merged .riscv.attributes input sections. The psABI
 // specifies merge policy for attributes. E.g. if we link an object without an
@@ -1357,4 +1417,12 @@ void elf::mergeRISCVAttributesSections(Ctx &ctx) {
                            mergeAttributesSection(ctx, sections));
 }
 
-void elf::setRISCVTargetInfo(Ctx &ctx) { ctx.target.reset(new RISCV(ctx)); }
+void elf::setRISCVTargetInfo(Ctx &ctx) {
+  RISCV *target;
+  if (ctx.arg.andFeatures & GNU_PROPERTY_RISCV_FEATURE_1_CFI_LP_UNLABELED)
+    target = new RISCVCfiLpUnlabeledPLT(ctx);
+  else
+    target = new RISCV(ctx);
+
+  ctx.target.reset(target);
+}
diff --git a/lld/test/ELF/riscv-plt-cfi-lp-unlabeled.s b/lld/test/ELF/riscv-plt-cfi-lp-unlabeled.s
new file mode 100644
index 0000000000000..4a80081ecc258
--- /dev/null
+++ b/lld/test/ELF/riscv-plt-cfi-lp-unlabeled.s
@@ -0,0 +1,135 @@
+# REQUIRES: riscv
+# RUN: rm -rf %t && split-file %s %t && cd %t
+
+# RUN: llvm-mc -filetype=obj -triple=riscv32 rv32-foo.s -o foo32.o
+# RUN: ld.lld -shared foo32.o -soname=libfoo32.so -z zicfilp-unlabeled-report=error --fatal-warnings -o libfoo32.so
+# RUN: llvm-mc -filetype=obj -triple=riscv32 rv32-start.s -o start32.o
+# RUN: ld.lld start32.o libfoo32.so -z zicfilp-unlabeled-report=error --fatal-warnings -o out32
+# RUN: llvm-readelf -S out32 | FileCheck --check-prefix=SEC32 %s
+# RUN: llvm-objdump -d --no-show-raw-insn --mattr=+experimental-zicfilp out32 | FileCheck --check-prefixes=DIS,DIS32 %s
+
+# RUN: llvm-mc -filetype=obj -triple=riscv64 rv64-foo.s -o foo64.o
+# RUN: ld.lld -shared foo64.o -soname=libfoo64.so -z zicfilp-unlabeled-report=error --fatal-warnings -o libfoo64.so
+# RUN: llvm-mc -filetype=obj -triple=riscv64 rv64-start.s -o start64.o
+# RUN: ld.lld start64.o libfoo64.so -z zicfilp-unlabeled-report=error --fatal-warnings -o out64
+# RUN: llvm-readelf -S out64 | FileCheck --check-prefix=SEC64 %s
+# RUN: llvm-objdump -d --no-show-raw-insn --mattr=+experimental-zicfilp out64 | FileCheck --check-prefixes=DIS,DIS64 %s
+
+# SEC32: .plt     PROGBITS {{0*}}00011210
+# SEC32: .got.plt PROGBITS {{0*}}000132b8
+
+# SEC64: .plt     PROGBITS {{0*}}00011330
+# SEC64: .got.plt PROGBITS {{0*}}00013440
+
+# DIS:      Disassembly of section .plt:
+# DIS:      <.plt>:
+# DIS-NEXT:     lpad 0x0
+# DIS-NEXT:     auipc t2, 0x2
+# DIS-NEXT:     sub t1, t1, t3
+# DIS32-NEXT:   lw t3, 0xa4(t2)
+# DIS64-NEXT:   ld t3, 0x10c(t2)
+# DIS-NEXT:     addi t1, t1, -0x40
+# DIS32-NEXT:   addi t0, t2, 0xa4
+# DIS64-NEXT:   addi t0, t2, 0x10c
+# DIS32-NEXT:   srli t1, t1, 0x2
+# DIS64-NEXT:   srli t1, t1, 0x1
+# DIS32-NEXT:   lw t0, 0x4(t0)
+# DIS64-NEXT:   ld t0, 0x8(t0)
+# DIS-NEXT:     jr t3
+# DIS-NEXT:     nop
+# DIS-NEXT:     nop
+# DIS-NEXT:     nop
+
+# DIS:          lpad 0x0
+# DIS-NEXT:     auipc t3, 0x2
+# DIS32-NEXT:   lw t3, 0x7c(t3)
+# DIS64-NEXT:   ld t3, 0xec(t3)
+# DIS-NEXT:     jalr t1, t3
+
+#--- rv32-start.s
+
+.section ".note.gnu.property", "a"
+.balign 4
+.4byte 4
+.4byte (ndesc_end - ndesc_begin)
+.4byte 0x5        // NT_GNU_PROPERTY_TYPE_0
+.asciz "GNU"
+ndesc_begin:
+.balign 4
+.4byte 0xc0000000 // GNU_PROPERTY_RISCV_FEATURE_1_AND
+.4byte 4
+.4byte 1          // GNU_PROPERTY_RISCV_FEATURE_1_CFI_LP_UNLABELED
+.balign 4
+ndesc_end:
+
+.text
+.global _start, foo
+
+_start:
+  call foo at plt
+
+#--- rv32-foo.s
+
+.section ".note.gnu.property", "a"
+.balign 4
+.4byte 4
+.4byte (ndesc_end - ndesc_begin)
+.4byte 0x5        // NT_GNU_PROPERTY_TYPE_0
+.asciz "GNU"
+ndesc_begin:
+.balign 4
+.4byte 0xc0000000 // GNU_PROPERTY_RISCV_FEATURE_1_AND
+.4byte 4
+.4byte 1          // GNU_PROPERTY_RISCV_FEATURE_1_CFI_LP_UNLABELED
+.balign 4
+ndesc_end:
+
+.text
+.global foo
+.type foo, @function
+foo:
+  ret
+
+#--- rv64-start.s
+
+.section ".note.gnu.property", "a"
+.balign 8
+.4byte 4
+.4byte (ndesc_end - ndesc_begin)
+.4byte 0x5        // NT_GNU_PROPERTY_TYPE_0
+.asciz "GNU"
+ndesc_begin:
+.balign 8
+.4byte 0xc0000000 // GNU_PROPERTY_RISCV_FEATURE_1_AND
+.4byte 4
+.4byte 1          // GNU_PROPERTY_RISCV_FEATURE_1_CFI_LP_UNLABELED
+.balign 8
+ndesc_end:
+
+.text
+.global _start, foo
+
+_start:
+  call foo at plt
+
+#--- rv64-foo.s
+
+.section ".note.gnu.property", "a"
+.balign 8
+.4byte 4
+.4byte (ndesc_end - ndesc_begin)
+.4byte 0x5        // NT_GNU_PROPERTY_TYPE_0
+.asciz "GNU"
+ndesc_begin:
+.balign 8
+.4byte 0xc0000000 // GNU_PROPERTY_RISCV_FEATURE_1_AND
+.4byte 4
+.4byte 1          // GNU_PROPERTY_RISCV_FEATURE_1_CFI_LP_UNLABELED
+.balign 8
+ndesc_end:
+
+.text
+.global foo
+.type foo, @function
+foo:
+  ret

``````````

</details>


https://github.com/llvm/llvm-project/pull/145461


More information about the llvm-commits mailing list