Skip to content

[LLD][RISCV][Zicfilp] Generate unlabeled landing pad-style PLT #145461

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: main
Choose a base branch
from

Conversation

mylai-mtk
Copy link
Contributor

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([email protected])
    l[w|d]  t3, %pcrel_lo(1b)(t3)
    jalr    t1, t3

(The PLT format is specified in the psABI draft at riscv-non-isa/riscv-elf-psabi-doc#417)

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([email protected])
    l[w|d]  t3, %pcrel_lo(1b)(t3)
    jalr    t1, t3
```
@llvmbot
Copy link
Member

llvmbot commented Jun 24, 2025

@llvm/pr-subscribers-lld-elf

Author: Ming-Yi Lai (mylai-mtk)

Changes

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([email protected])
    l[w|d]  t3, %pcrel_lo(1b)(t3)
    jalr    t1, t3

(The PLT format is specified in the psABI draft at <riscv-non-isa/riscv-elf-psabi-doc#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 --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([email protected])
+  // 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@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@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

@llvmbot
Copy link
Member

llvmbot commented Jun 24, 2025

@llvm/pr-subscribers-lld

Author: Ming-Yi Lai (mylai-mtk)

Changes

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)    # &amp;.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([email protected])
    l[w|d]  t3, %pcrel_lo(1b)(t3)
    jalr    t1, t3

(The PLT format is specified in the psABI draft at <riscv-non-isa/riscv-elf-psabi-doc#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 --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([email protected])
+  // 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@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@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

@lenary
Copy link
Member

lenary commented Jun 25, 2025

These sequences look right to me. This is following the AArch64 way of creating subclasses, which should work, but may be more complexity than we need? I don't feel qualified to make that call for certain.

@mylai-mtk
Copy link
Contributor Author

mylai-mtk commented Jun 25, 2025

@lenary

but may be more complexity than we need?

Yes, for the unlabeled-style PLT, this is a bit more complex than needed, but if you don't insist I change it, I would prefer to keep it as it is now due to the following reasons:

  • I prefer to dispatch between normal and unlabeled-style PLT generation logics with virtual function pointer loads instead of conditional branches (which is how I would refactor it if you insist to change), since it's (subjectively) cleaner codes, and reduced runtime costs (that is, the branch condition evaluations).
  • In the upcoming func-sig CFI PLT (cf. Add function signature based labeling scheme for landing pad riscv-non-isa/riscv-elf-psabi-doc#434), quite a few new data and method class members are added, which justifies (I hope so) the creation of a new class for this func-sig case. Given that the func-sig case would inherit from the base RISCV class, I would prefer to keep it simple and clean for now.
    • Besides, if the func-sig case gets its own class, it's (subjectively, again) cleaner to also keep the unlabeled-styled PLT in its own class.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants