[llvm] [ASan] Emit global metadata in a named section (PR #212890)

via llvm-commits llvm-commits at lists.llvm.org
Tue Aug 4 08:28:17 PDT 2026


llvmorg-github-actions[bot] wrote:


<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-compiler-rt-sanitizer

Author: Schrodinger ZHU Yifan (SchrodingerZhu)

<details>
<summary>Changes</summary>

Introduce `-asan-globals-metadata-section` option to emit global variable descriptions in a user-specified named section.

The idea originates from @<!-- -->ostannard's baremetal ASan demo. The motivation is that baremetals may not have a standard startup process and may need special handling for the metadata arrangement. This option allows a baremetal firmware to initialize its shadow properly during the booting process by iterating metadata from a dedicated section.

This implementation exposes the option as a string, allowing the user to specify the section name (e.g. -asan-globals-metadata-section=my_section). If the option is empty (default), the standard registration mechanism is used.

Co-authored-by: Oliver Stannard <oliver.stannard@<!-- -->arm.com>
Assisted-by: Gemini based automation tools (human-in-the-loop)

---
Full diff: https://github.com/llvm/llvm-project/pull/212890.diff


2 Files Affected:

- (modified) llvm/lib/Transforms/Instrumentation/AddressSanitizer.cpp (+38-1) 
- (added) llvm/test/Instrumentation/AddressSanitizer/global-metadata-section.ll (+13) 


``````````diff
diff --git a/llvm/lib/Transforms/Instrumentation/AddressSanitizer.cpp b/llvm/lib/Transforms/Instrumentation/AddressSanitizer.cpp
index 2fae7d8c15ff3..67469364fae24 100644
--- a/llvm/lib/Transforms/Instrumentation/AddressSanitizer.cpp
+++ b/llvm/lib/Transforms/Instrumentation/AddressSanitizer.cpp
@@ -19,6 +19,7 @@
 #include "llvm/ADT/ArrayRef.h"
 #include "llvm/ADT/DenseMap.h"
 #include "llvm/ADT/DepthFirstIterator.h"
+#include "llvm/ADT/STLExtras.h"
 #include "llvm/ADT/SmallPtrSet.h"
 #include "llvm/ADT/SmallSet.h"
 #include "llvm/ADT/SmallVector.h"
@@ -469,6 +470,12 @@ static cl::opt<int> ClDebugMin("asan-debug-min", cl::desc("Debug min inst"),
 static cl::opt<int> ClDebugMax("asan-debug-max", cl::desc("Debug max inst"),
                                cl::Hidden, cl::init(-1));
 
+static cl::opt<std::string> ClGlobalsMetadataSection(
+    "asan-globals-metadata-section",
+    cl::desc("Emit global variable descriptions in a named section for "
+             "baremetal/linker-script targets"),
+    cl::init(""));
+
 STATISTIC(NumInstrumentedReads, "Number of instrumented reads");
 STATISTIC(NumInstrumentedWrites, "Number of instrumented writes");
 STATISTIC(NumOptimizedAccessesToGlobalVar,
@@ -1016,6 +1023,9 @@ class ModuleAddressSanitizer {
                             ArrayRef<GlobalVariable *> ExtendedGlobals,
                             ArrayRef<Constant *> MetadataInitializers,
                             const std::string &UniqueModuleId);
+  void InstrumentGlobalsMetadataSection(
+      IRBuilder<> &IRB, ArrayRef<GlobalVariable *> ExtendedGlobals,
+      ArrayRef<Constant *> MetadataInitializers, StringRef SectionName);
   void InstrumentGlobalsMachO(IRBuilder<> &IRB,
                               ArrayRef<GlobalVariable *> ExtendedGlobals,
                               ArrayRef<Constant *> MetadataInitializers);
@@ -2535,6 +2545,26 @@ void ModuleAddressSanitizer::instrumentGlobalsELF(
   }
 }
 
+void ModuleAddressSanitizer::InstrumentGlobalsMetadataSection(
+    IRBuilder<> &IRB, ArrayRef<GlobalVariable *> ExtendedGlobals,
+    ArrayRef<Constant *> MetadataInitializers, StringRef SectionName) {
+  auto MetadataGlobals = llvm::to_vector_of<GlobalValue *>(llvm::map_range(
+      llvm::zip_equal(ExtendedGlobals, MetadataInitializers), [&](auto &&Pair) {
+        auto [G, Initializer] = Pair;
+        GlobalVariable *Metadata =
+            CreateMetadataGlobal(Initializer, G->getName());
+        MDNode *MD = MDNode::get(M.getContext(), ValueAsMetadata::get(G));
+        Metadata->setMetadata(LLVMContext::MD_associated, MD);
+        Metadata->setSection(SectionName);
+        return Metadata;
+      }));
+
+  // Update llvm.compiler.used, adding the new metadata globals. This is
+  // needed so that during LTO these variables stay alive.
+  if (!MetadataGlobals.empty())
+    appendToCompilerUsed(M, MetadataGlobals);
+}
+
 void ModuleAddressSanitizer::InstrumentGlobalsMachO(
     IRBuilder<> &IRB, ArrayRef<GlobalVariable *> ExtendedGlobals,
     ArrayRef<Constant *> MetadataInitializers) {
@@ -2781,7 +2811,14 @@ void ModuleAddressSanitizer::instrumentGlobals(IRBuilder<> &IRB,
   }
   appendToCompilerUsed(M, ArrayRef<GlobalValue *>(GlobalsToAddToUsedList));
 
-  if (UseGlobalsGC && TargetTriple.isOSBinFormatELF()) {
+  std::string ELFUniqueModuleId =
+      (UseGlobalsGC && TargetTriple.isOSBinFormatELF()) ? getUniqueModuleId(&M)
+                                                        : "";
+
+  if (!ClGlobalsMetadataSection.empty()) {
+    InstrumentGlobalsMetadataSection(IRB, NewGlobals, Initializers,
+                                     ClGlobalsMetadataSection);
+  } else if (UseGlobalsGC && TargetTriple.isOSBinFormatELF()) {
     // Use COMDAT and register globals even if n == 0 to ensure that (a) the
     // linkage unit will only have one module constructor, and (b) the register
     // function will be called. The module destructor is not created when n ==
diff --git a/llvm/test/Instrumentation/AddressSanitizer/global-metadata-section.ll b/llvm/test/Instrumentation/AddressSanitizer/global-metadata-section.ll
new file mode 100644
index 0000000000000..9ccbc0c3c19a5
--- /dev/null
+++ b/llvm/test/Instrumentation/AddressSanitizer/global-metadata-section.ll
@@ -0,0 +1,13 @@
+; Test that the -asan-globals-metadata-section option works as expected
+;
+; RUN: opt < %s -passes=asan -asan-globals-metadata-section=my_section -S | FileCheck %s
+target triple = "x86_64-unknown-linux-gnu"
+
+ at global = global i32 0, align 4
+
+; CHECK: @__asan_global_global = {{.*}} section "my_section"{{.*}}
+; CHECK: @llvm.compiler.used = {{.*}}ptr @__asan_global_global{{.*}}
+
+; CHECK: define internal void @asan.module_ctor()
+; CHECK-NOT: __asan_register
+; CHECK: ret void

``````````

</details>


https://github.com/llvm/llvm-project/pull/212890


More information about the llvm-commits mailing list