[llvm] [IR] Allow uses of `llvm.global_ctors` and `llvm.global_dtors` (PR #96477)

Daniil Kovalev via llvm-commits llvm-commits at lists.llvm.org
Mon Jun 24 14:30:50 PDT 2024


https://github.com/kovdan01 updated https://github.com/llvm/llvm-project/pull/96477

>From 9360bbd8408c59fa4c2b6f6eca08114397c0c2cd Mon Sep 17 00:00:00 2001
From: Daniil Kovalev <dkovalev at accesssoftek.com>
Date: Mon, 24 Jun 2024 13:39:58 +0300
Subject: [PATCH] [IR] Allow uses of `llvm.global_ctors` and
 `llvm.global_dtors`

With PAuth enabled, signed function pointers in init/fini arrays are
going to be represented with `ptrauth` constants (see #96478). To support
address discrimination for such signed pointers, we need to fill the storage
address with `getelementptr` referencing the array (`llvm.global_ctors`
or `llvm.global_dtors`) itself.

Such uses of these special arrays were previously disallowed since
`appendToGlobal{C|D}tors` did not update uses after construction of a new
array. This patch implements such update logic.

Test tools/llvm-reduce/remove-ifunc-program-addrspace.ll needs to be
updated since otherwise the following assertion in `Value::doRAUW` is
triggered:

```
assert(New->getType() == getType() &&
       "replaceAllUses of value with new value of different type!");
```

It's better not to omit `addrspace` in source IR.
---
 llvm/lib/IR/Verifier.cpp                         |  2 --
 llvm/lib/Transforms/Utils/ModuleUtils.cpp        | 14 ++++++++++----
 .../CodeGen/Generic/global-ctors-dtors-uses.ll   |  9 +++++++++
 llvm/test/Verifier/global-ctors-dtors-uses.ll    | 16 ----------------
 .../remove-ifunc-program-addrspace.ll            |  2 +-
 5 files changed, 20 insertions(+), 23 deletions(-)
 create mode 100644 llvm/test/CodeGen/Generic/global-ctors-dtors-uses.ll
 delete mode 100644 llvm/test/Verifier/global-ctors-dtors-uses.ll

diff --git a/llvm/lib/IR/Verifier.cpp b/llvm/lib/IR/Verifier.cpp
index 0abd5f76d449cd..ee17d266e5057d 100644
--- a/llvm/lib/IR/Verifier.cpp
+++ b/llvm/lib/IR/Verifier.cpp
@@ -850,8 +850,6 @@ void Verifier::visitGlobalVariable(const GlobalVariable &GV) {
                        GV.getName() == "llvm.global_dtors")) {
     Check(!GV.hasInitializer() || GV.hasAppendingLinkage(),
           "invalid linkage for intrinsic global variable", &GV);
-    Check(GV.materialized_use_empty(),
-          "invalid uses of intrinsic global variable", &GV);
 
     // Don't worry about emitting an error for it not being an array,
     // visitGlobalValue will complain on appending non-array.
diff --git a/llvm/lib/Transforms/Utils/ModuleUtils.cpp b/llvm/lib/Transforms/Utils/ModuleUtils.cpp
index 122279160cc7e8..47c5aa0cb25419 100644
--- a/llvm/lib/Transforms/Utils/ModuleUtils.cpp
+++ b/llvm/lib/Transforms/Utils/ModuleUtils.cpp
@@ -35,7 +35,8 @@ static void appendToGlobalArray(StringRef ArrayName, Module &M, Function *F,
   // to the list.
   SmallVector<Constant *, 16> CurrentCtors;
   StructType *EltTy;
-  if (GlobalVariable *GVCtor = M.getNamedGlobal(ArrayName)) {
+  GlobalVariable *GVCtor = M.getNamedGlobal(ArrayName);
+  if (GVCtor) {
     EltTy = cast<StructType>(GVCtor->getValueType()->getArrayElementType());
     if (Constant *Init = GVCtor->getInitializer()) {
       unsigned n = Init->getNumOperands();
@@ -43,7 +44,6 @@ static void appendToGlobalArray(StringRef ArrayName, Module &M, Function *F,
       for (unsigned i = 0; i != n; ++i)
         CurrentCtors.push_back(cast<Constant>(Init->getOperand(i)));
     }
-    GVCtor->eraseFromParent();
   } else {
     EltTy = StructType::get(IRB.getInt32Ty(),
                             PointerType::get(FnTy, F->getAddressSpace()),
@@ -67,8 +67,14 @@ static void appendToGlobalArray(StringRef ArrayName, Module &M, Function *F,
 
   // Create the new global variable and replace all uses of
   // the old global variable with the new one.
-  (void)new GlobalVariable(M, NewInit->getType(), false,
-                           GlobalValue::AppendingLinkage, NewInit, ArrayName);
+  auto *NewGVCtor =
+      new GlobalVariable(M, NewInit->getType(), false,
+                         GlobalValue::AppendingLinkage, NewInit, ArrayName);
+  if (GVCtor) {
+    NewGVCtor->takeName(GVCtor);
+    GVCtor->replaceAllUsesWith(NewGVCtor);
+    GVCtor->eraseFromParent();
+  }
 }
 
 void llvm::appendToGlobalCtors(Module &M, Function *F, int Priority, Constant *Data) {
diff --git a/llvm/test/CodeGen/Generic/global-ctors-dtors-uses.ll b/llvm/test/CodeGen/Generic/global-ctors-dtors-uses.ll
new file mode 100644
index 00000000000000..7b335ce7f692e9
--- /dev/null
+++ b/llvm/test/CodeGen/Generic/global-ctors-dtors-uses.ll
@@ -0,0 +1,9 @@
+;; Run opt with asan to trigger `appendToGlobalArray` call which should update uses of `llvm.global_ctors`
+; RUN: opt -passes=asan -S %s -o - | FileCheck %s
+; CHECK: @llvm.global_ctors = appending global [2 x { i32, ptr, ptr }] [{ i32, ptr, ptr } { i32 65535, ptr ptrauth (ptr @foo, i32 0, i64 55764, ptr getelementptr inbounds ([1 x { i32, ptr, ptr }], ptr @llvm.global_ctors, i32 0, i32 0, i32 1)), ptr null }, { i32, ptr, ptr } { i32 1, ptr @asan.module_ctor, ptr @asan.module_ctor }]
+
+ at llvm.global_ctors = appending global [1 x { i32, ptr, ptr }] [{ i32, ptr, ptr } { i32 65535, ptr ptrauth (ptr @foo, i32 0, i64 55764, ptr getelementptr inbounds ([1 x { i32, ptr, ptr }], ptr @llvm.global_ctors, i32 0, i32 0, i32 1)), ptr null }]
+
+define void @foo() {
+  ret void
+}
diff --git a/llvm/test/Verifier/global-ctors-dtors-uses.ll b/llvm/test/Verifier/global-ctors-dtors-uses.ll
deleted file mode 100644
index 1af4fb7ca9c0e2..00000000000000
--- a/llvm/test/Verifier/global-ctors-dtors-uses.ll
+++ /dev/null
@@ -1,16 +0,0 @@
-; RUN: not llvm-as %s -o /dev/null 2>&1 | FileCheck %s
-
-; CHECK: invalid uses of intrinsic global variable
-; CHECK-NEXT: ptr @llvm.global_ctors
- at llvm.global_ctors = appending global [1 x { i32, ptr, ptr } ] [
-  { i32, ptr, ptr } { i32 65535, ptr null, ptr null }
-]
-
-; CHECK: invalid uses of intrinsic global variable
-; CHECK-NEXT: ptr @llvm.global_dtors
- at llvm.global_dtors = appending global [1 x { i32, ptr, ptr } ] [
-  { i32, ptr, ptr } { i32 65535, ptr null, ptr null }
-]
-
- at ctor_user = global ptr @llvm.global_ctors
- at dtor_user = global ptr @llvm.global_dtors
diff --git a/llvm/test/tools/llvm-reduce/remove-ifunc-program-addrspace.ll b/llvm/test/tools/llvm-reduce/remove-ifunc-program-addrspace.ll
index e275d61764b216..9573c550302421 100644
--- a/llvm/test/tools/llvm-reduce/remove-ifunc-program-addrspace.ll
+++ b/llvm/test/tools/llvm-reduce/remove-ifunc-program-addrspace.ll
@@ -16,7 +16,7 @@ define void @existing_ctor() addrspace(1) {
 ; CHECK-FINAL: [[TABLE:@[0-9]+]] = internal addrspace(2) global [6 x ptr addrspace(1)] poison, align 8
 
 ; CHECK-FINAL: @llvm.global_ctors = appending addrspace(2) global [2 x { i32, ptr addrspace(1), ptr }] [{ i32, ptr addrspace(1), ptr } { i32 0, ptr addrspace(1) @existing_ctor, ptr null }, { i32, ptr addrspace(1), ptr } { i32 10, ptr addrspace(1) [[TABLE_CTOR:@[0-9]+]], ptr null }]
- at llvm.global_ctors = appending global [1 x { i32, ptr addrspace(1), ptr }] [{ i32, ptr addrspace(1), ptr } { i32 0, ptr addrspace(1) @existing_ctor, ptr null }]
+ at llvm.global_ctors = appending addrspace(2) global [1 x { i32, ptr addrspace(1), ptr }] [{ i32, ptr addrspace(1), ptr } { i32 0, ptr addrspace(1) @existing_ctor, ptr null }]
 
 
 



More information about the llvm-commits mailing list