Index: include/lld/Core/DefinedAtom.h =================================================================== --- include/lld/Core/DefinedAtom.h +++ include/lld/Core/DefinedAtom.h @@ -307,6 +307,10 @@ return _atom.derefIterator(_it); } + bool operator==(const reference_iterator &other) const { + return _it == other._it; + } + bool operator!=(const reference_iterator &other) const { return _it != other._it; } @@ -350,6 +354,14 @@ atomContentType == DefinedAtom::typeGnuLinkOnce); } + /// Utility function to check if relocations in this atom to other defined + /// atoms can be implicitly generated, and so we don't need to explicitly + /// emit those relocations. + bool relocsToDefinedCanBeImplicit() const { + ContentType atomContentType = contentType(); + return atomContentType == typeCFI; + } + // Returns true if lhs should be placed before rhs in the final output. static bool compareByPosition(const DefinedAtom *lhs, const DefinedAtom *rhs); Index: lib/ReaderWriter/MachO/ArchHandler.h =================================================================== --- lib/ReaderWriter/MachO/ArchHandler.h +++ lib/ReaderWriter/MachO/ArchHandler.h @@ -78,6 +78,11 @@ /// actually be used. virtual uint32_t dwarfCompactUnwindType() = 0; + /// Reference from an __eh_frame CIE atom to its personality function it's + /// describing. Usually pointer-sized and PC-relative, but differs in whether + /// it needs to be in relocatable objects. + virtual Reference::KindValue unwindRefToPersonalityFunctionKind() = 0; + /// Reference from an __eh_frame FDE to the CIE it's based on. virtual Reference::KindValue unwindRefToCIEKind() = 0; Index: lib/ReaderWriter/MachO/ArchHandler_arm.cpp =================================================================== --- lib/ReaderWriter/MachO/ArchHandler_arm.cpp +++ lib/ReaderWriter/MachO/ArchHandler_arm.cpp @@ -51,6 +51,10 @@ return invalid; } + Reference::KindValue unwindRefToPersonalityFunctionKind() override { + return invalid; + } + Reference::KindValue unwindRefToCIEKind() override { return invalid; } Index: lib/ReaderWriter/MachO/ArchHandler_arm64.cpp =================================================================== --- lib/ReaderWriter/MachO/ArchHandler_arm64.cpp +++ lib/ReaderWriter/MachO/ArchHandler_arm64.cpp @@ -53,6 +53,9 @@ case delta32ToGOT: canBypassGOT = false; return true; + case unwindCIEToPersonalityFunction: + canBypassGOT = false; + return true; case imageOffsetGot: canBypassGOT = false; return true; @@ -108,6 +111,10 @@ return imageOffsetGot; } + Reference::KindValue unwindRefToPersonalityFunctionKind() override { + return unwindCIEToPersonalityFunction; + } + Reference::KindValue unwindRefToCIEKind() override { return negDelta32; } @@ -197,6 +204,9 @@ imageOffset, /// Location contains offset of atom in final image imageOffsetGot, /// Location contains offset of GOT entry for atom in /// final image (typically personality function). + unwindCIEToPersonalityFunction, /// Nearly delta32ToGOT, but cannot be + /// rematerialized in relocatable object + /// (yay for implicit contracts!). unwindFDEToFunction, /// Nearly delta64, but cannot be rematerialized in /// relocatable object (yay for implicit contracts!). unwindInfoToEhFrame, /// Fix low 24 bits of compact unwind encoding to @@ -244,6 +254,7 @@ LLD_KIND_STRING_ENTRY(lazyImmediateLocation), LLD_KIND_STRING_ENTRY(imageOffset), LLD_KIND_STRING_ENTRY(imageOffsetGot), + LLD_KIND_STRING_ENTRY(unwindCIEToPersonalityFunction), LLD_KIND_STRING_ENTRY(unwindFDEToFunction), LLD_KIND_STRING_ENTRY(unwindInfoToEhFrame), @@ -433,7 +444,14 @@ return std::error_code(); case ARM64_RELOC_POINTER_TO_GOT | rPcRel | rExtern | rLength4: // ex: .long _foo@GOT - . - *kind = delta32ToGOT; + + // If we are in an .eh_frame section, then the kind of the relocation should + // not be delta32ToGOT. It may instead be unwindCIEToPersonalityFunction. + if (inAtom->contentType() == DefinedAtom::typeCFI) + *kind = unwindCIEToPersonalityFunction; + else + *kind = delta32ToGOT; + if (auto ec = atomFromSymbolIndex(reloc.symbol, target)) return ec; *addend = 0; @@ -479,9 +497,16 @@ case ((ARM64_RELOC_SUBTRACTOR | rExtern | rLength8) << 16 | ARM64_RELOC_UNSIGNED | rExtern | rLength8): // ex: .quad _foo - . - *kind = delta64; if (auto ec = atomFromSymbolIndex(reloc2.symbol, target)) return ec; + + // If we are in an .eh_frame section, then the kind of the relocation should + // not be delta64. It may instead be unwindFDEToFunction. + if (inAtom->contentType() == DefinedAtom::typeCFI) + *kind = unwindFDEToFunction; + else + *kind = delta64; + // The offsets of the 2 relocations must match if (reloc1.offset != reloc2.offset) return make_dynamic_error_code("paired relocs must have the same offset"); @@ -620,6 +645,7 @@ return; case delta32: case delta32ToGOT: + case unwindCIEToPersonalityFunction: *loc32 = (targetAddress - fixupAddress) + ref.addend(); return; case negDelta32: @@ -710,6 +736,13 @@ case delta32ToGOT: *loc32 = inAtomAddress - fixupAddress; return; + case unwindCIEToPersonalityFunction: + // We don't emit unwindCIEToPersonalityFunction in -r mode as they are + // implicitly generated from the data in the __eh_frame section. So here we + // need to use the targetAddress so that we can generate the full relocation + // when we parse again later. + *loc32 = targetAddress - fixupAddress; + return; case addOffset12: llvm_unreachable("lazy reference kind implies GOT pass was run"); case lazyPointer: @@ -832,6 +865,7 @@ case imageOffset: case imageOffsetGot: llvm_unreachable("deltas from mach_header can only be in final images"); + case unwindCIEToPersonalityFunction: case unwindFDEToFunction: case unwindInfoToEhFrame: case negDelta32: Index: lib/ReaderWriter/MachO/ArchHandler_x86.cpp =================================================================== --- lib/ReaderWriter/MachO/ArchHandler_x86.cpp +++ lib/ReaderWriter/MachO/ArchHandler_x86.cpp @@ -58,6 +58,10 @@ return invalid; } + Reference::KindValue unwindRefToPersonalityFunctionKind() override { + return invalid; + } + Reference::KindValue unwindRefToCIEKind() override { return negDelta32; } Index: lib/ReaderWriter/MachO/ArchHandler_x86_64.cpp =================================================================== --- lib/ReaderWriter/MachO/ArchHandler_x86_64.cpp +++ lib/ReaderWriter/MachO/ArchHandler_x86_64.cpp @@ -104,6 +104,10 @@ return imageOffsetGot; } + Reference::KindValue unwindRefToPersonalityFunctionKind() override { + return ripRel32Got; + } + Reference::KindValue unwindRefToCIEKind() override { return negDelta32; } Index: lib/ReaderWriter/MachO/MachONormalizedFileToAtoms.cpp =================================================================== --- lib/ReaderWriter/MachO/MachONormalizedFileToAtoms.cpp +++ lib/ReaderWriter/MachO/MachONormalizedFileToAtoms.cpp @@ -684,18 +684,21 @@ struct CIEInfo { bool _augmentationDataPresent = false; - bool _mayHaveLSDA = false; + bool _mayHaveEH = false; + uint32_t _offsetOfLSDA = ~0U; + uint32_t _offsetOfPersonality = ~0U; + uint32_t _offsetOfFDEPointerEncoding = ~0U; + uint32_t _augmentationDataLength = ~0U; }; typedef llvm::DenseMap CIEInfoMap; static std::error_code processAugmentationString(const uint8_t *augStr, CIEInfo &cieInfo, - unsigned *len = nullptr) { + unsigned &len) { if (augStr[0] == '\0') { - if (len) - *len = 1; + len = 1; return std::error_code(); } @@ -706,21 +709,54 @@ cieInfo._augmentationDataPresent = true; uint64_t idx = 1; + uint32_t offsetInAugmentationData = 0; while (augStr[idx] != '\0') { if (augStr[idx] == 'L') { - cieInfo._mayHaveLSDA = true; + cieInfo._offsetOfLSDA = offsetInAugmentationData; + // This adds a single byte to the augmentation data. + ++offsetInAugmentationData; ++idx; - } else + continue; + } + if (augStr[idx] == 'P') { + cieInfo._offsetOfPersonality = offsetInAugmentationData; + // This adds a single byte to the augmentation data for the encoding, + // then a number of bytes for the pointer data. + // FIXME: We are assuming 4 is correct here for the pointer size as we + // always currently use delta32ToGOT. + offsetInAugmentationData += 5; + ++idx; + continue; + } + if (augStr[idx] == 'R') { + cieInfo._offsetOfFDEPointerEncoding = offsetInAugmentationData; + // This adds a single byte to the augmentation data. + ++offsetInAugmentationData; ++idx; + continue; + } + if (augStr[idx] == 'e') { + if (augStr[idx + 1] != 'h') + return make_dynamic_error_code("expected 'eh' in augmentation string"); + cieInfo._mayHaveEH = true; + idx += 2; + continue; + } + ++idx; } - if (len) - *len = idx + 1; + cieInfo._augmentationDataLength = offsetInAugmentationData; + + len = idx + 1; return std::error_code(); } static std::error_code processCIE(const NormalizedFile &normalizedFile, + MachOFile &file, + mach_o::ArchHandler &handler, + const Section *ehFrameSection, MachODefinedAtom *atom, + uint64_t offset, CIEInfoMap &cieInfos) { const bool isBig = MachOLinkingContext::isBigEndian(normalizedFile.arch); const uint8_t *frameData = atom->rawContent().data(); @@ -734,10 +770,85 @@ uint64_t versionField = cieIDField + sizeof(uint32_t); uint64_t augmentationStringField = versionField + sizeof(uint8_t); + unsigned augmentationStringLength = 0; if (auto err = processAugmentationString(frameData + augmentationStringField, - cieInfo)) + cieInfo, augmentationStringLength)) return err; + if (cieInfo._offsetOfPersonality != ~0U) { + // If we have augmentation data for the personality function, then we may + // need to implicitly generate its relocation. + + // Parse the EH Data field which is pointer sized. + uint64_t EHDataField = augmentationStringField + augmentationStringLength; + const bool is64 = MachOLinkingContext::is64Bit(normalizedFile.arch); + unsigned EHDataFieldSize = (cieInfo._mayHaveEH ? (is64 ? 8 : 4) : 0); + + // Parse Code Align Factor which is a ULEB128. + uint64_t CodeAlignField = EHDataField + EHDataFieldSize; + unsigned lengthFieldSize = 0; + llvm::decodeULEB128(frameData + CodeAlignField, &lengthFieldSize); + + // Parse Data Align Factor which is a SLEB128. + uint64_t DataAlignField = CodeAlignField + lengthFieldSize; + llvm::decodeSLEB128(frameData + DataAlignField, &lengthFieldSize); + + // Parse Return Address Register which is a byte. + uint64_t ReturnAddressField = DataAlignField + lengthFieldSize; + + // Parse the augmentation length which is a ULEB128. + uint64_t AugmentationLengthField = ReturnAddressField + 1; + uint64_t AugmentationLength = + llvm::decodeULEB128(frameData + AugmentationLengthField, + &lengthFieldSize); + + if (AugmentationLength != cieInfo._augmentationDataLength) + return make_dynamic_error_code("CIE augmentation data length mismatch"); + + // Get the start address of the augmentation data. + uint64_t AugmentationDataField = AugmentationLengthField + lengthFieldSize; + + // Parse the personality function from the augmentation data. + uint64_t PersonalityField = + AugmentationDataField + cieInfo._offsetOfPersonality; + + // Parse the personality encoding. + // FIXME: Verify that this is a 32-bit pcrel offset. + uint64_t PersonalityFunctionField = PersonalityField + 1; + + if (atom->begin() != atom->end()) { + // If we have an explicit relocation, then make sure it matches this + // offset as this is where we'd expect it to be applied to. + DefinedAtom::reference_iterator CurrentRef = atom->begin(); + if (CurrentRef->offsetInAtom() != PersonalityFunctionField) + return make_dynamic_error_code("CIE personality reloc at wrong offset"); + + if (++CurrentRef != atom->end()) + return make_dynamic_error_code("CIE contains too many relocs"); + } else { + // Implicitly generate the personality function reloc. It's assumed to + // be a delta32 offset to a GOT entry. + // FIXME: Parse the encoding and check this. + int32_t funcDelta = read32(frameData + PersonalityFunctionField, isBig); + uint64_t funcAddress = ehFrameSection->address + offset + + PersonalityFunctionField; + funcAddress += funcDelta; + + const MachODefinedAtom *func = nullptr; + Reference::Addend addend; + func = findAtomCoveringAddress(normalizedFile, file, funcAddress, + &addend); + atom->addReference(PersonalityFunctionField, + handler.unwindRefToPersonalityFunctionKind(), func, + addend, handler.kindArch()); + } + } else if (atom->begin() != atom->end()) { + // Otherwise, we expect there to be no relocations in this atom as the only + // relocation would have been to the personality function. + return make_dynamic_error_code("unexpected relocation in CIE"); + } + + cieInfos[atom] = std::move(cieInfo); return std::error_code(); @@ -755,10 +866,46 @@ const bool is64 = MachOLinkingContext::is64Bit(normalizedFile.arch); // Compiler wasn't lazy and actually told us what it meant. + // Unfortunately, the compiler may not have generated references for all of + // [cie, func, lsda] and so we still need to parse the FDE and add references + // for any the compiler didn't generate. if (atom->begin() != atom->end()) - return std::error_code(); + atom->sortReferences(); + + DefinedAtom::reference_iterator CurrentRef = atom->begin(); + + // This helper returns the reference (if one exists) at the offset we are + // currently processing. It automatically increments the ref iterator if we + // do return a ref, and throws an error if we pass over a ref without + // comsuming it. + auto currentRefGetter = [&CurrentRef, + &atom](uint64_t Offset)->const Reference* { + // If there are no more refs found, then we are done. + if (CurrentRef == atom->end()) + return nullptr; + + const Reference *Ref = *CurrentRef; + + // If we haven't reached the offset for this reference, then return that + // we don't yet have a reference to process. + if (Offset < Ref->offsetInAtom()) + return nullptr; + + // If the offset is equal, then we want to process this ref. + if (Offset == Ref->offsetInAtom()) { + ++CurrentRef; + return Ref; + } + + // The current ref is at an offset which is earlier than the current + // offset, then we failed to consume it when we should have. In this case + // throw an error. + llvm::report_fatal_error("Skipped reference when processing FDE"); + }; + + const uint8_t *startFrameData = atom->rawContent().data(); + const uint8_t *frameData = startFrameData; - const uint8_t *frameData = atom->rawContent().data(); uint32_t size = read32(frameData, isBig); uint64_t cieFieldInFDE = size == 0xffffffffU ? sizeof(uint32_t) + sizeof(uint64_t) @@ -770,13 +917,23 @@ uint64_t cieAddress = ehFrameSection->address + offset + cieFieldInFDE; cieAddress -= cieDelta; - Reference::Addend addend; - const MachODefinedAtom *cie = - findAtomCoveringAddress(normalizedFile, file, cieAddress, &addend); - atom->addReference(cieFieldInFDE, handler.unwindRefToCIEKind(), cie, - addend, handler.kindArch()); + const MachODefinedAtom *cie = nullptr; + if (auto *cieRef = currentRefGetter(cieFieldInFDE)) { + // The compiler already emitted a relocation for the CIE ref. This should + // have been converted to the correct type of reference in + // get[Pair]ReferenceInfo(). + assert(cieRef->kindValue() == handler.unwindRefToCIEKind() && + "Incorrect FDE->CIE reference kind"); + cie = cast(cieRef->target()); + } else { + Reference::Addend addend; + cie = findAtomCoveringAddress(normalizedFile, file, cieAddress, &addend); + atom->addReference(cieFieldInFDE, handler.unwindRefToCIEKind(), cie, + addend, handler.kindArch()); - assert(cie && cie->contentType() == DefinedAtom::typeCFI && !addend && + assert(!addend && "FDE's CIE field does not point at the start of a CIE."); + } + assert(cie && cie->contentType() == DefinedAtom::typeCFI && "FDE's CIE field does not point at the start of a CIE."); const CIEInfo &cieInfo = cieInfos.find(cie)->second; @@ -792,10 +949,19 @@ uint64_t rangeStart = ehFrameSection->address + offset + rangeFieldInFDE; rangeStart += functionFromFDE; - const Atom *func = - findAtomCoveringAddress(normalizedFile, file, rangeStart, &addend); - atom->addReference(rangeFieldInFDE, handler.unwindRefToFunctionKind(), - func, addend, handler.kindArch()); + if (auto *funcRef = currentRefGetter(rangeFieldInFDE)) { + // The compiler already emitted a relocation for the func ref. This should + // have been converted to the correct type of reference in + // get[Pair]ReferenceInfo(). + assert(funcRef->kindValue() == handler.unwindRefToFunctionKind() && + "Incorrect FDE->function reference kind"); + } else { + Reference::Addend addend; + const Atom *func = + findAtomCoveringAddress(normalizedFile, file, rangeStart, &addend); + atom->addReference(rangeFieldInFDE, handler.unwindRefToFunctionKind(), + func, addend, handler.kindArch()); + } // Handle the augmentation data if there is any. if (cieInfo._augmentationDataPresent) { @@ -807,7 +973,7 @@ llvm::decodeULEB128(frameData + augmentationDataLengthFieldInFDE, &lengthFieldSize); - if (cieInfo._mayHaveLSDA && augmentationDataLength > 0) { + if (cieInfo._offsetOfLSDA != ~0U && augmentationDataLength > 0) { // Look at the augmentation data field. uint64_t augmentationDataFieldInFDE = @@ -818,11 +984,21 @@ uint64_t lsdaStart = ehFrameSection->address + offset + augmentationDataFieldInFDE + lsdaFromFDE; - const Atom *lsda = - findAtomCoveringAddress(normalizedFile, file, lsdaStart, &addend); - atom->addReference(augmentationDataFieldInFDE, - handler.unwindRefToFunctionKind(), - lsda, addend, handler.kindArch()); + + if (auto *lsdaRef = currentRefGetter(augmentationDataFieldInFDE)) { + // The compiler already emitted a relocation for the lsda ref. This + // should have been converted to the correct type of reference in + // get[Pair]ReferenceInfo(). + assert(lsdaRef->kindValue() == handler.unwindRefToFunctionKind() && + "Incorrect FDE->LSDA reference kind"); + } else { + Reference::Addend addend; + const Atom *lsda = + findAtomCoveringAddress(normalizedFile, file, lsdaStart, &addend); + atom->addReference(augmentationDataFieldInFDE, + handler.unwindRefToFunctionKind(), + lsda, addend, handler.kindArch()); + } } } @@ -858,7 +1034,8 @@ const bool isBig = MachOLinkingContext::isBigEndian(normalizedFile.arch); if (ArchHandler::isDwarfCIE(isBig, atom)) - ehFrameErr = processCIE(normalizedFile, atom, cieInfos); + ehFrameErr = processCIE(normalizedFile, file, handler, ehFrameSection, + atom, offset, cieInfos); else ehFrameErr = processFDE(normalizedFile, file, handler, ehFrameSection, atom, offset, cieInfos); Index: test/mach-o/do-not-emit-unwind-fde-arm64.yaml =================================================================== --- test/mach-o/do-not-emit-unwind-fde-arm64.yaml +++ test/mach-o/do-not-emit-unwind-fde-arm64.yaml @@ -74,7 +74,7 @@ address: 0x0000000000000050 content: [ 0x1C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x7A, 0x50, 0x4C, 0x52, 0x00, 0x01, 0x78, - 0x1E, 0x0B, 0x00, 0xED, 0xFF, 0xFF, 0xFF, 0xFF, + 0x1E, 0x07, 0x00, 0x9D, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x10, 0x0C, 0x1F, 0x00, 0x24, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, 0x88, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, @@ -142,8 +142,8 @@ # CHECK: - ref-name: L{{[0-9]*}} # CHECK: type: unwind-cfi # CHECK: content: [ 1C, 00, 00, 00, 00, 00, 00, 00, 01, 7A, 50, 4C, -# CHECK: 52, 00, 01, 78, 1E, 0B, 00, ED, FF, FF, FF, FF, -# CHECK: FF, FF, FF, 00, 10, 0C, 1F, 00 ] +# CHECK: 52, 00, 01, 78, 1E, 07, 00, {{..}}, {{..}}, {{..}}, {{..}}, {{..}}, +# CHECK: {{..}}, {{..}}, {{..}}, 00, 10, 0C, 1F, 00 ] # CHECK: - type: unwind-cfi # CHECK: content: [ 24, 00, 00, 00, 24, 00, 00, 00, {{..}}, {{..}}, {{..}}, {{..}}, # CHECK: {{..}}, {{..}}, {{..}}, {{..}}, 20, 00, 00, 00, 00, 00, 00, 00, @@ -197,7 +197,7 @@ # CODE: Contents of section __eh_frame: # This is the CIE: # CODE-NEXT: {{[0-9abcdef]*}} 1c000000 00000000 017a504c 52000178 -# CODE-NEXT: {{[0-9abcdef]*}} 1e0b00ed ffffffff ffffff00 100c1f00 +# CODE-NEXT: {{[0-9abcdef]*}} 1e0700bd ffffffff ffffff00 100c1f00 # This is the FDE: # CODE-NEXT: {{[0-9abcdef]*}} 24000000 24000000 a8ffffff ffffffff # This is the important offset for FDE->func ^~~~~~~~ ~~~~~~~~ Index: test/mach-o/eh-frame-relocs-arm64.yaml =================================================================== --- /dev/null +++ test/mach-o/eh-frame-relocs-arm64.yaml @@ -0,0 +1,318 @@ +# RUN: lld -flavor darwin -arch arm64 -r -print_atoms %s -o %t | FileCheck %s +# RUN: lld -flavor darwin -arch arm64 -r -print_atoms %t -o %t2 | FileCheck %s +# RUN: llvm-objdump -r -s -section="__eh_frame" -macho %t | FileCheck -check-prefix=CODE %s +# RUN: llvm-objdump -r -s -section="__eh_frame" -macho %t2 | FileCheck -check-prefix=CODE %s + + +--- !mach-o +arch: arm64 +file-type: MH_OBJECT +flags: [ MH_SUBSECTIONS_VIA_SYMBOLS ] +compat-version: 0.0 +current-version: 0.0 +has-UUID: false +OS: unknown +sections: + - segment: __TEXT + section: __text + type: S_REGULAR + attributes: [ S_ATTR_PURE_INSTRUCTIONS, S_ATTR_SOME_INSTRUCTIONS ] + alignment: 4 + address: 0x0000000000000000 + content: [ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xC0, 0x03, 0x5F, 0xD6, 0xC0, 0x03, 0x5F, 0xD6, + 0xC0, 0x03, 0x5F, 0xD6 ] + - segment: __TEXT + section: __gcc_except_tab + type: S_REGULAR + attributes: [ ] + address: 0x0000000000000014 + content: [ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 ] + - segment: __DATA + section: __data + type: S_REGULAR + attributes: [ ] + address: 0x000000000000001C + content: [ 0x00, 0x00, 0x00, 0x00 ] + - segment: __LD + section: __compact_unwind + type: S_REGULAR + attributes: [ ] + alignment: 8 + address: 0x0000000000000020 + content: [ 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 ] + relocations: + - offset: 0x00000020 + type: ARM64_RELOC_UNSIGNED + length: 3 + pc-rel: false + extern: false + symbol: 1 + - offset: 0x00000000 + type: ARM64_RELOC_UNSIGNED + length: 3 + pc-rel: false + extern: false + symbol: 1 + - segment: __TEXT + section: __eh_frame + type: S_COALESCED + attributes: [ ] + alignment: 8 + address: 0x0000000000000060 + content: [ 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x03, 0x7A, 0x50, 0x4C, 0x52, 0x00, 0x01, 0x78, + 0x1E, 0x07, 0x9B, 0xED, 0xFF, 0xFF, 0xFF, 0x10, + 0x10, 0x0C, 0x1F, 0x00, 0x28, 0x00, 0x00, 0x00, + 0x20, 0x00, 0x00, 0x00, 0xDC, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0x04, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x08, 0xCB, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x0E, 0x10, 0x9E, + 0x01, 0x9D, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x03, 0x7A, 0x50, 0x4C, 0x52, 0x00, 0x01, 0x78, + 0x1E, 0x07, 0x9B, 0xA9, 0xFF, 0xFF, 0xFF, 0x10, + 0x10, 0x0C, 0x1F, 0x00, 0x28, 0x00, 0x00, 0x00, + 0x20, 0x00, 0x00, 0x00, 0x94, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0x04, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x08, 0x83, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x0E, 0x10, 0x9E, + 0x01, 0x9D, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00 ] + relocations: + - offset: 0x0000007D + type: ARM64_RELOC_SUBTRACTOR + length: 3 + pc-rel: false + extern: true + symbol: 6 + - offset: 0x0000007D + type: ARM64_RELOC_UNSIGNED + length: 3 + pc-rel: false + extern: true + symbol: 3 + - offset: 0x0000006C + type: ARM64_RELOC_SUBTRACTOR + length: 3 + pc-rel: false + extern: true + symbol: 6 + - offset: 0x0000006C + type: ARM64_RELOC_UNSIGNED + length: 3 + pc-rel: false + extern: true + symbol: 8 + - offset: 0x0000005B + type: ARM64_RELOC_POINTER_TO_GOT + length: 2 + pc-rel: true + extern: true + symbol: 10 + - offset: 0x00000035 + type: ARM64_RELOC_SUBTRACTOR + length: 3 + pc-rel: false + extern: true + symbol: 6 + - offset: 0x00000035 + type: ARM64_RELOC_UNSIGNED + length: 3 + pc-rel: false + extern: true + symbol: 2 + - offset: 0x00000024 + type: ARM64_RELOC_SUBTRACTOR + length: 3 + pc-rel: false + extern: true + symbol: 6 + - offset: 0x00000024 + type: ARM64_RELOC_UNSIGNED + length: 3 + pc-rel: false + extern: true + symbol: 7 + - offset: 0x00000013 + type: ARM64_RELOC_POINTER_TO_GOT + length: 2 + pc-rel: true + extern: true + symbol: 9 +local-symbols: + - name: ltmp0 + type: N_SECT + sect: 1 + value: 0x0000000000000000 + - name: ltmp1 + type: N_SECT + sect: 2 + value: 0x0000000000000014 + - name: _bar1 + type: N_SECT + sect: 2 + value: 0x0000000000000014 + - name: _bar2 + type: N_SECT + sect: 2 + value: 0x0000000000000018 + - name: ltmp12 + type: N_SECT + sect: 3 + value: 0x000000000000001C + - name: ltmp13 + type: N_SECT + sect: 4 + value: 0x0000000000000020 + - name: ltmp16 + type: N_SECT + sect: 5 + value: 0x0000000000000060 +global-symbols: + - name: __Z3fooi + type: N_SECT + scope: [ N_EXT ] + sect: 1 + value: 0x0000000000000008 + - name: __Z4foo2i + type: N_SECT + scope: [ N_EXT ] + sect: 1 + value: 0x000000000000000C + - name: __gxx_personality_v0 + type: N_SECT + scope: [ N_EXT ] + sect: 1 + value: 0x0000000000000000 + - name: __gxx_personality_v1 + type: N_SECT + scope: [ N_EXT ] + sect: 1 + value: 0x0000000000000004 + - name: _main + type: N_SECT + scope: [ N_EXT ] + sect: 1 + value: 0x0000000000000010 + - name: _someData + type: N_SECT + scope: [ N_EXT ] + sect: 3 + value: 0x000000000000001C +page-size: 0x00000000 +... + +# CHECK: --- !native +# CHECK: path: '' +# CHECK: defined-atoms: +# CHECK: - ref-name: L000 +# CHECK: type: unwind-cfi +# CHECK: content: [ 18, 00, 00, 00, 00, 00, 00, 00, 03, 7A, 50, 4C, +# CHECK: 52, 00, 01, 78, 1E, 07, 9B, {{..}}, {{..}}, {{..}}, {{..}}, 10, +# CHECK: 10, 0C, 1F, 00 ] +# CHECK: alignment: 8 +# CHECK: references: +# CHECK: - kind: unwindCIEToPersonalityFunction +# CHECK: offset: 19 +# CHECK: target: __gxx_personality_v0 +# CHECK: - type: unwind-cfi +# CHECK: content: [ 28, 00, 00, 00, 20, 00, 00, 00, {{..}}, {{..}}, {{..}}, {{..}}, +# CHECK: {{..}}, {{..}}, {{..}}, {{..}}, 04, 00, 00, 00, 00, 00, 00, 00, +# CHECK: 08, {{..}}, {{..}}, {{..}}, {{..}}, {{..}}, {{..}}, {{..}}, {{..}}, 0E, 10, 9E, +# CHECK: 01, 9D, 02, 00, 00, 00, 00, 00 ] +# CHECK: alignment: 4 mod 8 +# CHECK: references: +# CHECK: - kind: negDelta32 +# CHECK: offset: 4 +# CHECK: target: L000 +# CHECK: - kind: unwindFDEToFunction +# CHECK: offset: 8 +# CHECK: target: __Z3fooi +# CHECK: - kind: unwindFDEToFunction +# CHECK: offset: 25 +# CHECK: target: _bar1 +# CHECK: - ref-name: L001 +# CHECK: type: unwind-cfi +# CHECK: content: [ 18, 00, 00, 00, 00, 00, 00, 00, 03, 7A, 50, 4C, +# CHECK: 52, 00, 01, 78, 1E, 07, 9B, {{..}}, {{..}}, {{..}}, {{..}}, 10, +# CHECK: 10, 0C, 1F, 00 ] +# CHECK: alignment: 8 +# CHECK: references: +# CHECK: - kind: unwindCIEToPersonalityFunction +# CHECK: offset: 19 +# CHECK: target: __gxx_personality_v1 +# CHECK: - type: unwind-cfi +# CHECK: content: [ 28, 00, 00, 00, 20, 00, 00, 00, {{..}}, {{..}}, {{..}}, {{..}}, +# CHECK: {{..}}, {{..}}, {{..}}, {{..}}, 04, 00, 00, 00, 00, 00, 00, 00, +# CHECK: 08, {{..}}, {{..}}, {{..}}, {{..}}, {{..}}, {{..}}, {{..}}, {{..}}, 0E, 10, 9E, +# CHECK: 01, 9D, 02, 00, 00, 00, 00, 00 ] +# CHECK: alignment: 4 mod 8 +# CHECK: references: +# CHECK: - kind: negDelta32 +# CHECK: offset: 4 +# CHECK: target: L001 +# CHECK: - kind: unwindFDEToFunction +# CHECK: offset: 8 +# CHECK: target: __Z4foo2i +# CHECK: - kind: unwindFDEToFunction +# CHECK: offset: 25 +# CHECK: target: _bar2 +# CHECK: - name: _bar1 +# CHECK: type: unwind-lsda +# CHECK: content: [ 00, 00, 00, 00 ] +# CHECK: - name: _bar2 +# CHECK: type: unwind-lsda +# CHECK: content: [ 00, 00, 00, 00 ] +# CHECK: - name: _someData +# CHECK: scope: global +# CHECK: type: data +# CHECK: content: [ 00, 00, 00, 00 ] +# CHECK: - name: __gxx_personality_v0 +# CHECK: scope: global +# CHECK: content: [ 00, 00, 00, 00 ] +# CHECK: alignment: 4 +# CHECK: - name: __gxx_personality_v1 +# CHECK: scope: global +# CHECK: content: [ 00, 00, 00, 00 ] +# CHECK: alignment: 4 +# CHECK: - name: __Z3fooi +# CHECK: scope: global +# CHECK: content: [ C0, 03, 5F, D6 ] +# CHECK: alignment: 4 +# CHECK: - name: __Z4foo2i +# CHECK: scope: global +# CHECK: content: [ C0, 03, 5F, D6 ] +# CHECK: alignment: 4 +# CHECK: - name: _main +# CHECK: scope: global +# CHECK: content: [ C0, 03, 5F, D6 ] +# CHECK: alignment: 4 +# CHECK: ... + +# # Make sure we don't have any relocations in the __eh_frame section +# CODE-NOT: RELOCATION RECORDS FOR [__eh_frame] + +# Also make sure the reloc for the CIE->personality function is the +# correct offset +# It should be the offset from the fixup location back to the address +# of the function we are referencing +# CODE: Contents of section __eh_frame: +# This is the CIE: +# CODE-NEXT: {{[0-9abcdef]*}} 18000000 00000000 037a504c 52000178 +# CODE-NEXT: {{[0-9abcdef]*}} 1e079bd1 ffffff10 100c1f00 28000000 +# This is the important offset for CIE->pfunc +# ^~~~~~~~~ +# Then we have an FDE starting from 28000000 above +# CODE-NEXT: {{[0-9abcdef]*}} 20000000 c8ffffff ffffffff 04000000 +# CODE-NEXT: {{[0-9abcdef]*}} 00000000 08c3ffff ffffffff ff0e109e +# And a new CIE starts at this 00000018 right below here +# CODE-NEXT: {{[0-9abcdef]*}} 019d0200 00000000 18000000 00000000 +# CODE-NEXT: {{[0-9abcdef]*}} 037a504c 52000178 1e079b8d ffffff10 +# This is the important offset for its CIE->pfunc ^~~~~~~~~ \ No newline at end of file