https://github.com/EliaGeretto updated https://github.com/llvm/llvm-project/pull/183275
>From fc022477b299a7e8430ab36871d7dbbf0ab98f44 Mon Sep 17 00:00:00 2001 From: Elia Geretto <[email protected]> Date: Fri, 20 Feb 2026 12:19:38 +0100 Subject: [PATCH 1/3] [ELF][MTE] Add generic -z memtag-* options This commit eliminates the Android-specific --android-memtag-* flags, replacing them with -z memtag-* generic equivalents. With these generic flags, the linker will emit only the dynamic array tags specified in the "Memtag ABI Extension to ELF", but no Android-specific memtag note. In addition, this commit adds an --android-memtag-note flag which should be used when the Android-specific memtag note should be emitted. --- lld/ELF/Config.h | 15 ++--- lld/ELF/Driver.cpp | 61 +++++++++++-------- lld/ELF/Options.td | 18 +++--- lld/ELF/SyntheticSections.cpp | 21 ++++--- lld/test/ELF/aarch64-memtag-abi.s | 58 ++++++++++++++++++ lld/test/ELF/aarch64-memtag-android-abi.s | 37 +++++------ lld/test/ELF/aarch64-memtag-globals.s | 8 +-- ...arch64-memtag-pauth-globals-out-of-range.s | 2 +- lld/test/ELF/aarch64-memtag-pauth-globals.s | 2 +- 9 files changed, 147 insertions(+), 75 deletions(-) create mode 100644 lld/test/ELF/aarch64-memtag-abi.s diff --git a/lld/ELF/Config.h b/lld/ELF/Config.h index 237df52194210..fb8eca34ddd50 100644 --- a/lld/ELF/Config.h +++ b/lld/ELF/Config.h @@ -511,17 +511,18 @@ struct Config { // 4 for ELF32, 8 for ELF64. int wordsize; - // Mode of MTE to write to the ELF note. Should be one of NT_MEMTAG_ASYNC (for - // async), NT_MEMTAG_SYNC (for sync), or NT_MEMTAG_LEVEL_NONE (for none). If - // async or sync is enabled, write the ELF note specifying the default MTE - // mode. - int androidMemtagMode; + // Mode of MTE to write to the dynamic array. Should be one of NT_MEMTAG_ASYNC + // (for async), NT_MEMTAG_SYNC (for sync), or NT_MEMTAG_LEVEL_NONE (for none). + // If async or sync is enabled, write the tag specifying the default MTE mode. + int memtagMode; // Signal to the dynamic loader to enable heap MTE. - bool androidMemtagHeap; + bool memtagHeap; // Signal to the dynamic loader that this binary expects stack MTE. Generally, // this means to map the primary and thread stacks as PROT_MTE. Note: This is // not supported on Android 11 & 12. - bool androidMemtagStack; + bool memtagStack; + // Whether to emit the Android-specific legacy memtag note. + bool memtagAndroidNote; // When using a unified pre-link LTO pipeline, specify the backend LTO mode. LtoKind ltoKind = LtoKind::Default; diff --git a/lld/ELF/Driver.cpp b/lld/ELF/Driver.cpp index d7bfa7357d4ed..d5c7f7e9885aa 100644 --- a/lld/ELF/Driver.cpp +++ b/lld/ELF/Driver.cpp @@ -630,6 +630,27 @@ static ZicfissPolicy getZZicfiss(Ctx &ctx, opt::InputArgList &args) { return ret; } +static int getZMemtagMode(Ctx &ctx, opt::InputArgList &args) { + auto ret = ELF::NT_MEMTAG_LEVEL_NONE; + + for (auto *arg : args.filtered(OPT_z)) { + std::pair<StringRef, StringRef> kv = StringRef(arg->getValue()).split('='); + if (kv.first == "memtag-mode") { + arg->claim(); + if (kv.second == "none") + ret = ELF::NT_MEMTAG_LEVEL_NONE; + else if (kv.second == "sync") + ret = ELF::NT_MEMTAG_LEVEL_SYNC; + else if (kv.second == "async") + ret = ELF::NT_MEMTAG_LEVEL_ASYNC; + else + ErrAlways(ctx) << "unknown -z memtag-mode= value: " << kv.second; + } + } + + return ret; +} + // Report a warning for an unknown -z option. static void checkZOptions(Ctx &ctx, opt::InputArgList &args) { // This function is called before getTarget(), when certain options are not @@ -846,27 +867,20 @@ static StringRef getDynamicLinker(Ctx &ctx, opt::InputArgList &args) { } static int getMemtagMode(Ctx &ctx, opt::InputArgList &args) { - StringRef memtagModeArg = args.getLastArgValue(OPT_android_memtag_mode); - if (memtagModeArg.empty()) { - if (ctx.arg.androidMemtagStack) - Warn(ctx) << "--android-memtag-mode is unspecified, leaving " - "--android-memtag-stack a no-op"; - else if (ctx.arg.androidMemtagHeap) - Warn(ctx) << "--android-memtag-mode is unspecified, leaving " - "--android-memtag-heap a no-op"; - return ELF::NT_MEMTAG_LEVEL_NONE; + auto memtagMode = getZMemtagMode(ctx, args); + if (memtagMode == ELF::NT_MEMTAG_LEVEL_NONE) { + if (ctx.arg.memtagStack) + Warn(ctx) << "-z memtag-mode is none, leaving " + "-z memtag-stack a no-op"; + if (ctx.arg.memtagHeap) + Warn(ctx) << "-z memtag-mode is none, leaving " + "-z memtag-heap a no-op"; + if (ctx.arg.memtagAndroidNote) + Warn(ctx) << "-z memtag-mode is none, leaving " + "--android-memtag-note a no-op"; } - if (memtagModeArg == "sync") - return ELF::NT_MEMTAG_LEVEL_SYNC; - if (memtagModeArg == "async") - return ELF::NT_MEMTAG_LEVEL_ASYNC; - if (memtagModeArg == "none") - return ELF::NT_MEMTAG_LEVEL_NONE; - - ErrAlways(ctx) << "unknown --android-memtag-mode value: \"" << memtagModeArg - << "\", should be one of {async, sync, none}"; - return ELF::NT_MEMTAG_LEVEL_NONE; + return memtagMode; } static ICFLevel getICF(opt::InputArgList &args) { @@ -1358,13 +1372,12 @@ static void readConfigs(Ctx &ctx, opt::InputArgList &args) { hasZOption(args, "muldefs") || args.hasFlag(OPT_allow_multiple_definition, OPT_no_allow_multiple_definition, false); - ctx.arg.androidMemtagHeap = - args.hasFlag(OPT_android_memtag_heap, OPT_no_android_memtag_heap, false); - ctx.arg.androidMemtagStack = args.hasFlag(OPT_android_memtag_stack, - OPT_no_android_memtag_stack, false); + ctx.arg.memtagHeap = hasZOption(args, "memtag-heap"); + ctx.arg.memtagStack = hasZOption(args, "memtag-stack"); + ctx.arg.memtagAndroidNote = args.hasArg(OPT_android_memtag_note); ctx.arg.fatLTOObjects = args.hasFlag(OPT_fat_lto_objects, OPT_no_fat_lto_objects, false); - ctx.arg.androidMemtagMode = getMemtagMode(ctx, args); + ctx.arg.memtagMode = getMemtagMode(ctx, args); ctx.arg.auxiliaryList = args::getStrings(args, OPT_auxiliary); ctx.arg.armBe8 = args.hasArg(OPT_be8); if (opt::Arg *arg = args.getLastArg( diff --git a/lld/ELF/Options.td b/lld/ELF/Options.td index c2111e58c12b9..d262f34c9d1dd 100644 --- a/lld/ELF/Options.td +++ b/lld/ELF/Options.td @@ -844,14 +844,10 @@ defm check_dynamic_relocations: BB<"check-dynamic-relocations", defm load_pass_plugins: EEq<"load-pass-plugin", "Load passes from plugin library">; -// Hidden options, used by clang's -fsanitize=memtag-* options to emit an ELF -// note to designate what kinds of memory (stack/heap) should be protected using -// ARM's MTE on armv8.5+. A binary's desire for stack MTE can't be obtained -// implicitly, so we have a specific bit in the note to signal to the loader to -// remap the stack as PROT_MTE. -defm android_memtag_stack: BB<"android-memtag-stack", - "Instruct the dynamic loader to prepare for MTE stack instrumentation", "">; -defm android_memtag_heap: BB<"android-memtag-heap", - "Instruct the dynamic loader to enable MTE protection for the heap", "">; -defm android_memtag_mode: EEq<"android-memtag-mode", - "Instruct the dynamic loader to start under MTE mode {async, sync, none}">; +// Hidden option, used by clang's -fsanitize=memtag-* option to emit an ELF note +// to designate what kinds of memory (stack/heap) should be protected using +// ARM's MTE on armv8.5+. This note is Android-specific and it is used only in +// older SDK versions. +defm android_memtag_note + : BB<"android-memtag-note", "Emit the Android-specific legacy memtag note", + "">; diff --git a/lld/ELF/SyntheticSections.cpp b/lld/ELF/SyntheticSections.cpp index 2cfc88d8389b0..5ec226f1621f3 100644 --- a/lld/ELF/SyntheticSections.cpp +++ b/lld/ELF/SyntheticSections.cpp @@ -1504,9 +1504,10 @@ DynamicSection<ELFT>::computeContents() { addInt(DT_AARCH64_PAC_PLT, 0); if (hasMemtag(ctx)) { - addInt(DT_AARCH64_MEMTAG_MODE, ctx.arg.androidMemtagMode == NT_MEMTAG_LEVEL_ASYNC); - addInt(DT_AARCH64_MEMTAG_HEAP, ctx.arg.androidMemtagHeap); - addInt(DT_AARCH64_MEMTAG_STACK, ctx.arg.androidMemtagStack); + addInt(DT_AARCH64_MEMTAG_MODE, + ctx.arg.memtagMode == NT_MEMTAG_LEVEL_ASYNC); + addInt(DT_AARCH64_MEMTAG_HEAP, ctx.arg.memtagHeap); + addInt(DT_AARCH64_MEMTAG_STACK, ctx.arg.memtagStack); if (ctx.mainPart->memtagGlobalDescriptors->isNeeded()) { addInSec(DT_AARCH64_MEMTAG_GLOBALS, *ctx.mainPart->memtagGlobalDescriptors); @@ -4500,7 +4501,7 @@ static bool needsInterpSection(Ctx &ctx) { bool elf::hasMemtag(Ctx &ctx) { return ctx.arg.emachine == EM_AARCH64 && - ctx.arg.androidMemtagMode != ELF::NT_MEMTAG_LEVEL_NONE; + ctx.arg.memtagMode != ELF::NT_MEMTAG_LEVEL_NONE; } // Fully static executables don't support MTE globals at this point in time, as @@ -4528,12 +4529,12 @@ void MemtagAndroidNote::writeTo(uint8_t *buf) { buf += 12 + alignTo(sizeof(kMemtagAndroidNoteName), 4); uint32_t value = 0; - value |= ctx.arg.androidMemtagMode; - if (ctx.arg.androidMemtagHeap) + value |= ctx.arg.memtagMode; + if (ctx.arg.memtagHeap) value |= ELF::NT_MEMTAG_HEAP; // Note, MTE stack is an ABI break. Attempting to run an MTE stack-enabled // binary on Android 11 or 12 will result in a checkfail in the loader. - if (ctx.arg.androidMemtagStack) + if (ctx.arg.memtagStack) value |= ELF::NT_MEMTAG_STACK; write32(ctx, buf, value); // note value } @@ -4740,8 +4741,10 @@ template <class ELFT> void elf::createSyntheticSections(Ctx &ctx) { part.dynamic = std::make_unique<DynamicSection<ELFT>>(ctx); if (hasMemtag(ctx)) { - part.memtagAndroidNote = std::make_unique<MemtagAndroidNote>(ctx); - add(*part.memtagAndroidNote); + if (ctx.arg.memtagAndroidNote) { + part.memtagAndroidNote = std::make_unique<MemtagAndroidNote>(ctx); + add(*part.memtagAndroidNote); + } if (canHaveMemtagGlobals(ctx)) { part.memtagGlobalDescriptors = std::make_unique<MemtagGlobalDescriptors>(ctx); diff --git a/lld/test/ELF/aarch64-memtag-abi.s b/lld/test/ELF/aarch64-memtag-abi.s new file mode 100644 index 0000000000000..86e53edc1fbaf --- /dev/null +++ b/lld/test/ELF/aarch64-memtag-abi.s @@ -0,0 +1,58 @@ +# REQUIRES: aarch64 + +# RUN: llvm-mc --filetype=obj -triple=aarch64-linux-gnu %s -o %t.o + +# RUN: ld.lld -shared -z memtag-mode=async -z memtag-heap %t.o -o %t +# RUN: llvm-readelf --memtag %t | FileCheck %s --check-prefixes=CHECK,HEAP,NOSTACK,ASYNC + +# RUN: ld.lld -shared -z memtag-mode=sync -z memtag-heap %t.o -o %t +# RUN: llvm-readelf --memtag %t | FileCheck %s --check-prefixes=CHECK,HEAP,NOSTACK,SYNC + +# RUN: ld.lld -shared -z memtag-mode=async -z memtag-stack %t.o -o %t +# RUN: llvm-readelf --memtag %t | FileCheck %s --check-prefixes=CHECK,NOHEAP,STACK,ASYNC + +# RUN: ld.lld -shared -z memtag-mode=sync -z memtag-stack %t.o -o %t +# RUN: llvm-readelf --memtag %t | FileCheck %s --check-prefixes=CHECK,NOHEAP,STACK,SYNC + +# RUN: ld.lld -shared -z memtag-mode=async -z memtag-heap \ +# RUN: -z memtag-stack %t.o -o %t +# RUN: llvm-readelf --memtag %t | FileCheck %s --check-prefixes=CHECK,HEAP,STACK,ASYNC + +# RUN: ld.lld -shared -z memtag-mode=sync -z memtag-heap \ +# RUN: -z memtag-stack %t.o -o %t +# RUN: llvm-readelf --memtag %t | FileCheck %s --check-prefixes=CHECK,HEAP,STACK,SYNC + +# RUN: ld.lld -shared -z memtag-heap %t.o -o %t 2>&1 | \ +# RUN: FileCheck %s --check-prefixes=MISSING-MODE +# RUN: ld.lld -shared -z memtag-stack %t.o -o %t 2>&1 | \ +# RUN: FileCheck %s --check-prefixes=MISSING-MODE +# RUN: ld.lld -shared -z memtag-heap -z memtag-stack %t.o -o %t 2>&1 | \ +# RUN: FileCheck %s --check-prefixes=MISSING-MODE +# MISSING-MODE: warning: -z memtag-mode is none, leaving +# MISSING-MODE-SAME: -z memtag-{{(heap|stack)}} a no-op + +# CHECK: Memtag Dynamic Entries +# SYNC: AARCH64_MEMTAG_MODE: Synchronous (0) +# ASYNC: AARCH64_MEMTAG_MODE: Asynchronous (1) +# HEAP: AARCH64_MEMTAG_HEAP: Enabled (1) +# NOHEAP: AARCH64_MEMTAG_HEAP: Disabled (0) +# STACK: AARCH64_MEMTAG_STACK: Enabled (1) +# NOSTACK: AARCH64_MEMTAG_STACK: Disabled (0) + +# CHECK-NOT: Memtag Android Note + +# RUN: not ld.lld -shared -z memtag-mode=asymm -z memtag-heap 2>&1 | \ +# RUN: FileCheck %s --check-prefix=BAD-MODE +# BAD-MODE: error: unknown -z memtag-mode= value: asymm + +# RUN: ld.lld -static -z memtag-mode=sync -z memtag-heap \ +# RUN: -z memtag-stack %t.o -o %t +# RUN: llvm-readelf --memtag %t | FileCheck %s --check-prefixes=STATIC + +# STATIC: Memtag Dynamic Entries: +# STATIC-NEXT: < none found > +# STATIC-NOT: Memtag Android Note + +.globl _start +_start: + ret diff --git a/lld/test/ELF/aarch64-memtag-android-abi.s b/lld/test/ELF/aarch64-memtag-android-abi.s index 57c85dcfe81d0..cba84d07ae227 100644 --- a/lld/test/ELF/aarch64-memtag-android-abi.s +++ b/lld/test/ELF/aarch64-memtag-android-abi.s @@ -6,34 +6,36 @@ ## can be run on these versions of Android. # RUN: llvm-mc --filetype=obj -triple=aarch64-linux-android %s -o %t.o -# RUN: ld.lld -shared --android-memtag-mode=async --android-memtag-heap %t.o -o %t +# RUN: ld.lld -shared -z memtag-mode=async -z memtag-heap --android-memtag-note %t.o -o %t # RUN: llvm-readelf --memtag %t | FileCheck %s --check-prefixes=CHECK,HEAP,NOSTACK,ASYNC -# RUN: ld.lld -shared --android-memtag-mode=sync --android-memtag-heap %t.o -o %t +# RUN: ld.lld -shared -z memtag-mode=sync -z memtag-heap --android-memtag-note %t.o -o %t # RUN: llvm-readelf --memtag %t | FileCheck %s --check-prefixes=CHECK,HEAP,NOSTACK,SYNC -# RUN: ld.lld -shared --android-memtag-mode=async --android-memtag-stack %t.o -o %t +# RUN: ld.lld -shared -z memtag-mode=async -z memtag-stack --android-memtag-note %t.o -o %t # RUN: llvm-readelf --memtag %t | FileCheck %s --check-prefixes=CHECK,NOHEAP,STACK,ASYNC -# RUN: ld.lld -shared --android-memtag-mode=sync --android-memtag-stack %t.o -o %t +# RUN: ld.lld -shared -z memtag-mode=sync -z memtag-stack --android-memtag-note %t.o -o %t # RUN: llvm-readelf --memtag %t | FileCheck %s --check-prefixes=CHECK,NOHEAP,STACK,SYNC -# RUN: ld.lld -shared --android-memtag-mode=async --android-memtag-heap \ -# RUN: --android-memtag-stack %t.o -o %t +# RUN: ld.lld -shared -z memtag-mode=async -z memtag-heap \ +# RUN: -z memtag-stack --android-memtag-note %t.o -o %t # RUN: llvm-readelf --memtag %t | FileCheck %s --check-prefixes=CHECK,HEAP,STACK,ASYNC -# RUN: ld.lld -shared --android-memtag-mode=sync --android-memtag-heap \ -# RUN: --android-memtag-stack %t.o -o %t +# RUN: ld.lld -shared -z memtag-mode=sync -z memtag-heap \ +# RUN: -z memtag-stack --android-memtag-note %t.o -o %t # RUN: llvm-readelf --memtag %t | FileCheck %s --check-prefixes=CHECK,HEAP,STACK,SYNC -# RUN: ld.lld -shared --android-memtag-heap %t.o -o %t 2>&1 | \ +# RUN: ld.lld -shared --android-memtag-note %t.o -o %t 2>&1 | \ # RUN: FileCheck %s --check-prefixes=MISSING-MODE -# RUN: ld.lld -shared --android-memtag-stack %t.o -o %t 2>&1 | \ +# RUN: ld.lld -shared -z memtag-heap --android-memtag-note %t.o -o %t 2>&1 | \ # RUN: FileCheck %s --check-prefixes=MISSING-MODE -# RUN: ld.lld -shared --android-memtag-heap --android-memtag-stack %t.o -o %t 2>&1 | \ +# RUN: ld.lld -shared -z memtag-stack --android-memtag-note %t.o -o %t 2>&1 | \ # RUN: FileCheck %s --check-prefixes=MISSING-MODE -# MISSING-MODE: warning: --android-memtag-mode is unspecified, leaving -# MISSING-MODE: --android-memtag-{{(heap|stack)}} a no-op +# RUN: ld.lld -shared -z memtag-heap -z memtag-stack --android-memtag-note %t.o -o %t 2>&1 | \ +# RUN: FileCheck %s --check-prefixes=MISSING-MODE +# MISSING-MODE: warning: -z memtag-mode is none, leaving +# MISSING-MODE-SAME: {{(--android-memtag-note|-z memtag-(heap|stack))}} a no-op # CHECK: Memtag Dynamic Entries # SYNC: AARCH64_MEMTAG_MODE: Synchronous (0) @@ -51,13 +53,12 @@ # STACK-NEXT: Stack: Enabled # NOSTACK-NEXT: Stack: Disabled -# RUN: not ld.lld -shared --android-memtag-mode=asymm --android-memtag-heap 2>&1 | \ +# RUN: not ld.lld -shared -z memtag-mode=asymm -z memtag-heap --android-memtag-note 2>&1 | \ # RUN: FileCheck %s --check-prefix=BAD-MODE -# BAD-MODE: error: unknown --android-memtag-mode value: "asymm", should be one of -# BAD-MODE: {async, sync, none} +# BAD-MODE: error: unknown -z memtag-mode= value: asymm -# RUN: ld.lld -static --android-memtag-mode=sync --android-memtag-heap \ -# RUN: --android-memtag-stack %t.o -o %t +# RUN: ld.lld -static -z memtag-mode=sync -z memtag-heap \ +# RUN: -z memtag-stack --android-memtag-note %t.o -o %t # RUN: llvm-readelf --memtag %t | FileCheck %s --check-prefixes=STATIC # STATIC: Memtag Dynamic Entries: diff --git a/lld/test/ELF/aarch64-memtag-globals.s b/lld/test/ELF/aarch64-memtag-globals.s index b109c1d2c2e9c..c10fbc7013423 100644 --- a/lld/test/ELF/aarch64-memtag-globals.s +++ b/lld/test/ELF/aarch64-memtag-globals.s @@ -4,7 +4,7 @@ ## Ensure MTE globals doesn't work with REL (only RELA). # RUN: yaml2obj %s -o %t.rel.o -# RUN: not ld.lld -shared --android-memtag-mode=sync %t.rel.o -o %t1.so 2>&1 | FileCheck %s --check-prefix=CHECK-RELA +# RUN: not ld.lld -shared -z memtag-mode=sync --android-memtag-note %t.rel.o -o %t1.so 2>&1 | FileCheck %s --check-prefix=CHECK-RELA # CHECK-RELA: non-RELA relocations are not allowed with memtag globals --- !ELF FileHeader: @@ -58,7 +58,7 @@ Symbols: # RUN: %t/input_1.s -o %t1.o # RUN: llvm-mc --filetype=obj -triple=aarch64-linux-android \ # RUN: %t/input_2.s -o %t2.o -# RUN: ld.lld -shared --android-memtag-mode=sync %t1.o %t2.o -o %t.so +# RUN: ld.lld -shared -z memtag-mode=sync --android-memtag-note %t1.o %t2.o -o %t.so ## Normally relocations are printed before the symbol tables, so reorder it a ## bit to make it easier on matching addresses of relocations up with the @@ -69,7 +69,7 @@ Symbols: # RUN: llvm-objdump -Dz %t.so | FileCheck %s --check-prefix=CHECK-SPECIAL-RELOCS ## And ensure that --apply-dynamic-relocs is banned. -# RUN: not ld.lld --apply-dynamic-relocs -shared --android-memtag-mode=sync \ +# RUN: not ld.lld --apply-dynamic-relocs -shared -z memtag-mode=sync --android-memtag-note \ # RUN: %t1.o %t2.o -o %t1.so 2>&1 | FileCheck %s --check-prefix=CHECK-DYNRELOC # CHECK-DYNRELOC: --apply-dynamic-relocs cannot be used with MTE globals @@ -78,7 +78,7 @@ Symbols: ## dynamic entries, etc. # RUN: llvm-mc --filetype=obj -triple=aarch64-linux-android \ # RUN: %t/input_3.s -o %t3.o -# RUN: ld.lld -static --android-memtag-mode=sync %t1.o %t2.o %t3.o -o %t.static.so +# RUN: ld.lld -static -z memtag-mode=sync --android-memtag-note %t1.o %t2.o %t3.o -o %t.static.so # RUN: llvm-readelf -s --section-headers --relocs --memtag %t.static.so | \ # RUN: FileCheck %s --check-prefix=CHECK-STATIC # CHECK-STATIC-NOT: .memtag.globals.static diff --git a/lld/test/ELF/aarch64-memtag-pauth-globals-out-of-range.s b/lld/test/ELF/aarch64-memtag-pauth-globals-out-of-range.s index c786d52a7ec1e..c0b5e6f657cec 100644 --- a/lld/test/ELF/aarch64-memtag-pauth-globals-out-of-range.s +++ b/lld/test/ELF/aarch64-memtag-pauth-globals-out-of-range.s @@ -1,6 +1,6 @@ # REQUIRES: aarch64 # RUN: llvm-mc -filetype=obj -triple=aarch64-linux-android %s -o %t.o -# RUN: not ld.lld --shared --android-memtag-mode=sync %t.o -o /dev/null 2>&1 | \ +# RUN: not ld.lld --shared -z memtag-mode=sync --android-memtag-note %t.o -o /dev/null 2>&1 | \ # RUN: FileCheck %s --implicit-check-not=error: ## Verify that, when composing PAuth and Memtag ABIs, we error if trying to diff --git a/lld/test/ELF/aarch64-memtag-pauth-globals.s b/lld/test/ELF/aarch64-memtag-pauth-globals.s index 2b468cbbb76c6..61e5d36c8d71c 100644 --- a/lld/test/ELF/aarch64-memtag-pauth-globals.s +++ b/lld/test/ELF/aarch64-memtag-pauth-globals.s @@ -1,6 +1,6 @@ # REQUIRES: aarch64 # RUN: llvm-mc -filetype=obj -triple=aarch64-linux-android %s -o %t.o -# RUN: ld.lld --shared --android-memtag-mode=sync %t.o -o %t +# RUN: ld.lld --shared -z memtag-mode=sync --android-memtag-note %t.o -o %t # RUN: llvm-readobj -r %t | FileCheck %s --check-prefix=RELA # RUN: llvm-readelf -x.data %t | FileCheck %s --check-prefix=DATA >From 803dd32ad3750f225d1f0db3b2797264b697d3a8 Mon Sep 17 00:00:00 2001 From: Elia Geretto <[email protected]> Date: Fri, 20 Feb 2026 14:20:18 +0100 Subject: [PATCH 2/3] [Driver][MTE] Use generic memtag flags This commit adds support for the generic -z memtag-* lld flags which allow to produce memtag-enabled ELFs for all supported OS-es. Android targets will use the --android-memtag-note flag to tell the linker to emit the Android-specific memtag note. --- clang/lib/Driver/ToolChains/CommonArgs.cpp | 25 +++++++---- clang/test/Driver/fsanitize-memtag.c | 2 +- clang/test/Driver/memtag-android-ld.c | 48 ++++++++++++++++++++++ clang/test/Driver/memtag-ld.c | 30 +++++++------- 4 files changed, 80 insertions(+), 25 deletions(-) create mode 100644 clang/test/Driver/memtag-android-ld.c diff --git a/clang/lib/Driver/ToolChains/CommonArgs.cpp b/clang/lib/Driver/ToolChains/CommonArgs.cpp index 9a17fa2546e68..865193be2e013 100644 --- a/clang/lib/Driver/ToolChains/CommonArgs.cpp +++ b/clang/lib/Driver/ToolChains/CommonArgs.cpp @@ -1796,16 +1796,23 @@ bool tools::addSanitizerRuntimes(const ToolChain &TC, const ArgList &Args, CmdArgs.push_back("--export-dynamic-symbol=__cfi_check"); if (SanArgs.hasMemTag()) { - if (!TC.getTriple().isAndroid()) { - TC.getDriver().Diag(diag::err_drv_unsupported_opt_for_target) - << "-fsanitize=memtag*" << TC.getTriple().str(); - } + CmdArgs.push_back("-z"); CmdArgs.push_back( - Args.MakeArgString("--android-memtag-mode=" + SanArgs.getMemtagMode())); - if (SanArgs.hasMemtagHeap()) - CmdArgs.push_back("--android-memtag-heap"); - if (SanArgs.hasMemtagStack()) - CmdArgs.push_back("--android-memtag-stack"); + Args.MakeArgString("memtag-mode=" + SanArgs.getMemtagMode())); + + if (SanArgs.hasMemtagHeap()) { + CmdArgs.push_back("-z"); + CmdArgs.push_back("memtag-heap"); + } + + if (SanArgs.hasMemtagStack()) { + CmdArgs.push_back("-z"); + CmdArgs.push_back("memtag-stack"); + } + + if (TC.getTriple().isAndroid()) { + CmdArgs.push_back("--android-memtag-note"); + } } return !StaticRuntimes.empty() || !NonWholeStaticRuntimes.empty() || diff --git a/clang/test/Driver/fsanitize-memtag.c b/clang/test/Driver/fsanitize-memtag.c index c842e6de1b62d..cfe9a2b0c1ad9 100644 --- a/clang/test/Driver/fsanitize-memtag.c +++ b/clang/test/Driver/fsanitize-memtag.c @@ -12,7 +12,7 @@ // CHECK-SANMT-MT: "-target-feature" "+mte" // CHECK-SANMT-MT-SAME: "-fsanitize=memtag-stack,memtag-heap,memtag-globals" -// RUN: not %clang --target=aarch64-linux -fsanitize=memtag -Xclang -target-feature -Xclang +mte %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-SANMT-MT +// RUN: %clang --target=aarch64-linux -fsanitize=memtag -Xclang -target-feature -Xclang +mte %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-SANMT-MT // RUN: not %clang --target=aarch64-linux -fsanitize=memtag %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-SANMT-NOMT-0 // CHECK-SANMT-NOMT-0: '-fsanitize=memtag-stack' requires hardware support (+memtag) diff --git a/clang/test/Driver/memtag-android-ld.c b/clang/test/Driver/memtag-android-ld.c new file mode 100644 index 0000000000000..36601a6e51d94 --- /dev/null +++ b/clang/test/Driver/memtag-android-ld.c @@ -0,0 +1,48 @@ +// RUN: %clang -### --target=aarch64-linux-android -march=armv8+memtag \ +// RUN: -fsanitize=memtag %s 2>&1 | FileCheck %s \ +// RUN: --check-prefixes=CHECK-SYNC,CHECK-HEAP,CHECK-STACK,CHECK-NOTE + +// RUN: %clang -### --target=aarch64-linux-android -march=armv8+memtag \ +// RUN: -fsanitize=memtag-stack %s 2>&1 | FileCheck %s \ +// RUN: --check-prefixes=CHECK-SYNC,CHECK-NO-HEAP,CHECK-STACK,CHECK-NOTE + +// RUN: %clang -### --target=aarch64-linux-android -march=armv8+memtag \ +// RUN: -fsanitize=memtag-heap %s 2>&1 | FileCheck %s \ +// RUN: --check-prefixes=CHECK-SYNC,CHECK-HEAP,CHECK-NO-STACK,CHECK-NOTE + +// RUN: %clang -### --target=aarch64-linux-android -march=armv8+memtag \ +// RUN: -fsanitize=memtag -fsanitize-memtag-mode=async %s 2>&1 | \ +// RUN: FileCheck %s --check-prefixes=CHECK-ASYNC,CHECK-HEAP,CHECK-STACK,CHECK-NOTE + +// RUN: %clang -### --target=aarch64-linux-android -march=armv8+memtag \ +// RUN: -fsanitize=memtag-stack -fsanitize-memtag-mode=async %s 2>&1 \ +// RUN: | FileCheck %s \ +// RUN: --check-prefixes=CHECK-ASYNC,CHECK-NO-HEAP,CHECK-STACK,CHECK-NOTE + +// RUN: %clang -### --target=aarch64-linux-android -march=armv8+memtag \ +// RUN: -fsanitize=memtag-heap -fsanitize-memtag-mode=async %s 2>&1 \ +// RUN: | FileCheck %s \ +// RUN: --check-prefixes=CHECK-ASYNC,CHECK-HEAP,CHECK-NO-STACK,CHECK-NOTE + +// RUN: not %clang -### --target=aarch64-linux-android -march=armv8+memtag \ +// RUN: -fsanitize=memtag-heap -fsanitize-memtag-mode=asymm %s 2>&1 \ +// RUN: | FileCheck %s --check-prefixes=CHECK-INVALID-MODE + +// RUN: not %clang -### --target=aarch64-linux-android -march=armv8+memtag \ +// RUN: -fsanitize=memtag-stack -fsanitize=memtag-heap \ +// RUN: -fsanitize-memtag-mode=asymm -fno-sanitize=memtag %s 2>&1 \ +// RUN: | FileCheck %s --check-prefixes=CHECK-NONE + +// CHECK-ASYNC: ld{{.*}} "-z" "memtag-mode=async" +// CHECK-SYNC: ld{{.*}} "-z" "memtag-mode=sync" +// CHECK-HEAP: "-z" "memtag-heap" +// CHECK-NO-HEAP-NOT: "-z" "memtag-heap" +// CHECK-STACK: "-z" "memtag-stack" +// CHECK-NO-STACK-NOT: "-z" "memtag-stack" +// CHECK-NOTE: "--android-memtag-note" +// CHECK-INVALID-MODE: invalid value 'asymm' in '-fsanitize-memtag-mode=', +// CHECK-INVALID-MODE-SAME: expected one of: {async, sync} +// CHECK-NONE-NOT: ld{{.*}} "-z" "memtag +// CHECK-NONE-NOT: ld{{.*}} "--android-memtag-note" + +void f() {} diff --git a/clang/test/Driver/memtag-ld.c b/clang/test/Driver/memtag-ld.c index aef08ddc5758a..05a648a6ac7a1 100644 --- a/clang/test/Driver/memtag-ld.c +++ b/clang/test/Driver/memtag-ld.c @@ -1,46 +1,46 @@ -// RUN: %clang -### --target=aarch64-linux-android -march=armv8+memtag \ +// RUN: %clang -### --target=aarch64-linux-gnu -march=armv8+memtag \ // RUN: -fsanitize=memtag %s 2>&1 | FileCheck %s \ // RUN: --check-prefixes=CHECK-SYNC,CHECK-HEAP,CHECK-STACK -// RUN: %clang -### --target=aarch64-linux-android -march=armv8+memtag \ +// RUN: %clang -### --target=aarch64-linux-gnu -march=armv8+memtag \ // RUN: -fsanitize=memtag-stack %s 2>&1 | FileCheck %s \ // RUN: --check-prefixes=CHECK-SYNC,CHECK-NO-HEAP,CHECK-STACK -// RUN: %clang -### --target=aarch64-linux-android -march=armv8+memtag \ +// RUN: %clang -### --target=aarch64-linux-gnu -march=armv8+memtag \ // RUN: -fsanitize=memtag-heap %s 2>&1 | FileCheck %s \ // RUN: --check-prefixes=CHECK-SYNC,CHECK-HEAP,CHECK-NO-STACK -// RUN: %clang -### --target=aarch64-linux-android -march=armv8+memtag \ +// RUN: %clang -### --target=aarch64-linux-gnu -march=armv8+memtag \ // RUN: -fsanitize=memtag -fsanitize-memtag-mode=async %s 2>&1 | \ // RUN: FileCheck %s --check-prefixes=CHECK-ASYNC,CHECK-HEAP,CHECK-STACK -// RUN: %clang -### --target=aarch64-linux-android -march=armv8+memtag \ +// RUN: %clang -### --target=aarch64-linux-gnu -march=armv8+memtag \ // RUN: -fsanitize=memtag-stack -fsanitize-memtag-mode=async %s 2>&1 \ // RUN: | FileCheck %s \ // RUN: --check-prefixes=CHECK-ASYNC,CHECK-NO-HEAP,CHECK-STACK -// RUN: %clang -### --target=aarch64-linux-android -march=armv8+memtag \ +// RUN: %clang -### --target=aarch64-linux-gnu -march=armv8+memtag \ // RUN: -fsanitize=memtag-heap -fsanitize-memtag-mode=async %s 2>&1 \ // RUN: | FileCheck %s \ // RUN: --check-prefixes=CHECK-ASYNC,CHECK-HEAP,CHECK-NO-STACK -// RUN: not %clang -### --target=aarch64-linux-android -march=armv8+memtag \ +// RUN: not %clang -### --target=aarch64-linux-gnu -march=armv8+memtag \ // RUN: -fsanitize=memtag-heap -fsanitize-memtag-mode=asymm %s 2>&1 \ // RUN: | FileCheck %s --check-prefixes=CHECK-INVALID-MODE -// RUN: not %clang -### --target=aarch64-linux-android -march=armv8+memtag \ +// RUN: not %clang -### --target=aarch64-linux-gnu -march=armv8+memtag \ // RUN: -fsanitize=memtag-stack -fsanitize=memtag-heap \ // RUN: -fsanitize-memtag-mode=asymm -fno-sanitize=memtag %s 2>&1 \ // RUN: | FileCheck %s --check-prefixes=CHECK-NONE -// CHECK-ASYNC: ld{{.*}} "--android-memtag-mode=async" -// CHECK-SYNC: ld{{.*}} "--android-memtag-mode=sync" -// CHECK-HEAP: "--android-memtag-heap" -// CHECK-NO-HEAP-NOT: "--android-memtag-heap" -// CHECK-STACK: "--android-memtag-stack" -// CHECK-NO-STACK-NOT: "--android-memtag-stack" +// CHECK-ASYNC: ld{{.*}} "-z" "memtag-mode=async" +// CHECK-SYNC: ld{{.*}} "-z" "memtag-mode=sync" +// CHECK-HEAP: "-z" "memtag-heap" +// CHECK-NO-HEAP-NOT: "-z" "memtag-heap" +// CHECK-STACK: "-z" "memtag-stack" +// CHECK-NO-STACK-NOT: "-z" "memtag-stack" // CHECK-INVALID-MODE: invalid value 'asymm' in '-fsanitize-memtag-mode=', // CHECK-INVALID-MODE-SAME: expected one of: {async, sync} -// CHECK-NONE-NOT: ld{{.*}} "--android-memtag +// CHECK-NONE-NOT: ld{{.*}} "-z" "memtag void f() {} >From 47ee2e5100c486293383c7681deea7a12f97b7a0 Mon Sep 17 00:00:00 2001 From: Elia Geretto <[email protected]> Date: Fri, 20 Feb 2026 14:36:19 +0100 Subject: [PATCH 3/3] [AsmPrinter][MTE] Support memtag-globals for all AArch64 targets --- llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp | 4 ++-- llvm/test/MC/AArch64/global-tagging.ll | 10 +++++++--- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp b/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp index 083b83567e47f..0eca99cfed563 100644 --- a/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp +++ b/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp @@ -833,10 +833,10 @@ void AsmPrinter::emitGlobalVariable(const GlobalVariable *GV) { if (GV->isTagged()) { Triple T = TM.getTargetTriple(); - if (T.getArch() != Triple::aarch64 || !T.isAndroid()) + if (T.getArch() != Triple::aarch64) OutContext.reportError(SMLoc(), "tagged symbols (-fsanitize=memtag-globals) are " - "only supported on AArch64 Android"); + "only supported on AArch64"); OutStreamer->emitSymbolAttribute(EmittedSym, MCSA_Memtag); } diff --git a/llvm/test/MC/AArch64/global-tagging.ll b/llvm/test/MC/AArch64/global-tagging.ll index c8b3f52401dc1..29463b1b86ff4 100644 --- a/llvm/test/MC/AArch64/global-tagging.ll +++ b/llvm/test/MC/AArch64/global-tagging.ll @@ -1,8 +1,12 @@ -;; Tagged symbols are only available on aarch64-linux-android. -; RUN: not llc -filetype=null %s -mtriple=aarch64-unknown-linux 2>&1 | FileCheck %s --check-prefix=ERR +;; Tagged symbols are only available on AArch64. ; RUN: %if x86-registered-target %{ not llc -filetype=null %s -mtriple=x86_64-unknown-linux 2>&1 | FileCheck %s --check-prefix=ERR %} -; ERR: error: tagged symbols (-fsanitize=memtag-globals) are only supported on AArch64 Android +; ERR: error: tagged symbols (-fsanitize=memtag-globals) are only supported on AArch64 + +; RUN: llc %s -mtriple=aarch64-unknown-linux -o %t.linux.S +; RUN: FileCheck %s --input-file=%t.linux.S --check-prefix=CHECK-ASM +; RUN: llvm-mc -filetype=obj %t.linux.S -triple=aarch64-unknown-linux -o %t.linux.o +; RUN: llvm-readelf -r %t.linux.o | FileCheck %s --check-prefix=CHECK-RELOCS ; RUN: llc %s -mtriple=aarch64-linux-android31 -o %t.S ; RUN: FileCheck %s --input-file=%t.S --check-prefix=CHECK-ASM _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
