Skip to content

Commit

Permalink
rewrite catchjmp asm to use normal relocations instead of manual editing
Browse files Browse the repository at this point in the history
  • Loading branch information
vtjnash committed Oct 4, 2024
1 parent a8d7b68 commit 218edea
Show file tree
Hide file tree
Showing 5 changed files with 78 additions and 97 deletions.
29 changes: 0 additions & 29 deletions src/cgmemmgr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -833,28 +833,6 @@ class RTDyldMemoryManagerJL : public SectionMemoryManager {
mapAddresses(Dyld, ro_alloc);
mapAddresses(Dyld, exe_alloc);
}
#ifdef _OS_WINDOWS_
template <typename Alloc>
void *lookupWriteAddressFor(void *rt_addr, Alloc &&allocator)
{
for (auto &alloc: allocator->allocations) {
if (alloc.rt_addr == rt_addr) {
return alloc.wr_addr;
}
}
return nullptr;
}
void *lookupWriteAddressFor(void *rt_addr)
{
if (!ro_alloc)
return rt_addr;
if (void *ptr = lookupWriteAddressFor(rt_addr, ro_alloc))
return ptr;
if (void *ptr = lookupWriteAddressFor(rt_addr, exe_alloc))
return ptr;
return rt_addr;
}
#endif // _OS_WINDOWS_
};

