Skip to content

Commit

Permalink
[MC] Add 'G' to augmentation string for MTE instrumented functions
Browse files Browse the repository at this point in the history
This was agreed on in
https://lists.llvm.org/pipermail/llvm-dev/2020-May/141345.html

The thread proposed two options
* add a character to augmentation string and handle in libuwind
* use a separate personality function.

It was determined that this is the simpler and better option.

This is part of ARM's Aarch64 ABI:
https://github.com/ARM-software/abi-aa/blob/main/aadwarf64/aadwarf64.rst#id22

The next step after this is teaching libunwind to untag when this
augmentation character is set.

Reviewed By: MaskRay, eugenis

Differential Revision: https://reviews.llvm.org/D127007
  • Loading branch information
fmayer committed Jun 8, 2022
1 parent 56eb8dc commit 0593ce5
Show file tree
Hide file tree
Showing 13 changed files with 100 additions and 0 deletions.
1 change: 1 addition & 0 deletions llvm/include/llvm/MC/MCDwarf.h
Expand Up @@ -688,6 +688,7 @@ struct MCDwarfFrameInfo {
bool IsSimple = false;
unsigned RAReg = static_cast<unsigned>(INT_MAX);
bool IsBKeyFrame = false;
bool IsMTETaggedFrame = false;
};

