Skip to content

Commit

Permalink
Re-apply "[ORC][ORC-RT] Add initial native-TLV support to MachOPlatfo…
Browse files Browse the repository at this point in the history
…rm."

Reapplies fe1fa43, which was reverted in
6d8c639, with fixes:

1. Remove .subsections_via_symbols directive from macho_tlv.x86-64.s (it's
not needed here anyway).

2. Return error from pthread_key_create to the MachOPlatform to silence unused
variable warning.
  • Loading branch information
lhames committed Jul 21, 2021
1 parent ec14ab9 commit a7733e9
Show file tree
Hide file tree
Showing 8 changed files with 395 additions and 19 deletions.
1 change: 1 addition & 0 deletions compiler-rt/lib/orc/CMakeLists.txt
Expand Up @@ -11,6 +11,7 @@ set(ORC_SOURCES
# Implementation files for all ORC architectures.
set(x86_64_SOURCES
# x86-64 specific assembly files will go here.
macho_tlv.x86-64.s
)

set(ORC_IMPL_HEADERS
Expand Down
121 changes: 121 additions & 0 deletions compiler-rt/lib/orc/macho_platform.cpp
Expand Up @@ -85,6 +85,12 @@ Error runModInits(const std::vector<ExecutorAddressRange> &ModInitsSections,
return Error::success();
}

struct TLVDescriptor {
void *(*Thunk)(TLVDescriptor *) = nullptr;
unsigned long Key = 0;
unsigned long DataAddress = 0;
};

class MachOPlatformRuntimeState {
private:
struct AtExitEntry {
Expand Down Expand Up @@ -126,11 +132,17 @@ class MachOPlatformRuntimeState {
int registerAtExit(void (*F)(void *), void *Arg, void *DSOHandle);
void runAtExits(void *DSOHandle);

/// Returns the base address of the section containing ThreadData.
Expected<std::pair<const char *, size_t>>
getThreadDataSectionFor(const char *ThreadData);

private:
PerJITDylibState *getJITDylibStateByHeaderAddr(void *DSOHandle);
PerJITDylibState *getJITDylibStateByName(string_view Path);
PerJITDylibState &getOrCreateJITDylibState(MachOJITDylibInitializers &MOJDIs);

Error registerThreadDataSection(span<const char> ThreadDataSec);

Expected<ExecutorAddress> lookupSymbolInJITDylib(void *DSOHandle,
string_view Symbol);

Expand All @@ -153,6 +165,9 @@ class MachOPlatformRuntimeState {
std::recursive_mutex JDStatesMutex;
std::unordered_map<void *, PerJITDylibState> JDStates;
std::unordered_map<std::string, void *> JDNameToHeader;

std::mutex ThreadDataSectionsMutex;
std::map<const char *, size_t> ThreadDataSections;
};

MachOPlatformRuntimeState *MachOPlatformRuntimeState::MOPS = nullptr;
Expand All @@ -178,6 +193,12 @@ Error MachOPlatformRuntimeState::registerObjectSections(
walkEHFrameSection(POSR.EHFrameSection.toSpan<const char>(),
__register_frame);

if (POSR.ThreadDataSection.StartAddress) {
if (auto Err = registerThreadDataSection(
POSR.ThreadDataSection.toSpan<const char>()))
return Err;
}

return Error::success();
}

Expand Down Expand Up @@ -256,6 +277,19 @@ void MachOPlatformRuntimeState::runAtExits(void *DSOHandle) {
}
}

Expected<std::pair<const char *, size_t>>
MachOPlatformRuntimeState::getThreadDataSectionFor(const char *ThreadData) {
std::lock_guard<std::mutex> Lock(ThreadDataSectionsMutex);
auto I = ThreadDataSections.upper_bound(ThreadData);
// Check that we have a valid entry covering this address.
if (I == ThreadDataSections.begin())
return make_error<StringError>("No thread local data section for key");
I = std::prev(I);
if (ThreadData >= I->first + I->second)
return make_error<StringError>("No thread local data section for key");
return *I;
}

MachOPlatformRuntimeState::PerJITDylibState *
MachOPlatformRuntimeState::getJITDylibStateByHeaderAddr(void *DSOHandle) {
auto I = JDStates.find(DSOHandle);
Expand Down Expand Up @@ -295,6 +329,20 @@ MachOPlatformRuntimeState::getOrCreateJITDylibState(
return JDS;
}

Error MachOPlatformRuntimeState::registerThreadDataSection(
span<const char> ThreadDataSection) {
std::lock_guard<std::mutex> Lock(ThreadDataSectionsMutex);
auto I = ThreadDataSections.upper_bound(ThreadDataSection.data());
if (I != ThreadDataSections.begin()) {
auto J = std::prev(I);
if (J->first + J->second > ThreadDataSection.data())
return make_error<StringError>("Overlapping __thread_data sections");
}
ThreadDataSections.insert(
I, std::make_pair(ThreadDataSection.data(), ThreadDataSection.size()));
return Error::success();
}

Expected<ExecutorAddress>
MachOPlatformRuntimeState::lookupSymbolInJITDylib(void *DSOHandle,
string_view Sym) {
Expand Down Expand Up @@ -367,6 +415,45 @@ Error MachOPlatformRuntimeState::initializeJITDylib(
return Error::success();
}

class MachOPlatformRuntimeTLVManager {
public:
void *getInstance(const char *ThreadData);

private:
std::unordered_map<const char *, char *> Instances;
std::unordered_map<const char *, std::unique_ptr<char[]>> AllocatedSections;
};

void *MachOPlatformRuntimeTLVManager::getInstance(const char *ThreadData) {
auto I = Instances.find(ThreadData);
if (I != Instances.end())
return I->second;

auto TDS =
MachOPlatformRuntimeState::get().getThreadDataSectionFor(ThreadData);
if (!TDS) {
__orc_rt_log_error(toString(TDS.takeError()).c_str());
return nullptr;
}

auto &Allocated = AllocatedSections[TDS->first];
if (!Allocated) {
Allocated = std::make_unique<char[]>(TDS->second);
memcpy(Allocated.get(), TDS->first, TDS->second);
}

size_t ThreadDataDelta = ThreadData - TDS->first;
assert(ThreadDataDelta <= TDS->second && "ThreadData outside section bounds");

char *Instance = Allocated.get() + ThreadDataDelta;
Instances[ThreadData] = Instance;
return Instance;
}

void destroyMachOTLVMgr(void *MachOTLVMgr) {
delete static_cast<MachOPlatformRuntimeTLVManager *>(MachOTLVMgr);
}

} // end anonymous namespace

//------------------------------------------------------------------------------
Expand Down Expand Up @@ -409,6 +496,40 @@ __orc_rt_macho_deregister_object_sections(char *ArgData, size_t ArgSize) {
.release();
}

//------------------------------------------------------------------------------
// TLV support
//------------------------------------------------------------------------------

ORC_RT_INTERFACE void *__orc_rt_macho_tlv_get_addr_impl(TLVDescriptor *D) {
auto *TLVMgr = static_cast<MachOPlatformRuntimeTLVManager *>(
pthread_getspecific(D->Key));
if (!TLVMgr) {
TLVMgr = new MachOPlatformRuntimeTLVManager();
if (pthread_setspecific(D->Key, TLVMgr)) {
__orc_rt_log_error("Call to pthread_setspecific failed");
return nullptr;
}
}

return TLVMgr->getInstance(
reinterpret_cast<char *>(static_cast<uintptr_t>(D->DataAddress)));
}

ORC_RT_INTERFACE __orc_rt_CWrapperFunctionResult
__orc_rt_macho_create_pthread_key(char *ArgData, size_t ArgSize) {
return WrapperFunction<SPSExpected<uint64_t>(void)>::handle(
ArgData, ArgSize,
[]() -> Expected<uint64_t> {
pthread_key_t Key;
if (int Err = pthread_key_create(&Key, destroyMachOTLVMgr)) {
__orc_rt_log_error("Call to pthread_key_create failed");
return make_error<StringError>(strerror(Err));
}
return static_cast<uint64_t>(Key);
})
.release();
}

//------------------------------------------------------------------------------
// cxa_atexit support
//------------------------------------------------------------------------------
Expand Down
10 changes: 6 additions & 4 deletions compiler-rt/lib/orc/macho_platform.h
Expand Up @@ -33,6 +33,7 @@ namespace macho {

struct MachOPerObjectSectionsToRegister {
ExecutorAddressRange EHFrameSection;
ExecutorAddressRange ThreadDataSection;
};

struct MachOJITDylibInitializers {
Expand Down Expand Up @@ -66,7 +67,8 @@ enum dlopen_mode : int {

} // end namespace macho

using SPSMachOPerObjectSectionsToRegister = SPSTuple<SPSExecutorAddressRange>;
using SPSMachOPerObjectSectionsToRegister =
SPSTuple<SPSExecutorAddressRange, SPSExecutorAddressRange>;

template <>
class SPSSerializationTraits<SPSMachOPerObjectSectionsToRegister,
Expand All @@ -75,19 +77,19 @@ class SPSSerializationTraits<SPSMachOPerObjectSectionsToRegister,
public:
static size_t size(const macho::MachOPerObjectSectionsToRegister &MOPOSR) {
return SPSMachOPerObjectSectionsToRegister::AsArgList::size(
MOPOSR.EHFrameSection);
MOPOSR.EHFrameSection, MOPOSR.ThreadDataSection);
}

static bool serialize(SPSOutputBuffer &OB,
const macho::MachOPerObjectSectionsToRegister &MOPOSR) {
return SPSMachOPerObjectSectionsToRegister::AsArgList::serialize(
OB, MOPOSR.EHFrameSection);
OB, MOPOSR.EHFrameSection, MOPOSR.ThreadDataSection);
}

static bool deserialize(SPSInputBuffer &IB,
macho::MachOPerObjectSectionsToRegister &MOPOSR) {
return SPSMachOPerObjectSectionsToRegister::AsArgList::deserialize(
IB, MOPOSR.EHFrameSection);
IB, MOPOSR.EHFrameSection, MOPOSR.ThreadDataSection);
}
};

Expand Down
68 changes: 68 additions & 0 deletions compiler-rt/lib/orc/macho_tlv.x86-64.s
@@ -0,0 +1,68 @@
//===-- orc_rt_macho_tlv.x86-64.s -------------------------------*- ASM -*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
// This file is a part of the ORC runtime support library.
//
//===----------------------------------------------------------------------===//

#define REGISTER_SAVE_SPACE_SIZE 512

.text

// returns address of TLV in %rax, all other registers preserved
.globl ___orc_rt_macho_tlv_get_addr
___orc_rt_macho_tlv_get_addr:
pushq %rbp
movq %rsp, %rbp
subq $REGISTER_SAVE_SPACE_SIZE, %rsp
movq %rbx, -8(%rbp)
movq %rcx, -16(%rbp)
movq %rdx, -24(%rbp)
movq %rsi, -32(%rbp)
movq %rdi, -40(%rbp)
movq %r8, -48(%rbp)
movq %r9, -56(%rbp)
movq %r10, -64(%rbp)
movq %r11, -72(%rbp)
movq %r12, -80(%rbp)
movq %r13, -88(%rbp)
movq %r14, -96(%rbp)
movq %r15, -104(%rbp)
movdqa %xmm0, -128(%rbp)
movdqa %xmm1, -144(%rbp)
movdqa %xmm2, -160(%rbp)
movdqa %xmm3, -176(%rbp)
movdqa %xmm4, -192(%rbp)
movdqa %xmm5, -208(%rbp)
movdqa %xmm6, -224(%rbp)
movdqa %xmm7, -240(%rbp)
call ___orc_rt_macho_tlv_get_addr_impl
movq -8(%rbp), %rbx
movq -16(%rbp), %rcx
movq -24(%rbp), %rdx
movq -32(%rbp), %rsi
movq -40(%rbp), %rdi
movq -48(%rbp), %r8
movq -56(%rbp), %r9
movq -64(%rbp), %r10
movq -72(%rbp), %r11
movq -80(%rbp), %r12
movq -88(%rbp), %r13
movq -96(%rbp), %r14
movq -104(%rbp), %r15
movdqa -128(%rbp), %xmm0
movdqa -144(%rbp), %xmm1
movdqa -160(%rbp), %xmm2
movdqa -176(%rbp), %xmm3
movdqa -192(%rbp), %xmm4
movdqa -208(%rbp), %xmm5
movdqa -224(%rbp), %xmm6
movdqa -240(%rbp), %xmm7
addq $REGISTER_SAVE_SPACE_SIZE, %rsp
popq %rbp
ret
63 changes: 63 additions & 0 deletions compiler-rt/test/orc/TestCases/Darwin/x86-64/trivial-tlv.S
@@ -0,0 +1,63 @@
// RUN: %clang -c -o %t %s
// RUN: %llvm_jitlink %t
//
// Test that basic MachO TLVs work by adding together TLVs with values
// 0, 1, and -1, and returning the result (0 for success). This setup
// tests both zero-initialized (__thread_bss) and non-zero-initialized
// (__thread_data) secitons.

.section __TEXT,__text,regular,pure_instructions
.build_version macos, 11, 0

.globl _main
.p2align 4, 0x90
_main:
pushq %rax
movq _x@TLVP(%rip), %rdi
callq *(%rdi)
movq %rax, %rcx
movq _y@TLVP(%rip), %rdi
callq *(%rdi)
movl (%rax), %edx
addl (%rcx), %edx
movq _z@TLVP(%rip), %rdi
callq *(%rdi)
addl (%rax), %edx
movl %edx, %eax
popq %rcx
retq

.tbss _x$tlv$init, 4, 2

.section __DATA,__thread_vars,thread_local_variables
.globl _x
_x:
.quad __tlv_bootstrap
.quad 0
.quad _x$tlv$init

.section __DATA,__thread_data,thread_local_regular
.p2align 2
_y$tlv$init:
.long 4294967295

.section __DATA,__thread_vars,thread_local_variables
.globl _y
_y:
.quad __tlv_bootstrap
.quad 0
.quad _y$tlv$init

.section __DATA,__thread_data,thread_local_regular
.p2align 2
_z$tlv$init:
.long 1

.section __DATA,__thread_vars,thread_local_variables
.globl _z
_z:
.quad __tlv_bootstrap
.quad 0
.quad _z$tlv$init

.subsections_via_symbols

0 comments on commit a7733e9

Please sign in to comment.