[compiler-rt] 2be5abb - [ORC][ORC_RT] Handle ELF .init_array with non-default priority

Peter S. Housel via llvm-commits llvm-commits at lists.llvm.org
Thu Jun 9 22:48:53 PDT 2022


Author: Peter S. Housel
Date: 2022-06-09T22:47:58-07:00
New Revision: 2be5abb7e9a1f837c550745900f0fb155b440122

URL: https://github.com/llvm/llvm-project/commit/2be5abb7e9a1f837c550745900f0fb155b440122
DIFF: https://github.com/llvm/llvm-project/commit/2be5abb7e9a1f837c550745900f0fb155b440122.diff

LOG: [ORC][ORC_RT] Handle ELF .init_array with non-default priority

ELF-based platforms currently support defining multiple static
initializer table sections with differing priorities, for example
.init_array.0 or .init_array.100; the default .init_array corresponds
to a priority of 65535. When building a shared library or executable,
the system linker normally sorts these sections and combines them into
a single .init_array section. This change adds the capability to
recognize ELF static initializers with priorities other than the
default, and to properly sort them by priority, to Orc and the Orc
runtime.

Reviewed By: lhames

Differential Revision: https://reviews.llvm.org/D127056

Added: 
    compiler-rt/test/orc/TestCases/FreeBSD/x86-64/priority-static-initializer.S
    compiler-rt/test/orc/TestCases/Linux/x86-64/priority-static-initializer.S

Modified: 
    compiler-rt/lib/orc/elfnix_platform.cpp
    compiler-rt/lib/orc/elfnix_platform.h
    llvm/lib/ExecutionEngine/Orc/ELFNixPlatform.cpp
    llvm/lib/ExecutionEngine/Orc/ObjectLinkingLayer.cpp

Removed: 
    


################################################################################
diff  --git a/compiler-rt/lib/orc/elfnix_platform.cpp b/compiler-rt/lib/orc/elfnix_platform.cpp
index 7800bcd7ff15..6f502b20f8ca 100644
--- a/compiler-rt/lib/orc/elfnix_platform.cpp
+++ b/compiler-rt/lib/orc/elfnix_platform.cpp
@@ -15,6 +15,7 @@
 #include "error.h"
 #include "wrapper_function_utils.h"
 
+#include <algorithm>
 #include <map>
 #include <mutex>
 #include <sstream>