class MCDwarfFrameEmitter {
Expand Down
1 change: 1 addition & 0 deletions llvm/include/llvm/MC/MCStreamer.h
Expand Up @@ -926,6 +926,7 @@ class MCStreamer {
unsigned CUID = 0);

virtual void emitCFIBKeyFrame();
virtual void emitCFIMTETaggedFrame();

/// This implements the DWARF2 '.loc fileno lineno ...' assembler
/// directive.
Expand Down
7 changes: 7 additions & 0 deletions llvm/lib/MC/MCAsmStreamer.cpp
Expand Up @@ -319,6 +319,7 @@ class MCAsmStreamer final : public MCStreamer {

void emitIdent(StringRef IdentString) override;
void emitCFIBKeyFrame() override;
void emitCFIMTETaggedFrame() override;
void emitCFISections(bool EH, bool Debug) override;
void emitCFIDefCfa(int64_t Register, int64_t Offset) override;
void emitCFIDefCfaOffset(int64_t Offset) override;
Expand Down Expand Up @@ -2025,6 +2026,12 @@ void MCAsmStreamer::emitCFIBKeyFrame() {
EmitEOL();
}

void MCAsmStreamer::emitCFIMTETaggedFrame() {
MCStreamer::emitCFIMTETaggedFrame();
OS << "\t.cfi_mte_tagged_frame";
EmitEOL();
}

void MCAsmStreamer::emitWinCFIStartProc(const MCSymbol *Symbol, SMLoc Loc) {
MCStreamer::emitWinCFIStartProc(Symbol, Loc);

Expand Down
2 changes: 2 additions & 0 deletions llvm/lib/MC/MCDwarf.cpp
Expand Up @@ -1604,6 +1604,8 @@ const MCSymbol &FrameEmitterImpl::EmitCIE(const MCDwarfFrameInfo &Frame) {
Augmentation += "S";
if (Frame.IsBKeyFrame)
Augmentation += "B";
if (Frame.IsMTETaggedFrame)
Augmentation += "G";
Streamer.emitBytes(Augmentation);
}
Streamer.emitInt8(0);
Expand Down
2 changes: 2 additions & 0 deletions llvm/lib/MC/MCParser/AsmParser.cpp
Expand Up @@ -540,6 +540,7 @@ class AsmParser : public MCAsmParser {
DK_PSEUDO_PROBE,
DK_LTO_DISCARD,
DK_LTO_SET_CONDITIONAL,
DK_CFI_MTE_TAGGED_FRAME,
DK_END
};

Expand Down Expand Up @@ -5556,6 +5557,7 @@ void AsmParser::initializeDirectiveKindMap() {
DirectiveKindMap[".cfi_register"] = DK_CFI_REGISTER;
DirectiveKindMap[".cfi_window_save"] = DK_CFI_WINDOW_SAVE;
DirectiveKindMap[".cfi_b_key_frame"] = DK_CFI_B_KEY_FRAME;
DirectiveKindMap[".cfi_mte_tagged_frame"] = DK_CFI_MTE_TAGGED_FRAME;
DirectiveKindMap[".macros_on"] = DK_MACROS_ON;
DirectiveKindMap[".macros_off"] = DK_MACROS_OFF;
DirectiveKindMap[".macro"] = DK_MACRO;
Expand Down
7 changes: 7 additions & 0 deletions llvm/lib/MC/MCStreamer.cpp
Expand Up @@ -252,6 +252,13 @@ void MCStreamer::emitCFIBKeyFrame() {
CurFrame->IsBKeyFrame = true;
}

void MCStreamer::emitCFIMTETaggedFrame() {
MCDwarfFrameInfo *CurFrame = getCurrentDwarfFrameInfo();
if (!CurFrame)
return;
CurFrame->IsMTETaggedFrame = true;
}

void MCStreamer::emitDwarfLocDirective(unsigned FileNo, unsigned Line,
unsigned Column, unsigned Flags,
unsigned Isa, unsigned Discriminator,
Expand Down
11 changes: 11 additions & 0 deletions llvm/lib/Target/AArch64/AArch64AsmPrinter.cpp
Expand Up @@ -1285,6 +1285,17 @@ void AArch64AsmPrinter::emitInstruction(const MachineInstr *MI) {
return;
}

case AArch64::EMITMTETAGGED: {
ExceptionHandling ExceptionHandlingType = MAI->getExceptionHandlingType();
if (ExceptionHandlingType != ExceptionHandling::DwarfCFI &&
ExceptionHandlingType != ExceptionHandling::ARM)
return;

if (getFunctionCFISectionType(*MF) != CFISection::None)
OutStreamer->emitCFIMTETaggedFrame();
return;
}

// Tail calls use pseudo instructions so they have the proper code-gen
// attributes (isCall, isReturn, etc.). We lower them to the real
// instruction here.
Expand Down
5 changes: 5 additions & 0 deletions llvm/lib/Target/AArch64/AArch64FrameLowering.cpp
Expand Up @@ -192,6 +192,7 @@
#include "AArch64Subtarget.h"
#include "AArch64TargetMachine.h"
#include "MCTargetDesc/AArch64AddressingModes.h"
#include "MCTargetDesc/AArch64MCTargetDesc.h"
#include "llvm/ADT/ScopeExit.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/Statistic.h"
Expand Down Expand Up @@ -1427,6 +1428,10 @@ void AArch64FrameLowering::emitPrologue(MachineFunction &MF,
.setMIFlags(MachineInstr::FrameSetup);
}
}
if (EmitCFI && MFnI.isMTETagged()) {
BuildMI(MBB, MBBI, DL, TII->get(AArch64::EMITMTETAGGED))
.setMIFlag(MachineInstr::FrameSetup);
}

// We signal the presence of a Swift extended frame to external tools by
// storing FP with 0b0001 in bits 63:60. In normal userland operation a simple
Expand Down
4 changes: 4 additions & 0 deletions llvm/lib/Target/AArch64/AArch64InstrInfo.td
Expand Up @@ -2438,6 +2438,10 @@ def TLSDESCCALL : Pseudo<(outs), (ins i64imm:$sym), []>, Sched<[]> {
// augmentation string.
def EMITBKEY : Pseudo<(outs), (ins), []>, Sched<[]> {}

// Pseudo instruction to tell the streamer to emit a 'G' character into the
// augmentation string.
def EMITMTETAGGED : Pseudo<(outs), (ins), []>, Sched<[]> {}

// FIXME: maybe the scratch register used shouldn't be fixed to X1?
// FIXME: can "hasSideEffects be dropped?
// This gets lowered to an instruction sequence which takes 16 bytes
Expand Down
2 changes: 2 additions & 0 deletions llvm/lib/Target/AArch64/AArch64MachineFunctionInfo.cpp
Expand Up @@ -89,6 +89,8 @@ AArch64FunctionInfo::AArch64FunctionInfo(MachineFunction &MF_) : MF(&MF_) {
const Function &F = MF->getFunction();
std::tie(SignReturnAddress, SignReturnAddressAll) = GetSignReturnAddress(F);
SignWithBKey = ShouldSignWithBKey(F);
// TODO: skip functions that have no instrumented allocas for optimization
IsMTETagged = F.hasFnAttribute(Attribute::SanitizeMemTag);

if (!F.hasFnAttribute("branch-target-enforcement")) {
if (const auto *BTE = mdconst::extract_or_null<ConstantInt>(
Expand Down
3 changes: 3 additions & 0 deletions llvm/lib/Target/AArch64/AArch64MachineFunctionInfo.h
Expand Up @@ -175,6 +175,8 @@ class AArch64FunctionInfo final : public MachineFunctionInfo {
/// The stack slot where the Swift asynchronous context is stored.
int SwiftAsyncContextFrameIdx = std::numeric_limits<int>::max();

bool IsMTETagged = false;

/// True if the function need unwind information.
mutable Optional<bool> NeedsDwarfUnwindInfo;

Expand Down Expand Up @@ -408,6 +410,7 @@ class AArch64FunctionInfo final : public MachineFunctionInfo {
bool shouldSignReturnAddress(bool SpillsLR) const;

bool shouldSignWithBKey() const { return SignWithBKey; }
bool isMTETagged() const { return IsMTETagged; }

bool branchTargetEnforcement() const { return BranchTargetEnforcement; }

Expand Down
12 changes: 12 additions & 0 deletions llvm/lib/Target/AArch64/AsmParser/AArch64AsmParser.cpp
Expand Up @@ -190,6 +190,7 @@ class AArch64AsmParser : public MCTargetAsmParser {
bool parseDirectiveUnreq(SMLoc L);
bool parseDirectiveCFINegateRAState();
bool parseDirectiveCFIBKeyFrame();
bool parseDirectiveCFIMTETaggedFrame();

bool parseDirectiveVariantPCS(SMLoc L);

Expand Down Expand Up @@ -6038,6 +6039,8 @@ bool AArch64AsmParser::ParseDirective(AsmToken DirectiveID) {
parseDirectiveCFINegateRAState();
else if (IDVal == ".cfi_b_key_frame")
parseDirectiveCFIBKeyFrame();
else if (IDVal == ".cfi_mte_tagged_frame")
parseDirectiveCFIMTETaggedFrame();
else if (IDVal == ".arch_extension")
parseDirectiveArchExtension(Loc);
else if (IDVal == ".variant_pcs")
Expand Down Expand Up @@ -6518,6 +6521,15 @@ bool AArch64AsmParser::parseDirectiveCFIBKeyFrame() {
return false;
}

/// parseDirectiveCFIMTETaggedFrame
/// ::= .cfi_mte_tagged_frame
bool AArch64AsmParser::parseDirectiveCFIMTETaggedFrame() {
if (parseEOL())
return true;
getStreamer().emitCFIMTETaggedFrame();
return false;
}

/// parseDirectiveVariantPCS
/// ::= .variant_pcs symbolname
bool AArch64AsmParser::parseDirectiveVariantPCS(SMLoc L) {
Expand Down
43 changes: 43 additions & 0 deletions llvm/test/CodeGen/AArch64/stack-tagging-cfi.ll
@@ -0,0 +1,43 @@
; RUN: llc < %s -mtriple=aarch64 -mattr=+mte | FileCheck %s

declare void @use32(ptr)

define void @WithUnwind() sanitize_memtag {
entry:
; CHECK-LABEL: WithUnwind:
; CHECK: .cfi_mte_tagged_frame
; CHECK: stg
%x = alloca i32, align 4
call void @use32(i32* %x)
ret void
}

define void @NoUnwind() sanitize_memtag nounwind {
entry:
; CHECK-LABEL: NoUnwind:
; CHECK-NOT: .cfi_mte_tagged_frame
; CHECK: stg
%x = alloca i32, align 4
call void @use32(i32* %x)
ret void
}

define void @NoUnwindUwTable() sanitize_memtag nounwind uwtable {
entry:
; CHECK-LABEL: NoUnwindUwTable:
; CHECK: .cfi_mte_tagged_frame
; CHECK: stg
%x = alloca i32, align 4
call void @use32(i32* %x)
ret void
}

define void @NoMemtag() {
entry:
; CHECK-LABEL: NoMemtag:
; CHECK-NOT: .cfi_mte_tagged_frame
; CHECK-NOT: stg
%x = alloca i32, align 4
call void @use32(i32* %x)
ret void
}

0 comments on commit 0593ce5

Please sign in to comment.