Index: lib/ReaderWriter/MachO/MachONormalizedFileToAtoms.cpp =================================================================== --- lib/ReaderWriter/MachO/MachONormalizedFileToAtoms.cpp +++ lib/ReaderWriter/MachO/MachONormalizedFileToAtoms.cpp @@ -749,8 +749,35 @@ const bool is64 = MachOLinkingContext::is64Bit(normalizedFile.arch); // Compiler wasn't lazy and actually told us what it meant. - if (atom->begin() != atom->end()) - return std::error_code(); + // Unfortunately, the compiler may not have set all the references we need, + // or set them to relocation types which aren't what we need internally. + Reference *cieRef = nullptr; + Reference *funcRef = nullptr; + Reference *lsdaRef = nullptr; + if (atom->begin() != atom->end()) { + for (auto *ref : *atom) { + auto contentType = cast(ref->target())->contentType(); + switch (contentType) { + case DefinedAtom::typeCFI: + // ref from FDE back to CIE + assert(!cieRef && "duplicate CIE ref"); + cieRef = const_cast(ref); + break; + case DefinedAtom::typeCode: + // ref from FDE to the function + assert(!funcRef && "duplicate function ref"); + funcRef = const_cast(ref); + break; + case DefinedAtom::typeLSDA: + // ref from LSDA + assert(!lsdaRef && "duplicate lsda ref"); + lsdaRef = const_cast(ref); + break; + default: + llvm_unreachable("unexpected FDE reference"); + } + } + } const uint8_t *frameData = atom->rawContent().data(); uint32_t size = read32(frameData, isBig); @@ -764,13 +791,21 @@ 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 (cieRef) { + // The compiler already emitted a relocation for the CIE ref. However, it + // might be the wrong kind of reference so we'll change it. + cieRef->setKindValue(handler.unwindRefToCIEKind()); + 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; @@ -786,10 +821,17 @@ 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 (funcRef) { + // The compiler already emitted a relocation for the func ref. However, it + // might be the wrong kind of reference so we'll change it. + funcRef->setKindValue(handler.unwindRefToFunctionKind()); + } 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) { @@ -812,11 +854,19 @@ 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 (lsdaRef) { + // The compiler already emitted a relocation for the lsda ref. + // However, it might be the wrong kind of reference so we'll change it. + lsdaRef->setKindValue(handler.unwindRefToFunctionKind()); + } else { + Reference::Addend addend; + const Atom *lsda = + findAtomCoveringAddress(normalizedFile, file, lsdaStart, &addend); + atom->addReference(augmentationDataFieldInFDE, + handler.unwindRefToFunctionKind(), + lsda, addend, handler.kindArch()); + } } } Index: test/mach-o/eh-frame-relocs-arm64.yaml =================================================================== --- /dev/null +++ test/mach-o/eh-frame-relocs-arm64.yaml @@ -0,0 +1,72 @@ +# RUN: lld -flavor darwin -arch arm64 -r -print_atoms %s -o %t | FileCheck %s + +# CHECK: - kind: unwindFDEToFunction +# CHECK-NEXT: offset: 20 +# CHECK-NEXT: target: _f1 +# CHECK-NEXT: addend: 20 + + +--- !mach-o +arch: arm64 +file-type: MH_OBJECT +flags: [ MH_SUBSECTIONS_VIA_SYMBOLS ] +sections: + - segment: __TEXT + section: __text + type: S_REGULAR + attributes: [ S_ATTR_PURE_INSTRUCTIONS, S_ATTR_SOME_INSTRUCTIONS ] + alignment: 4 + address: 0x0000000000000000 + content: [ 0xFF, 0x83, 0x00, 0xD1, 0xE0, 0x0B, 0x00, 0xF9, + 0x08, 0x00, 0x40, 0xB9, 0x08, 0x0D, 0x00, 0x71, + 0x08, 0x09, 0x00, 0x71, 0xE8, 0x0F, 0x00, 0xB9, + 0xC8, 0x00, 0x00, 0x54, 0x01, 0x00, 0x00, 0x14, + 0xE8, 0x03, 0x00, 0x32, 0x08, 0x01, 0x00, 0x12, + 0xE8, 0x7F, 0x00, 0x39, 0x02, 0x00, 0x00, 0x14 ] + - segment: __TEXT + section: __eh_frame + type: S_COALESCED + attributes: [ ] + alignment: 8 + address: 0x0000000000000030 + content: [ 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x7A, 0x52, 0x00, 0x01, 0x78, 0x1E, 0x01, + 0x10, 0x0C, 0x1F, 0x00, 0x18, 0x00, 0x00, 0x00, + 0x18, 0x00, 0x00, 0x00, 0xE4, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0x48, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 ] + relocations: + - offset: 0x00000028 + type: ARM64_RELOC_SUBTRACTOR + length: 3 + pc-rel: false + extern: true + symbol: 2 + - offset: 0x00000028 + type: ARM64_RELOC_UNSIGNED + length: 3 + pc-rel: false + extern: true + symbol: 1 +global-symbols: + - name: _f1 + type: N_SECT + sect: 1 + value: 0x0000000000000000 + - name: _f2 + type: N_SECT + sect: 1 + value: 0x0000000000000010 + - name: _f3 + type: N_SECT + sect: 1 + value: 0x0000000000000020 + - name: _f4 + type: N_SECT + sect: 2 + value: 0x0000000000000030 +local-symbols: + - name: ltmp0 + type: N_SECT + sect: 1 + value: 0x0000000000000030