diff --git a/llvm/include/llvm/BinaryFormat/ELF.h b/llvm/include/llvm/BinaryFormat/ELF.h --- a/llvm/include/llvm/BinaryFormat/ELF.h +++ b/llvm/include/llvm/BinaryFormat/ELF.h @@ -425,6 +425,8 @@ // Special values for the st_other field in the symbol table entry for AArch64. enum { + // This global is marked to be tagged by MTE. + STO_AARCH64_TAGGED = 0x20, // Symbol may follow different calling convention than base PCS. STO_AARCH64_VARIANT_PCS = 0x80 }; @@ -1578,6 +1580,7 @@ NT_ANDROID_TYPE_IDENT = 1, NT_ANDROID_TYPE_KUSER = 3, NT_ANDROID_TYPE_MEMTAG = 4, + NT_ANDROID_TYPE_MEMTAG_GLOBALS = 8, }; // Memory tagging values used in NT_ANDROID_TYPE_MEMTAG notes. @@ -1593,7 +1596,8 @@ NT_MEMTAG_LEVEL_SYNC = 2, NT_MEMTAG_LEVEL_MASK = 3, // Bits indicating whether the loader should prepare for MTE to be enabled on - // the heap and/or stack. + // the heap and/or stack. Whether globals are protected or not depends on the + // presence of the NT_ANDROID_TYPE_MEMTAG_GLOBALS note. NT_MEMTAG_HEAP = 4, NT_MEMTAG_STACK = 8, }; diff --git a/llvm/include/llvm/MC/MCAsmInfo.h b/llvm/include/llvm/MC/MCAsmInfo.h --- a/llvm/include/llvm/MC/MCAsmInfo.h +++ b/llvm/include/llvm/MC/MCAsmInfo.h @@ -442,6 +442,8 @@ /// protected visibility. Defaults to MCSA_Protected MCSymbolAttr ProtectedVisibilityAttr = MCSA_Protected; + MCSymbolAttr TaggedAttr = MCSA_Tagged; + //===--- Dwarf Emission Directives -----------------------------------===// /// True if target supports emission of debugging information. Defaults to @@ -772,6 +774,8 @@ return ProtectedVisibilityAttr; } + MCSymbolAttr getTaggedAttr() const { return TaggedAttr; } + bool doesSupportDebugInformation() const { return SupportsDebugInformation; } ExceptionHandling getExceptionHandlingType() const { return ExceptionsType; } diff --git a/llvm/include/llvm/MC/MCDirectives.h b/llvm/include/llvm/MC/MCDirectives.h --- a/llvm/include/llvm/MC/MCDirectives.h +++ b/llvm/include/llvm/MC/MCDirectives.h @@ -45,7 +45,8 @@ MCSA_Weak, ///< .weak MCSA_WeakDefinition, ///< .weak_definition (MachO) MCSA_WeakReference, ///< .weak_reference (MachO) - MCSA_WeakDefAutoPrivate ///< .weak_def_can_be_hidden (MachO) + MCSA_WeakDefAutoPrivate, ///< .weak_def_can_be_hidden (MachO) + MCSA_Tagged ///< .tagged (ELF) }; enum MCAssemblerFlag { diff --git a/llvm/include/llvm/MC/MCSymbolELF.h b/llvm/include/llvm/MC/MCSymbolELF.h --- a/llvm/include/llvm/MC/MCSymbolELF.h +++ b/llvm/include/llvm/MC/MCSymbolELF.h @@ -43,6 +43,9 @@ void setIsSignature() const; bool isSignature() const; + bool isMemoryTagged() const; + void setTagged(bool Tagged); + static bool classof(const MCSymbol *S) { return S->isELF(); } private: diff --git a/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp b/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp --- a/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp +++ b/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp @@ -710,6 +710,12 @@ // GV's or GVSym's attributes will be used for the EmittedSym. emitVisibility(EmittedSym, GV->getVisibility(), !GV->isDeclaration()); + if (GV->hasSanitizerMetadata() && GV->isTagged()) { + assert(TM.getTargetTriple().getArch() == Triple::aarch64 && + "Tagged symbols are only supported on aarch64."); + OutStreamer->emitSymbolAttribute(EmittedSym, MAI->getTaggedAttr()); + } + if (!GV->hasInitializer()) // External globals require no extra code. return; diff --git a/llvm/lib/MC/MCAsmStreamer.cpp b/llvm/lib/MC/MCAsmStreamer.cpp --- a/llvm/lib/MC/MCAsmStreamer.cpp +++ b/llvm/lib/MC/MCAsmStreamer.cpp @@ -764,6 +764,9 @@ case MCSA_Exported: // Non-AIX assemblers currently do not support exported visibility. return false; + case MCSA_Tagged: + OS << "\t.tagged\t"; + break; } Symbol->print(OS, MAI); diff --git a/llvm/lib/MC/MCELFStreamer.cpp b/llvm/lib/MC/MCELFStreamer.cpp --- a/llvm/lib/MC/MCELFStreamer.cpp +++ b/llvm/lib/MC/MCELFStreamer.cpp @@ -286,6 +286,10 @@ Symbol->setVisibility(ELF::STV_PROTECTED); break; + case MCSA_Tagged: + Symbol->setTagged(true); + break; + case MCSA_Hidden: Symbol->setVisibility(ELF::STV_HIDDEN); break; diff --git a/llvm/lib/MC/MCMachOStreamer.cpp b/llvm/lib/MC/MCMachOStreamer.cpp --- a/llvm/lib/MC/MCMachOStreamer.cpp +++ b/llvm/lib/MC/MCMachOStreamer.cpp @@ -360,6 +360,7 @@ case MCSA_Local: case MCSA_LGlobal: case MCSA_Exported: + case MCSA_Tagged: return false; case MCSA_Global: diff --git a/llvm/lib/MC/MCParser/AsmParser.cpp b/llvm/lib/MC/MCParser/AsmParser.cpp --- a/llvm/lib/MC/MCParser/AsmParser.cpp +++ b/llvm/lib/MC/MCParser/AsmParser.cpp @@ -541,6 +541,7 @@ DK_LTO_DISCARD, DK_LTO_SET_CONDITIONAL, DK_CFI_MTE_TAGGED_FRAME, + DK_TAGGED, DK_END }; @@ -2298,6 +2299,8 @@ return parseDirectivePseudoProbe(); case DK_LTO_DISCARD: return parseDirectiveLTODiscard(); + case DK_TAGGED: + return parseDirectiveSymbolAttribute(MCSA_Tagged); } return Error(IDLoc, "unknown directive"); @@ -4986,8 +4989,9 @@ MCSymbol *Sym = getContext().getOrCreateSymbol(Name); - // Assembler local symbols don't make any sense here. Complain loudly. - if (Sym->isTemporary()) + // Assembler local symbols don't make any sense here, except for directives + // that the symbol should be tagged. + if (Sym->isTemporary() && Attr != MCSA_Tagged) return Error(Loc, "non-local symbol required"); if (!getStreamer().emitSymbolAttribute(Sym, Attr)) @@ -5600,6 +5604,7 @@ DirectiveKindMap[".pseudoprobe"] = DK_PSEUDO_PROBE; DirectiveKindMap[".lto_discard"] = DK_LTO_DISCARD; DirectiveKindMap[".lto_set_conditional"] = DK_LTO_SET_CONDITIONAL; + DirectiveKindMap[".tagged"] = DK_TAGGED; } MCAsmMacro *AsmParser::parseMacroLikeBody(SMLoc DirectiveLoc) { diff --git a/llvm/lib/MC/MCSymbolELF.cpp b/llvm/lib/MC/MCSymbolELF.cpp --- a/llvm/lib/MC/MCSymbolELF.cpp +++ b/llvm/lib/MC/MCSymbolELF.cpp @@ -33,7 +33,10 @@ ELF_WeakrefUsedInReloc_Shift = 11, // One bit. - ELF_BindingSet_Shift = 12 + ELF_BindingSet_Shift = 12, + + // One bit. + ELF_IsMemoryTagged = 13, }; } @@ -193,4 +196,14 @@ bool MCSymbolELF::isBindingSet() const { return getFlags() & (0x1 << ELF_BindingSet_Shift); } + +bool MCSymbolELF::isMemoryTagged() const { + return getFlags() & (0x1 << ELF_IsMemoryTagged); +} + +void MCSymbolELF::setTagged(bool Tagged) { + uint32_t OtherFlags = getFlags() & ~(0x1 << ELF_IsMemoryTagged); + setFlags(OtherFlags | ((Tagged ? 1 : 0) << ELF_IsMemoryTagged)); + setOther(ELF::STO_AARCH64_TAGGED); +} } diff --git a/llvm/lib/ObjectYAML/ELFYAML.cpp b/llvm/lib/ObjectYAML/ELFYAML.cpp --- a/llvm/lib/ObjectYAML/ELFYAML.cpp +++ b/llvm/lib/ObjectYAML/ELFYAML.cpp @@ -181,6 +181,7 @@ ECase(NT_ANDROID_TYPE_IDENT); ECase(NT_ANDROID_TYPE_KUSER); ECase(NT_ANDROID_TYPE_MEMTAG); + ECase(NT_ANDROID_TYPE_MEMTAG_GLOBALS); #undef ECase IO.enumFallback(Value); } @@ -1226,8 +1227,10 @@ Map["STO_MIPS_OPTIONAL"] = ELF::STO_MIPS_OPTIONAL; } - if (EMachine == ELF::EM_AARCH64) + if (EMachine == ELF::EM_AARCH64) { Map["STO_AARCH64_VARIANT_PCS"] = ELF::STO_AARCH64_VARIANT_PCS; + Map["STO_AARCH64_TAGGED"] = ELF::STO_AARCH64_TAGGED; + } if (EMachine == ELF::EM_RISCV) Map["STO_RISCV_VARIANT_CC"] = ELF::STO_RISCV_VARIANT_CC; return Map; diff --git a/llvm/test/CodeGen/AArch64/global-tagging.ll b/llvm/test/CodeGen/AArch64/global-tagging.ll new file mode 100644 --- /dev/null +++ b/llvm/test/CodeGen/AArch64/global-tagging.ll @@ -0,0 +1,40 @@ +; RUN: llc %s -mtriple=aarch64-linux-android31 -o %t.S +; RUN: FileCheck %s --input-file=%t.S +; RUN: llvm-mc -filetype=obj %t.S -triple=aarch64-linux-android31 -o %t.o +; RUN: llvm-objdump -t %t.o | FileCheck %s + +; RUN: obj2yaml %t.o > %t.yaml +; RUN: FileCheck %s --input-file=%t.yaml --check-prefix=CHECK-YAML +; RUN: yaml2obj %t.yaml -o %t.o +; RUN: llvm-objdump -t %t.o | FileCheck %s + +; CHECK-YAML: Symbols: + +; CHECK: .tagged internal_four +; CHECK-YAML: - Name: internal_four +; CHECK-YAML-NOT: - +; CHECK-YAML: Other: [ STO_AARCH64_TAGGED ] +@internal_four = internal global i32 1, sanitize_memtag + +; CHECK: .tagged four +; CHECK-YAML: - Name: four +; CHECK-YAML-NOT: - +; CHECK-YAML: Other: [ STO_AARCH64_TAGGED ] +@four = global i32 1, sanitize_memtag + +; CHECK: .tagged sixteen +; CHECK-YAML: - Name: sixteen +; CHECK-YAML-NOT: - +; CHECK-YAML: Other: [ STO_AARCH64_TAGGED ] +@sixteen = global [16 x i8] zeroinitializer, sanitize_memtag + +; CHECK: .tagged huge +; CHECK-YAML: - Name: huge +; CHECK-YAML-NOT: - +; CHECK-YAML: Other: [ STO_AARCH64_TAGGED ] +@huge = global [16777232 x i8] zeroinitializer, sanitize_memtag + +; CHECK-NOT: .tagged specialcaselisted +; CHECK-YAML: - Name: specialcaselisted +; CHECK-NOT-YAML: Other: [ STO_AARCH64_TAGGED ] +@specialcaselisted = global i16 2, no_sanitize_memtag diff --git a/llvm/tools/llvm-objdump/llvm-objdump.cpp b/llvm/tools/llvm-objdump/llvm-objdump.cpp --- a/llvm/tools/llvm-objdump/llvm-objdump.cpp +++ b/llvm/tools/llvm-objdump/llvm-objdump.cpp @@ -2170,6 +2170,12 @@ } uint8_t Other = ELFSymbolRef(Symbol).getOther(); + if (isAArch64Elf(O)) { + if (Other & ELF::STO_AARCH64_TAGGED) + outs() << " .tagged"; + Other &= ~ELF::STO_AARCH64_TAGGED; + } + switch (Other) { case ELF::STV_DEFAULT: break;