diff --git a/lld/MachO/Arch/ARM64.cpp b/lld/MachO/Arch/ARM64.cpp new file mode 100644 --- /dev/null +++ b/lld/MachO/Arch/ARM64.cpp @@ -0,0 +1,264 @@ +//===- ARM64.cpp ----------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "InputFiles.h" +#include "Symbols.h" +#include "SyntheticSections.h" +#include "Target.h" + +#include "lld/Common/ErrorHandler.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/BinaryFormat/MachO.h" +#include "llvm/Support/Endian.h" +#include "llvm/Support/MathExtras.h" + +using namespace llvm::MachO; +using namespace llvm::support::endian; +using namespace lld; +using namespace lld::macho; + +namespace { + +struct ARM64 : TargetInfo { + ARM64(); + + uint64_t getEmbeddedAddend(MemoryBufferRef, const section_64 &, + const relocation_info) const override; + void relocateOne(uint8_t *loc, const Reloc &, uint64_t va, + uint64_t pc) const override; + + void writeStub(uint8_t *buf, const macho::Symbol &) const override; + void writeStubHelperHeader(uint8_t *buf) const override; + void writeStubHelperEntry(uint8_t *buf, const DylibSymbol &, + uint64_t entryAddr) const override; + + void relaxGotLoad(uint8_t *loc, uint8_t type) const override; + const TargetInfo::RelocAttrs &getRelocAttrs(uint8_t type) const override; + uint64_t getPageSize() const override { return 16 * 1024; } +}; + +} // namespace + +// Random notes on reloc types: +// ADDEND always pairs with BRANCH26, PAGE21, or PAGEOFF12 +// SUBTRACTOR always pairs with UNSIGNED (a delta between two sections) +// POINTER_TO_GOT: 4-byte is pc-relative, 8-byte is absolute + +const TargetInfo::RelocAttrs &ARM64::getRelocAttrs(uint8_t type) const { + static const std::array relocAttrsArray{{ +#define B(x) RelocAttrBits::x + {"UNSIGNED", B(ABSOLUTE) | B(EXTERN) | B(LOCAL) | B(TLV) | B(DYSYM8) | + B(BYTE4) | B(BYTE8)}, + {"SUBTRACTOR", B(SUBTRAHEND) | B(BYTE8)}, + {"BRANCH26", B(PCREL) | B(EXTERN) | B(BRANCH) | B(BYTE4)}, + {"PAGE21", B(PCREL) | B(EXTERN) | B(BYTE4)}, + {"PAGEOFF12", B(ABSOLUTE) | B(EXTERN) | B(BYTE4)}, + {"GOT_LOAD_PAGE21", B(PCREL) | B(EXTERN) | B(GOT) | B(BYTE4)}, + {"GOT_LOAD_PAGEOFF12", + B(ABSOLUTE) | B(EXTERN) | B(GOT) | B(LOAD) | B(BYTE4)}, + {"POINTER_TO_GOT", B(PCREL) | B(EXTERN) | B(GOT) | B(BYTE4) | B(BYTE8)}, + {"TLVP_LOAD_PAGE21", B(PCREL) | B(EXTERN) | B(TLV) | B(BYTE4)}, + {"TLVP_LOAD_PAGEOFF12", + B(ABSOLUTE) | B(EXTERN) | B(TLV) | B(LOAD) | B(BYTE4)}, + {"ADDEND", B(ADDEND)}, +#undef B + }}; + assert(type >= 0 && type < relocAttrsArray.size() && + "invalid relocation type"); + if (type < 0 || type >= relocAttrsArray.size()) + return TargetInfo::invalidRelocAttrs; + return relocAttrsArray[type]; +} + +uint64_t ARM64::getEmbeddedAddend(MemoryBufferRef mb, const section_64 &sec, + const relocation_info rel) const { + // TODO(gkm): extract embedded addend just so we can assert that it is 0 + return 0; +} + +inline uint64_t bitField(uint64_t value, int right, int width, int left) { + return ((value >> right) & ((1 << width) - 1)) << left; +} + +// 25 0 +// +-----------+---------------------------------------------------+ +// | | imm26 | +// +-----------+---------------------------------------------------+ + +inline uint64_t encodeBranch26(uint64_t base, uint64_t va) { + // Since branch destinations are 4-byte aligned, the 2 least- + // significant bits are 0. They are right shifted off the end. + return (base | bitField(va, 2, 26, 0)); +} + +// 30 29 23 5 +// +-+---+---------+-------------------------------------+---------+ +// | |ilo| | immhi | | +// +-+---+---------+-------------------------------------+---------+ + +inline uint64_t encodePage21(uint64_t base, uint64_t va) { + return (base | bitField(va, 12, 2, 29) | bitField(va, 14, 19, 5)); +} + +// 21 10 +// +-------------------+-----------------------+-------------------+ +// | | imm12 | | +// +-------------------+-----------------------+-------------------+ + +inline uint64_t encodePageOff12(uint64_t base, uint64_t va) { + int scale = ((base & 0x3b000000) == 0x39000000) ? base >> 30 : 0; + // TODO(gkm): extract embedded addend and warn if != 0 + // uint64_t addend = ((base & 0x003FFC00) >> 10); + return (base | bitField(va, scale, 12 - scale, 10)); +} + +inline uint64_t pageBits(uint64_t address) { + const uint64_t pageMask = ~0xfffull; + return address & pageMask; +} + +// For instruction relocations (load, store, add), the base +// instruction is pre-populated in the text section. A pre-populated +// instruction has opcode & register-operand bits set, with immediate +// operands zeroed. We read it from text, OR-in the immediate +// operands, then write-back the completed instruction. + +void ARM64::relocateOne(uint8_t *loc, const Reloc &r, uint64_t value, + uint64_t pc) const { + uint32_t base = ((r.length == 2) ? read32le(loc) : 0); + value += r.addend; + switch (r.type) { + case ARM64_RELOC_BRANCH26: + value = encodeBranch26(base, value - pc); + break; + case ARM64_RELOC_UNSIGNED: + break; + case ARM64_RELOC_POINTER_TO_GOT: + if (r.pcrel) + value -= pc; + break; + case ARM64_RELOC_PAGE21: + case ARM64_RELOC_GOT_LOAD_PAGE21: + case ARM64_RELOC_TLVP_LOAD_PAGE21: + assert(r.pcrel); + value = encodePage21(base, pageBits(value) - pageBits(pc)); + break; + case ARM64_RELOC_PAGEOFF12: + case ARM64_RELOC_GOT_LOAD_PAGEOFF12: + case ARM64_RELOC_TLVP_LOAD_PAGEOFF12: + assert(!r.pcrel); + value = encodePageOff12(base, value); + break; + default: + llvm_unreachable("unexpected relocation type"); + } + + switch (r.length) { + case 2: + write32le(loc, value); + break; + case 3: + write64le(loc, value); + break; + default: + llvm_unreachable("invalid r_length"); + } +} + +static constexpr uint32_t stubCode[] = { + 0x90000010, // 00: adrp x16, __la_symbol_ptr@page + 0xf9400210, // 04: ldr x16, [x16, __la_symbol_ptr@pageoff] + 0xd61f0200, // 08: br x16 +}; + +void ARM64::writeStub(uint8_t *buf8, const macho::Symbol &sym) const { + auto *buf32 = reinterpret_cast(buf8); + uint64_t pcPageBits = + pageBits(in.stubs->addr + sym.stubsIndex * sizeof(stubCode)); + uint64_t lazyPointerVA = in.lazyPointers->addr + sym.stubsIndex * WordSize; + buf32[0] = encodePage21(stubCode[0], pageBits(lazyPointerVA) - pcPageBits); + buf32[1] = encodePageOff12(stubCode[1], lazyPointerVA); + buf32[2] = stubCode[2]; +} + +static constexpr uint32_t stubHelperHeaderCode[] = { + 0x90000011, // 00: adrp x17, _dyld_private@page + 0x91000231, // 04: add x17, x17, _dyld_private@pageoff + 0xa9bf47f0, // 08: stp x16/x17, [sp, #-16]! + 0x90000010, // 0c: adrp x16, dyld_stub_binder@page + 0xf9400210, // 10: ldr x16, [x16, dyld_stub_binder@pageoff] + 0xd61f0200, // 14: br x16 +}; + +void ARM64::writeStubHelperHeader(uint8_t *buf8) const { + auto *buf32 = reinterpret_cast(buf8); + auto pcPageBits = [](int i) { + return pageBits(in.stubHelper->addr + i * sizeof(uint32_t)); + }; + uint64_t loaderVA = in.imageLoaderCache->getVA(); + buf32[0] = + encodePage21(stubHelperHeaderCode[0], pageBits(loaderVA) - pcPageBits(0)); + buf32[1] = encodePageOff12(stubHelperHeaderCode[1], loaderVA); + buf32[2] = stubHelperHeaderCode[2]; + uint64_t binderVA = + in.got->addr + in.stubHelper->stubBinder->gotIndex * WordSize; + buf32[3] = + encodePage21(stubHelperHeaderCode[3], pageBits(binderVA) - pcPageBits(3)); + buf32[4] = encodePageOff12(stubHelperHeaderCode[4], binderVA); + buf32[5] = stubHelperHeaderCode[5]; +} + +static constexpr uint32_t stubHelperEntryCode[] = { + 0x18000050, // 00: ldr w16, l0 + 0x14000000, // 04: b stubHelperHeader + 0x00000000, // 08: l0: .long 0 +}; + +void ARM64::writeStubHelperEntry(uint8_t *buf8, const DylibSymbol &sym, + uint64_t entryVA) const { + auto *buf32 = reinterpret_cast(buf8); + auto pcVA = [entryVA](int i) { return entryVA + i * sizeof(uint32_t); }; + uint64_t stubHelperHeaderVA = in.stubHelper->addr; + buf32[0] = stubHelperEntryCode[0]; + buf32[1] = + encodeBranch26(stubHelperEntryCode[1], stubHelperHeaderVA - pcVA(1)); + buf32[2] = sym.lazyBindOffset; +} + +void ARM64::relaxGotLoad(uint8_t *loc, uint8_t type) const { + // The instruction format comments below are quoted from + // ArmĀ® Architecture Reference Manual + // Armv8, for Armv8-A architecture profile + // ARM DDI 0487G.a (ID011921) + uint32_t instruction = read32le(loc); + // C6.2.132 LDR (immediate) + // LDR , [{, #}] + if ((instruction & 0xffc00000) != 0xf9400000) + error(getRelocAttrs(type).name + " reloc requires LDR instruction"); + assert(((instruction >> 10) & 0xfff) == 0 && + "non-zero embedded LDR immediate"); + // C6.2.4 ADD (immediate) + // ADD , , #{, } + instruction = ((instruction & 0x001fffff) | 0x91000000); + write32le(loc, instruction); +} + +ARM64::ARM64() { + cpuType = CPU_TYPE_ARM64; + cpuSubtype = CPU_SUBTYPE_ARM64_ALL; + + stubSize = sizeof(stubCode); + stubHelperHeaderSize = sizeof(stubHelperHeaderCode); + stubHelperEntrySize = sizeof(stubHelperEntryCode); +} + +TargetInfo *macho::createARM64TargetInfo() { + static ARM64 t; + return &t; +} diff --git a/lld/MachO/Arch/X86_64.cpp b/lld/MachO/Arch/X86_64.cpp --- a/lld/MachO/Arch/X86_64.cpp +++ b/lld/MachO/Arch/X86_64.cpp @@ -37,6 +37,7 @@ void relaxGotLoad(uint8_t *loc, uint8_t type) const override; const TargetInfo::RelocAttrs &getRelocAttrs(uint8_t type) const override; + uint64_t getPageSize() const override { return 4 * 1024; } }; } // namespace diff --git a/lld/MachO/CMakeLists.txt b/lld/MachO/CMakeLists.txt --- a/lld/MachO/CMakeLists.txt +++ b/lld/MachO/CMakeLists.txt @@ -6,6 +6,7 @@ add_lld_library(lldMachO2 Arch/X86_64.cpp + Arch/ARM64.cpp UnwindInfoSection.cpp Driver.cpp DriverUtils.cpp diff --git a/lld/MachO/Driver.cpp b/lld/MachO/Driver.cpp --- a/lld/MachO/Driver.cpp +++ b/lld/MachO/Driver.cpp @@ -126,15 +126,19 @@ } static TargetInfo *createTargetInfo(opt::InputArgList &args) { - StringRef arch = args.getLastArgValue(OPT_arch, "x86_64"); - config->arch = MachO::getArchitectureFromName( - args.getLastArgValue(OPT_arch, arch)); - switch (config->arch) { - case MachO::AK_x86_64: - case MachO::AK_x86_64h: + // TODO: should unspecified arch be an error rather than defaulting? + // Jez: ld64 seems to make unspecified arch an error when LTO is + // being used. I'm not sure why though. Feels like we should be able + // to infer the arch from our input files regardless + StringRef archName = args.getLastArgValue(OPT_arch, "x86_64"); + config->arch = MachO::getArchitectureFromName(archName); + switch (MachO::getCPUTypeFromArchitecture(config->arch).first) { + case MachO::CPU_TYPE_X86_64: return createX86_64TargetInfo(); + case MachO::CPU_TYPE_ARM64: + return createARM64TargetInfo(); default: - fatal("missing or unsupported -arch " + arch); + fatal("missing or unsupported -arch " + archName); } } @@ -436,7 +440,8 @@ if (cpuType != CPU_TYPE_ANY) line = line.drop_until([](char c) { return c == ':'; }).drop_front(); // TODO: Update when we extend support for other CPUs - if (cpuType != CPU_TYPE_ANY && cpuType != CPU_TYPE_X86_64) + if (cpuType != CPU_TYPE_ANY && cpuType != CPU_TYPE_X86_64 && + cpuType != CPU_TYPE_ARM64) continue; constexpr std::array fileEnds = {".o:", ".o):"}; @@ -634,9 +639,11 @@ static bool isPie(opt::InputArgList &args) { if (config->outputType != MH_EXECUTE || args.hasArg(OPT_no_pie)) return false; + if (config->arch == AK_arm64 || config->arch == AK_arm64e) + return true; // TODO: add logic here as we support more archs. E.g. i386 should default - // to PIE from 10.7, arm64 should always be PIE, etc + // to PIE from 10.7 assert(config->arch == AK_x86_64 || config->arch == AK_x86_64h); PlatformKind kind = config->platform.kind; diff --git a/lld/MachO/InputFiles.cpp b/lld/MachO/InputFiles.cpp --- a/lld/MachO/InputFiles.cpp +++ b/lld/MachO/InputFiles.cpp @@ -221,12 +221,11 @@ error(message(Twine("must ") + (rel.r_pcrel ? "not " : "") + "be PC-relative")); if (isThreadLocalVariables(sec.flags) && - (!relocAttrs.hasAttr(RelocAttrBits::TLV) || - relocAttrs.hasAttr(RelocAttrBits::LOAD))) + !relocAttrs.hasAttr(RelocAttrBits::TLV | RelocAttrBits::BYTE8)) error(message("not allowed in thread-local section, must be UNSIGNED")); if (rel.r_length < 2 || rel.r_length > 3 || !relocAttrs.hasAttr(static_cast(1 << rel.r_length))) { - static SmallVector widths{"INVALID", "4", "8", "4 or 8"}; + static SmallVector widths{"0", "4", "8", "4 or 8"}; error(message("has width " + std::to_string(1 << rel.r_length) + " bytes, but must be " + widths[(static_cast(relocAttrs.bits) >> 2) & 3] + diff --git a/lld/MachO/InputSection.h b/lld/MachO/InputSection.h --- a/lld/MachO/InputSection.h +++ b/lld/MachO/InputSection.h @@ -21,6 +21,7 @@ class InputSection; class OutputSection; class Symbol; +class Defined; struct Reloc { uint8_t type = llvm::MachO::GENERIC_RELOC_INVALID; diff --git a/lld/MachO/InputSection.cpp b/lld/MachO/InputSection.cpp --- a/lld/MachO/InputSection.cpp +++ b/lld/MachO/InputSection.cpp @@ -60,11 +60,11 @@ memcpy(buf, data.data(), data.size()); for (size_t i = 0; i < relocs.size(); i++) { - const Reloc &r = relocs[i]; - uint8_t *loc = buf + r.offset; - auto *fromSym = target->hasAttr(r.type, RelocAttrBits::SUBTRAHEND) + auto *fromSym = target->hasAttr(relocs[i].type, RelocAttrBits::SUBTRAHEND) ? relocs[i++].referent.dyn_cast() : nullptr; + const Reloc &r = relocs[i]; + uint8_t *loc = buf + r.offset; uint64_t referentVA = 0; if (fromSym) { auto *toSym = r.referent.dyn_cast(); diff --git a/lld/MachO/SyntheticSections.cpp b/lld/MachO/SyntheticSections.cpp --- a/lld/MachO/SyntheticSections.cpp +++ b/lld/MachO/SyntheticSections.cpp @@ -56,8 +56,8 @@ void MachHeaderSection::writeTo(uint8_t *buf) const { auto *hdr = reinterpret_cast(buf); hdr->magic = MachO::MH_MAGIC_64; - hdr->cputype = MachO::CPU_TYPE_X86_64; - hdr->cpusubtype = MachO::CPU_SUBTYPE_X86_64_ALL | MachO::CPU_SUBTYPE_LIB64; + hdr->cputype = target->cpuType; + hdr->cpusubtype = target->cpuSubtype | MachO::CPU_SUBTYPE_LIB64; hdr->filetype = config->outputType; hdr->ncmds = loadCommands.size(); hdr->sizeofcmds = sizeOfCmds; @@ -385,6 +385,8 @@ // get here llvm_unreachable("cannot bind to an undefined symbol"); } + // TODO: understand the DSOHandle case better. + // Is it bindable? Add a new test? } StubsSection::StubsSection() @@ -710,8 +712,11 @@ // TODO: when we implement -dead_strip, we should filter out symbols // that belong to dead sections. if (auto *defined = dyn_cast(sym)) { - if (!defined->isExternal()) - addSymbol(localSymbols, sym); + if (!defined->isExternal()) { + StringRef name = defined->getName(); + if (!name.startswith("l") && !name.startswith("L")) + addSymbol(localSymbols, sym); + } } } } diff --git a/lld/MachO/Target.h b/lld/MachO/Target.h --- a/lld/MachO/Target.h +++ b/lld/MachO/Target.h @@ -29,7 +29,6 @@ // We are currently only supporting 64-bit targets since macOS and iOS are // deprecating 32-bit apps. WordSize = 8, - PageSize = 4096, PageZeroSize = 1ull << 32, // XXX should be 4096 for 32-bit targets MaxAlignmentPowerOf2 = 32, }; @@ -49,7 +48,7 @@ TLV = 1 << 10, // Pertains to Thread-Local Variable slots DYSYM8 = 1 << 11, // Requires DySym width to be 8 bytes LOAD = 1 << 12, // Relaxable indirect load - LLVM_MARK_AS_BITMASK_ENUM(/*LargestValue*/ LOAD), + LLVM_MARK_AS_BITMASK_ENUM(/*LargestValue*/ (1 << 13) - 1), }; class TargetInfo { @@ -86,6 +85,8 @@ virtual const RelocAttrs &getRelocAttrs(uint8_t type) const = 0; + virtual uint64_t getPageSize() const = 0; + bool hasAttr(uint8_t type, RelocAttrBits bit) const { return getRelocAttrs(type).hasAttr(bit); } @@ -106,6 +107,7 @@ }; TargetInfo *createX86_64TargetInfo(); +TargetInfo *createARM64TargetInfo(); extern TargetInfo *target; diff --git a/lld/MachO/Target.cpp b/lld/MachO/Target.cpp --- a/lld/MachO/Target.cpp +++ b/lld/MachO/Target.cpp @@ -32,8 +32,8 @@ .str(); }; - if (relocAttrs.hasAttr(RelocAttrBits::TLV | RelocAttrBits::LOAD) != - sym->isTlv()) + if ((relocAttrs.hasAttr(RelocAttrBits::TLV) && + !relocAttrs.hasAttr(RelocAttrBits::BYTE8)) != sym->isTlv()) error(message(Twine("requires that variable ") + (sym->isTlv() ? "not " : "") + "be thread-local")); if (relocAttrs.hasAttr(RelocAttrBits::DYSYM8) && isa(sym) && diff --git a/lld/MachO/Writer.cpp b/lld/MachO/Writer.cpp --- a/lld/MachO/Writer.cpp +++ b/lld/MachO/Writer.cpp @@ -720,8 +720,9 @@ } void Writer::assignAddresses(OutputSegment *seg) { - addr = alignTo(addr, PageSize); - fileOff = alignTo(fileOff, PageSize); + uint64_t pageSize = target->getPageSize(); + addr = alignTo(addr, pageSize); + fileOff = alignTo(fileOff, pageSize); seg->fileOff = fileOff; for (OutputSection *osec : seg->getSections()) { diff --git a/lld/test/MachO/Inputs/MacOSX.sdk/usr/lib/libSystem.tbd b/lld/test/MachO/Inputs/MacOSX.sdk/usr/lib/libSystem.tbd --- a/lld/test/MachO/Inputs/MacOSX.sdk/usr/lib/libSystem.tbd +++ b/lld/test/MachO/Inputs/MacOSX.sdk/usr/lib/libSystem.tbd @@ -1,42 +1,42 @@ --- !tapi-tbd-v3 -archs: [ x86_64 ] -uuids: [ 'x86_64: 00000000-0000-0000-0000-000000000000' ] +archs: [ x86_64, arm64 ] +uuids: [ 'x86_64: 00000000-0000-0000-0000-000000000000', 'arm64: 00000000-0000-0000-0000-000000000010' ] platform: macosx install-name: '/usr/lib/libSystem.B.dylib' current-version: 0001.001.1 exports: - - archs: [ 'x86_64' ] + - archs: [ 'x86_64', 'arm64' ] re-exports: [ '/usr/lib/system/libdyld.dylib', '/usr/lib/system/libsystem_c.dylib', '/usr/lib/system/libsystem_m.dylib' ] --- !tapi-tbd-v3 -archs: [ x86_64 ] -uuids: [ 'x86_64: 00000000-0000-0000-0000-000000000001' ] +archs: [ x86_64, arm64 ] +uuids: [ 'x86_64: 00000000-0000-0000-0000-000000000001', 'arm64: 00000000-0000-0000-0000-000000000011' ] platform: macosx install-name: '/usr/lib/system/libdyld.dylib' current-version: 0001.001.1 parent-umbrella: System exports: - - archs: [ 'x86_64' ] + - archs: [ 'x86_64', 'arm64' ] symbols: [ dyld_stub_binder, __tlv_bootstrap ] --- !tapi-tbd-v3 -archs: [ x86_64 ] -uuids: [ 'x86_64: 00000000-0000-0000-0000-000000000002' ] +archs: [ x86_64, arm64 ] +uuids: [ 'x86_64: 00000000-0000-0000-0000-000000000002', 'arm64: 00000000-0000-0000-0000-000000000012' ] platform: macosx install-name: '/usr/lib/system/libsystem_c.dylib' current-version: 0001.001.1 parent-umbrella: System exports: - - archs: [ 'x86_64' ] + - archs: [ 'x86_64', 'arm64' ] symbols: [ ] --- !tapi-tbd-v3 -archs: [ x86_64 ] -uuids: [ 'x86_64: 00000000-0000-0000-0000-000000000003' ] +archs: [ x86_64, arm64 ] +uuids: [ 'x86_64: 00000000-0000-0000-0000-000000000003', 'arm64: 00000000-0000-0000-0000-000000000013' ] platform: macosx install-name: '/usr/lib/system/libsystem_m.dylib' current-version: 0001.001.1 parent-umbrella: System exports: - - archs: [ 'x86_64' ] + - archs: [ 'x86_64', 'arm64' ] symbols: [ ___nan ] ... diff --git a/lld/test/MachO/Inputs/MacOSX.sdk/usr/lib/libc++.tbd b/lld/test/MachO/Inputs/MacOSX.sdk/usr/lib/libc++.tbd --- a/lld/test/MachO/Inputs/MacOSX.sdk/usr/lib/libc++.tbd +++ b/lld/test/MachO/Inputs/MacOSX.sdk/usr/lib/libc++.tbd @@ -1,10 +1,10 @@ --- !tapi-tbd-v3 archs: [ i386, x86_64 ] -uuids: [ 'i386: 00000000-0000-0000-0000-000000000000', 'x86_64: 00000000-0000-0000-0000-000000000001' ] +uuids: [ 'i386: 00000000-0000-0000-0000-000000000000', 'x86_64: 00000000-0000-0000-0000-000000000001', 'arm64: 00000000-0000-0000-0000-000000000002' ] platform: macosx install-name: '/usr/lib/libc++.dylib' current-version: 1281 exports: - - archs: [ i386, x86_64 ] + - archs: [ i386, x86_64, arm64 ] re-exports: [ '/usr/lib/libc++abi.dylib' ] ... diff --git a/lld/test/MachO/Inputs/MacOSX.sdk/usr/lib/libc++abi.tbd b/lld/test/MachO/Inputs/MacOSX.sdk/usr/lib/libc++abi.tbd --- a/lld/test/MachO/Inputs/MacOSX.sdk/usr/lib/libc++abi.tbd +++ b/lld/test/MachO/Inputs/MacOSX.sdk/usr/lib/libc++abi.tbd @@ -1,10 +1,10 @@ --- !tapi-tbd-v3 -archs: [ i386, x86_64 ] -uuids: [ 'i386: 00000000-0000-0000-0000-000000000000', 'x86_64: 00000000-0000-0000-0000-000000000001' ] +archs: [ i386, x86_64, arm64 ] +uuids: [ 'i386: 00000000-0000-0000-0000-000000000000', 'x86_64: 00000000-0000-0000-0000-000000000001', 'arm64: 00000000-0000-0000-0000-000000000002' ] platform: macosx install-name: '/usr/lib/libc++abi.dylib' current-version: 1281 exports: - - archs: [ i386, x86_64 ] + - archs: [ i386, x86_64, arm64 ] symbols: [ ___gxx_personality_v0 ] ... diff --git a/lld/test/MachO/relocations.s b/lld/test/MachO/x86-64-relocs.s rename from lld/test/MachO/relocations.s rename to lld/test/MachO/x86-64-relocs.s