Skip to content

[RISCV] Support .note.gnu.property for enable Zicfiss and Zicfilp extension #77414

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

Closed
wants to merge 5 commits into from
Closed
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
4 changes: 4 additions & 0 deletions lld/ELF/Config.h
Original file line number Diff line number Diff line change
Expand Up @@ -188,6 +188,8 @@ struct Config {
StringRef zBtiReport = "none";
StringRef zCetReport = "none";
StringRef zPauthReport = "none";
StringRef zZicfilpReport = "none";
StringRef zZicfissReport = "none";
bool ltoBBAddrMap;
llvm::StringRef ltoBasicBlockSections;
std::pair<llvm::StringRef, llvm::StringRef> thinLTOObjectSuffixReplace;
Expand Down Expand Up @@ -331,6 +333,8 @@ struct Config {
bool zText;
bool zRetpolineplt;
bool zWxneeded;
bool zForceZicfilp;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure if using bool here is suitable now. Currently, we have a second PLT scheme for Zicfilp: the function-signature-based one at riscv-non-isa/riscv-elf-psabi-doc#434 , so in the foreseeable future, this field would likely to be changed to an enum.

bool zForceZicfiss;
DiscardPolicy discard;
GnuStackKind zGnustack;
ICFLevel icf;
Expand Down
44 changes: 42 additions & 2 deletions lld/ELF/Driver.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -468,6 +468,13 @@ static void checkOptions() {
error("-z pauth-report only supported on AArch64");
}

if (config->emachine != EM_RISCV) {
if (config->zZicfilpReport != "none")
error("-z zicfilip-report only supported on RISC-V");
if (config->zZicfissReport != "none")
error("-z zicfiss-report only supported on RISC-V");
}

if (config->emachine != EM_386 && config->emachine != EM_X86_64 &&
config->zCetReport != "none")
error("-z cet-report only supported on X86 and X86_64");
Expand Down Expand Up @@ -1465,6 +1472,8 @@ static void readConfigs(opt::InputArgList &args) {
config->zWxneeded = hasZOption(args, "wxneeded");
setUnresolvedSymbolPolicy(args);
config->power10Stubs = args.getLastArgValue(OPT_power10_stubs_eq) != "no";
config->zForceZicfilp = hasZOption(args, "force-zicfilp");
config->zForceZicfiss = hasZOption(args, "force-zicfiss");

if (opt::Arg *arg = args.getLastArg(OPT_eb, OPT_el)) {
if (arg->getOption().matches(OPT_eb))
Expand Down Expand Up @@ -1508,7 +1517,9 @@ static void readConfigs(opt::InputArgList &args) {

auto reports = {std::make_pair("bti-report", &config->zBtiReport),
std::make_pair("cet-report", &config->zCetReport),
std::make_pair("pauth-report", &config->zPauthReport)};
std::make_pair("pauth-report", &config->zPauthReport),
std::make_pair("zicfilp-report", &config->zZicfilpReport),
std::make_pair("zicfiss-report", &config->zZicfissReport)};
for (opt::Arg *arg : args.filtered(OPT_z)) {
std::pair<StringRef, StringRef> option =
StringRef(arg->getValue()).split('=');
Expand Down Expand Up @@ -2651,7 +2662,7 @@ static void checkAndReportMissingFeature(StringRef config, uint32_t features,
// ones can be allowed (see -z pauth-report).
static void readSecurityNotes() {
if (config->emachine != EM_386 && config->emachine != EM_X86_64 &&
config->emachine != EM_AARCH64)
config->emachine != EM_AARCH64 && config->emachine != EM_RISCV)
return;

config->andFeatures = -1;
Expand Down Expand Up @@ -2685,6 +2696,17 @@ static void readSecurityNotes() {
toString(f) + ": -z cet-report: file does not have "
"GNU_PROPERTY_X86_FEATURE_1_SHSTK property");

checkAndReportMissingFeature(
config->zZicfilpReport, features,
GNU_PROPERTY_RISCV_FEATURE_1_CFI_LP_SIMPLE,
toString(f) + ": -z zicfilp-report: file does not have "
"GNU_PROPERTY_RISCV_FEATURE_1_CFI_LP_SIMPLE property");

checkAndReportMissingFeature(
config->zZicfissReport, features, GNU_PROPERTY_RISCV_FEATURE_1_CFI_SS,
toString(f) + ": -z zicfiss-report: file does not have "
"GNU_PROPERTY_RISCV_FEATURE_1_CFI_SS property");

if (config->zForceBti && !(features & GNU_PROPERTY_AARCH64_FEATURE_1_BTI)) {
features |= GNU_PROPERTY_AARCH64_FEATURE_1_BTI;
if (config->zBtiReport == "none")
Expand All @@ -2697,6 +2719,24 @@ static void readSecurityNotes() {
"GNU_PROPERTY_X86_FEATURE_1_IBT property");
features |= GNU_PROPERTY_X86_FEATURE_1_IBT;
}

if (config->zForceZicfilp &&
!(features & GNU_PROPERTY_RISCV_FEATURE_1_CFI_LP_SIMPLE)) {
features |= GNU_PROPERTY_RISCV_FEATURE_1_CFI_LP_SIMPLE;
if (config->zZicfilpReport == "none")
warn(toString(f) +
": -z force-zicfilp: file does not have "
"GNU_PROPERTY_RISCV_FEATURE_1_CFI_LP_SIMPLE property");
}

if (config->zForceZicfiss &&
!(features & GNU_PROPERTY_RISCV_FEATURE_1_CFI_SS)) {
features |= GNU_PROPERTY_RISCV_FEATURE_1_CFI_SS;
if (config->zZicfissReport == "none")
warn(toString(f) + ": -z force-zicfiss: file does not have "
"GNU_PROPERTY_RISCV_FEATURE_1_CFI_SS property");
}

if (config->zPacPlt && !(features & GNU_PROPERTY_AARCH64_FEATURE_1_PAC)) {
warn(toString(f) + ": -z pac-plt: file does not have "
"GNU_PROPERTY_AARCH64_FEATURE_1_PAC property");
Expand Down
17 changes: 14 additions & 3 deletions lld/ELF/InputFiles.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -954,9 +954,20 @@ void readGnuProperty(const InputSection &sec, ObjFile<ELFT> &f) {
continue;
}

uint32_t featureAndType = config->emachine == EM_AARCH64
? GNU_PROPERTY_AARCH64_FEATURE_1_AND
: GNU_PROPERTY_X86_FEATURE_1_AND;
uint32_t featureAndType = 0;
switch (config->emachine) {
case EM_X86_64:
featureAndType = GNU_PROPERTY_X86_FEATURE_1_AND;
break;
case EM_AARCH64:
featureAndType = GNU_PROPERTY_AARCH64_FEATURE_1_AND;
break;
case EM_RISCV:
featureAndType = GNU_PROPERTY_RISCV_FEATURE_1_AND;
break;
default :
llvm_unreachable("unknow EMachine for GNU_PROPERTY AND");
}

// Read a body of a NOTE record, which consists of type-length-value fields.
ArrayRef<uint8_t> desc = note.getDesc(sec.addralign);
Expand Down
15 changes: 12 additions & 3 deletions lld/ELF/SyntheticSections.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -323,9 +323,18 @@ void GnuPropertySection::writeTo(uint8_t *buf) {
write32(buf + 8, NT_GNU_PROPERTY_TYPE_0); // Type
memcpy(buf + 12, "GNU", 4); // Name string

uint32_t featureAndType = config->emachine == EM_AARCH64
? GNU_PROPERTY_AARCH64_FEATURE_1_AND
: GNU_PROPERTY_X86_FEATURE_1_AND;
uint32_t featureAndType = 0;
switch (config->emachine) {
default:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also change the default statement to EM_X86_64 ?

featureAndType = GNU_PROPERTY_X86_FEATURE_1_AND;
break;
case EM_AARCH64:
featureAndType = GNU_PROPERTY_AARCH64_FEATURE_1_AND;
break;
case EM_RISCV:
featureAndType = GNU_PROPERTY_RISCV_FEATURE_1_AND;
break;
}

unsigned offset = 16;
if (config->andFeatures != 0) {
Expand Down
36 changes: 36 additions & 0 deletions lld/test/ELF/riscv-force-cfi-property.s
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
# REQUIRES: riscv

# RUN: llvm-mc -filetype=obj -triple=riscv32-unknown-elf %s -o %t.rv32_lp.o
# RUN: ld.lld %t.rv32_lp.o -zforce-zicfilp -o %t.rv32_lp | count 0
# RUN: llvm-readobj -n %t.rv32_lp | FileCheck -check-prefix=CHECK -check-prefix=CHECK_ZICFILP %s

# RUN: llvm-mc -filetype=obj -triple=riscv64-unknown-elf %s -o %t.rv64_lp.o
# RUN: ld.lld %t.rv64_lp.o -zforce-zicfilp -o %t.rv64_lp | count 0
# RUN: llvm-readobj -n %t.rv64_lp | FileCheck -check-prefix=CHECK -check-prefix=CHECK_ZICFILP %s

# RUN: llvm-mc -filetype=obj -triple=riscv32-unknown-elf %s -o %t.rv32_ss.o
# RUN: ld.lld %t.rv32_ss.o -zforce-zicfiss -o %t.rv32_ss | count 0
# RUN: llvm-readobj -n %t.rv32_ss | FileCheck -check-prefix=CHECK -check-prefix=CHECK_ZICFISS %s

# RUN: llvm-mc -filetype=obj -triple=riscv64-unknown-elf %s -o %t.rv64_ss.o
# RUN: ld.lld %t.rv64_ss.o -zforce-zicfiss -o %t.rv64_ss | count 0
# RUN: llvm-readobj -n %t.rv64_ss | FileCheck -check-prefix=CHECK -check-prefix=CHECK_ZICFISS %s

# RUN: llvm-mc -filetype=obj -triple=riscv32-unknown-elf %s -o %t.rv32_lp_ss.o
# RUN: ld.lld %t.rv32_lp_ss.o -zforce-zicfilp -zforce-zicfiss -o %t.rv32_lp_ss | count 0
# RUN: llvm-readobj -n %t.rv32_lp_ss | FileCheck -check-prefix=CHECK -check-prefix=CHECK_ZICFILP_ZICFISS %s

# RUN: llvm-mc -filetype=obj -triple=riscv64-unknown-elf %s -o %t.rv64_lp_ss.o
# RUN: ld.lld %t.rv64_lp_ss.o -zforce-zicfilp -zforce-zicfiss -o %t.rv64_lp_ss | count 0
# RUN: llvm-readobj -n %t.rv64_lp_ss | FileCheck -check-prefix=CHECK -check-prefix=CHECK_ZICFILP_ZICFISS %s



// CHECK: Name: .note.gnu.property
// CHECK: Type: NT_GNU_PROPERTY_TYPE_0 (property note)
// CHECK: Property [
// CHECK_ZICFISS: riscv feature: Zicfiss
// CHECK_ZICFILP: riscv feature: Zicfilp
// CHECK_ZICFILP_ZICFISS: riscv feature: Zicfilp, Zicfiss
// CHECK: ]

7 changes: 7 additions & 0 deletions llvm/include/llvm/BinaryFormat/ELF.h
Original file line number Diff line number Diff line change
Expand Up @@ -1737,6 +1737,7 @@ enum : unsigned {
GNU_PROPERTY_AARCH64_FEATURE_1_AND = 0xc0000000,
GNU_PROPERTY_AARCH64_FEATURE_PAUTH = 0xc0000001,
GNU_PROPERTY_X86_FEATURE_1_AND = 0xc0000002,
GNU_PROPERTY_RISCV_FEATURE_1_AND = 0xc0000000,

GNU_PROPERTY_X86_UINT32_OR_LO = 0xc0008000,
GNU_PROPERTY_X86_FEATURE_2_NEEDED = GNU_PROPERTY_X86_UINT32_OR_LO + 1,
Expand Down Expand Up @@ -1796,6 +1797,12 @@ enum : unsigned {
GNU_PROPERTY_X86_ISA_1_V4 = 1 << 3,
};

// riscv processor feature bits.
enum : unsigned {
GNU_PROPERTY_RISCV_FEATURE_1_CFI_LP_SIMPLE = 1 << 0,
GNU_PROPERTY_RISCV_FEATURE_1_CFI_SS = 1 << 1,
};

// FreeBSD note types.
enum {
NT_FREEBSD_ABI_TAG = 1,
Expand Down
53 changes: 52 additions & 1 deletion llvm/lib/Target/RISCV/MCTargetDesc/RISCVTargetStreamer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,10 @@
#include "RISCVTargetStreamer.h"
#include "RISCVBaseInfo.h"
#include "RISCVMCTargetDesc.h"
#include "llvm/MC/MCContext.h"
#include "llvm/MC/MCSectionELF.h"
#include "llvm/MC/MCSymbol.h"
#include "llvm/BinaryFormat/ELF.h"
#include "llvm/Support/FormattedStream.h"
#include "llvm/Support/RISCVAttributes.h"
#include "llvm/TargetParser/RISCVISAInfo.h"
Expand All @@ -22,7 +25,11 @@ using namespace llvm;

RISCVTargetStreamer::RISCVTargetStreamer(MCStreamer &S) : MCTargetStreamer(S) {}

void RISCVTargetStreamer::finish() { finishAttributeSection(); }
void RISCVTargetStreamer::finish() {
finishAttributeSection();
emitGNUProgramProperties();
}

void RISCVTargetStreamer::reset() {}

void RISCVTargetStreamer::emitDirectiveOptionPush() {}
Expand Down Expand Up @@ -52,6 +59,9 @@ void RISCVTargetStreamer::setFlagsFromFeatures(const MCSubtargetInfo &STI) {
HasRVC = STI.hasFeature(RISCV::FeatureStdExtC) ||
STI.hasFeature(RISCV::FeatureStdExtZca);
HasTSO = STI.hasFeature(RISCV::FeatureStdExtZtso);
HasZicfilp = STI.hasFeature(RISCV::FeatureStdExtZicfilp);
HasZicfiss = STI.hasFeature(RISCV::FeatureStdExtZicfiss);
IsRV64 = STI.hasFeature(RISCV::Feature64Bit);
}

void RISCVTargetStreamer::emitTargetAttributes(const MCSubtargetInfo &STI,
Expand All @@ -77,6 +87,47 @@ void RISCVTargetStreamer::emitTargetAttributes(const MCSubtargetInfo &STI,
}
}

void RISCVTargetStreamer::emitGNUProgramProperties() {
unsigned FeatureAndFlags = 0;
// Check Zicfilp or Zicfiss with features
// TODO should we check with codegen enable
// ex. -mllvm -riscv-hardware-shadow-stack=true ?
if (hasZicfilp())
FeatureAndFlags |= ELF::GNU_PROPERTY_RISCV_FEATURE_1_CFI_LP_SIMPLE;

if (hasZicfiss())
FeatureAndFlags |= ELF::GNU_PROPERTY_RISCV_FEATURE_1_CFI_SS;

if (FeatureAndFlags == 0)
return;

MCStreamer &OutStreamer = getStreamer();
MCContext &Context = OutStreamer.getContext();
MCSectionELF *Nt = Context.getELFSection(".note.gnu.property", ELF::SHT_NOTE,
ELF::SHF_ALLOC);
MCSection *Cur = OutStreamer.getCurrentSectionOnly();
OutStreamer.switchSection(Nt);

// Emit the note header.
uint64_t DataSize = isRV64() ? 4 : 3;
OutStreamer.emitValueToAlignment(isRV64() ? Align(8) : Align(4));
OutStreamer.emitIntValue(4, 4); // data size for note name
OutStreamer.emitIntValue(4 * DataSize, 4); // data size
OutStreamer.emitIntValue(ELF::NT_GNU_PROPERTY_TYPE_0, 4); // note type
OutStreamer.emitBytes(StringRef("GNU", 4)); // note name

// Emit the CFI(Zicfilp/Zicfiss) properties.
OutStreamer.emitIntValue(ELF::GNU_PROPERTY_RISCV_FEATURE_1_AND,
4); // and property
OutStreamer.emitIntValue(4, 4); // data size
OutStreamer.emitIntValue(FeatureAndFlags, 4); // data
if (isRV64())
OutStreamer.emitIntValue(0, 4); // Padding

OutStreamer.endSection(Nt);
OutStreamer.switchSection(Cur);
}

// This part is for ascii assembly output
RISCVTargetAsmStreamer::RISCVTargetAsmStreamer(MCStreamer &S,
formatted_raw_ostream &OS)
Expand Down
7 changes: 7 additions & 0 deletions llvm/lib/Target/RISCV/MCTargetDesc/RISCVTargetStreamer.h
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,9 @@ class RISCVTargetStreamer : public MCTargetStreamer {
RISCVABI::ABI TargetABI = RISCVABI::ABI_Unknown;
bool HasRVC = false;
bool HasTSO = false;
bool HasZicfilp = false;
bool HasZicfiss = false;
bool IsRV64 = false;

public:
RISCVTargetStreamer(MCStreamer &S);
Expand All @@ -58,11 +61,15 @@ class RISCVTargetStreamer : public MCTargetStreamer {
StringRef StringValue);

void emitTargetAttributes(const MCSubtargetInfo &STI, bool EmitStackAlign);
void emitGNUProgramProperties();
void setTargetABI(RISCVABI::ABI ABI);
RISCVABI::ABI getTargetABI() const { return TargetABI; }
void setFlagsFromFeatures(const MCSubtargetInfo &STI);
bool hasRVC() const { return HasRVC; }
bool hasTSO() const { return HasTSO; }
bool hasZicfilp() const { return HasZicfilp; }
bool hasZicfiss() const { return HasZicfiss; }
bool isRV64() const { return IsRV64; }
};

// This part is for ascii assembly output
Expand Down
78 changes: 78 additions & 0 deletions llvm/test/tools/llvm-readobj/ELF/RISCV/riscv-cfi-property.s
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
# RUN: rm -rf %t && split-file %s %t && cd %t

#--- gnu-property-riscv32.s
// RUN: llvm-mc -triple riscv32 -filetype obj gnu-property-riscv32.s -o gnu-property-riscv32.o
// RUN: llvm-readobj -n gnu-property-riscv32.o | FileCheck -check-prefix=LLVM gnu-property-riscv32.s
// RUN: llvm-readobj -n --elf-output-style=GNU gnu-property-riscv32.o | FileCheck -check-prefix=GNU gnu-property-riscv32.s


// LLVM: Notes [
// LLVM-NEXT: NoteSection {
// LLVM-NEXT: Name: .note.gnu.property
// LLVM-NEXT: Offset: 0x34
// LLVM-NEXT: Size: 0x1C
// LLVM-NEXT: Note {
// LLVM-NEXT: Owner: GNU
// LLVM-NEXT: Data size: 0xC
// LLVM-NEXT: Type: NT_GNU_PROPERTY_TYPE_0 (property note)
// LLVM-NEXT: Property [
// LLVM-NEXT: riscv feature: Zicfilp, Zicfiss
// LLVM-NEXT: ]
// LLVM-NEXT: }
// LLVM-NEXT: }
// LLVM-NEXT: ]

// GNU: Displaying notes found in: .note.gnu.property
// GNU-NEXT: Owner Data size Description
// GNU-NEXT: GNU 0x0000000c NT_GNU_PROPERTY_TYPE_0 (property note)
// GNU-NEXT: Properties: riscv feature: Zicfilp, Zicfiss

// GNU Note Section Example
.section .note.gnu.property, "a"
.p2align 2
.long 4
.long 12;
.long 5
.asciz "GNU"
.long 0xc0000000
.long 4
.long 3

#--- gnu-property-riscv64.s
// RUN: llvm-mc -triple riscv64 -filetype obj gnu-property-riscv64.s -o gnu-property-riscv64.o
// RUN: llvm-readobj -n gnu-property-riscv64.o | FileCheck -check-prefix=LLVM64 gnu-property-riscv64.s
// RUN: llvm-readobj -n --elf-output-style=GNU gnu-property-riscv64.o | FileCheck -check-prefix=GNU64 gnu-property-riscv64.s


// LLVM64: Notes [
// LLVM64-NEXT: NoteSection {
// LLVM64-NEXT: Name: .note.gnu.property
// LLVM64-NEXT: Offset: 0x40
// LLVM64-NEXT: Size: 0x20
// LLVM64-NEXT: Note {
// LLVM64-NEXT: Owner: GNU
// LLVM64-NEXT: Data size: 0x10
// LLVM64-NEXT: Type: NT_GNU_PROPERTY_TYPE_0 (property note)
// LLVM64-NEXT: Property [
// LLVM64-NEXT: riscv feature: Zicfilp, Zicfiss
// LLVM64-NEXT: ]
// LLVM64-NEXT: }
// LLVM64-NEXT: }
// LLVM64-NEXT: ]

// GNU64: Displaying notes found in: .note.gnu.property
// GNU64-NEXT: Owner Data size Description
// GNU64-NEXT: GNU 0x00000010 NT_GNU_PROPERTY_TYPE_0 (property note)
// GNU64-NEXT: Properties: riscv feature: Zicfilp, Zicfiss

// GNU Note Section Example
.section .note.gnu.property, "a"
.p2align 2
.long 4
.long 16;
.long 5
.asciz "GNU"
.long 0xc0000000
.long 4
.long 3
.long 0
Loading