Skip to content

Commit 691ca55

Browse files
authored
[RISCV] Emit .note.gnu.property section when Zicfiss-based shadow stack is enabled (llvm#127036)
RISC-V Zicfiss-based shadow stack needs to let the linker/loader know if the binary is built with the mechanism enabled to support proper link-time/load-time management of this feature. The information is encoded as a bit in the `.note.gnu.property` section. This patch implements emitting the section for RISC-V targets when Zicfiss-based shadow stack is enabled. When Clang receives the `-fcf-protection=return` flag, it adds the `hw-shadow-stack` attribute to LLVM functions, and adds a non-zero valued attribute named `cf-protection-return` to the LLVM module it generates. The backend depends on the `hw-shadow-stack` attributes to generate Zicfiss-based shadow stack instructions for each function, but at the module scope, the `cf-protection-return` attribute is a better indication of whether the translation unit is built with Zicfiss-based shadow stack enabled, so this patch emits the `.note.gnu.property` section with the "Zicfiss-based shadow stack" bit toggled on when it sees the `cf-protection-return` attribute.
1 parent 866f1cd commit 691ca55

File tree

4 files changed

+102
-1
lines changed

4 files changed

+102
-1
lines changed

llvm/lib/Target/RISCV/MCTargetDesc/RISCVTargetStreamer.cpp

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,15 @@
1313
#include "RISCVTargetStreamer.h"
1414
#include "RISCVBaseInfo.h"
1515
#include "RISCVMCTargetDesc.h"
16+
#include "llvm/BinaryFormat/ELF.h"
17+
#include "llvm/MC/MCContext.h"
18+
#include "llvm/MC/MCExpr.h"
19+
#include "llvm/MC/MCSectionELF.h"
20+
#include "llvm/MC/MCStreamer.h"
1621
#include "llvm/MC/MCSymbol.h"
22+
#include "llvm/Support/Alignment.h"
1723
#include "llvm/Support/CommandLine.h"
24+
#include "llvm/Support/ErrorHandling.h"
1825
#include "llvm/Support/FormattedStream.h"
1926
#include "llvm/Support/RISCVAttributes.h"
2027
#include "llvm/TargetParser/RISCVISAInfo.h"
@@ -53,6 +60,55 @@ void RISCVTargetStreamer::emitTextAttribute(unsigned Attribute,
5360
void RISCVTargetStreamer::emitIntTextAttribute(unsigned Attribute,
5461
unsigned IntValue,
5562
StringRef StringValue) {}
63+
64+
void RISCVTargetStreamer::emitNoteGnuPropertySection(
65+
const uint32_t Feature1And) {
66+
MCStreamer &OutStreamer = getStreamer();
67+
MCContext &Ctx = OutStreamer.getContext();
68+
69+
const Triple &Triple = Ctx.getTargetTriple();
70+
Align NoteAlign;
71+
if (Triple.isArch64Bit()) {
72+
NoteAlign = Align(8);
73+
} else {
74+
assert(Triple.isArch32Bit());
75+
NoteAlign = Align(4);
76+
}
77+
78+
assert(Ctx.getObjectFileType() == MCContext::Environment::IsELF);
79+
MCSection *const NoteSection =
80+
Ctx.getELFSection(".note.gnu.property", ELF::SHT_NOTE, ELF::SHF_ALLOC);
81+
NoteSection->setAlignment(NoteAlign);
82+
OutStreamer.pushSection();
83+
OutStreamer.switchSection(NoteSection);
84+
85+
// Emit the note header
86+
OutStreamer.emitIntValue(4, 4); // n_namsz
87+
88+
MCSymbol *const NDescBeginSym = Ctx.createTempSymbol();
89+
MCSymbol *const NDescEndSym = Ctx.createTempSymbol();
90+
const MCExpr *const NDescSzExpr =
91+
MCBinaryExpr::createSub(MCSymbolRefExpr::create(NDescEndSym, Ctx),
92+
MCSymbolRefExpr::create(NDescBeginSym, Ctx), Ctx);
93+
94+
OutStreamer.emitValue(NDescSzExpr, 4); // n_descsz
95+
OutStreamer.emitIntValue(ELF::NT_GNU_PROPERTY_TYPE_0, 4); // n_type
96+
OutStreamer.emitBytes(StringRef("GNU", 4)); // n_name
97+
98+
// Emit n_desc field
99+
OutStreamer.emitLabel(NDescBeginSym);
100+
OutStreamer.emitValueToAlignment(NoteAlign);
101+
102+
// Emit the feature_1_and property
103+
OutStreamer.emitIntValue(ELF::GNU_PROPERTY_RISCV_FEATURE_1_AND, 4); // pr_type
104+
OutStreamer.emitIntValue(4, 4); // pr_datasz
105+
OutStreamer.emitIntValue(Feature1And, 4); // pr_data
106+
OutStreamer.emitValueToAlignment(NoteAlign); // pr_padding
107+
108+
OutStreamer.emitLabel(NDescEndSym);
109+
OutStreamer.popSection();
110+
}
111+
56112
void RISCVTargetStreamer::setTargetABI(RISCVABI::ABI ABI) {
57113
assert(ABI != RISCVABI::ABI_Unknown && "Improperly initialized target ABI");
58114
TargetABI = ABI;

llvm/lib/Target/RISCV/MCTargetDesc/RISCVTargetStreamer.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@ class RISCVTargetStreamer : public MCTargetStreamer {
5858
virtual void emitTextAttribute(unsigned Attribute, StringRef String);
5959
virtual void emitIntTextAttribute(unsigned Attribute, unsigned IntValue,
6060
StringRef StringValue);
61+
void emitNoteGnuPropertySection(const uint32_t Feature1And);
6162

6263
void emitTargetAttributes(const MCSubtargetInfo &STI, bool EmitStackAlign);
6364
void setTargetABI(RISCVABI::ABI ABI);

llvm/lib/Target/RISCV/RISCVAsmPrinter.cpp

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,8 @@ class RISCVAsmPrinter : public AsmPrinter {
112112
void emitFunctionEntryLabel() override;
113113
bool emitDirectiveOptionArch();
114114

115+
void emitNoteGnuProperty(const Module &M);
116+
115117
private:
116118
void emitAttributes(const MCSubtargetInfo &SubtargetInfo);
117119

@@ -581,8 +583,10 @@ void RISCVAsmPrinter::emitEndOfAsmFile(Module &M) {
581583
RISCVTargetStreamer &RTS =
582584
static_cast<RISCVTargetStreamer &>(*OutStreamer->getTargetStreamer());
583585

584-
if (TM.getTargetTriple().isOSBinFormatELF())
586+
if (TM.getTargetTriple().isOSBinFormatELF()) {
585587
RTS.finishAttributeSection();
588+
emitNoteGnuProperty(M);
589+
}
586590
EmitHwasanMemaccessSymbols(M);
587591
}
588592

@@ -941,6 +945,15 @@ void RISCVAsmPrinter::EmitHwasanMemaccessSymbols(Module &M) {
941945
}
942946
}
943947

948+
void RISCVAsmPrinter::emitNoteGnuProperty(const Module &M) {
949+
if (const Metadata *const Flag = M.getModuleFlag("cf-protection-return");
950+
Flag && !mdconst::extract<ConstantInt>(Flag)->isZero()) {
951+
RISCVTargetStreamer &RTS =
952+
static_cast<RISCVTargetStreamer &>(*OutStreamer->getTargetStreamer());
953+
RTS.emitNoteGnuPropertySection(ELF::GNU_PROPERTY_RISCV_FEATURE_1_CFI_SS);
954+
}
955+
}
956+
944957
static MCOperand lowerSymbolOperand(const MachineOperand &MO, MCSymbol *Sym,
945958
const AsmPrinter &AP) {
946959
MCContext &Ctx = AP.OutContext;
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
; RUN: llc --mtriple=riscv32 --filetype=obj -o - %s | llvm-readelf -n - | FileCheck --check-prefixes=READELF %s
2+
; RUN: llc --mtriple=riscv64 --filetype=obj -o - %s | llvm-readelf -n - | FileCheck --check-prefixes=READELF %s
3+
; RUN: llc --mtriple=riscv32 -o - %s | FileCheck --check-prefixes=ASM,ASM32 %s
4+
; RUN: llc --mtriple=riscv64 -o - %s | FileCheck --check-prefixes=ASM,ASM64 %s
5+
6+
; READELF: Properties: RISC-V feature: ZICFISS
7+
8+
; ASM: .section ".note.GNU-stack","",@progbits
9+
; ASM-NEXT: .section .note.gnu.property,"a",@note
10+
; ASM-NEXT: .word 4
11+
; ASM-NEXT: .word .Ltmp1-.Ltmp0
12+
; ASM-NEXT: .word 5
13+
; ASM-NEXT: .asciz "GNU"
14+
; ASM-NEXT: .Ltmp0:
15+
; ASM32-NEXT: .p2align 2, 0x0
16+
; ASM64-NEXT: .p2align 3, 0x0
17+
; ASM-NEXT: .word 3221225472
18+
; ASM-NEXT: .word 4
19+
; ASM-NEXT: .word 2
20+
; ASM32-NEXT: .p2align 2, 0x0
21+
; ASM64-NEXT: .p2align 3, 0x0
22+
; ASM-NEXT: .Ltmp1:
23+
24+
define i32 @f() "hw-shadow-stack" {
25+
entry:
26+
ret i32 0
27+
}
28+
29+
!llvm.module.flags = !{!0}
30+
31+
!0 = !{i32 8, !"cf-protection-return", i32 1}

0 commit comments

Comments
 (0)