uint8_t *RTDyldMemoryManagerJL::allocateCodeSection(uintptr_t Size,
Expand Down Expand Up @@ -947,13 +925,6 @@ void RTDyldMemoryManagerJL::deregisterEHFrames(uint8_t *Addr,

}

#ifdef _OS_WINDOWS_
void *lookupWriteAddressFor(RTDyldMemoryManager *memmgr, void *rt_addr)
{
return ((RTDyldMemoryManagerJL*)memmgr)->lookupWriteAddressFor(rt_addr);
}
#endif

RTDyldMemoryManager* createRTDyldMemoryManager()
{
return new RTDyldMemoryManagerJL();
Expand Down
1 change: 1 addition & 0 deletions src/codegen.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10371,6 +10371,7 @@ static void init_jit_functions(void)

#ifdef _OS_WINDOWS_
#if defined(_CPU_X86_64_)
add_named_global("__julia_personality", &__julia_personality);
#if defined(_COMPILER_GCC_)
add_named_global("___chkstk_ms", &___chkstk_ms);
#else
Expand Down
3 changes: 1 addition & 2 deletions src/debug-registry.h
Original file line number Diff line number Diff line change
Expand Up @@ -145,8 +145,7 @@ class JITDebugInfoRegistry
void add_code_in_flight(llvm::StringRef name, jl_code_instance_t *codeinst, const llvm::DataLayout &DL) JL_NOTSAFEPOINT;
jl_method_instance_t *lookupLinfo(size_t pointer) JL_NOTSAFEPOINT;
void registerJITObject(const llvm::object::ObjectFile &Object,
std::function<uint64_t(const llvm::StringRef &)> getLoadAddress,
std::function<void*(void*)> lookupWriteAddress);
std::function<uint64_t(const llvm::StringRef &)> getLoadAddress);
objectmap_t& getObjectMap() JL_NOTSAFEPOINT;
void add_image_info(image_info_t info) JL_NOTSAFEPOINT;
bool get_image_info(uint64_t base, image_info_t *info) const JL_NOTSAFEPOINT;
Expand Down
47 changes: 17 additions & 30 deletions src/debuginfo.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -223,11 +223,21 @@ static void create_PRUNTIME_FUNCTION(uint8_t *Code, size_t Size, StringRef fnnam
#endif

void JITDebugInfoRegistry::registerJITObject(const object::ObjectFile &Object,
std::function<uint64_t(const StringRef &)> getLoadAddress,
std::function<void*(void*)> lookupWriteAddress)
std::function<uint64_t(const StringRef &)> getLoadAddress)
{
object::section_iterator EndSection = Object.section_end();

bool anyfunctions = false;
for (const object::SymbolRef &sym_iter : Object.symbols()) {
object::SymbolRef::Type SymbolType = cantFail(sym_iter.getType());
if (SymbolType != object::SymbolRef::ST_Function)
continue;
anyfunctions = true;
break;
}
if (!anyfunctions)
return;

#ifdef _CPU_ARM_
// ARM does not have/use .eh_frame
uint64_t arm_exidx_addr = 0;
Expand Down Expand Up @@ -281,14 +291,13 @@ void JITDebugInfoRegistry::registerJITObject(const object::ObjectFile &Object,
#if defined(_OS_WINDOWS_)
uint64_t SectionAddrCheck = 0;
uint64_t SectionLoadCheck = 0; (void)SectionLoadCheck;
uint64_t SectionWriteCheck = 0; (void)SectionWriteCheck;
uint8_t *UnwindData = NULL;
#if defined(_CPU_X86_64_)
uint8_t *catchjmp = NULL;
for (const object::SymbolRef &sym_iter : Object.symbols()) {
StringRef sName = cantFail(sym_iter.getName());
if (sName.equals("__UnwindData") || sName.equals("__catchjmp")) {
uint64_t Addr = cantFail(sym_iter.getAddress());
uint64_t Addr = cantFail(sym_iter.getAddress()); // offset into object (including section offset)
auto Section = cantFail(sym_iter.getSection());
assert(Section != EndSection && Section->isText());
uint64_t SectionAddr = Section->getAddress();
Expand All @@ -300,10 +309,7 @@ void JITDebugInfoRegistry::registerJITObject(const object::ObjectFile &Object,
SectionLoadCheck == SectionLoadAddr);
SectionAddrCheck = SectionAddr;
SectionLoadCheck = SectionLoadAddr;
SectionWriteCheck = SectionLoadAddr;
if (lookupWriteAddress)
SectionWriteCheck = (uintptr_t)lookupWriteAddress((void*)SectionLoadAddr);
Addr += SectionWriteCheck - SectionLoadCheck;
Addr += SectionLoadAddr - SectionAddr;
if (sName.equals("__UnwindData")) {
UnwindData = (uint8_t*)Addr;
}
Expand All @@ -314,25 +320,7 @@ void JITDebugInfoRegistry::registerJITObject(const object::ObjectFile &Object,
}
assert(catchjmp);
assert(UnwindData);
assert(SectionAddrCheck);
assert(SectionLoadCheck);
assert(!memcmp(catchjmp, "\0\0\0\0\0\0\0\0\0\0\0\0", 12) &&
!memcmp(UnwindData, "\0\0\0\0\0\0\0\0\0\0\0\0", 12));
catchjmp[0] = 0x48;
catchjmp[1] = 0xb8; // mov RAX, QWORD PTR [&__julia_personality]
*(uint64_t*)(&catchjmp[2]) = (uint64_t)&__julia_personality;
catchjmp[10] = 0xff;
catchjmp[11] = 0xe0; // jmp RAX
UnwindData[0] = 0x09; // version info, UNW_FLAG_EHANDLER
UnwindData[1] = 4; // size of prolog (bytes)
UnwindData[2] = 2; // count of unwind codes (slots)
UnwindData[3] = 0x05; // frame register (rbp) = rsp
UnwindData[4] = 4; // second instruction
UnwindData[5] = 0x03; // mov RBP, RSP
UnwindData[6] = 1; // first instruction
UnwindData[7] = 0x50; // push RBP
*(DWORD*)&UnwindData[8] = (DWORD)(catchjmp - (uint8_t*)SectionWriteCheck); // relative location of catchjmp
UnwindData -= SectionWriteCheck - SectionLoadCheck;
#endif // defined(_OS_X86_64_)
#endif // defined(_OS_WINDOWS_)

Expand All @@ -353,7 +341,7 @@ void JITDebugInfoRegistry::registerJITObject(const object::ObjectFile &Object,
uint64_t SectionAddr = Section->getAddress();
StringRef secName = cantFail(Section->getName());
uint64_t SectionLoadAddr = getLoadAddress(secName);
Addr -= SectionAddr - SectionLoadAddr;
Addr += SectionLoadAddr - SectionAddr;
StringRef sName = cantFail(sym_iter.getName());
uint64_t SectionSize = Section->getSize();
size_t Size = sym_size.second;
Expand Down Expand Up @@ -404,10 +392,9 @@ void JITDebugInfoRegistry::registerJITObject(const object::ObjectFile &Object,
}

void jl_register_jit_object(const object::ObjectFile &Object,
std::function<uint64_t(const StringRef &)> getLoadAddress,
std::function<void *(void *)> lookupWriteAddress)
std::function<uint64_t(const StringRef &)> getLoadAddress)
{
getJITDebugRegistry().registerJITObject(Object, getLoadAddress, lookupWriteAddress);
getJITDebugRegistry().registerJITObject(Object, getLoadAddress);
}

// TODO: convert the safe names from aotcomile.cpp:makeSafeName back into symbols
Expand Down
95 changes: 59 additions & 36 deletions src/jitlayers.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -665,8 +665,7 @@ static Expected<orc::ThreadSafeModule> selectOptLevel(orc::ThreadSafeModule TSM,
}

void jl_register_jit_object(const object::ObjectFile &debugObj,
std::function<uint64_t(const StringRef &)> getLoadAddress,
std::function<void *(void *)> lookupWriteAddress);
std::function<uint64_t(const StringRef &)> getLoadAddress);

namespace {

Expand Down Expand Up @@ -726,7 +725,7 @@ class JLDebuginfoPlugin : public ObjectLinkingLayer::Plugin {
return result->second;
};

jl_register_jit_object(*NewInfo->Object, getLoadAddress, nullptr);
jl_register_jit_object(*NewInfo->Object, getLoadAddress);
PendingObjs.erase(&MR);
}

Expand Down Expand Up @@ -957,10 +956,6 @@ class ForwardingMemoryManager : public RuntimeDyld::MemoryManager {
};


#if defined(_OS_WINDOWS_) && defined(_CPU_X86_64_)
void *lookupWriteAddressFor(RTDyldMemoryManager *MemMgr, void *rt_addr);
#endif

void registerRTDyldJITObject(const object::ObjectFile &Object,
const RuntimeDyld::LoadedObjectInfo &L,
const std::shared_ptr<RTDyldMemoryManager> &MemMgr)
Expand All @@ -983,14 +978,7 @@ void registerRTDyldJITObject(const object::ObjectFile &Object,
};

auto DebugObject = L.getObjectForDebug(Object); // ELF requires us to make a copy to mutate the header with the section load addresses. On other platforms this is a no-op.
jl_register_jit_object(DebugObject.getBinary() ? *DebugObject.getBinary() : Object,
getLoadAddress,
#if defined(_OS_WINDOWS_) && defined(_CPU_X86_64_)
[MemMgr](void *p) { return lookupWriteAddressFor(MemMgr.get(), p); }
#else
nullptr
#endif
);
jl_register_jit_object(DebugObject.getBinary() ? *DebugObject.getBinary() : Object, getLoadAddress);
}
namespace {
static std::unique_ptr<TargetMachine> createTargetMachine() JL_NOTSAFEPOINT {
Expand Down Expand Up @@ -1281,8 +1269,9 @@ namespace {
}

// Windows needs some inline asm to help
// build unwind tables
jl_decorate_module(M);
// build unwind tables, if they have any functions to decorate
if (!M.functions().empty())
jl_decorate_module(M);
});
return std::move(TSM);
}
Expand Down Expand Up @@ -2255,30 +2244,64 @@ static void jl_decorate_module(Module &M) {
if (TT.isOSWindows() && TT.getArch() == Triple::x86_64) {
// Add special values used by debuginfo to build the UnwindData table registration for Win64
// This used to be GV, but with https://reviews.llvm.org/D100944 we no longer can emit GV into `.text`
// TODO: The data is set in debuginfo.cpp but it should be okay to actually emit it here.
std::string inline_asm = "\
.section ";
inline_asm +=
// and with JITLink it became difficult to change the content afterwards, but we
// would prefer that this simple content wasn't recompiled in every single module,
// so we emit the necessary PLT trampoline as inline assembly.
// This is somewhat duplicated with the .pdata section, but we haven't been able to
// use that yet due to relocation issues.
#define ASM_USES_ELF // use ELF or COFF syntax based on FORCE_ELF
StringRef inline_asm(
".section"
#if JL_LLVM_VERSION >= 180000
".ltext,\"ax\",@progbits";
" .ltext,\"ax\",@progbits\n"
#else
".text";
" .text\n"
#endif
inline_asm += "\n\
.type __UnwindData,@object \n\
.p2align 2, 0x90 \n\
__UnwindData: \n\
.zero 12 \n\
.size __UnwindData, 12 \n\
\n\
.type __catchjmp,@object \n\
.p2align 2, 0x90 \n\
__catchjmp: \n\
.zero 12 \n\
.size __catchjmp, 12";

".globl __julia_personality\n"
"\n"
#ifdef ASM_USES_ELF
".type __UnwindData,@object\n"
#else
".def __UnwindData\n"
".scl 2\n"
".type 0\n"
".endef\n"
#endif
".p2align 2, 0x90\n"
"__UnwindData:\n"
" .byte 0x09;\n" // version info, UNW_FLAG_EHANDLER
" .byte 4;\n" // size of prolog (bytes)
" .byte 2;\n" // count of unwind codes (slots)
" .byte 0x05;\n" // frame register (rbp) = rsp
" .byte 4;\n" // second instruction
" .byte 0x03;\n" // mov RBP, RSP
" .byte 1;\n" // first instruction
" .byte 0x50;\n" // push RBP
" .int __catchjmp - "
#if JL_LLVM_VERSION >= 180000
".ltext;\n" // Section-relative offset (if using COFF and JITLink, this can be relative to __ImageBase instead, though then we could possibly use pdata/xdata directly then)
#else
".text;\n"
#endif
".size __UnwindData, 12\n"
"\n"
#ifdef ASM_USES_ELF
".type __catchjmp,@function\n"
#else
".def __catchjmp\n"
".scl 2\n"
".type 32\n"
".endef\n"
#endif
".p2align 2, 0x90\n"
"__catchjmp:\n"
" movabsq $__julia_personality, %rax\n"
" jmpq *%rax\n"
".size __catchjmp, . - __catchjmp\n"
"\n");
M.appendModuleInlineAsm(inline_asm);
}
#undef ASM_USES_ELF
}

#ifndef JL_USE_JITLINK
Expand Down

0 comments on commit 218edea

Please sign in to comment.