Files
clang-p2996/lld/lib/ReaderWriter/MachO/ArchHandler_x86.cpp
Rui Ueyama ea65b5aa49 [MACH-O] Fix the ASM code generated for __stub_helpers section
Patch by Patricio Villalobos.

I discovered that lld for darwin is generating the wrong code for lazy
bindings in the __stub_helper section (at least for osx 10.12). This is
the way i can reproduce this problem, using this program:

  #include <stdio.h>

  int main(int argc, char **argv) {
      printf("C: printf!\n");
      puts("C: puts!\n");
      return 0;
  }

Then I link it using i have tested it in 3.9, 4.0 and 4.1 versions:

  $ clang -c hello.c
  $ lld -flavor darwin hello.o -o h1  -lc

When i execute the binary h1 the system gives me the following error:

  C: printf!
  dyld: lazy symbol binding failed:
  BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB
  has segment 4 which is too large (0..3)
  dyld: BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB has segment 4 which is too
  large (0..3)
  Trace/BPT trap: 5

Investigating the code, it seems that the problem is that the asm code
generated in the file StubPass.cpp, specifically in the line 323,when it
adds, what it seems an arbitrary number (12) to the offset into the lazy
bind opcodes section, but it should be calculated depending on the
MachONormalizedFileBinaryWrite::lazyBindingInfo result.

I confirmed this bug by patching the code manually in the binary and
writing the right offset in the asm code (__stub_helper).

This patch fixes the content of the atom that contains the assembly code
when the offset is known.

Differential Revision: https://reviews.llvm.org/D35387

llvm-svn: 311734
2017-08-24 23:51:40 +00:00

645 lines
24 KiB
C++

