danielkiss created this revision.
danielkiss added reviewers: nsz, tamas.petz, pbarrio, ostannard, chill.
Herald added subscribers: llvm-commits, cfe-commits, hiraditya, kristof.beyls.
Herald added projects: clang, LLVM.
Writing the .note.gnu.property manually is error prone and hard to
maintain in the assembly files.
The -mbti is for the assembler to emit the section with the
GNU_PROPERTY_AARCH64_FEATURE_1_BTI. To be used when C/C++ is compiled
with -mbranch-protection=bti.
This patch refactors the .note.gnu.property handling.
Repository:
rG LLVM Github Monorepo
https://reviews.llvm.org/D81930
Files:
clang/include/clang/Driver/Options.td
clang/lib/Driver/ToolChains/Arch/AArch64.cpp
clang/test/Driver/arm64-markbti.S
llvm/lib/Target/AArch64/AArch64.td
llvm/lib/Target/AArch64/AArch64AsmPrinter.cpp
llvm/lib/Target/AArch64/AArch64Subtarget.h
llvm/lib/Target/AArch64/AsmParser/AArch64AsmParser.cpp
llvm/lib/Target/AArch64/MCTargetDesc/AArch64TargetStreamer.cpp
llvm/lib/Target/AArch64/MCTargetDesc/AArch64TargetStreamer.h
Index: llvm/lib/Target/AArch64/MCTargetDesc/AArch64TargetStreamer.h
===================================================================
--- llvm/lib/Target/AArch64/MCTargetDesc/AArch64TargetStreamer.h
+++ llvm/lib/Target/AArch64/MCTargetDesc/AArch64TargetStreamer.h
@@ -20,6 +20,7 @@
class AArch64TargetStreamer : public MCTargetStreamer {
public:
AArch64TargetStreamer(MCStreamer &S);
+ AArch64TargetStreamer(MCStreamer &S, const MCSubtargetInfo *STI);
~AArch64TargetStreamer() override;
void finish() override;
@@ -36,6 +37,9 @@
/// Callback used to implement the .inst directive.
virtual void emitInst(uint32_t Inst);
+ /// Callback used to implement the .note.gnu.property section.
+ virtual void emitNoteSection(unsigned Flags);
+
virtual void EmitARM64WinCFIAllocStack(unsigned Size) {}
virtual void EmitARM64WinCFISaveFPLR(int Offset) {}
virtual void EmitARM64WinCFISaveFPLRX(int Offset) {}
@@ -56,6 +60,7 @@
private:
std::unique_ptr<AssemblerConstantPools> ConstantPools;
+ const MCSubtargetInfo *STI;
};
class AArch64TargetELFStreamer : public AArch64TargetStreamer {
@@ -65,7 +70,8 @@
void emitInst(uint32_t Inst) override;
public:
- AArch64TargetELFStreamer(MCStreamer &S) : AArch64TargetStreamer(S) {}
+ AArch64TargetELFStreamer(MCStreamer &S, const MCSubtargetInfo *STI)
+ : AArch64TargetStreamer(S, STI) {}
};
class AArch64TargetWinCOFFStreamer : public llvm::AArch64TargetStreamer {
@@ -76,8 +82,8 @@
// Symbol of the current epilog for which we are processing SEH directives.
MCSymbol *CurrentEpilog = nullptr;
public:
- AArch64TargetWinCOFFStreamer(llvm::MCStreamer &S)
- : AArch64TargetStreamer(S) {}
+ AArch64TargetWinCOFFStreamer(llvm::MCStreamer &S, const MCSubtargetInfo *STI)
+ : AArch64TargetStreamer(S, STI) {}
// The unwind codes on ARM64 Windows are documented at
// https://docs.microsoft.com/en-us/cpp/build/arm64-exception-handling
Index: llvm/lib/Target/AArch64/MCTargetDesc/AArch64TargetStreamer.cpp
===================================================================
--- llvm/lib/Target/AArch64/MCTargetDesc/AArch64TargetStreamer.cpp
+++ llvm/lib/Target/AArch64/MCTargetDesc/AArch64TargetStreamer.cpp
@@ -11,8 +11,12 @@
//===----------------------------------------------------------------------===//
#include "AArch64TargetStreamer.h"
+#include "AArch64Subtarget.h"
+#include "llvm/BinaryFormat/ELF.h"
#include "llvm/MC/ConstantPools.h"
+#include "llvm/MC/MCContext.h"
#include "llvm/MC/MCSection.h"
+#include "llvm/MC/MCSectionELF.h"
#include "llvm/MC/MCSubtargetInfo.h"
using namespace llvm;
@@ -21,7 +25,13 @@
// AArch64TargetStreamer Implemenation
//
AArch64TargetStreamer::AArch64TargetStreamer(MCStreamer &S)
- : MCTargetStreamer(S), ConstantPools(new AssemblerConstantPools()) {}
+ : MCTargetStreamer(S), ConstantPools(new AssemblerConstantPools()),
+ STI(nullptr) {}
+
+AArch64TargetStreamer::AArch64TargetStreamer(MCStreamer &S,
+ const MCSubtargetInfo *STI)
+ : MCTargetStreamer(S), ConstantPools(new AssemblerConstantPools()),
+ STI(STI) {}
AArch64TargetStreamer::~AArch64TargetStreamer() = default;
@@ -37,8 +47,54 @@
ConstantPools->emitForCurrentSection(Streamer);
}
-// finish() - write out any non-empty assembler constant pools.
-void AArch64TargetStreamer::finish() { ConstantPools->emitAll(Streamer); }
+// finish() - write out any non-empty assembler constant pools and
+// write out note.gnu.properties if need.
+void AArch64TargetStreamer::finish() {
+ ConstantPools->emitAll(Streamer);
+ if (!STI)
+ return;
+
+ if (STI->getFeatureBits()[AArch64::FeatureEmitNoteBTI]) {
+ emitNoteSection(ELF::GNU_PROPERTY_AARCH64_FEATURE_1_BTI);
+ }
+}
+
+void AArch64TargetStreamer::emitNoteSection(unsigned Flags) {
+ if (Flags == 0) {
+ return;
+ }
+ MCStreamer &OutStreamer = getStreamer();
+ MCContext &Context = OutStreamer.getContext();
+ // Emit a .note.gnu.property section with the flags.
+ MCSection *Cur = OutStreamer.getCurrentSectionOnly();
+ MCSectionELF *Nt = Context.getELFSection(".note.gnu.property", ELF::SHT_NOTE,
+ ELF::SHF_ALLOC);
+ if (Nt->isRegistered()) {
+ SMLoc Loc;
+ Context.reportWarning(
+ Loc,
+ "The .note.gnu.property is not emitted because it is already present.");
+ return;
+ }
+
+ OutStreamer.SwitchSection(Nt);
+
+ // Emit the note header.
+ OutStreamer.emitValueToAlignment(Align(8).value());
+ OutStreamer.emitIntValue(4, 4); // data size for "GNU\0"
+ OutStreamer.emitIntValue(4 * 4, 4); // Elf_Prop size
+ OutStreamer.emitIntValue(ELF::NT_GNU_PROPERTY_TYPE_0, 4);
+ OutStreamer.emitBytes(StringRef("GNU", 4)); // note name
+
+ // Emit the PAC/BTI properties.
+ OutStreamer.emitIntValue(ELF::GNU_PROPERTY_AARCH64_FEATURE_1_AND, 4);
+ OutStreamer.emitIntValue(4, 4); // data size
+ OutStreamer.emitIntValue(Flags, 4); // data
+ OutStreamer.emitIntValue(0, 4); // pad
+
+ OutStreamer.endSection(Nt);
+ OutStreamer.SwitchSection(Cur);
+}
void AArch64TargetStreamer::emitInst(uint32_t Inst) {
char Buffer[4];
@@ -60,9 +116,9 @@
createAArch64ObjectTargetStreamer(MCStreamer &S, const MCSubtargetInfo &STI) {
const Triple &TT = STI.getTargetTriple();
if (TT.isOSBinFormatELF())
- return new AArch64TargetELFStreamer(S);
+ return new AArch64TargetELFStreamer(S, &STI);
if (TT.isOSBinFormatCOFF())
- return new AArch64TargetWinCOFFStreamer(S);
+ return new AArch64TargetWinCOFFStreamer(S, &STI);
return nullptr;
}
Index: llvm/lib/Target/AArch64/AsmParser/AArch64AsmParser.cpp
===================================================================
--- llvm/lib/Target/AArch64/AsmParser/AArch64AsmParser.cpp
+++ llvm/lib/Target/AArch64/AsmParser/AArch64AsmParser.cpp
@@ -240,7 +240,7 @@
MCAsmParserExtension::Initialize(Parser);
MCStreamer &S = getParser().getStreamer();
if (S.getTargetStreamer() == nullptr)
- new AArch64TargetStreamer(S);
+ new AArch64TargetStreamer(S, &STI);
// Alias .hword/.word/.[dx]word to the target-independent
// .2byte/.4byte/.8byte directives as they have the same form and
Index: llvm/lib/Target/AArch64/AArch64Subtarget.h
===================================================================
--- llvm/lib/Target/AArch64/AArch64Subtarget.h
+++ llvm/lib/Target/AArch64/AArch64Subtarget.h
@@ -185,6 +185,9 @@
// Enable 64-bit vectorization in SLP.
unsigned MinVectorRegisterBitWidth = 64;
+ // Emitting .note.gnu.property in the assembler
+ bool MarkBTI = false;
+
bool UseAA = false;
bool PredictableSelectIsExpensive = false;
bool BalanceFPOps = false;
@@ -481,6 +484,8 @@
bool hasFMI() const { return HasFMI; }
bool hasRCPC_IMMO() const { return HasRCPC_IMMO; }
+ bool markBTI() const { return MarkBTI; }
+
bool addrSinkUsingGEPs() const override {
// Keeping GEPs inbounds is important for exploiting AArch64
// addressing-modes in ILP32 mode.
Index: llvm/lib/Target/AArch64/AArch64AsmPrinter.cpp
===================================================================
--- llvm/lib/Target/AArch64/AArch64AsmPrinter.cpp
+++ llvm/lib/Target/AArch64/AArch64AsmPrinter.cpp
@@ -200,26 +200,9 @@
return;
// Emit a .note.gnu.property section with the flags.
- MCSection *Cur = OutStreamer->getCurrentSectionOnly();
- MCSection *Nt = MMI->getContext().getELFSection(
- ".note.gnu.property", ELF::SHT_NOTE, ELF::SHF_ALLOC);
- OutStreamer->SwitchSection(Nt);
-
- // Emit the note header.
- emitAlignment(Align(8));
- OutStreamer->emitInt32(4); // data size for "GNU\0"
- OutStreamer->emitInt32(4 * 4); // Elf_Prop size
- OutStreamer->emitInt32(ELF::NT_GNU_PROPERTY_TYPE_0);
- OutStreamer->emitBytes(StringRef("GNU", 4)); // note name
-
- // Emit the PAC/BTI properties.
- OutStreamer->emitInt32(ELF::GNU_PROPERTY_AARCH64_FEATURE_1_AND);
- OutStreamer->emitInt32(4); // data size
- OutStreamer->emitInt32(Flags); // data
- OutStreamer->emitInt32(0); // pad
-
- OutStreamer->endSection(Nt);
- OutStreamer->SwitchSection(Cur);
+ if (auto *TS = static_cast<AArch64TargetStreamer *>(
+ OutStreamer->getTargetStreamer()))
+ TS->emitNoteSection(Flags);
}
void AArch64AsmPrinter::emitFunctionHeaderComment() {
Index: llvm/lib/Target/AArch64/AArch64.td
===================================================================
--- llvm/lib/Target/AArch64/AArch64.td
+++ llvm/lib/Target/AArch64/AArch64.td
@@ -349,6 +349,9 @@
def FeatureBranchTargetId : SubtargetFeature<"bti", "HasBTI",
"true", "Enable Branch Target Identification" >;
+def FeatureEmitNoteBTI : SubtargetFeature<"markbti", "MarkBTI",
+ "true", "Emit .note.gnu.property for Branch Target Identification" >;
+
def FeatureRandGen : SubtargetFeature<"rand", "HasRandGen",
"true", "Enable Random Number generation instructions" >;
Index: clang/test/Driver/arm64-markbti.S
===================================================================
--- /dev/null
+++ clang/test/Driver/arm64-markbti.S
@@ -0,0 +1,24 @@
+// When -mbti is passed the generated file object gets BTI marking.
+// RUN: %clang -target arm64-linux-none -mbti -c %s -o -| llvm-readobj -n | FileCheck -check-prefix=CHECK -check-prefix=CHECK_GEN %s
+// RUN: %clang -target arm64-linux-none -DNOTE_PRESENT -c %s -o - | llvm-readobj -n | FileCheck -check-prefix=CHECK -check-prefix=CHECK_PRESET %s
+// RUN: %clang -target arm64-linux-none -mbti -DNOTE_PRESENT -c %s -o - | llvm-readobj -n | FileCheck -check-prefix=CHECK -check-prefix=CHECK_PRESET %s
+// RUN: %clang -target arm64-linux-none -mbti -DNOTE_PRESENT -c %s -o - 2>&1 | FileCheck -check-prefix=CHECK_WARNING %s
+//
+// CHECK_WARNING: The .note.gnu.property is not emitted because it is already present.
+// CHECK: Name: .note.gnu.property
+// CHECK: Type: NT_GNU_PROPERTY_TYPE_0
+// CHECK_GEN: aarch64 feature: BTI
+// CHECK_PRESET: aarch64 feature: BTI, PAC
+
+#ifdef NOTE_PRESENT
+ .section .note.gnu.property, "a";
+ .balign 8;
+ .long 4;
+ .long 0x10;
+ .long 0x5
+ .asciz "GNU"
+ .long 0xc0000000
+ .long 4
+ .long 3
+ .long 0
+#endif
Index: clang/lib/Driver/ToolChains/Arch/AArch64.cpp
===================================================================
--- clang/lib/Driver/ToolChains/Arch/AArch64.cpp
+++ clang/lib/Driver/ToolChains/Arch/AArch64.cpp
@@ -441,4 +441,7 @@
if (Args.hasArg(options::OPT_mno_neg_immediates))
Features.push_back("+no-neg-immediates");
+
+ if (Args.hasArg(options::OPT_mbti))
+ Features.push_back("+markbti");
}
Index: clang/include/clang/Driver/Options.td
===================================================================
--- clang/include/clang/Driver/Options.td
+++ clang/include/clang/Driver/Options.td
@@ -2297,6 +2297,9 @@
def mno_fix_cortex_a53_835769 : Flag<["-"], "mno-fix-cortex-a53-835769">,
Group<m_aarch64_Features_Group>,
HelpText<"Don't workaround Cortex-A53 erratum 835769 (AArch64 only)">;
+def mbti : Flag<["-"], "mbti">,
+ Group<m_aarch64_Features_Group>,
+ HelpText<"Add .note.gnu.property with BTI to assembly files (AArch64 only)">;
foreach i = {1-31} in
def ffixed_x#i : Flag<["-"], "ffixed-x"#i>, Group<m_Group>,
HelpText<"Reserve the x"#i#" register (AArch64/RISC-V only)">;
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits