[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