[lld] [lld] [MTE] Drop MTE globals for fully static executables, not ban (PR #68217)

Mitch Phillips via llvm-commits llvm-commits at lists.llvm.org
Tue Oct 10 08:26:41 PDT 2023


https://github.com/hctim updated https://github.com/llvm/llvm-project/pull/68217

>From 79ab3d9dc4b7da14652ad2d30878d941c2feea77 Mon Sep 17 00:00:00 2001
From: Mitch Phillips <mitchp at google.com>
Date: Wed, 4 Oct 2023 15:05:07 +0200
Subject: [PATCH 1/4] [lld] [MTE] Drop MTE globals for fully static
 executables, not ban

Integrating MTE globals on Android revealed a lot of cases where
libraries are built as both archives and DSOs, and they're linked into
fully static and dynamic executables respectively.

MTE globals doesn't work for fully static executables. They need a
dynamic loader to process the special R_AARCH64_RELATIVE relocation
semantics with the encoded offset. Fully static executables that had
out-of-bounds derived symbols (like 'int* foo_end = foo[16]') crash
under MTE globals w/ static executables. So, LLD in its current form
simply errors out when you try and compile a fully static executable
that has a single MTE global variable in it.

It seems like a much better idea to simply have LLD not do the special
work for MTE globals in fully static contexts, and to drop any
unnecessary metadata. This means that you can build archives with MTE
globals and link them into both fully-static and dynamic executables.
---
 lld/ELF/Driver.cpp                           | 14 ++++++--
 lld/ELF/Writer.cpp                           | 15 ++++++---
 lld/ELF/Writer.h                             |  2 ++
 lld/test/ELF/Inputs/aarch64-memtag-globals.s | 35 ++++++++++++++++++++
 lld/test/ELF/aarch64-memtag-globals.s        | 31 ++++++++++++++---
 5 files changed, 86 insertions(+), 11 deletions(-)

diff --git a/lld/ELF/Driver.cpp b/lld/ELF/Driver.cpp
index 6272276e94b2d35..46ca8c94a362d2a 100644
--- a/lld/ELF/Driver.cpp
+++ b/lld/ELF/Driver.cpp
@@ -3029,10 +3029,20 @@ void LinkerDriver::link(opt::InputArgList &args) {
   // partition.
   copySectionsIntoPartitions();
 
-  if (config->emachine == EM_AARCH64 &&
-      config->androidMemtagMode != ELF::NT_MEMTAG_LEVEL_NONE) {
+  if (canHaveMemtagGlobals()) {
     llvm::TimeTraceScope timeScope("Process memory tagged symbols");
     createTaggedSymbols(ctx.objectFiles);
+  } else if (config->emachine == EM_AARCH64) {
+    // For fully static executables, make sure we prune any potential
+    // SHT_AARCH64_MEMTAG_GLOBALS_STATIC sections.
+    for (InputFile* file : ctx.objectFiles) {
+      if (file->kind() != InputFile::ObjKind)
+        continue;
+      for (InputSectionBase *section : file->getSections()) {
+        if (section && section->type == SHT_AARCH64_MEMTAG_GLOBALS_STATIC)
+          section->markDead();
+      }
+    }
   }
 
   // Create synthesized sections such as .got and .plt. This is called before
diff --git a/lld/ELF/Writer.cpp b/lld/ELF/Writer.cpp
index ce72189015348a4..6e7209e231c2857 100644
--- a/lld/ELF/Writer.cpp
+++ b/lld/ELF/Writer.cpp
@@ -251,6 +251,15 @@ void elf::addReservedSymbols() {
   ElfSym::edata2 = add("_edata", -1);
 }
 
+// Fully static executables can't have MTE globals, because we need:
+//  - A dynamic loader to process relocations, and
+//  - Dynamic entries.
+bool elf::canHaveMemtagGlobals() {
+  return config->emachine == EM_AARCH64 &&
+         config->androidMemtagMode != ELF::NT_MEMTAG_LEVEL_NONE &&
+         (config->relocatable || config->shared || needsInterpSection());
+}
+
 static OutputSection *findSection(StringRef name, unsigned partition = 1) {
   for (SectionCommand *cmd : script->sectionCommands)
     if (auto *osd = dyn_cast<OutputDesc>(cmd))
@@ -345,11 +354,7 @@ template <class ELFT> void elf::createSyntheticSections() {
         std::make_unique<SymbolTableSection<ELFT>>(*part.dynStrTab);
     part.dynamic = std::make_unique<DynamicSection<ELFT>>();
 
-    if (config->emachine == EM_AARCH64 &&
-        config->androidMemtagMode != ELF::NT_MEMTAG_LEVEL_NONE) {
-      if (!config->relocatable && !config->shared && !needsInterpSection())
-        error("--android-memtag-mode is incompatible with fully-static "
-              "executables (-static)");
+    if (canHaveMemtagGlobals()) {
       part.memtagAndroidNote = std::make_unique<MemtagAndroidNote>();
       add(*part.memtagAndroidNote);
       part.memtagDescriptors = std::make_unique<MemtagDescriptors>();
diff --git a/lld/ELF/Writer.h b/lld/ELF/Writer.h
index c69de54f76e9b4b..eaf021aac42ef56 100644
--- a/lld/ELF/Writer.h
+++ b/lld/ELF/Writer.h
@@ -56,6 +56,8 @@ uint8_t getMipsFpAbiFlag(uint8_t oldFlag, uint8_t newFlag,
 bool isMipsN32Abi(const InputFile *f);
 bool isMicroMips();
 bool isMipsR6();
+
+bool canHaveMemtagGlobals();
 } // namespace lld::elf
 
 #endif
diff --git a/lld/test/ELF/Inputs/aarch64-memtag-globals.s b/lld/test/ELF/Inputs/aarch64-memtag-globals.s
index c48083f5550f871..cc7ca6e3d13dc51 100644
--- a/lld/test/ELF/Inputs/aarch64-memtag-globals.s
+++ b/lld/test/ELF/Inputs/aarch64-memtag-globals.s
@@ -380,3 +380,38 @@ global_extern_const_definition_but_nonconst_import:
 global_extern_untagged_definition_but_tagged_import:
 	.word	0
 	.size	global_extern_untagged_definition_but_tagged_import, 4
+
+#--- input_3.s
+## Generated with:
+##
+##  - clang <input_file.c> -fsanitize=memtag-globals -O2 -S -o - \
+##          --target=aarch64-linux-android31 -fno-asynchronous-unwind-tables
+##
+## <input_file.c> contents:
+##
+##     int global_extern_outside_this_dso;
+##
+##     int main() {
+##       return 0;
+##     }
+
+	.text
+	.file	"main.c"
+	.globl	main                            // -- Begin function main
+	.p2align	2
+	.type	main, at function
+main:                                   // @main
+// %bb.0:                               // %entry
+	mov	w0, wzr
+	ret
+.Lfunc_end0:
+	.size	main, .Lfunc_end0-main
+                                        // -- End function
+	.memtag	global_extern_outside_this_dso  // @global_extern_outside_this_dso
+	.type	global_extern_outside_this_dso, at object
+	.bss
+	.globl	global_extern_outside_this_dso
+	.p2align	4, 0x0
+global_extern_outside_this_dso:
+	.zero	16
+	.size	global_extern_outside_this_dso, 16
diff --git a/lld/test/ELF/aarch64-memtag-globals.s b/lld/test/ELF/aarch64-memtag-globals.s
index fab6a032f0ce5c3..90eae0ad646dbf2 100644
--- a/lld/test/ELF/aarch64-memtag-globals.s
+++ b/lld/test/ELF/aarch64-memtag-globals.s
@@ -73,10 +73,33 @@ Symbols:
 # 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
 
-## And ensure that fully-static executables are banned.
-# RUN: not ld.lld --static --android-memtag-mode=sync \
-# RUN:   %t1.o %t2.o -o %t1.so 2>&1 | FileCheck %s --check-prefix=CHECK-NOSTATIC
-# CHECK-NOSTATIC: --android-memtag-mode is incompatible with fully-static executables (-static)
+## Ensure that fully statically linked executables just simply drop the MTE
+## globals stuff: special relocations, data in the place to be relocated,
+## dynamic entries, etc.
+# RUN: llvm-mc --filetype=obj -triple=aarch64-none-linux-android \
+# RUN:   %t/input_3.s -o %t3.o
+# RUN: ld.lld -static -Bstatic --android-memtag-mode=sync %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
+# CHECK-STATIC-NOT: DT_AARCH64_MEMTAG_
+
+# CHECK-STATIC:      There are no relocations in this file
+# CHECK-STATIC:      Memtag Dynamic Entries:
+# CHECK-STATIC-NEXT: < none found >
+
+# RUN: llvm-objdump -tDz %t.static.so | FileCheck %s --check-prefix=CHECK-STATIC-SPECIAL-RELOCS
+# CHECK-STATIC-SPECIAL-RELOCS:      [[#%x,HIDDEN_GLOBAL_ADDR:]] {{.*}} .bss {{0*}}10 hidden_global
+# CHECK-STATIC-SPECIAL-RELOCS:      <pointer_to_hidden_global_end>:
+# CHECK-STATIC-SPECIAL-RELOCS-NEXT:   .word 0x{{0*}}[[#HIDDEN_GLOBAL_ADDR + 12]]
+# CHECK-STATIC-SPECIAL-RELOCS-NEXT:   .word 0x00000000
+# CHECK-STATIC-SPECIAL-RELOCS-NEXT:   .word 0x00000000
+# CHECK-STATIC-SPECIAL-RELOCS-NEXT:   .word 0x00000000
+# CHECK-STATIC-SPECIAL-RELOCS:      <pointer_past_hidden_global_end>:
+# CHECK-STATIC-SPECIAL-RELOCS-NEXT:   .word 0x{{0*}}[[#HIDDEN_GLOBAL_ADDR + 16]]
+# CHECK-STATIC-SPECIAL-RELOCS-NEXT:   .word 0x00000000
+# CHECK-STATIC-SPECIAL-RELOCS-NEXT:   .word 0x00000000
+# CHECK-STATIC-SPECIAL-RELOCS-NEXT:   .word 0x00000000
 
 # CHECK:     Symbol table '.dynsym' contains
 # CHECK-DAG: [[#%x,GLOBAL:]] 32 OBJECT GLOBAL DEFAULT [[#]] global{{$}}

>From caacf44473b9b9078d675f53e92bd065214a63a7 Mon Sep 17 00:00:00 2001
From: Mitch Phillips <mitchp at google.com>
Date: Fri, 6 Oct 2023 15:58:34 +0200
Subject: [PATCH 2/4] Move metadata section discarding inside of the input file
 parsing.

---
 lld/ELF/Driver.cpp     | 11 -----------
 lld/ELF/InputFiles.cpp |  9 +++++++++
 lld/ELF/Writer.cpp     |  9 ++++++---
 3 files changed, 15 insertions(+), 14 deletions(-)

diff --git a/lld/ELF/Driver.cpp b/lld/ELF/Driver.cpp
index 46ca8c94a362d2a..d082463d34e576c 100644
--- a/lld/ELF/Driver.cpp
+++ b/lld/ELF/Driver.cpp
@@ -3032,17 +3032,6 @@ void LinkerDriver::link(opt::InputArgList &args) {
   if (canHaveMemtagGlobals()) {
     llvm::TimeTraceScope timeScope("Process memory tagged symbols");
     createTaggedSymbols(ctx.objectFiles);
-  } else if (config->emachine == EM_AARCH64) {
-    // For fully static executables, make sure we prune any potential
-    // SHT_AARCH64_MEMTAG_GLOBALS_STATIC sections.
-    for (InputFile* file : ctx.objectFiles) {
-      if (file->kind() != InputFile::ObjKind)
-        continue;
-      for (InputSectionBase *section : file->getSections()) {
-        if (section && section->type == SHT_AARCH64_MEMTAG_GLOBALS_STATIC)
-          section->markDead();
-      }
-    }
   }
 
   // Create synthesized sections such as .got and .plt. This is called before
diff --git a/lld/ELF/InputFiles.cpp b/lld/ELF/InputFiles.cpp
index a2c83adc18f54f0..ded1a476ff27b51 100644
--- a/lld/ELF/InputFiles.cpp
+++ b/lld/ELF/InputFiles.cpp
@@ -624,6 +624,15 @@ template <class ELFT> void ObjFile<ELFT>::parse(bool ignoreComdats) {
       }
     }
 
+    // Producing a static binary with MTE globals is not currently supported,
+    // remove all SHT_AARCH64_MEMTAG_GLOBALS_STATIC sections as they're unused
+    // medatada, and we don't want them to end up in the output file for static
+    // executables.
+    if (sec.sh_type == SHT_AARCH64_MEMTAG_GLOBALS_STATIC && !canHaveMemtagGlobals()){
+      this->sections[i] = &InputSection::discarded;
+      continue;
+    }
+
     if (sec.sh_type != SHT_GROUP)
       continue;
     StringRef signature = getShtGroupSignature(objSections, sec);
diff --git a/lld/ELF/Writer.cpp b/lld/ELF/Writer.cpp
index 6e7209e231c2857..5077c972658a140 100644
--- a/lld/ELF/Writer.cpp
+++ b/lld/ELF/Writer.cpp
@@ -251,9 +251,12 @@ void elf::addReservedSymbols() {
   ElfSym::edata2 = add("_edata", -1);
 }
 
-// Fully static executables can't have MTE globals, because we need:
-//  - A dynamic loader to process relocations, and
-//  - Dynamic entries.
+// Fully static executables don't support MTE globals at this point in time, as
+// we currently rely on:
+//   - A dynamic loader to process relocations, and
+//   - Dynamic entries.
+// This restriction could be removed in future by re-using some of the ideas
+// that ifuncs use in fully static executables.
 bool elf::canHaveMemtagGlobals() {
   return config->emachine == EM_AARCH64 &&
          config->androidMemtagMode != ELF::NT_MEMTAG_LEVEL_NONE &&

>From 1595b1ea0d8bd563ebf0890a13fd49630c7380d0 Mon Sep 17 00:00:00 2001
From: Mitch Phillips <mitchp at google.com>
Date: Fri, 6 Oct 2023 16:27:20 +0200
Subject: [PATCH 3/4] clang-format

---
 lld/ELF/InputFiles.cpp | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/lld/ELF/InputFiles.cpp b/lld/ELF/InputFiles.cpp
index ded1a476ff27b51..3413586f6b854bc 100644
--- a/lld/ELF/InputFiles.cpp
+++ b/lld/ELF/InputFiles.cpp
@@ -628,7 +628,8 @@ template <class ELFT> void ObjFile<ELFT>::parse(bool ignoreComdats) {
     // remove all SHT_AARCH64_MEMTAG_GLOBALS_STATIC sections as they're unused
     // medatada, and we don't want them to end up in the output file for static
     // executables.
-    if (sec.sh_type == SHT_AARCH64_MEMTAG_GLOBALS_STATIC && !canHaveMemtagGlobals()){
+    if (sec.sh_type == SHT_AARCH64_MEMTAG_GLOBALS_STATIC &&
+        !canHaveMemtagGlobals()) {
       this->sections[i] = &InputSection::discarded;
       continue;
     }

>From adbdbd4408f4f83b2f7341475f50b546d39519bd Mon Sep 17 00:00:00 2001
From: Mitch Phillips <mitchp at google.com>
Date: Tue, 10 Oct 2023 17:21:49 +0200
Subject: [PATCH 4/4] Remove -Bstatic from test.

---
 lld/test/ELF/aarch64-memtag-globals.s | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/lld/test/ELF/aarch64-memtag-globals.s b/lld/test/ELF/aarch64-memtag-globals.s
index 90eae0ad646dbf2..cbea01edc70456b 100644
--- a/lld/test/ELF/aarch64-memtag-globals.s
+++ b/lld/test/ELF/aarch64-memtag-globals.s
@@ -78,7 +78,7 @@ Symbols:
 ## dynamic entries, etc.
 # RUN: llvm-mc --filetype=obj -triple=aarch64-none-linux-android \
 # RUN:   %t/input_3.s -o %t3.o
-# RUN: ld.lld -static -Bstatic --android-memtag-mode=sync %t1.o %t2.o %t3.o -o %t.static.so
+# RUN: ld.lld -static --android-memtag-mode=sync %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



More information about the llvm-commits mailing list