diff --git a/lld/ELF/Driver.cpp b/lld/ELF/Driver.cpp --- a/lld/ELF/Driver.cpp +++ b/lld/ELF/Driver.cpp @@ -736,15 +736,25 @@ static int getMemtagMode(opt::InputArgList &args) { StringRef memtagModeArg = args.getLastArgValue(OPT_android_memtag_mode); + + if (memtagModeArg.empty()) { + if (config->androidMemtagStack) + warn("--android-memtag-mode is unspecified, leaving " + "--android-memtag-stack a no-op"); + else if (config->androidMemtagHeap) + warn("--android-memtag-mode is unspecified, leaving " + "--android-memtag-heap a no-op"); + return ELF::NT_MEMTAG_LEVEL_NONE; + } + if (!config->androidMemtagHeap && !config->androidMemtagStack) { - if (!memtagModeArg.empty()) - error("when using --android-memtag-mode, at least one of " - "--android-memtag-heap or " - "--android-memtag-stack is required"); + error("when using --android-memtag-mode, at least one of " + "--android-memtag-heap or " + "--android-memtag-stack is required"); return ELF::NT_MEMTAG_LEVEL_NONE; } - if (memtagModeArg == "sync" || memtagModeArg.empty()) + if (memtagModeArg == "sync") return ELF::NT_MEMTAG_LEVEL_SYNC; if (memtagModeArg == "async") return ELF::NT_MEMTAG_LEVEL_ASYNC; diff --git a/lld/ELF/SyntheticSections.cpp b/lld/ELF/SyntheticSections.cpp --- a/lld/ELF/SyntheticSections.cpp +++ b/lld/ELF/SyntheticSections.cpp @@ -1441,6 +1441,12 @@ addInt(DT_AARCH64_BTI_PLT, 0); if (config->zPacPlt) addInt(DT_AARCH64_PAC_PLT, 0); + + if (config->androidMemtagMode != ELF::NT_MEMTAG_LEVEL_NONE) { + addInt(DT_AARCH64_MEMTAG_MODE, config->androidMemtagMode == NT_MEMTAG_LEVEL_ASYNC); + addInt(DT_AARCH64_MEMTAG_HEAP, config->androidMemtagHeap); + addInt(DT_AARCH64_MEMTAG_STACK, config->androidMemtagStack); + } } addInSec(DT_SYMTAB, *part.dynSymTab); @@ -3835,16 +3841,16 @@ constexpr char kMemtagAndroidNoteName[] = "Android"; void MemtagAndroidNote::writeTo(uint8_t *buf) { - static_assert(sizeof(kMemtagAndroidNoteName) == 8, - "ABI check for Android 11 & 12."); - assert((config->androidMemtagStack || config->androidMemtagHeap) && - "Should only be synthesizing a note if heap || stack is enabled."); + static_assert( + sizeof(kMemtagAndroidNoteName) == 8, + "Android 11 & 12 have an ABI that the note name is 8 bytes long. Keep it " + "that way for backwards compatibility."); write32(buf, sizeof(kMemtagAndroidNoteName)); write32(buf + 4, sizeof(uint32_t)); write32(buf + 8, ELF::NT_ANDROID_TYPE_MEMTAG); memcpy(buf + 12, kMemtagAndroidNoteName, sizeof(kMemtagAndroidNoteName)); - buf += 12 + sizeof(kMemtagAndroidNoteName); + buf += 12 + alignTo(sizeof(kMemtagAndroidNoteName), 4); uint32_t value = 0; value |= config->androidMemtagMode; @@ -3859,7 +3865,7 @@ size_t MemtagAndroidNote::getSize() const { return sizeof(llvm::ELF::Elf64_Nhdr) + - /*namesz=*/sizeof(kMemtagAndroidNoteName) + + /*namesz=*/alignTo(sizeof(kMemtagAndroidNoteName), 4) + /*descsz=*/sizeof(uint32_t); } diff --git a/lld/test/ELF/aarch64-memtag-android-abi.s b/lld/test/ELF/aarch64-memtag-android-abi.s --- a/lld/test/ELF/aarch64-memtag-android-abi.s +++ b/lld/test/ELF/aarch64-memtag-android-abi.s @@ -6,56 +6,58 @@ ## can be run on these versions of Android. # RUN: llvm-mc --filetype=obj -triple=aarch64-none-linux-android %s -o %t.o -# RUN: ld.lld --android-memtag-mode=async --android-memtag-heap %t.o -o %t -# RUN: llvm-readelf -n %t | FileCheck %s --check-prefixes=NOTE,HEAP,NOSTACK,ASYNC +# RUN: ld.lld -shared --android-memtag-mode=async --android-memtag-heap %t.o -o %t +# RUN: llvm-readelf --memtag %t | FileCheck %s --check-prefixes=CHECK,HEAP,NOSTACK,ASYNC -# RUN: ld.lld --android-memtag-mode=sync --android-memtag-heap %t.o -o %t -# RUN: llvm-readelf -n %t | FileCheck %s --check-prefixes=NOTE,HEAP,NOSTACK,SYNC +# RUN: ld.lld -shared --android-memtag-mode=sync --android-memtag-heap %t.o -o %t +# RUN: llvm-readelf --memtag %t | FileCheck %s --check-prefixes=CHECK,HEAP,NOSTACK,SYNC -# RUN: ld.lld --android-memtag-mode=async --android-memtag-stack %t.o -o %t -# RUN: llvm-readelf -n %t | FileCheck %s --check-prefixes=NOTE,NOHEAP,STACK,ASYNC +# RUN: ld.lld -shared --android-memtag-mode=async --android-memtag-stack %t.o -o %t +# RUN: llvm-readelf --memtag %t | FileCheck %s --check-prefixes=CHECK,NOHEAP,STACK,ASYNC -# RUN: ld.lld --android-memtag-mode=sync --android-memtag-stack %t.o -o %t -# RUN: llvm-readelf -n %t | FileCheck %s --check-prefixes=NOTE,NOHEAP,STACK,SYNC +# RUN: ld.lld -shared --android-memtag-mode=sync --android-memtag-stack %t.o -o %t +# RUN: llvm-readelf --memtag %t | FileCheck %s --check-prefixes=CHECK,NOHEAP,STACK,SYNC -# RUN: ld.lld --android-memtag-mode=async --android-memtag-heap \ +# RUN: ld.lld -shared --android-memtag-mode=async --android-memtag-heap \ # RUN: --android-memtag-stack %t.o -o %t -# RUN: llvm-readelf -n %t | FileCheck %s --check-prefixes=NOTE,HEAP,STACK,ASYNC +# RUN: llvm-readelf --memtag %t | FileCheck %s --check-prefixes=CHECK,HEAP,STACK,ASYNC -# RUN: ld.lld --android-memtag-mode=sync --android-memtag-heap \ +# RUN: ld.lld -shared --android-memtag-mode=sync --android-memtag-heap \ # RUN: --android-memtag-stack %t.o -o %t -# RUN: llvm-readelf -n %t | FileCheck %s --check-prefixes=NOTE,HEAP,STACK,SYNC +# RUN: llvm-readelf --memtag %t | FileCheck %s --check-prefixes=CHECK,HEAP,STACK,SYNC -# RUN: ld.lld --android-memtag-heap %t.o -o %t -# RUN: llvm-readelf -n %t | FileCheck %s --check-prefixes=NOTE,HEAP,NOSTACK,SYNC +# RUN: ld.lld -shared --android-memtag-heap %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: FileCheck %s --check-prefixes=MISSING-MODE +# RUN: ld.lld -shared --android-memtag-heap --android-memtag-stack %t.o -o %t 2>&1 | \ +# RUN: FileCheck %s --check-prefixes=MISSING-MODE +# MISSING-MODE: --android-memtag-mode is unspecified, leaving --android-memtag-{{(heap|stack)}} a no-op -# RUN: ld.lld --android-memtag-stack %t.o -o %t -# RUN: llvm-readelf -n %t | FileCheck %s --check-prefixes=NOTE,NOHEAP,STACK,SYNC +# 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) -# RUN: ld.lld --android-memtag-heap --android-memtag-stack %t.o -o %t -# RUN: llvm-readelf -n %t | FileCheck %s --check-prefixes=NOTE,HEAP,STACK,SYNC - -# NOTE: .note.android.memtag -# NOTE-NEXT: Owner -# NOTE-NEXT: Android 0x00000004 NT_ANDROID_TYPE_MEMTAG (Android memory tagging -# NOTE-SAME: information) -# ASYNC-NEXT: Tagging Mode: ASYNC -# SYNC-NEXT: Tagging Mode: SYNC -# HEAP-NEXT: Heap: Enabled +# CHECK: Memtag Android Note +# ASYNC-NEXT: Tagging Mode: ASYNC +# SYNC-NEXT: Tagging Mode: SYNC +# HEAP-NEXT: Heap: Enabled # NOHEAP-NEXT: Heap: Disabled -## As of Android 12, stack MTE is unimplemented. However, we pre-emptively emit -## a bit that signifies to the dynamic loader to map the primary and thread -## stacks as PROT_MTE, in preparation for the bionic support. # STACK-NEXT: Stack: Enabled # NOSTACK-NEXT: Stack: Disabled -# RUN: not ld.lld --android-memtag-mode=asymm --android-memtag-heap 2>&1 | \ +# RUN: not ld.lld -shared --android-memtag-mode=asymm --android-memtag-heap 2>&1 | \ # RUN: FileCheck %s --check-prefix=BAD-MODE # BAD-MODE: unknown --android-memtag-mode value: "asymm", should be one of {async, sync, none} -# RUN: not ld.lld --android-memtag-mode=async 2>&1 | \ +# RUN: not ld.lld -shared --android-memtag-mode=async 2>&1 | \ # RUN: FileCheck %s --check-prefix=MISSING-STACK-OR-HEAP -# MISSING-STACK-OR-HEAP: when using --android-memtag-mode, at least one of --android-memtag-heap or --android-memtag-stack is required +# MISSING-STACK-OR-HEAP: when using --android-memtag-mode, at least one of +# MISSING-STACK-OR-HEAP-SAME: --android-memtag-heap or --android-memtag-stack is required .globl _start _start: