This patch refactors the MachO/x86-64 implementation of JITLink to replace the
MachO-specific edge kinds with generic x86-64 edges and fixup expressions. The
new, generic x86-64 edge kinds should be re-usable for other formats (ELF, and
COFF if/when support for that is added) and simplify the writing of format
agnostic (but architecture specific) JITLink passes.
Details
Diff Detail
- Repository
- rG LLVM Github Monorepo
Event Timeline
Factoring out architecture specific code sounds like a reasonable approach to reduce code duplication across the JITLink backends. As far as I can see, the patch only ports the MachOJITLinker_x86_64 to use the generic functionality. The ELFJITLinker_x86_64 mostly remains unchanged. Is there a conceptual reason for it or would that be a rather straightforward next step?
What I am not sure I understand yet is how endianness is handled in this scheme. The new applyFixup() function is using hard casts to little-endian when writing fixup values into memory. Is that because addRelocations() is supposed to populate the fixup values with the correct endian already? I think the ELF implementation didn't consider it at all so far, so there is no loss of functionality. Just asking for interest.
Great documentation for the edge kinds!
llvm/include/llvm/ExecutionEngine/JITLink/x86_64.h | ||
---|---|---|
207 | Typo: from |
Yes -- that's a logical next step. I know @jaredwy is working on a refactor of the ELF/x86-64 backend to extract a generic ELF graph builder at the moment, so I wanted to hold off on any changes to the ELF backend in case they interfered with his work.
What I am not sure I understand yet is how endianness is handled in this scheme. The new applyFixup() function is using hard casts to little-endian when writing fixup values into memory. Is that because addRelocations() is supposed to populate the fixup values with the correct endian already? I think the ELF implementation didn't consider it at all so far, so there is no loss of functionality. Just asking for interest.
There is a hard (but poorly documented) boundary here: Linker *working memory* (block content) should always be in the executor's (target's) endianness, hence the hard casts here. That's because it comes from the object file (which is in the executor's endianness) and will be transferred byte-for-byte to the executor. All other graph values including symbol and block addresses should be in the host's endianness to avoid any unnecessary conversions during arithmetic. Conversions to/from executor endianness should be done on write/reads of working memory only.
Great documentation for the edge kinds!
Thanks!
I believe this change, or one of the subsequent ones (I can't find them on Differential, sorry), broke a test on the Windows Debug build.
Failed Tests (1): LLVM :: ExecutionEngine/JITLink/X86/ELF_skip_debug_sections.s
Here's the trace:
E:\llvm-project-merge\build_windows>"e:\llvm-project-merge\build_windows\bin\llvm-jitlink.exe" "-debug-only=jitlink" "-noexec" "E:\llvm-project-merge\build_windows\test\ExecutionEngine\JITLink\X86\Output\ELF_skip_debug_sections.s.tmp" Building jitlink graph for new input E:\llvm-project-merge\build_windows\test\ExecutionEngine\JITLink\X86\Output\ELF_skip_debug_sections.s.tmp... Creating normalized sections... .strtab: 0x0000000000000000 -- 0x00000000000000ab, align: 1 Flags: 0x0 .text: 0x0000000000000000 -- 0x0000000000000016, align: 16 Flags: 0x6 .debug_str is a debug section: No graph section will be created. .debug_abbrev is a debug section: No graph section will be created. .debug_info is a debug section: No graph section will be created. .rela.debug_info: 0x0000000000000000 -- 0x0000000000000150, align: 8 Flags: 0x0 .comment: 0x0000000000000000 -- 0x0000000000000020, align: 1 Flags: 0x30 .debug_line is a debug section: No graph section will be created. .rela.debug_line: 0x0000000000000000 -- 0x0000000000000018, align: 8 Flags: 0x0 .eh_frame: 0x0000000000000000 -- 0x0000000000000040, align: 8 Flags: 0x2 .rela.eh_frame: 0x0000000000000000 -- 0x0000000000000030, align: 8 Flags: 0x0 .symtab: 0x0000000000000000 -- 0x00000000000000c0, align: 8 Flags: 0x0 Creating normalized symbols... value = 0x0000000000000000, type = 0x00, binding = 0x00, size = 0x0000000000000000, info = 0x00 : value = 0x0000000000000000, type = 0x04, binding = 0x00, size = 0x0000000000000000, info = 0x04 :ELF_skip_debug_sections.c value = 0x0000000000000000, type = 0x03, binding = 0x00, size = 0x0000000000000000, info = 0x03 : value = 0x0000000000000000, type = 0x03, binding = 0x00, size = 0x0000000000000000, info = 0x03 : value = 0x0000000000000000, type = 0x03, binding = 0x00, size = 0x0000000000000000, info = 0x03 : value = 0x0000000000000000, type = 0x03, binding = 0x00, size = 0x0000000000000000, info = 0x03 : value = 0x0000000000000000, type = 0x02, binding = 0x01, size = 0x0000000000000006, info = 0x12 :foo value = 0x0000000000000010, type = 0x02, binding = 0x01, size = 0x0000000000000006, info = 0x12 :main Creating graph symbols... Processing symbol section .symtab: at index 2 foo at index 6 main at index 7 Adding relocations Adding relocations from section .rela.debug_info Target is dwarf section .debug_info. Skipping. Adding relocations from section .rela.debug_line Target is dwarf section .debug_line. Skipping. Adding relocations from section .rela.eh_frame For target section .eh_frame Relocation Type: 2 Name: R_X86_64_PC32 Processing relocation at 0x0000000000000020 edge@0x0000000000000020: 0x0000000000000000 + 0x20 -- PCRel32 -> .text Relocation Type: 2 Name: R_X86_64_PC32 Processing relocation at 0x0000000000000034 edge@0x0000000000000034: 0x0000000000000000 + 0x34 -- PCRel32 -> .text + 16 Starting link phase 1 for graph E:\llvm-project-merge\build_windows\test\ExecutionEngine\JITLink\X86\Output\ELF_skip_debug_sections.s.tmp EHFrameSplitter: Processing .eh_frame... Processing block at 0x0000000000000000 Processing CFI record at 0x0000000000000000 Extracted 0x0000000000000000 -- 0x00000018: size = 0x00000018, content, align = 8, align-ofs = 0, section = .eh_frame Processing CFI record at 0x0000000000000018 Extracted 0x0000000000000018 -- 0x0000002c: size = 0x00000014, content, align = 8, align-ofs = 0, section = .eh_frame Processing CFI record at 0x000000000000002c Extracted 0x000000000000002c -- 0x00000040: size = 0x00000014, content, align = 8, align-ofs = 4, section = .eh_frame EHFrameEdgeFixer: Processing .eh_frame... Processing block at 0x0000000000000000 Processing CFI record at 0x0000000000000000 Record is CIE Processing block at 0x0000000000000018 Processing CFI record at 0x0000000000000018 Record is FDE Adding edge at 0x000000000000001c to CIE at: 0x0000000000000000 Already has edge at 0x0000000000000020 to PC at 0x0000000000000000 Adding keep-alive edge from target at 0x0000000000000000 to FDE at 0x0000000000000018 Record does not have LSDA field. Processing block at 0x000000000000002c Processing CFI record at 0x000000000000002c Record is FDE Adding edge at 0x0000000000000030 to CIE at: 0x0000000000000000 Already has edge at 0x0000000000000034 to PC at 0x0000000000000000 + 0x0000000000000010 Adding keep-alive edge from target at 0x0000000000000000 to FDE at 0x000000000000002c Record does not have LSDA field. EHFrameNullTerminator adding null terminator to .eh_frame Link graph "E:\llvm-project-merge\build_windows\test\ExecutionEngine\JITLink\X86\Output\ELF_skip_debug_sections.s.tmp" pre-pruning: PLEASE submit a bug report to https://bugs.llvm.org/ and include the crash backtrace. Stack dump: 0. Program arguments: e:\\llvm-project-merge\\build_windows\\bin\\llvm-jitlink.exe -debug-only=jitlink -noexec E:\\llvm-project-merge\\build_windows\\test\\ExecutionEngine\\JITLink\\X86\\Output\\ELF_skip_debug_sections.s.tmp #0 0x00007ff7a1cbb55e std::_Debug_lt_pred<<lambda_7aeefcb115b0a8ce43b4c96fdac18921> &,llvm::jitlink::Symbol * &,llvm::jitlink::Symbol * &,0> C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\VC\Tools\MSVC\14.28.29910\include\xutility:1626:0 #1 0x00007ff7a1cbccc0 std::_Insertion_sort_unchecked<llvm::jitlink::Symbol * *,<lambda_7aeefcb115b0a8ce43b4c96fdac18921> > C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\VC\Tools\MSVC\14.28.29910\include\algorithm:7361:0 #2 0x00007ff7a1cc0a8c std::_Sort_unchecked<llvm::jitlink::Symbol * *,<lambda_7aeefcb115b0a8ce43b4c96fdac18921> > C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\VC\Tools\MSVC\14.28.29910\include\algorithm:7486:0 #3 0x00007ff7a1cc487e std::sort<std::_Vector_iterator<std::_Vector_val<std::_Simple_types<llvm::jitlink::Symbol *> > >,<lambda_7aeefcb115b0a8ce43b4c96fdac18921> > C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\VC\Tools\MSVC\14.28.29910\include\algorithm:7516:0 #4 0x00007ff7a1cc47a1 llvm::sort<std::_Vector_iterator<std::_Vector_val<std::_Simple_types<llvm::jitlink::Symbol *> > >,<lambda_7aeefcb115b0a8ce43b4c96fdac18921> > E:\llvm-project-merge\llvm\include\llvm\ADT\STLExtras.h:1449:0 #5 0x00007ff7a1cc436b llvm::sort<std::vector<llvm::jitlink::Symbol *,std::allocator<llvm::jitlink::Symbol *> > &,<lambda_7aeefcb115b0a8ce43b4c96fdac18921> > E:\llvm-project-merge\llvm\include\llvm\ADT\STLExtras.h:1454:0 #6 0x00007ff7a1cb6822 llvm::jitlink::LinkGraph::dump(class llvm::raw_ostream &) E:\llvm-project-merge\llvm\lib\ExecutionEngine\JITLink\JITLink.cpp:252:0 #7 0x00007ff7a1d35ca3 llvm::jitlink::JITLinkerBase::linkPhase1(class std::unique_ptr<class llvm::jitlink::JITLinkerBase, struct std::default_delete<class llvm::jitlink::JITLinkerBase>>) E:\llvm-project-merge\llvm\lib\ExecutionEngine\JITLink\JITLinkGeneric.cpp:35:0 #8 0x00007ff7a1ce238d llvm::jitlink::JITLinker<class llvm::jitlink::ELFJITLinker_x86_64>::link<class std::unique_ptr<class llvm::jitlink::JITLinkContext, struct std::default_delete<class llvm::jitlink::JITLinkContext>>, class std::unique_ptr<class llvm::jitlink::LinkGraph, struct std::default_delete<class llvm::jitlink::LinkGraph>>, struct llvm::jitlink::PassConfiguration>(class std::unique_ptr<class llvm::jitlink::JITLinkContext, struct std::default_delete<class llvm::jitlink::JITLinkContext>> &&, class std::unique_ptr<class llvm::jitlink::LinkGraph, struct std::default_delete<class llvm::jitlink::LinkGraph>> &&, struct llvm::jitlink::PassConfiguration &&) E:\llvm-project-merge\llvm\lib\ExecutionEngine\JITLink\JITLinkGeneric.h:140:0 #9 0x00007ff7a1cd46d6 llvm::jitlink::link_ELF_x86_64(class std::unique_ptr<class llvm::jitlink::LinkGraph, struct std::default_delete<class llvm::jitlink::LinkGraph>>, class std::unique_ptr<class llvm::jitlink::JITLinkContext, struct std::default_delete<class llvm::jitlink::JITLinkContext>>) E:\llvm-project-merge\llvm\lib\ExecutionEngine\JITLink\ELF_x86_64.cpp:931:0 #10 0x00007ff7a1cd0411 llvm::jitlink::link_ELF(class std::unique_ptr<class llvm::jitlink::LinkGraph, struct std::default_delete<class llvm::jitlink::LinkGraph>>, class std::unique_ptr<class llvm::jitlink::JITLinkContext, struct std::default_delete<class llvm::jitlink::JITLinkContext>>) E:\llvm-project-merge\llvm\lib\ExecutionEngine\JITLink\ELF.cpp:81:0 #11 0x00007ff7a1cb7ff0 llvm::jitlink::link(class std::unique_ptr<class llvm::jitlink::LinkGraph, struct std::default_delete<class llvm::jitlink::LinkGraph>>, class std::unique_ptr<class llvm::jitlink::JITLinkContext, struct std::default_delete<class llvm::jitlink::JITLinkContext>>) E:\llvm-project-merge\llvm\lib\ExecutionEngine\JITLink\JITLink.cpp:409:0 #12 0x00007ff7a219660f llvm::orc::ObjectLinkingLayer::emit(class std::unique_ptr<class llvm::orc::MaterializationResponsibility, struct std::default_delete<class llvm::orc::MaterializationResponsibility>>, class std::unique_ptr<class llvm::MemoryBuffer, struct std::default_delete<class llvm::MemoryBuffer>>) E:\llvm-project-merge\llvm\lib\ExecutionEngine\Orc\ObjectLinkingLayer.cpp:602:0 #13 0x00007ff7a218dfa8 llvm::orc::BasicObjectLayerMaterializationUnit::materialize(class std::unique_ptr<class llvm::orc::MaterializationResponsibility, struct std::default_delete<class llvm::orc::MaterializationResponsibility>>) E:\llvm-project-merge\llvm\lib\ExecutionEngine\Orc\Layer.cpp:205:0 #14 0x00007ff7a210da99 llvm::orc::MaterializationTask::run(void) E:\llvm-project-merge\llvm\lib\ExecutionEngine\Orc\Core.cpp:1760:0 #15 0x00007ff7a2185d8d llvm::orc::ExecutionSession::runOnCurrentThread(class std::unique_ptr<class llvm::orc::Task, struct std::default_delete<class llvm::orc::Task>>) E:\llvm-project-merge\llvm\include\llvm\ExecutionEngine\Orc\Core.h:1429:0 #16 0x00007ff7a211c098 llvm::detail::UniqueFunctionBase<void, class std::unique_ptr<class llvm::orc::Task, struct std::default_delete<class llvm::orc::Task>>>::CallImpl<void (__cdecl *)(class std::unique_ptr<class llvm::orc::Task, struct std::default_delete<class llvm::orc::Task>>)>(void *, class std::unique_ptr<class llvm::orc::Task, struct std::default_delete<class llvm::orc::Task>> &) E:\llvm-project-merge\llvm\include\llvm\ADT\FunctionExtras.h:206:0 #17 0x00007ff7a215c008 llvm::unique_function<(class std::unique_ptr<class llvm::orc::Task, struct std::default_delete<class llvm::orc::Task>>)>::operator()(class std::unique_ptr<class llvm::orc::Task, struct std::default_delete<class llvm::orc::Task>>) E:\llvm-project-merge\llvm\include\llvm\ADT\FunctionExtras.h:367:0 #18 0x00007ff7a217332c llvm::orc::ExecutionSession::dispatchTask(class std::unique_ptr<class llvm::orc::Task, struct std::default_delete<class llvm::orc::Task>>) E:\llvm-project-merge\llvm\include\llvm\ExecutionEngine\Orc\Core.h:1419:0 #19 0x00007ff7a210f147 llvm::orc::ExecutionSession::dispatchOutstandingMUs(void) E:\llvm-project-merge\llvm\lib\ExecutionEngine\Orc\Core.cpp:2035:0 #20 0x00007ff7a2110edf llvm::orc::ExecutionSession::OL_completeLookup(class std::unique_ptr<class llvm::orc::InProgressLookupState, struct std::default_delete<class llvm::orc::InProgressLookupState>>, class std::shared_ptr<class llvm::orc::AsynchronousSymbolQuery>, class std::function<(class llvm::DenseMap<class llvm::orc::JITDylib *, class llvm::DenseSet<class llvm::orc::SymbolStringPtr, struct llvm::DenseMapInfo<class llvm::orc::SymbolStringPtr>>, struct llvm::DenseMapInfo<class llvm::orc::JITDylib *>, struct llvm::detail::DenseMapPair<class llvm::orc::JITDylib *, class llvm::DenseSet<class llvm::orc::SymbolStringPtr, struct llvm::DenseMapInfo<class llvm::orc::SymbolStringPtr>>>> const &)>) E:\llvm-project-merge\llvm\lib\ExecutionEngine\Orc\Core.cpp:2565:0 #21 0x00007ff7a2171408 llvm::orc::InProgressFullLookupState::complete(class std::unique_ptr<class llvm::orc::InProgressLookupState, struct std::default_delete<class llvm::orc::InProgressLookupState>>) E:\llvm-project-merge\llvm\lib\ExecutionEngine\Orc\Core.cpp:550:0 #22 0x00007ff7a2110995 llvm::orc::ExecutionSession::OL_applyQueryPhase1(class std::unique_ptr<class llvm::orc::InProgressLookupState, struct std::default_delete<class llvm::orc::InProgressLookupState>>, class llvm::Error) E:\llvm-project-merge\llvm\lib\ExecutionEngine\Orc\Core.cpp:2321:0 #23 0x00007ff7a210e6c1 llvm::orc::ExecutionSession::lookup(enum llvm::orc::LookupKind, class std::vector<struct std::pair<class llvm::orc::JITDylib *, enum llvm::orc::JITDylibLookupFlags>, class std::allocator<struct std::pair<class llvm::orc::JITDylib *, enum llvm::orc::JITDylibLookupFlags>>> const &, class llvm::orc::SymbolLookupSet, enum llvm::orc::SymbolState, class llvm::unique_function<(class llvm::Expected<class llvm::DenseMap<class llvm::orc::SymbolStringPtr, class llvm::JITEvaluatedSymbol, struct llvm::DenseMapInfo<class llvm::orc::SymbolStringPtr>, struct llvm::detail::DenseMapPair<class llvm::orc::SymbolStringPtr, class llvm::JITEvaluatedSymbol>>>)>, class std::function<(class llvm::DenseMap<class llvm::orc::JITDylib *, class llvm::DenseSet<class llvm::orc::SymbolStringPtr, struct llvm::DenseMapInfo<class llvm::orc::SymbolStringPtr>>, struct llvm::DenseMapInfo<class llvm::orc::JITDylib *>, struct llvm::detail::DenseMapPair<class llvm::orc::JITDylib *, class llvm::DenseSet<class llvm::orc::SymbolStringPtr, struct llvm::DenseMapInfo<class llvm::orc::SymbolStringPtr>>>> const &)>) E:\llvm-project-merge\llvm\lib\ExecutionEngine\Orc\Core.cpp:1925:0 #24 0x00007ff7a210e8a3 llvm::orc::ExecutionSession::lookup(class std::vector<struct std::pair<class llvm::orc::JITDylib *, enum llvm::orc::JITDylibLookupFlags>, class std::allocator<struct std::pair<class llvm::orc::JITDylib *, enum llvm::orc::JITDylibLookupFlags>>> const &, class llvm::orc::SymbolLookupSet const &, enum llvm::orc::LookupKind, enum llvm::orc::SymbolState, class std::function<(class llvm::DenseMap<class llvm::orc::JITDylib *, class llvm::DenseSet<class llvm::orc::SymbolStringPtr, struct llvm::DenseMapInfo<class llvm::orc::SymbolStringPtr>>, struct llvm::DenseMapInfo<class llvm::orc::JITDylib *>, struct llvm::detail::DenseMapPair<class llvm::orc::JITDylib *, class llvm::DenseSet<class llvm::orc::SymbolStringPtr, struct llvm::DenseMapInfo<class llvm::orc::SymbolStringPtr>>>> const &)>) E:\llvm-project-merge\llvm\lib\ExecutionEngine\Orc\Core.cpp:1966:0 #25 0x00007ff7a210eb10 llvm::orc::ExecutionSession::lookup(class std::vector<struct std::pair<class llvm::orc::JITDylib *, enum llvm::orc::JITDylibLookupFlags>, class std::allocator<struct std::pair<class llvm::orc::JITDylib *, enum llvm::orc::JITDylibLookupFlags>>> const &, class llvm::orc::SymbolStringPtr, enum llvm::orc::SymbolState) E:\llvm-project-merge\llvm\lib\ExecutionEngine\Orc\Core.cpp:1987:0 #26 0x00007ff7a210ed8a llvm::orc::ExecutionSession::lookup(class llvm::ArrayRef<class llvm::orc::JITDylib *>, class llvm::orc::SymbolStringPtr, enum llvm::orc::SymbolState) E:\llvm-project-merge\llvm\lib\ExecutionEngine\Orc\Core.cpp:1999:0 #27 0x00007ff7a210ee69 llvm::orc::ExecutionSession::lookup(class llvm::ArrayRef<class llvm::orc::JITDylib *>, class llvm::StringRef, enum llvm::orc::SymbolState) E:\llvm-project-merge\llvm\lib\ExecutionEngine\Orc\Core.cpp:2005:0 #28 0x00007ff7a1b9b192 getMainEntryPoint E:\llvm-project-merge\llvm\tools\llvm-jitlink\llvm-jitlink.cpp:1320:0 #29 0x00007ff7a1b9b72e main E:\llvm-project-merge\llvm\tools\llvm-jitlink\llvm-jitlink.cpp:1369:0 #30 0x00007ff7a32f7139 invoke_main D:\a01\_work\26\s\src\vctools\crt\vcstartup\src\startup\exe_common.inl:79:0 #31 0x00007ff7a32f701e __scrt_common_main_seh D:\a01\_work\26\s\src\vctools\crt\vcstartup\src\startup\exe_common.inl:288:0 #32 0x00007ff7a32f6ede __scrt_common_main D:\a01\_work\26\s\src\vctools\crt\vcstartup\src\startup\exe_common.inl:331:0 #33 0x00007ff7a32f71ce mainCRTStartup D:\a01\_work\26\s\src\vctools\crt\vcstartup\src\startup\exe_main.cpp:17:0 #34 0x00007ffc92777034 (C:\WINDOWS\System32\KERNEL32.DLL+0x17034) #35 0x00007ffc92cc2651 (C:\WINDOWS\SYSTEM32\ntdll.dll+0x52651)
Hi Nathaniel,
Where are you seeing this test fail? If it's failing on a Buildbot could you please share a link to a failed build? If it's failing locally, are you building top-of-tree, and what is your build configuration?
- Lang.
Hi Lang,
Unfortunately, I don't think there's currently a working bot running the LLVM tests on Windows. I can see the failure locally on my machine and in our internal CI, top of tree with the following configuration (host triple is x86_64-pc-windows-msvc):
-G Ninja -DCMAKE_BUILD_TYPE=Debug -DLLVM_ENABLE_PROJECTS=clang;lld;lldb;mlir -DLLVM_TARGETS_TO_BUILD=host -DLLDB_INCLUDE_TESTS=OFF -DLLVM_ENABLE_ASSERTIONS=ON
Hi Nathaniel,
I don't have access to a Windows machine to test on, but I think Dave Blaikie has spotted the bug -- A think-o in the existing comparator meant that it did not provide a strict weak ordering. Could you let you know if d1a7630369bc fixes the issue for you?
Thanks for reporting this, and thanks Dave for spotting the issue.
- Lang.
Typo: from