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))
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;
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();
}
<< 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();
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)
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;
};
--- /dev/null
+# 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
# 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
# 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:
# 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:
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)
# 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
# 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:
# 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
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:
} // 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();
}
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;
}
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);
}
Session S(getFirstFileTriple());
+ setEntryPointNameIfNotProvided(S);
+
if (!NoProcessSymbols)
ExitOnErr(loadProcessSymbols(S));
ExitOnErr(loadDylibs());