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 @@ -997,6 +997,11 @@ // https://android.googlesource.com/platform/bionic/+/6f12bfece5dcc01325e0abba56a46b1bcf991c69/tools/relocation_packer/src/elf_file.cc#37 SHT_ANDROID_REL = 0x60000001, SHT_ANDROID_RELA = 0x60000002, + // Temporary Android-specific section types for global variable tagging on + // AArch64 MTE. Once made as an official ABI + // (https://github.com/ARM-software/abi-aa/pull/166), these section types will + // be deprecated. + SHT_ANDROID_MEMTAG_GLOBALS_STATIC = 0x60000003, SHT_LLVM_ODRTAB = 0x6fff4c00, // LLVM ODR table. SHT_LLVM_LINKER_OPTIONS = 0x6fff4c01, // LLVM Linker Options. SHT_LLVM_ADDRSIG = 0x6fff4c03, // List of address-significant symbols 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 MemtagAttr = MCSA_Memtag; + //===--- Dwarf Emission Directives -----------------------------------===// /// True if target supports emission of debugging information. Defaults to @@ -772,6 +774,8 @@ return ProtectedVisibilityAttr; } + MCSymbolAttr getMemtagAttr() const { return MemtagAttr; } + 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_Memtag, ///< .memtag (ELF) }; enum MCAssemblerFlag { diff --git a/llvm/include/llvm/MC/MCELFObjectWriter.h b/llvm/include/llvm/MC/MCELFObjectWriter.h --- a/llvm/include/llvm/MC/MCELFObjectWriter.h +++ b/llvm/include/llvm/MC/MCELFObjectWriter.h @@ -139,6 +139,14 @@ unsigned setRSsym(unsigned Value, unsigned Type) const { return (Type & R_SSYM_MASK) | ((Value & 0xff) << R_SSYM_SHIFT); } + + // On AArch64, return a new section to be added to the ELF object that + // contains relocations used to describe every symbol that should have memory + // tags applied. Returns nullptr if no such section is necessary (i.e. there's + // no tagged globals). + virtual MCSectionELF *getMemtagRelocsSection(MCContext &Ctx) const { + return nullptr; + } }; /// Construct a new ELF writer instance. 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; + void setMemtag(bool Tagged); + bool isMemtag() const; + 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->getMemtagAttr()); + } + if (!GV->hasInitializer()) // External globals require no extra code. return; diff --git a/llvm/lib/MC/ELFObjectWriter.cpp b/llvm/lib/MC/ELFObjectWriter.cpp --- a/llvm/lib/MC/ELFObjectWriter.cpp +++ b/llvm/lib/MC/ELFObjectWriter.cpp @@ -192,6 +192,8 @@ MCSectionELF *createRelocationSection(MCContext &Ctx, const MCSectionELF &Sec); + void createMemtagRelocs(MCAssembler &Asm); + void writeSectionHeader(const MCAsmLayout &Layout, const SectionIndexMapTy &SectionIndexMap, const SectionOffsetsTy &SectionOffsets); @@ -608,6 +610,23 @@ return true; } +void ELFWriter::createMemtagRelocs(MCAssembler &Asm) { + MCSectionELF *MemtagRelocs = nullptr; + for (const MCSymbol &Sym : Asm.symbols()) { + const auto &SymE = cast(Sym); + if (!SymE.isMemtag()) + continue; + if (MemtagRelocs == nullptr) { + MemtagRelocs = OWriter.TargetObjectWriter->getMemtagRelocsSection(Asm.getContext()); + assert(MemtagRelocs != nullptr && + "Tagged globals are only supported on AArch64"); + Asm.registerSection(*MemtagRelocs); + } + ELFRelocationEntry Rec(0, &SymE, ELF::R_AARCH64_NONE, 0, nullptr, 0); + OWriter.Relocations[MemtagRelocs].push_back(Rec); + } +} + void ELFWriter::computeSymbolTable( MCAssembler &Asm, const MCAsmLayout &Layout, const SectionIndexMapTy &SectionIndexMap, const RevGroupMapTy &RevGroupMap, @@ -1059,6 +1078,8 @@ Ctx.getELFSection(".strtab", ELF::SHT_STRTAB, 0); StringTableIndex = addToSectionTable(StrtabSection); + createMemtagRelocs(Asm); + RevGroupMapTy RevGroupMap; SectionIndexMapTy SectionIndexMap; @@ -1302,6 +1323,15 @@ return true; } + // For memory-tagged symbols, ensure that the relocation uses the symbol. For + // tagged symbols, we emit an empty relocation (R_AARCH64_NONE) in a special + // section (SHT_ANDROID_MEMTAG_GLOBALS_STATIC) to indicate to the linker that + // this global needs to be tagged. In addition, the linker needs to know + // whether to emit a special addend when relocating `end` symbols, and this + // can only be determined by the attributes of the symbol itself. + if (Sym->isMemtag()) + return true; + // An undefined symbol is not in any section, so the relocation has to point // to the symbol itself. assert(Sym && "Expected a symbol"); 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 @@ -762,6 +762,9 @@ case MCSA_Exported: // Non-AIX assemblers currently do not support exported visibility. return false; + case MCSA_Memtag: + OS << "\t.memtag\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_Memtag: + Symbol->setMemtag(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_Memtag: 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_MEMTAG, DK_END }; @@ -2298,6 +2299,8 @@ return parseDirectivePseudoProbe(); case DK_LTO_DISCARD: return parseDirectiveLTODiscard(); + case DK_MEMTAG: + return parseDirectiveSymbolAttribute(MCSA_Memtag); } 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_Memtag) 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[".memtag"] = DK_MEMTAG; } 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_Shift = 13, }; } @@ -193,4 +196,16 @@ bool MCSymbolELF::isBindingSet() const { return getFlags() & (0x1 << ELF_BindingSet_Shift); } + +bool MCSymbolELF::isMemtag() const { + return getFlags() & (0x1 << ELF_IsMemoryTagged_Shift); +} + +void MCSymbolELF::setMemtag(bool Tagged) { + uint32_t OtherFlags = getFlags() & ~(1 << ELF_IsMemoryTagged_Shift); + if (Tagged) + setFlags(OtherFlags | (1 << ELF_IsMemoryTagged_Shift)); + else + setFlags(OtherFlags); +} } diff --git a/llvm/lib/Target/AArch64/MCTargetDesc/AArch64ELFObjectWriter.cpp b/llvm/lib/Target/AArch64/MCTargetDesc/AArch64ELFObjectWriter.cpp --- a/llvm/lib/Target/AArch64/MCTargetDesc/AArch64ELFObjectWriter.cpp +++ b/llvm/lib/Target/AArch64/MCTargetDesc/AArch64ELFObjectWriter.cpp @@ -34,6 +34,8 @@ ~AArch64ELFObjectWriter() override = default; + MCSectionELF *getMemtagRelocsSection(MCContext &Ctx) const override; + protected: unsigned getRelocType(MCContext &Ctx, const MCValue &Target, const MCFixup &Fixup, bool IsPCRel) const override; @@ -453,6 +455,12 @@ llvm_unreachable("Unimplemented fixup -> relocation"); } +MCSectionELF * +AArch64ELFObjectWriter::getMemtagRelocsSection(MCContext &Ctx) const { + return Ctx.getELFSection(".memtag.globals.static", + ELF::SHT_ANDROID_MEMTAG_GLOBALS_STATIC, 0); +} + std::unique_ptr llvm::createAArch64ELFObjectWriter(uint8_t OSABI, bool IsILP32) { return std::make_unique(OSABI, IsILP32); diff --git a/llvm/test/MC/AArch64/global-tagging.ll b/llvm/test/MC/AArch64/global-tagging.ll new file mode 100644 --- /dev/null +++ b/llvm/test/MC/AArch64/global-tagging.ll @@ -0,0 +1,42 @@ +; RUN: llc %s -mtriple=aarch64-linux-android31 -o %t.S +; RUN: FileCheck %s --input-file=%t.S --check-prefix=CHECK-ASM +; RUN: llvm-mc -filetype=obj %t.S -triple=aarch64-linux-android31 -o %t.o +; RUN: llvm-readelf -r %t.o | FileCheck %s --check-prefix=CHECK-RELOCS + +; RUN: obj2yaml %t.o -o %t.yaml +; RUN: FileCheck %s --input-file=%t.yaml --check-prefix=CHECK-YAML +; RUN: yaml2obj %t.yaml -o %t.o +; RUN: llvm-readelf -r %t.o | FileCheck %s --check-prefix=CHECK-RELOCS + +; CHECK-RELOCS: Relocation section '.rela.memtag.globals.static' {{.*}} contains 4 entries +; CHECK-RELOCS: R_AARCH64_NONE {{.*}} internal_four +; CHECK-RELOCS: R_AARCH64_NONE {{.*}} four +; CHECK-RELOCS: R_AARCH64_NONE {{.*}} sixteen +; CHECK-RELOCS: R_AARCH64_NONE {{.*}} huge +; CHECK-RELOCS-NOT: specialcaselisted + +; CHECK-YAML: Sections: +; CHECK-YAML: - Name: .rela.memtag.globals.static +; CHECK-YAML-NOT: - Name: +; CHECK-YAML: Relocations: +; CHECK-YAML-NEXT: - Symbol: internal_four +; CHECK-YAML-NEXT: Type: R_AARCH64_NONE +; CHECK-YAML-NEXT: - Symbol: four +; CHECK-YAML-NEXT: Type: R_AARCH64_NONE +; CHECK-YAML-NEXT: - Symbol: sixteen +; CHECK-YAML-NEXT: Type: R_AARCH64_NONE +; CHECK-YAML-NEXT: - Symbol: huge +; CHECK-YAML-NEXT: Type: R_AARCH64_NONE +; CHECK-YAML-NEXT: - + +; CHECK-ASM: .memtag internal_four +; CHECK-ASM: .memtag four +; CHECK-ASM: .memtag sixteen +; CHECK-ASM: .memtag huge +; CHECK-ASM-NOT: .memtag specialcaselisted + +@internal_four = internal global i32 1, sanitize_memtag +@four = global i32 1, sanitize_memtag +@sixteen = global [16 x i8] zeroinitializer, sanitize_memtag +@huge = global [16777232 x i8] zeroinitializer, sanitize_memtag +@specialcaselisted = global i16 2