@@ -133,12 +134,6 @@ class ELFNixPlatformRuntimeState {
 
   static ELFNixPlatformRuntimeState *MOPS;
 
-  using InitSectionHandler =
-      Error (*)(const std::vector<ExecutorAddrRange> &Sections,
-                const ELFNixJITDylibInitializers &MOJDIs);
-  const std::vector<std::pair<const char *, InitSectionHandler>> InitSections =
-      {{".init_array", runInitArray}};
-
   void *PlatformJDDSOHandle;
 
   // FIXME: Move to thread-state.
@@ -378,21 +373,29 @@ Expected<void *> ELFNixPlatformRuntimeState::dlopenInitialize(string_view Path,
   return JDS->Header;
 }
 
+long getPriority(const std::string &name) {
+  auto pos = name.find_last_not_of("0123456789");
+  if (pos == name.size() - 1)
+    return 65535;
+  else
+    return std::strtol(name.c_str() + pos + 1, nullptr, 10);
+}
+
 Error ELFNixPlatformRuntimeState::initializeJITDylib(
     ELFNixJITDylibInitializers &MOJDIs) {
 
   auto &JDS = getOrCreateJITDylibState(MOJDIs);
   ++JDS.RefCount;
 
-  for (auto &KV : InitSections) {
-    const auto &Name = KV.first;
-    const auto &Handler = KV.second;
-    auto I = MOJDIs.InitSections.find(Name);
-    if (I != MOJDIs.InitSections.end()) {
-      if (auto Err = Handler(I->second, MOJDIs))
-        return Err;
-    }
-  }
+  using SectionList = std::vector<ExecutorAddrRange>;
+  std::sort(MOJDIs.InitSections.begin(), MOJDIs.InitSections.end(),
+            [](const std::pair<std::string, SectionList> &LHS,
+               const std::pair<std::string, SectionList> &RHS) -> bool {
+              return getPriority(LHS.first) < getPriority(RHS.first);
+            });
+  for (auto &Entry : MOJDIs.InitSections)
+    if (auto Err = runInitArray(Entry.second, MOJDIs))
+      return Err;
 
   return Error::success();
 }

diff  --git a/compiler-rt/lib/orc/elfnix_platform.h b/compiler-rt/lib/orc/elfnix_platform.h
index 12b9591979b7..e0ee9591dfc6 100644
--- a/compiler-rt/lib/orc/elfnix_platform.h
+++ b/compiler-rt/lib/orc/elfnix_platform.h
@@ -47,7 +47,7 @@ struct ELFNixJITDylibInitializers {
   std::string Name;
   ExecutorAddr DSOHandleAddress;
 
-  std::unordered_map<std::string, SectionList> InitSections;
+  std::vector<std::pair<std::string, SectionList>> InitSections;
 };
 
 class ELFNixJITDylibDeinitializers {};

diff  --git a/compiler-rt/test/orc/TestCases/FreeBSD/x86-64/priority-static-initializer.S b/compiler-rt/test/orc/TestCases/FreeBSD/x86-64/priority-static-initializer.S
new file mode 100644
index 000000000000..13a52f32cef2
--- /dev/null
+++ b/compiler-rt/test/orc/TestCases/FreeBSD/x86-64/priority-static-initializer.S
@@ -0,0 +1,99 @@
+// Test that ELF static initializers with 
diff erent constructor priorities work
+// and are executed in the proper order.
+//
+// RUN: %clang -c -o %t %s
+// RUN: %llvm_jitlink %t | FileCheck %s
+
+// CHECK: constructor 100
+// CHECK-NEXT: constructor 200
+// CHECK-NEXT: constructor 65535
+// CHECK-NEXT: main
+// CHECK-NEXT: destructor
+
+	.text
+
+	.globl	destructor
+	.p2align	4, 0x90
+	.type	destructor, at function
+destructor:
+.Ldestructor$local:
+
+	leaq	.L.str.d(%rip), %rdi
+	jmp	puts at PLT
+
+	.globl	main
+	.p2align	4, 0x90
+	.type	main, at function
+main:
+.Lmain$local:
+
+	pushq	%rax
+	leaq	.L.str(%rip), %rdi
+	callq	puts at PLT
+	xorl	%eax, %eax
+	popq	%rcx
+	retq
+
+	.p2align	4, 0x90
+	.type	constructor.65535, at function
+constructor.65535:
+
+	pushq	%rax
+	leaq	.L.str.65535(%rip), %rdi
+	callq	puts at PLT
+	leaq	.Ldestructor$local(%rip), %rdi
+	leaq	__dso_handle(%rip), %rdx
+	xorl	%esi, %esi
+	popq	%rax
+	jmp	__cxa_atexit at PLT
+
+	.p2align	4, 0x90
+	.type	constructor.200, at function
+constructor.200:
+
+	leaq	.L.str.200(%rip), %rdi
+	jmp	puts at PLT
+
+	.p2align	4, 0x90
+	.type	constructor.100, at function
+constructor.100:
+
+	leaq	.L.str.100(%rip), %rdi
+	jmp	puts at PLT
+
+	.hidden	__dso_handle
+	.type	.L.str, at object
+	.section	.rodata.str1.1,"aMS", at progbits,1
+.L.str:
+	.asciz	"main"
+	.size	.L.str, 5
+
+	.type	.L.str.100, at object
+.L.str.100:
+	.asciz	"constructor 100"
+	.size	.L.str.100, 16
+
+	.type	.L.str.200, at object
+.L.str.200:
+	.asciz	"constructor 200"
+	.size	.L.str.200, 16
+
+	.type	.L.str.65535, at object
+.L.str.65535:
+	.asciz	"constructor 65535"
+	.size	.L.str.65535, 18
+
+	.type	.L.str.d, at object
+.L.str.d:
+	.asciz	"destructor"
+	.size	.L.str.d, 11
+
+	.section	.init_array.100,"aw", at init_array
+	.p2align	3
+	.quad	constructor.100
+	.section	.init_array.200,"aw", at init_array
+	.p2align	3
+	.quad	constructor.200
+	.section	.init_array,"aw", at init_array
+	.p2align	3
+	.quad	constructor.65535

diff  --git a/compiler-rt/test/orc/TestCases/Linux/x86-64/priority-static-initializer.S b/compiler-rt/test/orc/TestCases/Linux/x86-64/priority-static-initializer.S
new file mode 100644
index 000000000000..13a52f32cef2
--- /dev/null
+++ b/compiler-rt/test/orc/TestCases/Linux/x86-64/priority-static-initializer.S
@@ -0,0 +1,99 @@
+// Test that ELF static initializers with 
diff erent constructor priorities work
+// and are executed in the proper order.
+//
+// RUN: %clang -c -o %t %s
+// RUN: %llvm_jitlink %t | FileCheck %s
+
+// CHECK: constructor 100
+// CHECK-NEXT: constructor 200
+// CHECK-NEXT: constructor 65535
+// CHECK-NEXT: main
+// CHECK-NEXT: destructor
+
+	.text
+
+	.globl	destructor
+	.p2align	4, 0x90
+	.type	destructor, at function
+destructor:
+.Ldestructor$local:
+
+	leaq	.L.str.d(%rip), %rdi
+	jmp	puts at PLT
+
+	.globl	main
+	.p2align	4, 0x90
+	.type	main, at function
+main:
+.Lmain$local:
+
+	pushq	%rax
+	leaq	.L.str(%rip), %rdi
+	callq	puts at PLT
+	xorl	%eax, %eax
+	popq	%rcx
+	retq
+
+	.p2align	4, 0x90
+	.type	constructor.65535, at function
+constructor.65535:
+
+	pushq	%rax
+	leaq	.L.str.65535(%rip), %rdi
+	callq	puts at PLT
+	leaq	.Ldestructor$local(%rip), %rdi
+	leaq	__dso_handle(%rip), %rdx
+	xorl	%esi, %esi
+	popq	%rax
+	jmp	__cxa_atexit at PLT
+
+	.p2align	4, 0x90
+	.type	constructor.200, at function
+constructor.200:
+
+	leaq	.L.str.200(%rip), %rdi
+	jmp	puts at PLT
+
+	.p2align	4, 0x90
+	.type	constructor.100, at function
+constructor.100:
+
+	leaq	.L.str.100(%rip), %rdi
+	jmp	puts at PLT
+
+	.hidden	__dso_handle
+	.type	.L.str, at object
+	.section	.rodata.str1.1,"aMS", at progbits,1
+.L.str:
+	.asciz	"main"
+	.size	.L.str, 5
+
+	.type	.L.str.100, at object
+.L.str.100:
+	.asciz	"constructor 100"
+	.size	.L.str.100, 16
+
+	.type	.L.str.200, at object
+.L.str.200:
+	.asciz	"constructor 200"
+	.size	.L.str.200, 16
+
+	.type	.L.str.65535, at object
+.L.str.65535:
+	.asciz	"constructor 65535"
+	.size	.L.str.65535, 18
+
+	.type	.L.str.d, at object
+.L.str.d:
+	.asciz	"destructor"
+	.size	.L.str.d, 11
+
+	.section	.init_array.100,"aw", at init_array
+	.p2align	3
+	.quad	constructor.100
+	.section	.init_array.200,"aw", at init_array
+	.p2align	3
+	.quad	constructor.200
+	.section	.init_array,"aw", at init_array
+	.p2align	3
+	.quad	constructor.65535

diff  --git a/llvm/lib/ExecutionEngine/Orc/ELFNixPlatform.cpp b/llvm/lib/ExecutionEngine/Orc/ELFNixPlatform.cpp
index 730e193ec41b..e476c549412a 100644
--- a/llvm/lib/ExecutionEngine/Orc/ELFNixPlatform.cpp
+++ b/llvm/lib/ExecutionEngine/Orc/ELFNixPlatform.cpp
@@ -101,8 +101,6 @@ StringRef InitArrayFuncSectionName = ".init_array";
 StringRef ThreadBSSSectionName = ".tbss";
 StringRef ThreadDataSectionName = ".tdata";
 
-StringRef InitSectionNames[] = {InitArrayFuncSectionName};
-
 } // end anonymous namespace
 
 namespace llvm {
@@ -274,10 +272,9 @@ ELFNixPlatform::standardRuntimeUtilityAliases() {
 }
 
 bool ELFNixPlatform::isInitializerSection(StringRef SecName) {
-  for (auto &Name : InitSectionNames) {
-    if (Name.equals(SecName))
-      return true;
-  }
+  if (SecName.consume_front(InitArrayFuncSectionName) &&
+      (SecName.empty() || SecName[0] == '.'))
+    return true;
   return false;
 }
 
@@ -781,16 +778,15 @@ Error ELFNixPlatform::ELFNixPlatformPlugin::preserveInitSections(
     jitlink::LinkGraph &G, MaterializationResponsibility &MR) {
 
   JITLinkSymbolSet InitSectionSymbols;
-  for (auto &InitSectionName : InitSectionNames) {
+  for (auto &InitSection : G.sections()) {
     // Skip non-init sections.
-    auto *InitSection = G.findSectionByName(InitSectionName);
-    if (!InitSection)
+    if (!isInitializerSection(InitSection.getName()))
       continue;
 
     // Make a pass over live symbols in the section: those blocks are already
     // preserved.
     DenseSet<jitlink::Block *> AlreadyLiveBlocks;
-    for (auto &Sym : InitSection->symbols()) {
+    for (auto &Sym : InitSection.symbols()) {
       auto &B = Sym->getBlock();
       if (Sym->isLive() && Sym->getOffset() == 0 &&
           Sym->getSize() == B.getSize() && !AlreadyLiveBlocks.count(&B)) {
@@ -800,7 +796,7 @@ Error ELFNixPlatform::ELFNixPlatformPlugin::preserveInitSections(
     }
 
     // Add anonymous symbols to preserve any not-already-preserved blocks.
-    for (auto *B : InitSection->blocks())
+    for (auto *B : InitSection.blocks())
       if (!AlreadyLiveBlocks.count(B))
         InitSectionSymbols.insert(
             &G.addAnonymousSymbol(*B, 0, B->getSize(), false, true));
@@ -821,9 +817,9 @@ Error ELFNixPlatform::ELFNixPlatformPlugin::registerInitSections(
 
   LLVM_DEBUG({ dbgs() << "ELFNixPlatform::registerInitSections\n"; });
 
-  for (auto InitSectionName : InitSectionNames) {
-    if (auto *Sec = G.findSectionByName(InitSectionName)) {
-      InitSections.push_back(Sec);
+  for (auto &Sec : G.sections()) {
+    if (isInitializerSection(Sec.getName())) {
+      InitSections.push_back(&Sec);
     }
   }
 

diff  --git a/llvm/lib/ExecutionEngine/Orc/ObjectLinkingLayer.cpp b/llvm/lib/ExecutionEngine/Orc/ObjectLinkingLayer.cpp
index 4461b6c6d3d4..5ddb35cbafd5 100644
--- a/llvm/lib/ExecutionEngine/Orc/ObjectLinkingLayer.cpp
+++ b/llvm/lib/ExecutionEngine/Orc/ObjectLinkingLayer.cpp
@@ -78,9 +78,12 @@ class LinkGraphMaterializationUnit : public MaterializationUnit {
   }
 
   static bool hasELFInitSection(LinkGraph &G) {
-    for (auto &Sec : G.sections())
-      if (Sec.getName() == ".init_array")
+    for (auto &Sec : G.sections()) {
+      auto SecName = Sec.getName();
+      if (SecName.consume_front(".init_array") &&
+          (SecName.empty() || SecName[0] == '.'))
         return true;
+    }
     return false;
   }
 


        


More information about the llvm-commits mailing list