diff --git a/llvm/docs/LangRef.rst b/llvm/docs/LangRef.rst --- a/llvm/docs/LangRef.rst +++ b/llvm/docs/LangRef.rst @@ -748,6 +748,7 @@ [, comdat [($name)]] [, align ] [, no_sanitize] [, no_sanitize_address] [, no_sanitize_hwaddress] [, sanitize_address_dyninit] + [, sanitize_memtag] [, no_sanitize_memtag] (, !name !N)* For example, the following defines a global in a numbered address space @@ -2336,6 +2337,17 @@ This attribute indicates that the global variable should not have HWAddressSanitizer instrumentation applied to it, because it was annotated with `__attribute__((no_sanitize("hwaddress")))`. +``no_sanitize_memtag`` + This attribute indicates that the global variable should not have AArch64 + memory tags (MTE) instrumentation applied to it, because it was annotated + with `__attribute__((no_sanitize("memtag")))`. +``sanitize_memtag`` + This attribute indicates that the global variable should have AArch64 memory + tags (MTE) instrumentation applied to it. This attribute causes the + suppression of certain optimisations, like GlobalMerge, as well as ensuring + extra directives are emitted in the assembly and extra bits of metadata are + placed in the object file so that the linker can ensure the accesses are + protected by MTE. ``sanitize_address_dyninit`` This attribute indicates that the global variable, when instrumented with AddressSanitizer, should be checked for ODR violations. This attribute is diff --git a/llvm/include/llvm/IR/GlobalValue.h b/llvm/include/llvm/IR/GlobalValue.h --- a/llvm/include/llvm/IR/GlobalValue.h +++ b/llvm/include/llvm/IR/GlobalValue.h @@ -311,10 +311,23 @@ struct SanitizerMetadata { SanitizerMetadata() : NoAddress(false), NoHWAddress(false), NoMemtag(false), - IsDynInit(false) {} + Memtag(false), IsDynInit(false) {} unsigned NoAddress : 1; unsigned NoHWAddress : 1; + + // Memtag has both an include- and exclude-bit. The exclude-bit (as + // described above) is added by clang and used to control selection in the + // memtag globals tagging pass. The include-bit is added by the memtag + // globals tagging pass, and is used by the Asm writer / ELF writers to + // create special assembly directives, sections, relocations, and supression + // of certain optimisations. ASan/HWASan do not need an include-bit, as they + // simply rewrite the global variable and accesses, and don't need to + // interact with other parts of LLVM. + // + // Use `GlobalValue::isTagged()` to check whether tagging should be enabled + // for a global variable. unsigned NoMemtag : 1; + unsigned Memtag : 1; // ASan-specific metadata. Is this global variable dynamically initialized // (from a C++ language perspective), and should therefore be checked for @@ -331,6 +344,12 @@ void setSanitizerMetadata(SanitizerMetadata Meta); void removeSanitizerMetadata(); + bool isTagged() const { + if (!hasSanitizerMetadata()) return false; + const SanitizerMetadata& Meta = getSanitizerMetadata(); + return Meta.Memtag && !Meta.NoMemtag; + } + static LinkageTypes getLinkOnceLinkage(bool ODR) { return ODR ? LinkOnceODRLinkage : LinkOnceAnyLinkage; } diff --git a/llvm/lib/AsmParser/LLParser.cpp b/llvm/lib/AsmParser/LLParser.cpp --- a/llvm/lib/AsmParser/LLParser.cpp +++ b/llvm/lib/AsmParser/LLParser.cpp @@ -1108,6 +1108,7 @@ case lltok::kw_no_sanitize_address: case lltok::kw_no_sanitize_hwaddress: case lltok::kw_no_sanitize_memtag: + case lltok::kw_sanitize_memtag: case lltok::kw_sanitize_address_dyninit: return true; default: @@ -1131,6 +1132,9 @@ case lltok::kw_no_sanitize_memtag: Meta.NoMemtag = true; break; + case lltok::kw_sanitize_memtag: + Meta.Memtag = true; + break; case lltok::kw_sanitize_address_dyninit: Meta.IsDynInit = true; break; diff --git a/llvm/lib/Bitcode/Reader/BitcodeReader.cpp b/llvm/lib/Bitcode/Reader/BitcodeReader.cpp --- a/llvm/lib/Bitcode/Reader/BitcodeReader.cpp +++ b/llvm/lib/Bitcode/Reader/BitcodeReader.cpp @@ -3674,6 +3674,8 @@ Meta.NoMemtag = true; if (V & (1 << 3)) Meta.IsDynInit = true; + if (V & (1 << 4)) + Meta.Memtag = true; return Meta; } diff --git a/llvm/lib/Bitcode/Writer/BitcodeWriter.cpp b/llvm/lib/Bitcode/Writer/BitcodeWriter.cpp --- a/llvm/lib/Bitcode/Writer/BitcodeWriter.cpp +++ b/llvm/lib/Bitcode/Writer/BitcodeWriter.cpp @@ -1230,7 +1230,7 @@ static unsigned serializeSanitizerMetadata(const GlobalValue::SanitizerMetadata &Meta) { return Meta.NoAddress | (Meta.NoHWAddress << 1) | - (Meta.NoMemtag << 2) | (Meta.IsDynInit << 3); + (Meta.NoMemtag << 2) | (Meta.IsDynInit << 3) | (Meta.Memtag << 4); } /// Emit top-level description of module, including target triple, inline asm, diff --git a/llvm/lib/IR/AsmWriter.cpp b/llvm/lib/IR/AsmWriter.cpp --- a/llvm/lib/IR/AsmWriter.cpp +++ b/llvm/lib/IR/AsmWriter.cpp @@ -3544,6 +3544,8 @@ Out << ", no_sanitize_hwaddress"; if (MD.NoMemtag) Out << ", no_sanitize_memtag"; + if (MD.Memtag) + Out << ", sanitize_memtag"; if (MD.IsDynInit) Out << ", sanitize_address_dyninit"; } diff --git a/llvm/test/Assembler/globalvariable-attributes.ll b/llvm/test/Assembler/globalvariable-attributes.ll --- a/llvm/test/Assembler/globalvariable-attributes.ll +++ b/llvm/test/Assembler/globalvariable-attributes.ll @@ -9,6 +9,9 @@ @g7 = global i32 2, no_sanitize_memtag, align 4 @g8 = global i32 2, sanitize_address_dyninit, align 4 @g9 = global i32 2, no_sanitize_address, no_sanitize_hwaddress, no_sanitize_memtag, align 4 +@g10 = global i32 2, sanitize_memtag, align 4 +@g11 = global i32 2, no_sanitize_memtag, sanitize_memtag, align 4 +@g12 = global i32 2, no_sanitize_address, no_sanitize_hwaddress, sanitize_memtag, align 4 attributes #0 = { "string" = "value" nobuiltin norecurse } @@ -21,6 +24,9 @@ ; CHECK: @g7 = global i32 2, no_sanitize_memtag, align 4 ; CHECK: @g8 = global i32 2, sanitize_address_dyninit, align 4 ; CHECK: @g9 = global i32 2, no_sanitize_address, no_sanitize_hwaddress, no_sanitize_memtag, align 4 +; CHECK: @g10 = global i32 2, sanitize_memtag, align 4 +; CHECK: @g11 = global i32 2, no_sanitize_memtag, sanitize_memtag, align 4 +; CHECK: @g12 = global i32 2, no_sanitize_address, no_sanitize_hwaddress, sanitize_memtag, align 4 ; CHECK: attributes #0 = { "key"="value" "key2"="value2" } ; CHECK: attributes #1 = { "key3"="value3" } diff --git a/llvm/test/Bitcode/compatibility.ll b/llvm/test/Bitcode/compatibility.ll --- a/llvm/test/Bitcode/compatibility.ll +++ b/llvm/test/Bitcode/compatibility.ll @@ -207,11 +207,15 @@ @g.no_sanitize_address = global i32 0, no_sanitize_address @g.no_sanitize_hwaddress = global i32 0, no_sanitize_hwaddress @g.no_sanitize_memtag = global i32 0, no_sanitize_memtag +@g.sanitize_memtag = global i32 0, sanitize_memtag +@g.sanitize_and_nosanitize_memtag = global i32 0, no_sanitize_memtag, sanitize_memtag @g.no_sanitize_multiple = global i32 0, no_sanitize_address, no_sanitize_hwaddress, no_sanitize_memtag @g.sanitize_address_dyninit = global i32 0, sanitize_address_dyninit ; CHECK: @g.no_sanitize_address = global i32 0, no_sanitize_address ; CHECK: @g.no_sanitize_hwaddress = global i32 0, no_sanitize_hwaddress ; CHECK: @g.no_sanitize_memtag = global i32 0, no_sanitize_memtag +; CHECK: @g.sanitize_memtag = global i32 0, sanitize_memtag +; CHECK: @g.sanitize_and_nosanitize_memtag = global i32 0, no_sanitize_memtag, sanitize_memtag ; CHECK: @g.no_sanitize_multiple = global i32 0, no_sanitize_address, no_sanitize_hwaddress, no_sanitize_memtag ; CHECK: @g.sanitize_address_dyninit = global i32 0, sanitize_address_dyninit