diff options
-rw-r--r-- | llvm/lib/ExecutionEngine/JITLink/EHFrameSupport.cpp | 31 | ||||
-rw-r--r-- | llvm/lib/ExecutionEngine/JITLink/EHFrameSupportImpl.h | 9 | ||||
-rw-r--r-- | llvm/test/ExecutionEngine/JITLink/X86/Inputs/MachO_x86-64_ehframe.o | bin | 0 -> 1056 bytes | |||
-rw-r--r-- | llvm/test/ExecutionEngine/JITLink/X86/MachO_x86-64_ehframe.test | 5 | ||||
-rw-r--r-- | llvm/test/ExecutionEngine/JITLink/X86/MachO_x86-64_relocations.s | 30 | ||||
-rw-r--r-- | llvm/tools/llvm-jitlink/llvm-jitlink.cpp | 48 |
6 files changed, 74 insertions, 49 deletions
diff --git a/llvm/lib/ExecutionEngine/JITLink/EHFrameSupport.cpp b/llvm/lib/ExecutionEngine/JITLink/EHFrameSupport.cpp index 6517b3b0d0c..c531df82446 100644 --- a/llvm/lib/ExecutionEngine/JITLink/EHFrameSupport.cpp +++ b/llvm/lib/ExecutionEngine/JITLink/EHFrameSupport.cpp @@ -163,8 +163,7 @@ Error EHFrameParser::processCIE() { LLVM_DEBUG(dbgs() << " Record is CIE\n"); - /// Reset state for the new CIE. - LSDAFieldPresent = false; + CIEInformation CIEInfo(*CurRecordAtom); uint8_t Version = 0; if (auto Err = EHFrameReader.readInteger(Version)) @@ -219,7 +218,7 @@ Error EHFrameParser::processCIE() { while (uint8_t Field = *NextField++) { switch (Field) { case 'L': { - LSDAFieldPresent = true; + CIEInfo.FDEsHaveLSDAField = true; uint8_t LSDAPointerEncoding; if (auto Err = EHFrameReader.readInteger(LSDAPointerEncoding)) return Err; @@ -268,6 +267,10 @@ Error EHFrameParser::processCIE() { return make_error<JITLinkError>("Read past the end of the augmentation " "data while parsing fields"); + assert(!CIEInfos.count(CurRecordAtom->getAddress()) && + "Multiple CIEs recorded at the same address?"); + CIEInfos[CurRecordAtom->getAddress()] = std::move(CIEInfo); + return Error::success(); } @@ -280,14 +283,18 @@ Error EHFrameParser::processFDE(JITTargetAddress CIEPointerAddress, << format("0x%016" PRIx64, CIEPointerAddress - CIEPointer) << "\n"; }); - auto CIEAtom = G.findAtomByAddress(CIEPointerAddress - CIEPointer); - if (!CIEAtom) - return CIEAtom.takeError(); + auto CIEInfoItr = CIEInfos.find(CIEPointerAddress - CIEPointer); + if (CIEInfoItr == CIEInfos.end()) + return make_error<JITLinkError>( + "FDE at " + formatv("{0:x16}", CurRecordAtom->getAddress()) + + " points to non-existant CIE at " + + formatv("{0:x16}", CIEPointerAddress - CIEPointer)); + auto &CIEInfo = CIEInfoItr->second; // The CIEPointer looks good. Add a relocation. CurRecordAtom->addEdge(FDEToCIERelocKind, CIEPointerAddress - CurRecordAtom->getAddress(), - *CIEAtom, 0); + *CIEInfo.CIEAtom, 0); // Read and sanity check the PC-start pointer and size. JITTargetAddress PCBeginAddress = EHFrameAddress + EHFrameReader.getOffset(); @@ -329,15 +336,15 @@ Error EHFrameParser::processFDE(JITTargetAddress CIEPointerAddress, if (auto Err = EHFrameReader.skip(G.getPointerSize())) return Err; - if (LSDAFieldPresent) { + if (CIEInfo.FDEsHaveLSDAField) { uint64_t AugmentationDataSize; if (auto Err = EHFrameReader.readULEB128(AugmentationDataSize)) return Err; if (AugmentationDataSize != G.getPointerSize()) - return make_error<JITLinkError>("Unexpected FDE augmentation data size " - "(expected " + - Twine(G.getPointerSize()) + ", got " + - Twine(AugmentationDataSize) + ")"); + return make_error<JITLinkError>( + "Unexpected FDE augmentation data size (expected " + + Twine(G.getPointerSize()) + ", got " + Twine(AugmentationDataSize) + + ") for FDE at " + formatv("{0:x16}", CurRecordAtom->getAddress())); JITTargetAddress LSDAAddress = EHFrameAddress + EHFrameReader.getOffset(); auto LSDADelta = readAbsolutePointer(); if (!LSDADelta) diff --git a/llvm/lib/ExecutionEngine/JITLink/EHFrameSupportImpl.h b/llvm/lib/ExecutionEngine/JITLink/EHFrameSupportImpl.h index 78be89cfca9..d679edef7ea 100644 --- a/llvm/lib/ExecutionEngine/JITLink/EHFrameSupportImpl.h +++ b/llvm/lib/ExecutionEngine/JITLink/EHFrameSupportImpl.h @@ -44,13 +44,20 @@ private: Error processCIE(); Error processFDE(JITTargetAddress CIEPointerAddress, uint32_t CIEPointer); + struct CIEInformation { + CIEInformation() = default; + CIEInformation(DefinedAtom &CIEAtom) : CIEAtom(&CIEAtom) {} + DefinedAtom *CIEAtom = nullptr; + bool FDEsHaveLSDAField = false; + }; + AtomGraph &G; Section &EHFrameSection; StringRef EHFrameContent; JITTargetAddress EHFrameAddress; BinaryStreamReader EHFrameReader; DefinedAtom *CurRecordAtom = nullptr; - bool LSDAFieldPresent = false; + DenseMap<JITTargetAddress, CIEInformation> CIEInfos; Edge::Kind FDEToCIERelocKind; Edge::Kind FDEToTargetRelocKind; }; diff --git a/llvm/test/ExecutionEngine/JITLink/X86/Inputs/MachO_x86-64_ehframe.o b/llvm/test/ExecutionEngine/JITLink/X86/Inputs/MachO_x86-64_ehframe.o Binary files differnew file mode 100644 index 00000000000..ba489b0cd9b --- /dev/null +++ b/llvm/test/ExecutionEngine/JITLink/X86/Inputs/MachO_x86-64_ehframe.o diff --git a/llvm/test/ExecutionEngine/JITLink/X86/MachO_x86-64_ehframe.test b/llvm/test/ExecutionEngine/JITLink/X86/MachO_x86-64_ehframe.test new file mode 100644 index 00000000000..84bc14e3b23 --- /dev/null +++ b/llvm/test/ExecutionEngine/JITLink/X86/MachO_x86-64_ehframe.test @@ -0,0 +1,5 @@ +# RUN: llvm-jitlink -noexec %S/Inputs/MachO_x86-64_ehframe.o +# +# Perform a no-exec link of MachO_x86-64_ehframe and verify that it does not +# generate any errors despite the last FDE referring to the first CIE (rather +# than the most recent).
\ No newline at end of file diff --git a/llvm/test/ExecutionEngine/JITLink/X86/MachO_x86-64_relocations.s b/llvm/test/ExecutionEngine/JITLink/X86/MachO_x86-64_relocations.s index c1f6bc955e9..330695aebe1 100644 --- a/llvm/test/ExecutionEngine/JITLink/X86/MachO_x86-64_relocations.s +++ b/llvm/test/ExecutionEngine/JITLink/X86/MachO_x86-64_relocations.s @@ -1,6 +1,6 @@ # RUN: rm -rf %t && mkdir -p %t -# RUN: llvm-mc -triple=x86_64-apple-macosx10.9 -filetype=obj -o %t/test_x86-64.o %s -# RUN: llvm-jitlink -noexec -define-abs external_data=0xdeadbeef -define-abs external_func=0xcafef00d -check=%s %t/test_x86-64.o +# RUN: llvm-mc -triple=x86_64-apple-macosx10.9 -filetype=obj -o %t/macho_reloc.o %s +# RUN: llvm-jitlink -noexec -define-abs external_data=0xdeadbeef -define-abs external_func=0xcafef00d -check=%s %t/macho_reloc.o .section __TEXT,__text,regular,pure_instructions @@ -32,8 +32,8 @@ _main: # Validate both the reference to the GOT entry, and also the content of the GOT # entry. # -# jitlink-check: decode_operand(test_gotld, 4) = got_addr(test_x86-64.o, external_data) - next_pc(test_gotld) -# jitlink-check: *{8}(got_addr(test_x86-64.o, external_data)) = external_data +# jitlink-check: decode_operand(test_gotld, 4) = got_addr(macho_reloc.o, external_data) - next_pc(test_gotld) +# jitlink-check: *{8}(got_addr(macho_reloc.o, external_data)) = external_data .globl test_gotld .align 4, 0x90 test_gotld: @@ -43,8 +43,8 @@ test_gotld: # Check that calls to external functions trigger the generation of stubs and GOT # entries. # -# jitlink-check: decode_operand(test_external_call, 0) = stub_addr(test_x86-64.o, external_func) - next_pc(test_external_call) -# jitlink-check: *{8}(got_addr(test_x86-64.o, external_func)) = external_func +# jitlink-check: decode_operand(test_external_call, 0) = stub_addr(macho_reloc.o, external_func) - next_pc(test_external_call) +# jitlink-check: *{8}(got_addr(macho_reloc.o, external_func)) = external_func .globl test_external_call .align 4, 0x90 test_external_call: @@ -84,22 +84,22 @@ signed4: movl $0xAAAAAAAA, named_data(%rip) .globl signedanon -# jitlink-check: decode_operand(signedanon, 4) = section_addr(test_x86-64.o, __data) - next_pc(signedanon) +# jitlink-check: decode_operand(signedanon, 4) = section_addr(macho_reloc.o, __data) - next_pc(signedanon) signedanon: movq Lanon_data(%rip), %rax .globl signed1anon -# jitlink-check: decode_operand(signed1anon, 3) = section_addr(test_x86-64.o, __data) - next_pc(signed1anon) +# jitlink-check: decode_operand(signed1anon, 3) = section_addr(macho_reloc.o, __data) - next_pc(signed1anon) signed1anon: movb $0xAA, Lanon_data(%rip) .globl signed2anon -# jitlink-check: decode_operand(signed2anon, 3) = section_addr(test_x86-64.o, __data) - next_pc(signed2anon) +# jitlink-check: decode_operand(signed2anon, 3) = section_addr(macho_reloc.o, __data) - next_pc(signed2anon) signed2anon: movw $0xAAAA, Lanon_data(%rip) .globl signed4anon -# jitlink-check: decode_operand(signed4anon, 3) = section_addr(test_x86-64.o, __data) - next_pc(signed4anon) +# jitlink-check: decode_operand(signed4anon, 3) = section_addr(macho_reloc.o, __data) - next_pc(signed4anon) signed4anon: movl $0xAAAAAAAA, Lanon_data(%rip) @@ -117,13 +117,13 @@ Lanon_data: # invalid because the minuend can not be local. # # Note: +8 offset in expression below to accounts for sizeof(Lanon_data). -# jitlink-check: *{8}(section_addr(test_x86-64.o, __data) + 8) = (section_addr(test_x86-64.o, __data) + 8) - named_data + 2 +# jitlink-check: *{8}(section_addr(macho_reloc.o, __data) + 8) = (section_addr(macho_reloc.o, __data) + 8) - named_data + 2 .p2align 3 Lanon_minuend_quad: .quad Lanon_minuend_quad - named_data + 2 # Note: +16 offset in expression below to accounts for sizeof(Lanon_data) + sizeof(Lanon_minuend_long). -# jitlink-check: *{4}(section_addr(test_x86-64.o, __data) + 16) = ((section_addr(test_x86-64.o, __data) + 16) - named_data + 2)[31:0] +# jitlink-check: *{4}(section_addr(macho_reloc.o, __data) + 16) = ((section_addr(macho_reloc.o, __data) + 16) - named_data + 2)[31:0] .p2align 2 Lanon_minuend_long: .long Lanon_minuend_long - named_data + 2 @@ -147,7 +147,7 @@ named_func_addr: # Check X86_64_RELOC_UNSIGNED / non-extern handling by putting the address of a # local anonymous function in a pointer variable. # -# jitlink-check: *{8}anon_func_addr = section_addr(test_x86-64.o, __text) +# jitlink-check: *{8}anon_func_addr = section_addr(macho_reloc.o, __text) .globl anon_func_addr .p2align 3 anon_func_addr: @@ -155,7 +155,7 @@ anon_func_addr: # X86_64_RELOC_SUBTRACTOR Quad/Long in named storage with anonymous minuend # -# jitlink-check: *{8}minuend_quad1 = section_addr(test_x86-64.o, __data) - minuend_quad1 + 2 +# jitlink-check: *{8}minuend_quad1 = section_addr(macho_reloc.o, __data) - minuend_quad1 + 2 # Only the form "B: .quad LA - B + C" is tested. The form "B: .quad B - LA + C" is # invalid because the minuend can not be local. .globl minuend_quad1 @@ -163,7 +163,7 @@ anon_func_addr: minuend_quad1: .quad Lanon_data - minuend_quad1 + 2 -# jitlink-check: *{4}minuend_long1 = (section_addr(test_x86-64.o, __data) - minuend_long1 + 2)[31:0] +# jitlink-check: *{4}minuend_long1 = (section_addr(macho_reloc.o, __data) - minuend_long1 + 2)[31:0] .globl minuend_long1 .p2align 2 minuend_long1: diff --git a/llvm/tools/llvm-jitlink/llvm-jitlink.cpp b/llvm/tools/llvm-jitlink/llvm-jitlink.cpp index f3333f23faf..29516f093fe 100644 --- a/llvm/tools/llvm-jitlink/llvm-jitlink.cpp +++ b/llvm/tools/llvm-jitlink/llvm-jitlink.cpp @@ -326,14 +326,37 @@ Session::findSymbolInfo(StringRef SymbolName, Twine ErrorMsgStem) { } // end namespace llvm +Triple getFirstFileTriple() { + assert(!InputFiles.empty() && "InputFiles can not be empty"); + auto ObjBuffer = + ExitOnErr(errorOrToExpected(MemoryBuffer::getFile(InputFiles.front()))); + auto Obj = ExitOnErr( + object::ObjectFile::createObjectFile(ObjBuffer->getMemBufferRef())); + return Obj->makeTriple(); +} + +void setEntryPointNameIfNotProvided(const Session &S) { + if (EntryPointName.empty()) { + if (S.TT.getObjectFormat() == Triple::MachO) + EntryPointName = "_main"; + else + EntryPointName = "main"; + } +} + Error loadProcessSymbols(Session &S) { std::string ErrMsg; if (sys::DynamicLibrary::LoadLibraryPermanently(nullptr, &ErrMsg)) return make_error<StringError>(std::move(ErrMsg), inconvertibleErrorCode()); char GlobalPrefix = S.TT.getObjectFormat() == Triple::MachO ? '_' : '\0'; - S.ES.getMainJITDylib().setGenerator(ExitOnErr( - orc::DynamicLibrarySearchGenerator::GetForCurrentProcess(GlobalPrefix))); + auto InternedEntryPointName = S.ES.intern(EntryPointName); + auto FilterMainEntryPoint = [InternedEntryPointName](SymbolStringPtr Name) { + return Name != InternedEntryPointName; + }; + S.ES.getMainJITDylib().setGenerator( + ExitOnErr(orc::DynamicLibrarySearchGenerator::GetForCurrentProcess( + GlobalPrefix, FilterMainEntryPoint))); return Error::success(); } @@ -352,15 +375,6 @@ Error loadDylibs() { return Error::success(); } -Triple getFirstFileTriple() { - assert(!InputFiles.empty() && "InputFiles can not be empty"); - auto ObjBuffer = - ExitOnErr(errorOrToExpected(MemoryBuffer::getFile(InputFiles.front()))); - auto Obj = ExitOnErr( - object::ObjectFile::createObjectFile(ObjBuffer->getMemBufferRef())); - return Obj->makeTriple(); -} - Error loadObjects(Session &S) { std::map<unsigned, JITDylib *> IdxToJLD; @@ -542,16 +556,6 @@ static void dumpSessionStats(Session &S) { } static Expected<JITEvaluatedSymbol> getMainEntryPoint(Session &S) { - - // First, if the entry point has not been set, set it to a sensible default - // for this process. - if (EntryPointName.empty()) { - if (S.TT.getObjectFormat() == Triple::MachO) - EntryPointName = "_main"; - else - EntryPointName = "main"; - } - return S.ES.lookup(S.JDSearchOrder, EntryPointName); } @@ -584,6 +588,8 @@ int main(int argc, char *argv[]) { Session S(getFirstFileTriple()); + setEntryPointNameIfNotProvided(S); + if (!NoProcessSymbols) ExitOnErr(loadProcessSymbols(S)); ExitOnErr(loadDylibs()); |