[llvm] [RISCV] Emit .note.gnu.property section when Zicfiss-based shadow stack is enabled (PR #127036)

Ming-Yi Lai via llvm-commits llvm-commits at lists.llvm.org
Thu Feb 13 02:14:52 PST 2025


https://github.com/mylai-mtk updated https://github.com/llvm/llvm-project/pull/127036

>From 0b9890991d50a3edf49694b08edcf73b68e8a70c Mon Sep 17 00:00:00 2001
From: Ming-Yi Lai <ming-yi.lai at mediatek.com>
Date: Fri, 24 Jan 2025 18:42:35 +0800
Subject: [PATCH] [RISCV] Emit .note.gnu.property section when Zicfiss-based
 shadow stack is enabled

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.
---
 .../MCTargetDesc/RISCVTargetStreamer.cpp      | 65 +++++++++++++++++++
 .../RISCV/MCTargetDesc/RISCVTargetStreamer.h  |  1 +
 llvm/lib/Target/RISCV/RISCVAsmPrinter.cpp     | 15 ++++-
 .../RISCV/note-gnu-property-zicfiss.ll        | 13 ++++
 4 files changed, 93 insertions(+), 1 deletion(-)
 create mode 100644 llvm/test/CodeGen/RISCV/note-gnu-property-zicfiss.ll

diff --git a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVTargetStreamer.cpp b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVTargetStreamer.cpp
index 72b3e56c8a72f..28008ee985b9c 100644
--- a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVTargetStreamer.cpp
+++ b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVTargetStreamer.cpp
@@ -13,8 +13,12 @@
 #include "RISCVTargetStreamer.h"
 #include "RISCVBaseInfo.h"
 #include "RISCVMCTargetDesc.h"
+#include "llvm/BinaryFormat/ELF.h"
+#include "llvm/MC/MCContext.h"
+#include "llvm/MC/MCSectionELF.h"
 #include "llvm/MC/MCSymbol.h"
 #include "llvm/Support/CommandLine.h"
+#include "llvm/Support/ErrorHandling.h"
 #include "llvm/Support/FormattedStream.h"
 #include "llvm/Support/RISCVAttributes.h"
 #include "llvm/TargetParser/RISCVISAInfo.h"
@@ -51,6 +55,67 @@ void RISCVTargetStreamer::emitTextAttribute(unsigned Attribute,
 void RISCVTargetStreamer::emitIntTextAttribute(unsigned Attribute,
                                                unsigned IntValue,
                                                StringRef StringValue) {}
+
+void RISCVTargetStreamer::emitNoteGnuPropertySection(
+    const uint32_t Feature1And) {
+  MCStreamer &OutStreamer = getStreamer();
+  MCContext &Ctx = OutStreamer.getContext();
+
+  const Triple &Triple = Ctx.getTargetTriple();
+  Align NoteAlign;
+  if (Triple.isArch64Bit())
+    NoteAlign = Align(8);
+  else if (Triple.isArch32Bit())
+    NoteAlign = Align(4);
+  else
+    report_fatal_error("unsupported arch bit width");
+
+  MCSection *NoteSection;
+  switch (Ctx.getObjectFileType()) {
+  case MCContext::Environment::IsELF:
+    NoteSection =
+        Ctx.getELFSection(".note.gnu.property", ELF::SHT_NOTE, ELF::SHF_ALLOC);
+    break;
+  case MCContext::Environment::IsMachO:
+  case MCContext::Environment::IsGOFF:
+  case MCContext::Environment::IsCOFF:
+  case MCContext::Environment::IsSPIRV:
+  case MCContext::Environment::IsWasm:
+  case MCContext::Environment::IsXCOFF:
+  case MCContext::Environment::IsDXContainer:
+    report_fatal_error("unsupported object file type");
+  }
+  NoteSection->setAlignment(NoteAlign);
+  OutStreamer.pushSection();
+  OutStreamer.switchSection(NoteSection);
+
+  // Emit the note header
+  OutStreamer.emitIntValue(4, 4); // n_namsz
+
+  MCSymbol *const NDescBeginSym = Ctx.createTempSymbol();
+  MCSymbol *const NDescEndSym = Ctx.createTempSymbol();
+  const MCExpr *const NDescSzExpr =
+      MCBinaryExpr::createSub(MCSymbolRefExpr::create(NDescEndSym, Ctx),
+                              MCSymbolRefExpr::create(NDescBeginSym, Ctx), Ctx);
+
+  OutStreamer.emitValue(NDescSzExpr, 4);                    // n_descsz
+  OutStreamer.emitIntValue(ELF::NT_GNU_PROPERTY_TYPE_0, 4); // n_type
+  OutStreamer.emitBytes(StringRef("GNU", 4));               // n_name
+
+  // Emit n_desc field
+  OutStreamer.emitLabel(NDescBeginSym);
+  OutStreamer.emitValueToAlignment(NoteAlign);
+
+  // Emit the feature_1_and property
+  OutStreamer.emitIntValue(ELF::GNU_PROPERTY_RISCV_FEATURE_1_AND, 4); // pr_type
+  OutStreamer.emitIntValue(4, 4);              // pr_datasz
+  OutStreamer.emitIntValue(Feature1And, 4);    // pr_data
+  OutStreamer.emitValueToAlignment(NoteAlign); // pr_padding
+
+  OutStreamer.emitLabel(NDescEndSym);
+  OutStreamer.popSection();
+}
+
 void RISCVTargetStreamer::setTargetABI(RISCVABI::ABI ABI) {
   assert(ABI != RISCVABI::ABI_Unknown && "Improperly initialized target ABI");
   TargetABI = ABI;
diff --git a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVTargetStreamer.h b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVTargetStreamer.h
index cb8bc21cb6355..811157f16fff2 100644
--- a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVTargetStreamer.h
+++ b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVTargetStreamer.h
@@ -56,6 +56,7 @@ class RISCVTargetStreamer : public MCTargetStreamer {
   virtual void emitTextAttribute(unsigned Attribute, StringRef String);
   virtual void emitIntTextAttribute(unsigned Attribute, unsigned IntValue,
                                     StringRef StringValue);
+  void emitNoteGnuPropertySection(const uint32_t Feature1And);
 
   void emitTargetAttributes(const MCSubtargetInfo &STI, bool EmitStackAlign);
   void setTargetABI(RISCVABI::ABI ABI);
diff --git a/llvm/lib/Target/RISCV/RISCVAsmPrinter.cpp b/llvm/lib/Target/RISCV/RISCVAsmPrinter.cpp
index 7dcf2ba2ac405..c0ead6e3b989f 100644
--- a/llvm/lib/Target/RISCV/RISCVAsmPrinter.cpp
+++ b/llvm/lib/Target/RISCV/RISCVAsmPrinter.cpp
@@ -108,6 +108,8 @@ class RISCVAsmPrinter : public AsmPrinter {
   void emitFunctionEntryLabel() override;
   bool emitDirectiveOptionArch();
 
+  void emitNoteGnuProperty(const Module &M);
+
 private:
   void emitAttributes(const MCSubtargetInfo &SubtargetInfo);
 
@@ -578,8 +580,10 @@ void RISCVAsmPrinter::emitEndOfAsmFile(Module &M) {
   RISCVTargetStreamer &RTS =
       static_cast<RISCVTargetStreamer &>(*OutStreamer->getTargetStreamer());
 
-  if (TM.getTargetTriple().isOSBinFormatELF())
+  if (TM.getTargetTriple().isOSBinFormatELF()) {
     RTS.finishAttributeSection();
+    emitNoteGnuProperty(M);
+  }
   EmitHwasanMemaccessSymbols(M);
 }
 
@@ -938,6 +942,15 @@ void RISCVAsmPrinter::EmitHwasanMemaccessSymbols(Module &M) {
   }
 }
 
+void RISCVAsmPrinter::emitNoteGnuProperty(const Module &M) {
+  if (const Metadata *const Flag = M.getModuleFlag("cf-protection-return");
+      Flag && !mdconst::extract<ConstantInt>(Flag)->isZero()) {
+    RISCVTargetStreamer &RTS =
+        static_cast<RISCVTargetStreamer &>(*OutStreamer->getTargetStreamer());
+    RTS.emitNoteGnuPropertySection(ELF::GNU_PROPERTY_RISCV_FEATURE_1_CFI_SS);
+  }
+}
+
 static MCOperand lowerSymbolOperand(const MachineOperand &MO, MCSymbol *Sym,
                                     const AsmPrinter &AP) {
   MCContext &Ctx = AP.OutContext;
diff --git a/llvm/test/CodeGen/RISCV/note-gnu-property-zicfiss.ll b/llvm/test/CodeGen/RISCV/note-gnu-property-zicfiss.ll
new file mode 100644
index 0000000000000..acdd1dc93e5ab
--- /dev/null
+++ b/llvm/test/CodeGen/RISCV/note-gnu-property-zicfiss.ll
@@ -0,0 +1,13 @@
+; RUN: llc -mtriple=riscv32-unknown-linux-gnu -filetype=obj -o - %s | llvm-readelf -n - | FileCheck %s
+; RUN: llc -mtriple=riscv64-unknown-linux-gnu -filetype=obj -o - %s | llvm-readelf -n - | FileCheck %s
+
+; CHECK: Properties: RISC-V feature: ZICFISS
+
+define i32 @f() "hw-shadow-stack" {
+entry:
+  ret i32 0
+}
+
+!llvm.module.flags = !{!0}
+
+!0 = !{i32 8, !"cf-protection-return", i32 1}



More information about the llvm-commits mailing list