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
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
72 changes: 70 additions & 2 deletions lld/ELF/Arch/RISCV.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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@.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
Expand Down Expand Up @@ -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);
}
135 changes: 135 additions & 0 deletions lld/test/ELF/riscv-plt-cfi-lp-unlabeled.s
Original file line number Diff line number Diff line change
@@ -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
Loading