//===- lib/FileFormat/MachO/ArchHandler_x86.cpp ---------------------------===//
//
// The LLVM Linker
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#include "ArchHandler.h"
#include "Atoms.h"
#include "MachONormalizedFileBinaryUtils.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/ADT/StringSwitch.h"
#include "llvm/ADT/Triple.h"
#include "llvm/Support/Endian.h"
#include "llvm/Support/ErrorHandling.h"
using namespace llvm::MachO;
using namespace lld::mach_o::normalized;
namespace lld {
namespace mach_o {
using llvm::support::ulittle16_t;
using llvm::support::ulittle32_t;
using llvm::support::little16_t;
using llvm::support::little32_t;
class ArchHandler_x86 : public ArchHandler {
public:
ArchHandler_x86() = default;
~ArchHandler_x86() override = default;
const Registry::KindStrings *kindStrings() override { return _sKindStrings; }
Reference::KindArch kindArch() override { return Reference::KindArch::x86; }
const StubInfo &stubInfo() override { return _sStubInfo; }
bool isCallSite(const Reference &) override;
bool isNonCallBranch(const Reference &) override {
return false;
}
bool isPointer(const Reference &) override;
bool isPairedReloc(const normalized::Relocation &) override;
bool needsCompactUnwind() override {
return false;
}
Reference::KindValue imageOffsetKind() override {
return invalid;
}
Reference::KindValue imageOffsetKindIndirect() override {
return invalid;
}
Reference::KindValue unwindRefToPersonalityFunctionKind() override {
return invalid;
}
Reference::KindValue unwindRefToCIEKind() override {
return negDelta32;
}
Reference::KindValue unwindRefToFunctionKind() override{
return delta32;
}
Reference::KindValue lazyImmediateLocationKind() override {
return lazyImmediateLocation;
}
Reference::KindValue unwindRefToEhFrameKind() override {
return invalid;
}
Reference::KindValue pointerKind() override {
return invalid;
}
uint32_t dwarfCompactUnwindType() override {
return 0x04000000U;
}
llvm::Error getReferenceInfo(const normalized::Relocation &reloc,
const DefinedAtom *inAtom,
uint32_t offsetInAtom,
uint64_t fixupAddress, bool swap,
FindAtomBySectionAndAddress atomFromAddress,
FindAtomBySymbolIndex atomFromSymbolIndex,
Reference::KindValue *kind,
const lld::Atom **target,
Reference::Addend *addend) override;
llvm::Error
getPairReferenceInfo(const normalized::Relocation &reloc1,
const normalized::Relocation &reloc2,
const DefinedAtom *inAtom,
uint32_t offsetInAtom,
uint64_t fixupAddress, bool swap, bool scatterable,
FindAtomBySectionAndAddress atomFromAddress,
FindAtomBySymbolIndex atomFromSymbolIndex,
Reference::KindValue *kind,
const lld::Atom **target,
Reference::Addend *addend) override;
void generateAtomContent(const DefinedAtom &atom, bool relocatable,
FindAddressForAtom findAddress,
FindAddressForAtom findSectionAddress,
uint64_t imageBaseAddress,
llvm::MutableArrayRef<uint8_t> atomContentBuffer) override;
void appendSectionRelocations(const DefinedAtom &atom,
uint64_t atomSectionOffset,
const Reference &ref,
FindSymbolIndexForAtom symbolIndexForAtom,
FindSectionIndexForAtom sectionIndexForAtom,
FindAddressForAtom addressForAtom,
normalized::Relocations &relocs) override;
bool isDataInCodeTransition(Reference::KindValue refKind) override {
return refKind == modeCode || refKind == modeData;
}
Reference::KindValue dataInCodeTransitionStart(
const MachODefinedAtom &atom) override {
return modeData;
}
Reference::KindValue dataInCodeTransitionEnd(
const MachODefinedAtom &atom) override {
return modeCode;
}
private:
static const Registry::KindStrings _sKindStrings[];
static const StubInfo _sStubInfo;
enum X86Kind : Reference::KindValue {
invalid, /// for error condition
modeCode, /// Content starting at this offset is code.
modeData, /// Content starting at this offset is data.
// Kinds found in mach-o .o files:
branch32, /// ex: call _foo
branch16, /// ex: callw _foo
abs32, /// ex: movl _foo, %eax
funcRel32, /// ex: movl _foo-L1(%eax), %eax
pointer32, /// ex: .long _foo
delta32, /// ex: .long _foo - .
negDelta32, /// ex: .long . - _foo
// Kinds introduced by Passes:
lazyPointer, /// Location contains a lazy pointer.
lazyImmediateLocation, /// Location contains immediate value used in stub.
};
static bool useExternalRelocationTo(const Atom &target);
void applyFixupFinal(const Reference &ref, uint8_t *location,
uint64_t fixupAddress, uint64_t targetAddress,
uint64_t inAtomAddress);
void applyFixupRelocatable(const Reference &ref, uint8_t *location,
uint64_t fixupAddress,
uint64_t targetAddress,
uint64_t inAtomAddress);
};
//===----------------------------------------------------------------------===//
// ArchHandler_x86
//===----------------------------------------------------------------------===//
const Registry::KindStrings ArchHandler_x86::_sKindStrings[] = {
LLD_KIND_STRING_ENTRY(invalid),
LLD_KIND_STRING_ENTRY(modeCode),
LLD_KIND_STRING_ENTRY(modeData),
LLD_KIND_STRING_ENTRY(branch32),
LLD_KIND_STRING_ENTRY(branch16),
LLD_KIND_STRING_ENTRY(abs32),
LLD_KIND_STRING_ENTRY(funcRel32),
LLD_KIND_STRING_ENTRY(pointer32),
LLD_KIND_STRING_ENTRY(delta32),
LLD_KIND_STRING_ENTRY(negDelta32),
LLD_KIND_STRING_ENTRY(lazyPointer),
LLD_KIND_STRING_ENTRY(lazyImmediateLocation),
LLD_KIND_STRING_END
};
const ArchHandler::StubInfo ArchHandler_x86::_sStubInfo = {
"dyld_stub_binder",
// Lazy pointer references
{ Reference::KindArch::x86, pointer32, 0, 0 },
{ Reference::KindArch::x86, lazyPointer, 0, 0 },
// GOT pointer to dyld_stub_binder
{ Reference::KindArch::x86, pointer32, 0, 0 },
// x86 code alignment
1,
// Stub size and code
6,
{ 0xff, 0x25, 0x00, 0x00, 0x00, 0x00 }, // jmp *lazyPointer
{ Reference::KindArch::x86, abs32, 2, 0 },
{ false, 0, 0, 0 },
// Stub Helper size and code
10,
{ 0x68, 0x00, 0x00, 0x00, 0x00, // pushl $lazy-info-offset
0xE9, 0x00, 0x00, 0x00, 0x00 }, // jmp helperhelper
{ Reference::KindArch::x86, lazyImmediateLocation, 1, 0 },
{ Reference::KindArch::x86, branch32, 6, 0 },
// Stub helper image cache content type
DefinedAtom::typeNonLazyPointer,
// Stub Helper-Common size and code
12,
// Stub helper alignment
2,
{ 0x68, 0x00, 0x00, 0x00, 0x00, // pushl $dyld_ImageLoaderCache
0xFF, 0x25, 0x00, 0x00, 0x00, 0x00, // jmp *_fast_lazy_bind
0x90 }, // nop
{ Reference::KindArch::x86, abs32, 1, 0 },
{ false, 0, 0, 0 },
{ Reference::KindArch::x86, abs32, 7, 0 },
{ false, 0, 0, 0 }
};
bool ArchHandler_x86::isCallSite(const Reference &ref) {
return (ref.kindValue() == branch32);
}
bool ArchHandler_x86::isPointer(const Reference &ref) {
return (ref.kindValue() == pointer32);
}
bool ArchHandler_x86::isPairedReloc(const Relocation &reloc) {
if (!reloc.scattered)
return false;
return (reloc.type == GENERIC_RELOC_LOCAL_SECTDIFF) ||
(reloc.type == GENERIC_RELOC_SECTDIFF);
}
llvm::Error
ArchHandler_x86::getReferenceInfo(const Relocation &reloc,
const DefinedAtom *inAtom,
uint32_t offsetInAtom,
uint64_t fixupAddress, bool swap,
FindAtomBySectionAndAddress atomFromAddress,
FindAtomBySymbolIndex atomFromSymbolIndex,
Reference::KindValue *kind,
const lld::Atom **target,
Reference::Addend *addend) {
DefinedAtom::ContentPermissions perms;
const uint8_t *fixupContent = &inAtom->rawContent()[offsetInAtom];
uint64_t targetAddress;
switch (relocPattern(reloc)) {
case GENERIC_RELOC_VANILLA | rPcRel | rExtern | rLength4:
// ex: call _foo (and _foo undefined)
*kind = branch32;
if (auto ec = atomFromSymbolIndex(reloc.symbol, target))
return ec;
*addend = fixupAddress + 4 + (int32_t)*(const little32_t *)fixupContent;
break;
case GENERIC_RELOC_VANILLA | rPcRel | rLength4:
// ex: call _foo (and _foo defined)
*kind = branch32;
targetAddress =
fixupAddress + 4 + (int32_t) * (const little32_t *)fixupContent;
return atomFromAddress(reloc.symbol, targetAddress, target, addend);
break;
case GENERIC_RELOC_VANILLA | rScattered | rPcRel | rLength4:
// ex: call _foo+n (and _foo defined)
*kind = branch32;
targetAddress =
fixupAddress + 4 + (int32_t) * (const little32_t *)fixupContent;
if (auto ec = atomFromAddress(0, reloc.value, target, addend))
return ec;
*addend = targetAddress - reloc.value;
break;
case GENERIC_RELOC_VANILLA | rPcRel | rExtern | rLength2:
// ex: callw _foo (and _foo undefined)
*kind = branch16;
if (auto ec = atomFromSymbolIndex(reloc.symbol, target))
return ec;
*addend = fixupAddress + 2 + (int16_t)*(const little16_t *)fixupContent;
break;
case GENERIC_RELOC_VANILLA | rPcRel | rLength2:
// ex: callw _foo (and _foo defined)
*kind = branch16;
targetAddress =
fixupAddress + 2 + (int16_t) * (const little16_t *)fixupContent;
return atomFromAddress(reloc.symbol, targetAddress, target, addend);
break;
case GENERIC_RELOC_VANILLA | rScattered | rPcRel | rLength2:
// ex: callw _foo+n (and _foo defined)
*kind = branch16;
targetAddress =
fixupAddress + 2 + (int16_t) * (const little16_t *)fixupContent;
if (auto ec = atomFromAddress(0, reloc.value, target, addend))
return ec;
*addend = targetAddress - reloc.value;
break;
case GENERIC_RELOC_VANILLA | rExtern | rLength4:
// ex: movl _foo, %eax (and _foo undefined)
// ex: .long _foo (and _foo undefined)
perms = inAtom->permissions();
*kind =
((perms & DefinedAtom::permR_X) == DefinedAtom::permR_X) ? abs32
: pointer32;
if (auto ec = atomFromSymbolIndex(reloc.symbol, target))
return ec;
*addend = *(const ulittle32_t *)fixupContent;
break;
case GENERIC_RELOC_VANILLA | rLength4:
// ex: movl _foo, %eax (and _foo defined)
// ex: .long _foo (and _foo defined)
perms = inAtom->permissions();
*kind =
((perms & DefinedAtom::permR_X) == DefinedAtom::permR_X) ? abs32
: pointer32;
targetAddress = *(const ulittle32_t *)fixupContent;
return atomFromAddress(reloc.symbol, targetAddress, target, addend);
break;
case GENERIC_RELOC_VANILLA | rScattered | rLength4:
// ex: .long _foo+n (and _foo defined)
perms = inAtom->permissions();
*kind =
((perms & DefinedAtom::permR_X) == DefinedAtom::permR_X) ? abs32
: pointer32;
if (auto ec = atomFromAddress(0, reloc.value, target, addend))
return ec;
*addend = *(const ulittle32_t *)fixupContent - reloc.value;
break;
default:
return llvm::make_error<GenericError>("unsupported i386 relocation type");
}
return llvm::Error::success();
}
llvm::Error
ArchHandler_x86::getPairReferenceInfo(const normalized::Relocation &reloc1,
const normalized::Relocation &reloc2,
const DefinedAtom *inAtom,
uint32_t offsetInAtom,
uint64_t fixupAddress, bool swap,
bool scatterable,
FindAtomBySectionAndAddress atomFromAddr,
FindAtomBySymbolIndex atomFromSymbolIndex,
Reference::KindValue *kind,
const lld::Atom **target,
Reference::Addend *addend) {
const uint8_t *fixupContent = &inAtom->rawContent()[offsetInAtom];
DefinedAtom::ContentPermissions perms = inAtom->permissions();
uint32_t fromAddress;
uint32_t toAddress;
uint32_t value;
const lld::Atom *fromTarget;
Reference::Addend offsetInTo;
Reference::Addend offsetInFrom;
switch (relocPattern(reloc1) << 16 | relocPattern(reloc2)) {
case ((GENERIC_RELOC_SECTDIFF | rScattered | rLength4) << 16 |
GENERIC_RELOC_PAIR | rScattered | rLength4):
case ((GENERIC_RELOC_LOCAL_SECTDIFF | rScattered | rLength4) << 16 |
GENERIC_RELOC_PAIR | rScattered | rLength4):
toAddress = reloc1.value;
fromAddress = reloc2.value;
value = *(const little32_t *)fixupContent;
if (auto ec = atomFromAddr(0, toAddress, target, &offsetInTo))
return ec;
if (auto ec = atomFromAddr(0, fromAddress, &fromTarget, &offsetInFrom))
return ec;
if (fromTarget != inAtom) {
if (*target != inAtom)
return llvm::make_error<GenericError>(
"SECTDIFF relocation where neither target is in atom");
*kind = negDelta32;
*addend = toAddress - value - fromAddress;
*target = fromTarget;
} else {
if ((perms & DefinedAtom::permR_X) == DefinedAtom::permR_X) {
// SECTDIFF relocations are used in i386 codegen where the function
// prolog does a CALL to the next instruction which POPs the return
// address into EBX which becomes the pic-base register. The POP
// instruction is label the used for the subtrahend in expressions.
// The funcRel32 kind represents the 32-bit delta to some symbol from
// the start of the function (atom) containing the funcRel32.
*kind = funcRel32;
uint32_t ta = fromAddress + value - toAddress;
*addend = ta - offsetInFrom;
} else {
*kind = delta32;
*addend = fromAddress + value - toAddress;
}
}
return llvm::Error::success();
break;
default:
return llvm::make_error<GenericError>("unsupported i386 relocation type");
}
}
void ArchHandler_x86::generateAtomContent(const DefinedAtom &atom,
bool relocatable,
FindAddressForAtom findAddress,
FindAddressForAtom findSectionAddress,
uint64_t imageBaseAddress,
llvm::MutableArrayRef<uint8_t> atomContentBuffer) {
// Copy raw bytes.
std::copy(atom.rawContent().begin(), atom.rawContent().end(),
atomContentBuffer.begin());
// Apply fix-ups.
for (const Reference *ref : atom) {
uint32_t offset = ref->offsetInAtom();
const Atom *target = ref->target();
uint64_t targetAddress = 0;
if (isa<DefinedAtom>(target))
targetAddress = findAddress(*target);
uint64_t atomAddress = findAddress(atom);
uint64_t fixupAddress = atomAddress + offset;
if (relocatable) {
applyFixupRelocatable(*ref, &atomContentBuffer[offset],
fixupAddress, targetAddress,
atomAddress);
} else {
applyFixupFinal(*ref, &atomContentBuffer[offset],
fixupAddress, targetAddress,
atomAddress);
}
}
}
void ArchHandler_x86::applyFixupFinal(const Reference &ref, uint8_t *loc,
uint64_t fixupAddress,
uint64_t targetAddress,
uint64_t inAtomAddress) {
if (ref.kindNamespace() != Reference::KindNamespace::mach_o)
return;
assert(ref.kindArch() == Reference::KindArch::x86);
ulittle32_t *loc32 = reinterpret_cast<ulittle32_t *>(loc);
switch (static_cast<X86Kind>(ref.kindValue())) {
case branch32:
*loc32 = (targetAddress - (fixupAddress + 4)) + ref.addend();
break;
case branch16:
*loc32 = (targetAddress - (fixupAddress + 2)) + ref.addend();
break;
case pointer32:
case abs32:
*loc32 = targetAddress + ref.addend();
break;
case funcRel32:
*loc32 = targetAddress - inAtomAddress + ref.addend();
break;
case delta32:
*loc32 = targetAddress - fixupAddress + ref.addend();
break;
case negDelta32:
*loc32 = fixupAddress - targetAddress + ref.addend();
break;
case modeCode:
case modeData:
case lazyPointer:
// do nothing
break;
case lazyImmediateLocation:
*loc32 = ref.addend();
break;
case invalid:
llvm_unreachable("invalid x86 Reference Kind");
break;
}
}
void ArchHandler_x86::applyFixupRelocatable(const Reference &ref,
uint8_t *loc,
uint64_t fixupAddress,
uint64_t targetAddress,
uint64_t inAtomAddress) {
if (ref.kindNamespace() != Reference::KindNamespace::mach_o)
return;
assert(ref.kindArch() == Reference::KindArch::x86);
bool useExternalReloc = useExternalRelocationTo(*ref.target());
ulittle16_t *loc16 = reinterpret_cast<ulittle16_t *>(loc);
ulittle32_t *loc32 = reinterpret_cast<ulittle32_t *>(loc);
switch (static_cast<X86Kind>(ref.kindValue())) {
case branch32:
if (useExternalReloc)
*loc32 = ref.addend() - (fixupAddress + 4);
else
*loc32 =(targetAddress - (fixupAddress+4)) + ref.addend();
break;
case branch16:
if (useExternalReloc)
*loc16 = ref.addend() - (fixupAddress + 2);
else
*loc16 = (targetAddress - (fixupAddress+2)) + ref.addend();
break;
case pointer32:
case abs32:
*loc32 = targetAddress + ref.addend();
break;
case funcRel32:
*loc32 = targetAddress - inAtomAddress + ref.addend(); // FIXME
break;
case delta32:
*loc32 = targetAddress - fixupAddress + ref.addend();
break;
case negDelta32:
*loc32 = fixupAddress - targetAddress + ref.addend();
break;
case modeCode:
case modeData:
case lazyPointer:
case lazyImmediateLocation:
// do nothing
break;
case invalid:
llvm_unreachable("invalid x86 Reference Kind");
break;
}
}
bool ArchHandler_x86::useExternalRelocationTo(const Atom &target) {
// Undefined symbols are referenced via external relocations.
if (isa<UndefinedAtom>(&target))
return true;
if (const DefinedAtom *defAtom = dyn_cast<DefinedAtom>(&target)) {
switch (defAtom->merge()) {
case DefinedAtom::mergeAsTentative:
// Tentative definitions are referenced via external relocations.
return true;
case DefinedAtom::mergeAsWeak:
case DefinedAtom::mergeAsWeakAndAddressUsed:
// Global weak-defs are referenced via external relocations.
return (defAtom->scope() == DefinedAtom::scopeGlobal);
default:
break;
}
}
// Everything else is reference via an internal relocation.
return false;
}
void ArchHandler_x86::appendSectionRelocations(
const DefinedAtom &atom,
uint64_t atomSectionOffset,
const Reference &ref,
FindSymbolIndexForAtom symbolIndexForAtom,
FindSectionIndexForAtom sectionIndexForAtom,
FindAddressForAtom addressForAtom,
normalized::Relocations &relocs) {
if (ref.kindNamespace() != Reference::KindNamespace::mach_o)
return;
assert(ref.kindArch() == Reference::KindArch::x86);
uint32_t sectionOffset = atomSectionOffset + ref.offsetInAtom();
bool useExternalReloc = useExternalRelocationTo(*ref.target());
switch (static_cast<X86Kind>(ref.kindValue())) {
case modeCode:
case modeData:
break;
case branch32:
if (useExternalReloc) {
appendReloc(relocs, sectionOffset, symbolIndexForAtom(*ref.target()), 0,
GENERIC_RELOC_VANILLA | rExtern | rPcRel | rLength4);
} else {
if (ref.addend() != 0)
appendReloc(relocs, sectionOffset, 0, addressForAtom(*ref.target()),
GENERIC_RELOC_VANILLA | rScattered | rPcRel | rLength4);
else
appendReloc(relocs, sectionOffset, sectionIndexForAtom(*ref.target()),0,
GENERIC_RELOC_VANILLA | rPcRel | rLength4);
}
break;
case branch16:
if (useExternalReloc) {
appendReloc(relocs, sectionOffset, symbolIndexForAtom(*ref.target()), 0,
GENERIC_RELOC_VANILLA | rExtern | rPcRel | rLength2);
} else {
if (ref.addend() != 0)
appendReloc(relocs, sectionOffset, 0, addressForAtom(*ref.target()),
GENERIC_RELOC_VANILLA | rScattered | rPcRel | rLength2);
else
appendReloc(relocs, sectionOffset, sectionIndexForAtom(*ref.target()),0,
GENERIC_RELOC_VANILLA | rPcRel | rLength2);
}
break;
case pointer32:
case abs32:
if (useExternalReloc)
appendReloc(relocs, sectionOffset, symbolIndexForAtom(*ref.target()), 0,
GENERIC_RELOC_VANILLA | rExtern | rLength4);
else {
if (ref.addend() != 0)
appendReloc(relocs, sectionOffset, 0, addressForAtom(*ref.target()),
GENERIC_RELOC_VANILLA | rScattered | rLength4);
else
appendReloc(relocs, sectionOffset, sectionIndexForAtom(*ref.target()), 0,
GENERIC_RELOC_VANILLA | rLength4);
}
break;
case funcRel32:
appendReloc(relocs, sectionOffset, 0, addressForAtom(*ref.target()),
GENERIC_RELOC_SECTDIFF | rScattered | rLength4);
appendReloc(relocs, sectionOffset, 0, addressForAtom(atom) - ref.addend(),
GENERIC_RELOC_PAIR | rScattered | rLength4);
break;
case delta32:
appendReloc(relocs, sectionOffset, 0, addressForAtom(*ref.target()),
GENERIC_RELOC_SECTDIFF | rScattered | rLength4);
appendReloc(relocs, sectionOffset, 0, addressForAtom(atom) +
ref.offsetInAtom(),
GENERIC_RELOC_PAIR | rScattered | rLength4);
break;
case negDelta32:
appendReloc(relocs, sectionOffset, 0, addressForAtom(atom) +
ref.offsetInAtom(),
GENERIC_RELOC_SECTDIFF | rScattered | rLength4);
appendReloc(relocs, sectionOffset, 0, addressForAtom(*ref.target()),
GENERIC_RELOC_PAIR | rScattered | rLength4);
break;
case lazyPointer:
case lazyImmediateLocation:
llvm_unreachable("lazy reference kind implies Stubs pass was run");
break;
case invalid:
llvm_unreachable("unknown x86 Reference Kind");
break;
}
}
std::unique_ptr<mach_o::ArchHandler> ArchHandler::create_x86() {
return std::unique_ptr<mach_o::ArchHandler>(new ArchHandler_x86());
}
} // namespace mach_o
} // namespace lld