namespace lld {
namespace mach_o {
-class KindHandler; // defined in lib. this header is in include.
+class ArchHandler;
}
class MachOLinkingContext : public LinkingContext {
virtual uint64_t pageZeroSize() const { return _pageZeroSize; }
virtual uint64_t pageSize() const { return _pageSize; }
- mach_o::KindHandler &kindHandler() const;
+ mach_o::ArchHandler &archHandler() const;
HeaderFileType outputMachOType() const { return _outputMachOType; }
StringRef dyldPath() const { return "/usr/lib/dyld"; }
+ /// Stub creation Pass should be run.
+ bool needsStubsPass() const;
+
+ // GOT createion Pass should be run.
+ bool needsGOTPass() const;
+
+ /// Magic symbol name stubs will need to help lazy bind.
+ StringRef binderSymbolName() const;
+
static Arch archFromCpuType(uint32_t cputype, uint32_t cpusubtype);
static Arch archFromName(StringRef archName);
static StringRef nameFromArch(Arch arch);
bool _printAtoms;
bool _testingLibResolution;
StringRef _bundleLoader;
- mutable std::unique_ptr<mach_o::KindHandler> _kindHandler;
+ mutable std::unique_ptr<mach_o::ArchHandler> _archHandler;
mutable std::unique_ptr<Writer> _writer;
};
class LinkingContext;
class PECOFFLinkingContext;
class TargetHandlerBase;
+class MachOLinkingContext;
/// \brief An abstract class for reading object files, library files, and
/// executable files.
void addSupportNativeObjects();
void addSupportCOFFObjects(PECOFFLinkingContext &);
void addSupportCOFFImportLibraries();
- void addSupportMachOObjects(StringRef archName);
+ void addSupportMachOObjects(const MachOLinkingContext &);
void addSupportELFObjects(bool atomizeStrings, TargetHandlerBase *handler);
void addSupportELFDynamicSharedObjects(bool useShlibUndefines,
TargetHandlerBase *handler);
return true;
// Register possible input file parsers.
- ctx.registry().addSupportMachOObjects(ctx.archName());
+ ctx.registry().addSupportMachOObjects(ctx);
ctx.registry().addSupportArchives(ctx.logInputFiles());
ctx.registry().addSupportNativeObjects();
ctx.registry().addSupportYamlFiles();
--- /dev/null
+//===- lib/FileFormat/MachO/ArchHandler.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/ErrorHandling.h"
+
+using namespace llvm::MachO;
+using namespace lld::mach_o::normalized;
+
+namespace lld {
+namespace mach_o {
+
+
+ArchHandler::ArchHandler() {
+}
+
+ArchHandler::~ArchHandler() {
+}
+
+std::unique_ptr<mach_o::ArchHandler> ArchHandler::create(
+ MachOLinkingContext::Arch arch) {
+ switch (arch) {
+ case MachOLinkingContext::arch_x86_64:
+ return create_x86_64();
+ case MachOLinkingContext::arch_x86:
+ return create_x86();
+ case MachOLinkingContext::arch_armv6:
+ case MachOLinkingContext::arch_armv7:
+ case MachOLinkingContext::arch_armv7s:
+ return create_arm();
+ default:
+ llvm_unreachable("Unknown arch");
+ }
+}
+
+
+bool ArchHandler::isLazyPointer(const Reference &ref) {
+ // A lazy bind entry is needed for a lazy pointer.
+ const StubInfo &info = stubInfo();
+ if (ref.kindNamespace() != Reference::KindNamespace::mach_o)
+ return false;
+ if (ref.kindArch() != info.lazyPointerReferenceToFinal.arch)
+ return false;
+ return (ref.kindValue() == info.lazyPointerReferenceToFinal.kind);
+}
+
+
+ArchHandler::RelocPattern ArchHandler::relocPattern(const Relocation &reloc) {
+ assert((reloc.type & 0xFFF0) == 0);
+ uint16_t result = reloc.type;
+ if (reloc.scattered)
+ result |= rScattered;
+ if (reloc.pcRel)
+ result |= rPcRel;
+ if (reloc.isExtern)
+ result |= rExtern;
+ switch(reloc.length) {
+ case 0:
+ break;
+ case 1:
+ result |= rLength2;
+ break;
+ case 2:
+ result |= rLength4;
+ break;
+ case 3:
+ result |= rLength8;
+ break;
+ default:
+ llvm_unreachable("bad r_length");
+ }
+ return result;
+}
+
+int16_t ArchHandler::readS16(bool swap, const uint8_t *addr) {
+ return read16(swap, *reinterpret_cast<const uint16_t*>(addr));
+}
+
+int32_t ArchHandler::readS32(bool swap, const uint8_t *addr) {
+ return read32(swap, *reinterpret_cast<const uint32_t*>(addr));
+}
+
+uint32_t ArchHandler::readU32(bool swap, const uint8_t *addr) {
+ return read32(swap, *reinterpret_cast<const uint32_t*>(addr));
+}
+
+int64_t ArchHandler::readS64(bool swap, const uint8_t *addr) {
+ return read64(swap, *reinterpret_cast<const uint64_t*>(addr));
+}
+
+} // namespace mach_o
+} // namespace lld
+
+
+
--- /dev/null
+//===- lib/FileFormat/MachO/ArchHandler.h ---------------------------------===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "MachONormalizedFile.h"
+
+#include "lld/Core/LLVM.h"
+#include "lld/Core/Reference.h"
+#include "lld/Core/Simple.h"
+#include "lld/ReaderWriter/MachOLinkingContext.h"
+
+#include "llvm/ADT/Triple.h"
+
+#ifndef LLD_READER_WRITER_MACHO_ARCH_HANDLER_H
+#define LLD_READER_WRITER_MACHO_ARCH_HANDLER_H
+
+namespace lld {
+namespace mach_o {
+
+///
+/// The ArchHandler class handles all architecture specific aspects of
+/// mach-o linking.
+///
+class ArchHandler {
+public:
+ virtual ~ArchHandler();
+
+ /// There is no public interface to subclasses of ArchHandler, so this
+ /// is the only way to instantiate an ArchHandler.
+ static std::unique_ptr<ArchHandler> create(MachOLinkingContext::Arch arch);
+
+ /// Get (arch specific) kind strings used by Registry.
+ virtual const Registry::KindStrings *kindStrings() = 0;
+
+ /// Convert mach-o Arch to Reference::KindArch.
+ virtual Reference::KindArch kindArch() = 0;
+
+ /// Used by StubPass to update References to shared library functions
+ /// to be references to a stub.
+ virtual bool isCallSite(const Reference &) = 0;
+
+ /// Used by GOTPass to locate GOT References
+ virtual bool isGOTAccess(const Reference &, bool &canBypassGOT) {
+ return false;
+ }
+
+ /// Used by GOTPass to update GOT References
+ virtual void updateReferenceToGOT(const Reference *, bool targetIsNowGOT) {}
+
+ /// Used by normalizedFromAtoms() to know where to generated rebasing and
+ /// binding info in final executables.
+ virtual bool isPointer(const Reference &) = 0;
+
+ /// Used by normalizedFromAtoms() to know where to generated lazy binding
+ /// info in final executables.
+ virtual bool isLazyPointer(const Reference &);
+
+ /// Returns true if the specified relocation is paired to the next relocation.
+ virtual bool isPairedReloc(const normalized::Relocation &) = 0;
+
+ /// Prototype for a helper function. Given a sectionIndex and address,
+ /// finds the atom and offset with that atom of that address.
+ typedef std::function<std::error_code (uint32_t sectionIndex, uint64_t addr,
+ const lld::Atom **, Reference::Addend *)>
+ FindAtomBySectionAndAddress;
+
+ /// Prototype for a helper function. Given a symbolIndex, finds the atom
+ /// representing that symbol.
+ typedef std::function<std::error_code (uint32_t symbolIndex,
+ const lld::Atom **)> FindAtomBySymbolIndex;
+
+ /// Analyzes a relocation from a .o file and returns the info
+ /// (kind, target, addend) needed to instantiate a Reference.
+ /// Two helper functions are passed as parameters to find the target atom
+ /// given a symbol index or address.
+ virtual std::error_code
+ 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) = 0;
+
+ /// Analyzes a pair of relocations from a .o file and returns the info
+ /// (kind, target, addend) needed to instantiate a Reference.
+ /// Two helper functions are passed as parameters to find the target atom
+ /// given a symbol index or address.
+ virtual std::error_code
+ getPairReferenceInfo(const normalized::Relocation &reloc1,
+ const normalized::Relocation &reloc2,
+ 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) = 0;
+
+ /// Fixup an atom when generating a final linked binary.
+ virtual void applyFixup(Reference::KindNamespace ns, Reference::KindArch arch,
+ Reference::KindValue kindValue, uint64_t addend,
+ uint8_t *location, uint64_t fixupAddress,
+ uint64_t targetAddress, uint64_t inAtomAddress) = 0;
+
+ struct ReferenceInfo {
+ Reference::KindArch arch;
+ uint16_t kind;
+ uint32_t offset;
+ int32_t addend;
+ };
+
+ /// Table of architecture specific information for creating stubs.
+ struct StubInfo {
+ const char* binderSymbolName;
+ ReferenceInfo lazyPointerReferenceToHelper;
+ ReferenceInfo lazyPointerReferenceToFinal;
+ ReferenceInfo nonLazyPointerReferenceToBinder;
+ uint8_t codeAlignment;
+
+ uint32_t stubSize;
+ uint8_t stubBytes[16];
+ ReferenceInfo stubReferenceToLP;
+
+ uint32_t stubHelperSize;
+ uint8_t stubHelperBytes[16];
+ ReferenceInfo stubHelperReferenceToImm;
+ ReferenceInfo stubHelperReferenceToHelperCommon;
+
+ uint32_t stubHelperCommonSize;
+ uint8_t stubHelperCommonBytes[36];
+ ReferenceInfo stubHelperCommonReferenceToCache;
+ ReferenceInfo stubHelperCommonReferenceToBinder;
+ };
+
+ virtual const StubInfo &stubInfo() = 0;
+
+protected:
+ ArchHandler();
+
+ static std::unique_ptr<mach_o::ArchHandler> create_x86_64();
+ static std::unique_ptr<mach_o::ArchHandler> create_x86();
+ static std::unique_ptr<mach_o::ArchHandler> create_arm();
+
+ // Handy way to pack mach-o r_type and other bit fields into one 16-bit value.
+ typedef uint16_t RelocPattern;
+ enum {
+ rScattered = 0x8000,
+ rPcRel = 0x4000,
+ rExtern = 0x2000,
+ rLength1 = 0x0000,
+ rLength2 = 0x0100,
+ rLength4 = 0x0200,
+ rLength8 = 0x0300
+ };
+ static RelocPattern relocPattern(const normalized::Relocation &reloc);
+
+ static int16_t readS16(bool swap, const uint8_t *addr);
+ static int32_t readS32(bool swap, const uint8_t *addr);
+ static uint32_t readU32(bool swap, const uint8_t *addr);
+ static int64_t readS64(bool swap, const uint8_t *addr);
+};
+
+} // namespace mach_o
+} // namespace lld
+
+#endif // LLD_READER_WRITER_MACHO_ARCH_HANDLER_H
--- /dev/null
+//===- lib/FileFormat/MachO/ArchHandler_arm.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/ErrorHandling.h"
+
+using namespace llvm::MachO;
+using namespace lld::mach_o::normalized;
+
+namespace lld {
+namespace mach_o {
+
+class ArchHandler_arm : public ArchHandler {
+public:
+ ArchHandler_arm();
+ virtual ~ArchHandler_arm();
+
+ const Registry::KindStrings *kindStrings() override { return _sKindStrings; }
+
+ Reference::KindArch kindArch() override { return Reference::KindArch::ARM; }
+
+ const ArchHandler::StubInfo &stubInfo() override;
+ bool isCallSite(const Reference &) override;
+ bool isPointer(const Reference &) override;
+ bool isPairedReloc(const normalized::Relocation &) override;
+ std::error_code 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;
+ std::error_code
+ getPairReferenceInfo(const normalized::Relocation &reloc1,
+ const normalized::Relocation &reloc2,
+ 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;
+
+ void applyFixup(Reference::KindNamespace ns, Reference::KindArch arch,
+ Reference::KindValue kindValue, uint64_t addend,
+ uint8_t *location, uint64_t fixupAddress,
+ uint64_t targetAddress, uint64_t inAtomAddress)
+ override;
+
+private:
+ static const Registry::KindStrings _sKindStrings[];
+ static const StubInfo _sStubInfoArmPIC;
+
+ enum : Reference::KindValue {
+ invalid, /// for error condition
+
+ // Kinds found in mach-o .o files:
+ thumb_b22, /// ex: bl _foo
+ thumb_movw, /// ex: movw r1, :lower16:_foo
+ thumb_movt, /// ex: movt r1, :lower16:_foo
+ thumb_movw_funcRel, /// ex: movw r1, :lower16:(_foo-(L1+4))
+ thumb_movt_funcRel, /// ex: movt r1, :upper16:(_foo-(L1+4))
+ arm_b24, /// ex: bl _foo
+ arm_movw, /// ex: movw r1, :lower16:_foo
+ arm_movt, /// ex: movt r1, :lower16:_foo
+ arm_movw_funcRel, /// ex: movw r1, :lower16:(_foo-(L1+4))
+ arm_movt_funcRel, /// ex: movt r1, :upper16:(_foo-(L1+4))
+ pointer32, /// ex: .long _foo
+ delta32, /// ex: .long _foo - .
+
+ // Kinds introduced by Passes:
+ lazyPointer, /// Location contains a lazy pointer.
+ lazyImmediateLocation, /// Location contains immediate value used in stub.
+ };
+
+ int32_t getDisplacementFromThumbBranch(uint32_t instruction);
+ int32_t getDisplacementFromArmBranch(uint32_t instruction);
+ uint16_t getWordFromThumbMov(uint32_t instruction);
+ uint16_t getWordFromArmMov(uint32_t instruction);
+ uint32_t clearThumbBit(uint32_t value, const Atom *target);
+ uint32_t setDisplacementInArmBranch(uint32_t instruction, int32_t disp);
+
+
+ const bool _swap;
+};
+
+//===----------------------------------------------------------------------===//
+// ArchHandler_arm
+//===----------------------------------------------------------------------===//
+
+ArchHandler_arm::ArchHandler_arm() :
+ _swap(!MachOLinkingContext::isHostEndian(MachOLinkingContext::arch_armv7)) {}
+
+ArchHandler_arm::~ArchHandler_arm() { }
+
+const Registry::KindStrings ArchHandler_arm::_sKindStrings[] = {
+ LLD_KIND_STRING_ENTRY(thumb_b22),
+ LLD_KIND_STRING_ENTRY(thumb_movw),
+ LLD_KIND_STRING_ENTRY(thumb_movt),
+ LLD_KIND_STRING_ENTRY(thumb_movw_funcRel),
+ LLD_KIND_STRING_ENTRY(thumb_movt_funcRel),
+ LLD_KIND_STRING_ENTRY(arm_b24),
+ LLD_KIND_STRING_ENTRY(arm_movw),
+ LLD_KIND_STRING_ENTRY(arm_movt),
+ LLD_KIND_STRING_ENTRY(arm_movw_funcRel),
+ LLD_KIND_STRING_ENTRY(arm_movt_funcRel),
+ LLD_KIND_STRING_ENTRY(pointer32),
+ LLD_KIND_STRING_ENTRY(delta32),
+ LLD_KIND_STRING_ENTRY(lazyPointer),
+ LLD_KIND_STRING_ENTRY(lazyImmediateLocation),
+ LLD_KIND_STRING_END
+};
+
+const ArchHandler::StubInfo ArchHandler_arm::_sStubInfoArmPIC = {
+ "dyld_stub_binder",
+
+ // References in lazy pointer
+ { Reference::KindArch::ARM, pointer32, 0, 0 },
+ { Reference::KindArch::ARM, lazyPointer, 0, 0 },
+
+ // GOT pointer to dyld_stub_binder
+ { Reference::KindArch::ARM, pointer32, 0, 0 },
+
+ // arm code alignment 2^2
+ 2,
+
+ // Stub size and code
+ 16,
+ { 0x04, 0xC0, 0x9F, 0xE5, // ldr ip, pc + 12
+ 0x0C, 0xC0, 0x8F, 0xE0, // add ip, pc, ip
+ 0x00, 0xF0, 0x9C, 0xE5, // ldr pc, [ip]
+ 0x00, 0x00, 0x00, 0x00 }, // .long L_foo$lazy_ptr - (L1$scv + 8)
+ { Reference::KindArch::ARM, delta32, 12, 0 },
+
+ // Stub Helper size and code
+ 12,
+ { 0x00, 0xC0, 0x9F, 0xE5, // ldr ip, [pc, #0]
+ 0x00, 0x00, 0x00, 0xEA, // b _helperhelper
+ 0x00, 0x00, 0x00, 0x00 }, // .long lazy-info-offset
+ { Reference::KindArch::ARM, lazyImmediateLocation, 8, 0 },
+ { Reference::KindArch::ARM, arm_b24, 4, 0 },
+
+ // Stub Helper-Common size and code
+ 36,
+ { // push lazy-info-offset
+ 0x04, 0xC0, 0x2D, 0xE5, // str ip, [sp, #-4]!
+ // push address of dyld_mageLoaderCache
+ 0x10, 0xC0, 0x9F, 0xE5, // ldr ip, L1
+ 0x0C, 0xC0, 0x8F, 0xE0, // add ip, pc, ip
+ 0x04, 0xC0, 0x2D, 0xE5, // str ip, [sp, #-4]!
+ // jump through dyld_stub_binder
+ 0x08, 0xC0, 0x9F, 0xE5, // ldr ip, L2
+ 0x0C, 0xC0, 0x8F, 0xE0, // add ip, pc, ip
+ 0x00, 0xF0, 0x9C, 0xE5, // ldr pc, [ip]
+ 0x00, 0x00, 0x00, 0x00, // L1: .long fFastStubGOTAtom - (helper+16)
+ 0x00, 0x00, 0x00, 0x00 }, // L2: .long dyld_stub_binder - (helper+28)
+ { Reference::KindArch::ARM, delta32, 28, 0 },
+ { Reference::KindArch::ARM, delta32, 32, 0 }
+};
+
+const ArchHandler::StubInfo &ArchHandler_arm::stubInfo() {
+ // If multiple kinds of stubs are supported, select which StubInfo here.
+ return _sStubInfoArmPIC;
+}
+
+bool ArchHandler_arm::isCallSite(const Reference &ref) {
+ return (ref.kindValue() == thumb_b22) || (ref.kindValue() == arm_b24);
+}
+
+bool ArchHandler_arm::isPointer(const Reference &ref) {
+ return (ref.kindValue() == pointer32);
+}
+
+bool ArchHandler_arm::isPairedReloc(const Relocation &reloc) {
+ switch (reloc.type) {
+ case ARM_RELOC_SECTDIFF:
+ case ARM_RELOC_LOCAL_SECTDIFF:
+ case ARM_RELOC_HALF_SECTDIFF:
+ case ARM_RELOC_HALF:
+ return true;
+ default:
+ return false;
+ }
+}
+
+int32_t ArchHandler_arm::getDisplacementFromThumbBranch(uint32_t instruction) {
+ uint32_t s = (instruction >> 10) & 0x1;
+ uint32_t j1 = (instruction >> 29) & 0x1;
+ uint32_t j2 = (instruction >> 27) & 0x1;
+ uint32_t imm10 = instruction & 0x3FF;
+ uint32_t imm11 = (instruction >> 16) & 0x7FF;
+ uint32_t i1 = (j1 == s);
+ uint32_t i2 = (j2 == s);
+ uint32_t dis =
+ (s << 24) | (i1 << 23) | (i2 << 22) | (imm10 << 12) | (imm11 << 1);
+ int32_t sdis = dis;
+ if (s)
+ return (sdis | 0xFE000000);
+ else
+ return sdis;
+}
+
+int32_t ArchHandler_arm::getDisplacementFromArmBranch(uint32_t instruction) {
+ // Sign-extend imm24
+ int32_t displacement = (instruction & 0x00FFFFFF) << 2;
+ if ((displacement & 0x02000000) != 0)
+ displacement |= 0xFC000000;
+ // If this is BLX and H bit set, add 2.
+ if ((instruction & 0xFF000000) == 0xFB000000)
+ displacement += 2;
+ return displacement;
+}
+
+uint32_t ArchHandler_arm::setDisplacementInArmBranch(uint32_t instruction,
+ int32_t displacement) {
+ // FIXME: handle BLX and out-of-range.
+ uint32_t newInstruction = (instruction & 0xFF000000);
+ newInstruction |= ((displacement >> 2) & 0x00FFFFFF);
+ return newInstruction;
+}
+
+uint16_t ArchHandler_arm::getWordFromThumbMov(uint32_t instruction) {
+ uint32_t i = ((instruction & 0x00000400) >> 10);
+ uint32_t imm4 = (instruction & 0x0000000F);
+ uint32_t imm3 = ((instruction & 0x70000000) >> 28);
+ uint32_t imm8 = ((instruction & 0x00FF0000) >> 16);
+ return (imm4 << 12) | (i << 11) | (imm3 << 8) | imm8;
+}
+
+uint16_t ArchHandler_arm::getWordFromArmMov(uint32_t instruction) {
+ uint32_t imm4 = ((instruction & 0x000F0000) >> 16);
+ uint32_t imm12 = (instruction & 0x00000FFF);
+ return (imm4 << 12) | imm12;
+}
+
+uint32_t ArchHandler_arm::clearThumbBit(uint32_t value, const Atom *target) {
+ // The assembler often adds one to the address of a thumb function.
+ // We need to undo that so it does not look like an addend.
+ if (value & 1) {
+ if (isa<DefinedAtom>(target)) {
+ const MachODefinedAtom *machoTarget =
+ reinterpret_cast<const MachODefinedAtom *>(target);
+ if (machoTarget->isThumb())
+ value &= -2; // mask off thumb-bit
+ }
+ }
+ return value;
+}
+
+std::error_code ArchHandler_arm::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) {
+ typedef std::error_code E;
+ const uint8_t *fixupContent = &inAtom->rawContent()[offsetInAtom];
+ uint64_t targetAddress;
+ uint32_t instruction = readU32(swap, fixupContent);
+ int32_t displacement;
+ switch (relocPattern(reloc)) {
+ case ARM_THUMB_RELOC_BR22 | rPcRel | rExtern | rLength4:
+ // ex: bl _foo (and _foo is undefined)
+ *kind = thumb_b22;
+ if (E ec = atomFromSymbolIndex(reloc.symbol, target))
+ return ec;
+ // Instruction contains branch to addend.
+ displacement = getDisplacementFromThumbBranch(instruction);
+ *addend = fixupAddress + 4 + displacement;
+ return std::error_code();
+ case ARM_THUMB_RELOC_BR22 | rPcRel | rLength4:
+ // ex: bl _foo (and _foo is defined)
+ *kind = thumb_b22;
+ displacement = getDisplacementFromThumbBranch(instruction);
+ targetAddress = fixupAddress + 4 + displacement;
+ return atomFromAddress(reloc.symbol, targetAddress, target, addend);
+ case ARM_THUMB_RELOC_BR22 | rScattered | rPcRel | rLength4:
+ // ex: bl _foo+4 (and _foo is defined)
+ *kind = thumb_b22;
+ displacement = getDisplacementFromThumbBranch(instruction);
+ targetAddress = fixupAddress + 4 + displacement;
+ if (E ec = atomFromAddress(0, reloc.value, target, addend))
+ return ec;
+ // reloc.value is target atom's address. Instruction contains branch
+ // to atom+addend.
+ *addend += (targetAddress - reloc.value);
+ return std::error_code();
+ case ARM_RELOC_BR24 | rPcRel | rExtern | rLength4:
+ // ex: bl _foo (and _foo is undefined)
+ *kind = arm_b24;
+ if (E ec = atomFromSymbolIndex(reloc.symbol, target))
+ return ec;
+ // Instruction contains branch to addend.
+ displacement = getDisplacementFromArmBranch(instruction);
+ *addend = fixupAddress + 8 + displacement;
+ return std::error_code();
+ case ARM_RELOC_BR24 | rPcRel | rLength4:
+ // ex: bl _foo (and _foo is defined)
+ *kind = arm_b24;
+ displacement = getDisplacementFromArmBranch(instruction);
+ targetAddress = fixupAddress + 8 + displacement;
+ return atomFromAddress(reloc.symbol, targetAddress, target, addend);
+ case ARM_RELOC_BR24 | rScattered | rPcRel | rLength4:
+ // ex: bl _foo+4 (and _foo is defined)
+ *kind = arm_b24;
+ displacement = getDisplacementFromArmBranch(instruction);
+ targetAddress = fixupAddress + 8 + displacement;
+ if (E ec = atomFromAddress(0, reloc.value, target, addend))
+ return ec;
+ // reloc.value is target atom's address. Instruction contains branch
+ // to atom+addend.
+ *addend += (targetAddress - reloc.value);
+ return std::error_code();
+ case ARM_RELOC_VANILLA | rExtern | rLength4:
+ // ex: .long _foo (and _foo is undefined)
+ *kind = pointer32;
+ if (E ec = atomFromSymbolIndex(reloc.symbol, target))
+ return ec;
+ *addend = instruction;
+ return std::error_code();
+ case ARM_RELOC_VANILLA | rLength4:
+ // ex: .long _foo (and _foo is defined)
+ *kind = pointer32;
+ if (E ec = atomFromAddress(reloc.symbol, instruction, target, addend))
+ return ec;
+ *addend = clearThumbBit((uint32_t) * addend, *target);
+ return std::error_code();
+ case ARM_RELOC_VANILLA | rScattered | rLength4:
+ // ex: .long _foo+a (and _foo is defined)
+ *kind = pointer32;
+ if (E ec = atomFromAddress(0, reloc.value, target, addend))
+ return ec;
+ *addend += (clearThumbBit(instruction, *target) - reloc.value);
+ return std::error_code();
+ default:
+ return make_dynamic_error_code(Twine("unsupported arm relocation type"));
+ }
+ return std::error_code();
+}
+
+std::error_code
+ArchHandler_arm::getPairReferenceInfo(const normalized::Relocation &reloc1,
+ const normalized::Relocation &reloc2,
+ const DefinedAtom *inAtom,
+ uint32_t offsetInAtom,
+ uint64_t fixupAddress, bool swap,
+ FindAtomBySectionAndAddress atomFromAddr,
+ FindAtomBySymbolIndex atomFromSymbolIndex,
+ Reference::KindValue *kind,
+ const lld::Atom **target,
+ Reference::Addend *addend) {
+ bool pointerDiff = false;
+ bool funcRel;
+ bool top;
+ bool thumbReloc;
+ switch(relocPattern(reloc1) << 16 | relocPattern(reloc2)) {
+ case ((ARM_RELOC_HALF_SECTDIFF | rScattered | rLength4) << 16 |
+ ARM_RELOC_PAIR | rScattered | rLength4):
+ // ex: movw r1, :lower16:(_x-L1) [thumb mode]
+ *kind = thumb_movw_funcRel;
+ funcRel = true;
+ top = false;
+ thumbReloc = true;
+ break;
+ case ((ARM_RELOC_HALF_SECTDIFF | rScattered | rLength8) << 16 |
+ ARM_RELOC_PAIR | rScattered | rLength8):
+ // ex: movt r1, :upper16:(_x-L1) [thumb mode]
+ *kind = thumb_movt_funcRel;
+ funcRel = true;
+ top = true;
+ thumbReloc = true;
+ break;
+ case ((ARM_RELOC_HALF_SECTDIFF | rScattered | rLength1) << 16 |
+ ARM_RELOC_PAIR | rScattered | rLength1):
+ // ex: movw r1, :lower16:(_x-L1) [arm mode]
+ *kind = arm_movw_funcRel;
+ funcRel = true;
+ top = false;
+ thumbReloc = false;
+ break;
+ case ((ARM_RELOC_HALF_SECTDIFF | rScattered | rLength2) << 16 |
+ ARM_RELOC_PAIR | rScattered | rLength2):
+ // ex: movt r1, :upper16:(_x-L1) [arm mode]
+ *kind = arm_movt_funcRel;
+ funcRel = true;
+ top = true;
+ thumbReloc = false;
+ break;
+ case ((ARM_RELOC_HALF | rLength4) << 16 |
+ ARM_RELOC_PAIR | rLength4):
+ // ex: movw r1, :lower16:_x [thumb mode]
+ *kind = thumb_movw;
+ funcRel = false;
+ top = false;
+ thumbReloc = true;
+ break;
+ case ((ARM_RELOC_HALF | rLength8) << 16 |
+ ARM_RELOC_PAIR | rLength8):
+ // ex: movt r1, :upper16:_x [thumb mode]
+ *kind = thumb_movt;
+ funcRel = false;
+ top = true;
+ thumbReloc = true;
+ break;
+ case ((ARM_RELOC_HALF | rLength1) << 16 |
+ ARM_RELOC_PAIR | rLength1):
+ // ex: movw r1, :lower16:_x [arm mode]
+ *kind = arm_movw;
+ funcRel = false;
+ top = false;
+ thumbReloc = false;
+ break;
+ case ((ARM_RELOC_HALF | rLength2) << 16 |
+ ARM_RELOC_PAIR | rLength2):
+ // ex: movt r1, :upper16:_x [arm mode]
+ *kind = arm_movt;
+ funcRel = false;
+ top = true;
+ thumbReloc = false;
+ break;
+ case ((ARM_RELOC_HALF | rScattered | rLength4) << 16 |
+ ARM_RELOC_PAIR | rLength4):
+ // ex: movw r1, :lower16:_x+a [thumb mode]
+ *kind = thumb_movw;
+ funcRel = false;
+ top = false;
+ thumbReloc = true;
+ break;
+ case ((ARM_RELOC_HALF | rScattered | rLength8) << 16 |
+ ARM_RELOC_PAIR | rLength8):
+ // ex: movt r1, :upper16:_x+a [thumb mode]
+ *kind = thumb_movt;
+ funcRel = false;
+ top = true;
+ thumbReloc = true;
+ break;
+ case ((ARM_RELOC_HALF | rScattered | rLength1) << 16 |
+ ARM_RELOC_PAIR | rLength1):
+ // ex: movw r1, :lower16:_x+a [arm mode]
+ *kind = arm_movw;
+ funcRel = false;
+ top = false;
+ thumbReloc = false;
+ break;
+ case ((ARM_RELOC_HALF | rScattered | rLength2) << 16 |
+ ARM_RELOC_PAIR | rLength2):
+ // ex: movt r1, :upper16:_x+a [arm mode]
+ *kind = arm_movt;
+ funcRel = false;
+ top = true;
+ thumbReloc = false;
+ break;
+ case ((ARM_RELOC_HALF | rExtern | rLength4) << 16 |
+ ARM_RELOC_PAIR | rLength4):
+ // ex: movw r1, :lower16:_undef [thumb mode]
+ *kind = thumb_movw;
+ funcRel = false;
+ top = false;
+ thumbReloc = true;
+ break;
+ case ((ARM_RELOC_HALF | rExtern | rLength8) << 16 |
+ ARM_RELOC_PAIR | rLength8):
+ // ex: movt r1, :upper16:_undef [thumb mode]
+ *kind = thumb_movt;
+ funcRel = false;
+ top = true;
+ thumbReloc = true;
+ break;
+ case ((ARM_RELOC_HALF | rExtern | rLength1) << 16 |
+ ARM_RELOC_PAIR | rLength1):
+ // ex: movw r1, :lower16:_undef [arm mode]
+ *kind = arm_movw;
+ funcRel = false;
+ top = false;
+ thumbReloc = false;
+ break;
+ case ((ARM_RELOC_HALF | rExtern | rLength2) << 16 |
+ ARM_RELOC_PAIR | rLength2):
+ // ex: movt r1, :upper16:_undef [arm mode]
+ *kind = arm_movt;
+ funcRel = false;
+ top = true;
+ thumbReloc = false;
+ break;
+ case ((ARM_RELOC_SECTDIFF | rScattered | rLength4) << 16 |
+ ARM_RELOC_PAIR | rScattered | rLength4):
+ case ((ARM_RELOC_LOCAL_SECTDIFF | rScattered | rLength4) << 16 |
+ ARM_RELOC_PAIR | rScattered | rLength4):
+ // ex: .long _foo - .
+ pointerDiff = true;
+ break;
+ default:
+ return make_dynamic_error_code(Twine("unsupported arm relocation pair"));
+ }
+ const uint8_t *fixupContent = &inAtom->rawContent()[offsetInAtom];
+ std::error_code ec;
+ uint32_t instruction = readU32(swap, fixupContent);
+ uint32_t value;
+ uint32_t fromAddress;
+ uint32_t toAddress;
+ uint16_t instruction16;
+ uint16_t other16;
+ const lld::Atom *fromTarget;
+ Reference::Addend offsetInTo;
+ Reference::Addend offsetInFrom;
+ if (pointerDiff) {
+ toAddress = reloc1.value;
+ fromAddress = reloc2.value;
+ ec = atomFromAddr(0, toAddress, target, &offsetInTo);
+ if (ec)
+ return ec;
+ ec = atomFromAddr(0, fromAddress, &fromTarget, &offsetInFrom);
+ if (ec)
+ return ec;
+ if (fromTarget != inAtom)
+ return make_dynamic_error_code(Twine("SECTDIFF relocation where "
+ "subtrahend label is not in atom"));
+ *kind = delta32;
+ value = clearThumbBit(instruction, *target);
+ *addend = value - (toAddress - fromAddress);
+ } else if (funcRel) {
+ toAddress = reloc1.value;
+ fromAddress = reloc2.value;
+ ec = atomFromAddr(0, toAddress, target, &offsetInTo);
+ if (ec)
+ return ec;
+ ec = atomFromAddr(0, fromAddress, &fromTarget, &offsetInFrom);
+ if (ec)
+ return ec;
+ if (fromTarget != inAtom)
+ return make_dynamic_error_code(
+ Twine("ARM_RELOC_HALF_SECTDIFF relocation "
+ "where subtrahend label is not in atom"));
+ other16 = (reloc2.offset & 0xFFFF);
+ if (thumbReloc)
+ instruction16 = getWordFromThumbMov(instruction);
+ else
+ instruction16 = getWordFromArmMov(instruction);
+ if (top)
+ value = (instruction16 << 16) | other16;
+ else
+ value = (other16 << 16) | instruction16;
+ value = clearThumbBit(value, *target);
+ int64_t ta = (int64_t) value - (toAddress - fromAddress);
+ *addend = ta - offsetInFrom;
+ return std::error_code();
+ } else {
+ uint32_t sectIndex;
+ if (thumbReloc)
+ instruction16 = getWordFromThumbMov(instruction);
+ else
+ instruction16 = getWordFromArmMov(instruction);
+ other16 = (reloc2.offset & 0xFFFF);
+ if (top)
+ value = (instruction16 << 16) | other16;
+ else
+ value = (other16 << 16) | instruction16;
+ if (reloc1.isExtern) {
+ ec = atomFromSymbolIndex(reloc1.symbol, target);
+ if (ec)
+ return ec;
+ *addend = value;
+ } else {
+ if (reloc1.scattered) {
+ toAddress = reloc1.value;
+ sectIndex = 0;
+ } else {
+ toAddress = value;
+ sectIndex = reloc1.symbol;
+ }
+ ec = atomFromAddr(sectIndex, toAddress, target, &offsetInTo);
+ if (ec)
+ return ec;
+ *addend = value - toAddress;
+ }
+ }
+
+ return std::error_code();
+}
+
+void ArchHandler_arm::applyFixup(Reference::KindNamespace ns,
+ Reference::KindArch arch,
+ Reference::KindValue kindValue,
+ uint64_t addend, uint8_t *location,
+ uint64_t fixupAddress, uint64_t targetAddress,
+ uint64_t inAtomAddress) {
+ if (ns != Reference::KindNamespace::mach_o)
+ return;
+ assert(arch == Reference::KindArch::ARM);
+ int32_t *loc32 = reinterpret_cast<int32_t *>(location);
+ int32_t displacement;
+ // FIXME: these writes may need a swap.
+ switch (kindValue) {
+ case thumb_b22:
+ // FIXME
+ break;
+ case thumb_movw:
+ // FIXME
+ break;
+ case thumb_movt:
+ // FIXME
+ break;
+ case thumb_movw_funcRel:
+ // FIXME
+ break;
+ case thumb_movt_funcRel:
+ // FIXME
+ break;
+ case arm_b24:
+ displacement = (targetAddress - (fixupAddress + 8)) + addend;
+ *loc32 = setDisplacementInArmBranch(*loc32, displacement);
+ break;
+ case arm_movw:
+ // FIXME
+ break;
+ case arm_movt:
+ // FIXME
+ break;
+ case arm_movw_funcRel:
+ // FIXME
+ break;
+ case arm_movt_funcRel:
+ // FIXME
+ break;
+ case pointer32:
+ // FIXME
+ break;
+ case delta32:
+ // FIXME
+ break;
+ case lazyPointer:
+ case lazyImmediateLocation:
+ // do nothing
+ break;
+ case invalid:
+ llvm_unreachable("invalid ARM Reference Kind");
+ break;
+ }
+}
+
+std::unique_ptr<mach_o::ArchHandler> ArchHandler::create_arm() {
+ return std::unique_ptr<mach_o::ArchHandler>(new ArchHandler_arm());
+}
+
+} // namespace mach_o
+} // namespace lld
--- /dev/null
+//===- 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/ErrorHandling.h"
+
+using namespace llvm::MachO;
+using namespace lld::mach_o::normalized;
+
+namespace lld {
+namespace mach_o {
+
+class ArchHandler_x86 : public ArchHandler {
+public:
+ ArchHandler_x86();
+ virtual ~ArchHandler_x86();
+
+ 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 isPointer(const Reference &) override;
+ bool isPairedReloc(const normalized::Relocation &) override;
+ std::error_code 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;
+ std::error_code
+ getPairReferenceInfo(const normalized::Relocation &reloc1,
+ const normalized::Relocation &reloc2,
+ 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;
+
+ void applyFixup(Reference::KindNamespace ns, Reference::KindArch arch,
+ Reference::KindValue kindValue, uint64_t addend,
+ uint8_t *location, uint64_t fixupAddress,
+ uint64_t targetAddress, uint64_t inAtomAddress)
+ override;
+
+private:
+ static const Registry::KindStrings _sKindStrings[];
+ static const StubInfo _sStubInfo;
+
+ enum : Reference::KindValue {
+ invalid, /// for error condition
+
+ // 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 - .
+
+ // Kinds introduced by Passes:
+ lazyPointer, /// Location contains a lazy pointer.
+ lazyImmediateLocation, /// Location contains immediate value used in stub.
+ };
+
+ const bool _swap;
+};
+
+//===----------------------------------------------------------------------===//
+// ArchHandler_x86
+//===----------------------------------------------------------------------===//
+
+ArchHandler_x86::ArchHandler_x86() :
+ _swap(!MachOLinkingContext::isHostEndian(MachOLinkingContext::arch_x86)) {}
+
+ArchHandler_x86::~ArchHandler_x86() { }
+
+const Registry::KindStrings ArchHandler_x86::_sKindStrings[] = {
+ LLD_KIND_STRING_ENTRY(invalid),
+ 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(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 },
+
+ // 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-Common size and code
+ 12,
+ { 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 },
+ { Reference::KindArch::x86, abs32, 7, 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);
+}
+
+std::error_code
+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) {
+ typedef std::error_code E;
+ 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 (E ec = atomFromSymbolIndex(reloc.symbol, target))
+ return ec;
+ *addend = fixupAddress + 4 + readS32(swap, fixupContent);
+ break;
+ case GENERIC_RELOC_VANILLA | rPcRel | rLength4:
+ // ex: call _foo (and _foo defined)
+ *kind = branch32;
+ targetAddress = fixupAddress + 4 + readS32(swap, fixupContent);
+ return atomFromAddress(reloc.symbol, targetAddress, target, addend);
+ break;
+ case GENERIC_RELOC_VANILLA | rPcRel | rExtern | rLength2:
+ // ex: callw _foo (and _foo undefined)
+ *kind = branch16;
+ if (E ec = atomFromSymbolIndex(reloc.symbol, target))
+ return ec;
+ *addend = fixupAddress + 2 + readS16(swap, fixupContent);
+ break;
+ case GENERIC_RELOC_VANILLA | rPcRel | rLength2:
+ // ex: callw _foo (and _foo defined)
+ *kind = branch16;
+ targetAddress = fixupAddress + 2 + readS16(swap, fixupContent);
+ return atomFromAddress(reloc.symbol, targetAddress, target, addend);
+ 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 (E ec = atomFromSymbolIndex(reloc.symbol, target))
+ return ec;
+ *addend = readU32(swap, 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 = readU32(swap, fixupContent);
+ return atomFromAddress(reloc.symbol, targetAddress, target, addend);
+ break;
+ default:
+ return make_dynamic_error_code(Twine("unsupported i386 relocation type"));
+ }
+ return std::error_code();
+}
+
+std::error_code
+ArchHandler_x86::getPairReferenceInfo(const normalized::Relocation &reloc1,
+ const normalized::Relocation &reloc2,
+ const DefinedAtom *inAtom,
+ uint32_t offsetInAtom,
+ uint64_t fixupAddress, bool swap,
+ FindAtomBySectionAndAddress atomFromAddr,
+ FindAtomBySymbolIndex atomFromSymbolIndex,
+ Reference::KindValue *kind,
+ const lld::Atom **target,
+ Reference::Addend *addend) {
+ const uint8_t *fixupContent = &inAtom->rawContent()[offsetInAtom];
+ std::error_code ec;
+ 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 = readS32(swap, fixupContent);
+ ec = atomFromAddr(0, toAddress, target, &offsetInTo);
+ if (ec)
+ return ec;
+ ec = atomFromAddr(0, fromAddress, &fromTarget, &offsetInFrom);
+ if (ec)
+ return ec;
+ if (fromTarget != inAtom)
+ return make_dynamic_error_code(Twine("SECTDIFF relocation where "
+ "subtrahend label is not in atom"));
+ *kind = ((perms & DefinedAtom::permR_X) == DefinedAtom::permR_X) ? funcRel32
+ : delta32;
+ if (*kind == funcRel32) {
+ // 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.
+ uint32_t ta = fromAddress + value - toAddress;
+ *addend = ta - offsetInFrom;
+ } else {
+ *addend = fromAddress + value - toAddress;
+ }
+ return std::error_code();
+ break;
+ default:
+ return make_dynamic_error_code(Twine("unsupported i386 relocation type"));
+ }
+}
+
+void ArchHandler_x86::applyFixup(Reference::KindNamespace ns,
+ Reference::KindArch arch,
+ Reference::KindValue kindValue,
+ uint64_t addend, uint8_t *location,
+ uint64_t fixupAddress, uint64_t targetAddress,
+ uint64_t inAtomAddress) {
+ if (ns != Reference::KindNamespace::mach_o)
+ return;
+ assert(arch == Reference::KindArch::x86);
+ int32_t *loc32 = reinterpret_cast<int32_t *>(location);
+ int16_t *loc16 = reinterpret_cast<int16_t *>(location);
+ switch (kindValue) {
+ case branch32:
+ write32(*loc32, _swap, (targetAddress - (fixupAddress + 4)) + addend);
+ break;
+ case branch16:
+ write16(*loc16, _swap, (targetAddress - (fixupAddress + 4)) + addend);
+ break;
+ case pointer32:
+ case abs32:
+ write32(*loc32, _swap, targetAddress + addend);
+ break;
+ case funcRel32:
+ write32(*loc32, _swap, targetAddress - inAtomAddress + addend); // FIXME
+ break;
+ case delta32:
+ write32(*loc32, _swap, targetAddress - fixupAddress + addend);
+ break;
+ case lazyPointer:
+ case lazyImmediateLocation:
+ // do nothing
+ break;
+ default:
+ llvm_unreachable("invalid 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
--- /dev/null
+//===- lib/FileFormat/MachO/ArchHandler_x86_64.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/ErrorHandling.h"
+
+using namespace llvm::MachO;
+using namespace lld::mach_o::normalized;
+
+namespace lld {
+namespace mach_o {
+
+class ArchHandler_x86_64 : public ArchHandler {
+public:
+ ArchHandler_x86_64();
+ virtual ~ArchHandler_x86_64();
+
+ const Registry::KindStrings *kindStrings() override { return _sKindStrings; }
+
+ Reference::KindArch kindArch() override {
+ return Reference::KindArch::x86_64;
+ }
+
+ /// Used by GOTPass to locate GOT References
+ bool isGOTAccess(const Reference &ref, bool &canBypassGOT) override {
+ if (ref.kindNamespace() != Reference::KindNamespace::mach_o)
+ return false;
+ assert(ref.kindArch() == Reference::KindArch::x86_64);
+ switch (ref.kindValue()) {
+ case ripRel32GotLoad:
+ canBypassGOT = true;
+ return true;
+ case ripRel32Got:
+ canBypassGOT = false;
+ return true;
+ default:
+ return false;
+ }
+ }
+
+ /// Used by GOTPass to update GOT References
+ void updateReferenceToGOT(const Reference *ref, bool targetNowGOT) override {
+ assert(ref->kindNamespace() == Reference::KindNamespace::mach_o);
+ assert(ref->kindArch() == Reference::KindArch::x86_64);
+ const_cast<Reference *>(ref)
+ ->setKindValue(targetNowGOT ? ripRel32 : ripRel32GotLoadNowLea);
+ }
+
+ const StubInfo &stubInfo() override { return _sStubInfo; }
+
+ bool isCallSite(const Reference &) override;
+ bool isPointer(const Reference &) override;
+ bool isPairedReloc(const normalized::Relocation &) override;
+ std::error_code 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;
+ std::error_code
+ getPairReferenceInfo(const normalized::Relocation &reloc1,
+ const normalized::Relocation &reloc2,
+ 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;
+
+ virtual void applyFixup(Reference::KindNamespace ns, Reference::KindArch arch,
+ Reference::KindValue kindValue, uint64_t addend,
+ uint8_t *location, uint64_t fixupAddress,
+ uint64_t targetAddress, uint64_t inAtomAddress)
+ override;
+
+private:
+ static const Registry::KindStrings _sKindStrings[];
+ static const StubInfo _sStubInfo;
+
+ enum : Reference::KindValue {
+ invalid, /// for error condition
+
+ // Kinds found in mach-o .o files:
+ branch32, /// ex: call _foo
+ ripRel32, /// ex: movq _foo(%rip), %rax
+ ripRel32Minus1, /// ex: movb $0x12, _foo(%rip)
+ ripRel32Minus2, /// ex: movw $0x1234, _foo(%rip)
+ ripRel32Minus4, /// ex: movl $0x12345678, _foo(%rip)
+ ripRel32Anon, /// ex: movq L1(%rip), %rax
+ ripRel32GotLoad, /// ex: movq _foo@GOTPCREL(%rip), %rax
+ ripRel32Got, /// ex: pushq _foo@GOTPCREL(%rip)
+ pointer64, /// ex: .quad _foo
+ pointer64Anon, /// ex: .quad L1
+ delta64, /// ex: .quad _foo - .
+ delta32, /// ex: .long _foo - .
+ delta64Anon, /// ex: .quad L1 - .
+ delta32Anon, /// ex: .long L1 - .
+
+ // Kinds introduced by Passes:
+ ripRel32GotLoadNowLea, /// Target of GOT load is in linkage unit so
+ /// "movq _foo@GOTPCREL(%rip), %rax" can be changed
+ /// to "leaq _foo(%rip), %rax
+ lazyPointer, /// Location contains a lazy pointer.
+ lazyImmediateLocation, /// Location contains immediate value used in stub.
+ };
+
+ Reference::KindValue kindFromReloc(const normalized::Relocation &reloc);
+ Reference::KindValue kindFromRelocPair(const normalized::Relocation &reloc1,
+ const normalized::Relocation &reloc2);
+
+ const bool _swap;
+};
+
+
+ArchHandler_x86_64::ArchHandler_x86_64() :
+ _swap(!MachOLinkingContext::isHostEndian(MachOLinkingContext::arch_x86_64)) {}
+
+ArchHandler_x86_64::~ArchHandler_x86_64() { }
+
+const Registry::KindStrings ArchHandler_x86_64::_sKindStrings[] = {
+ LLD_KIND_STRING_ENTRY(invalid), LLD_KIND_STRING_ENTRY(branch32),
+ LLD_KIND_STRING_ENTRY(ripRel32), LLD_KIND_STRING_ENTRY(ripRel32Minus1),
+ LLD_KIND_STRING_ENTRY(ripRel32Minus2), LLD_KIND_STRING_ENTRY(ripRel32Minus4),
+ LLD_KIND_STRING_ENTRY(ripRel32Anon), LLD_KIND_STRING_ENTRY(ripRel32GotLoad),
+ LLD_KIND_STRING_ENTRY(ripRel32GotLoadNowLea),
+ LLD_KIND_STRING_ENTRY(ripRel32Got), LLD_KIND_STRING_ENTRY(lazyPointer),
+ LLD_KIND_STRING_ENTRY(lazyImmediateLocation),
+ LLD_KIND_STRING_ENTRY(pointer64), LLD_KIND_STRING_ENTRY(pointer64Anon),
+ LLD_KIND_STRING_ENTRY(delta32), LLD_KIND_STRING_ENTRY(delta64),
+ LLD_KIND_STRING_ENTRY(delta32Anon), LLD_KIND_STRING_ENTRY(delta64Anon),
+ LLD_KIND_STRING_END
+};
+
+const ArchHandler::StubInfo ArchHandler_x86_64::_sStubInfo = {
+ "dyld_stub_binder",
+
+ // Lazy pointer references
+ { Reference::KindArch::x86_64, pointer64, 0, 0 },
+ { Reference::KindArch::x86_64, lazyPointer, 0, 0 },
+
+ // GOT pointer to dyld_stub_binder
+ { Reference::KindArch::x86_64, pointer64, 0, 0 },
+
+ // x86_64 code alignment 2^1
+ 1,
+
+ // Stub size and code
+ 6,
+ { 0xff, 0x25, 0x00, 0x00, 0x00, 0x00 }, // jmp *lazyPointer
+ { Reference::KindArch::x86_64, ripRel32, 2, 0 },
+
+ // Stub Helper size and code
+ 10,
+ { 0x68, 0x00, 0x00, 0x00, 0x00, // pushq $lazy-info-offset
+ 0xE9, 0x00, 0x00, 0x00, 0x00 }, // jmp helperhelper
+ { Reference::KindArch::x86_64, lazyImmediateLocation, 1, 0 },
+ { Reference::KindArch::x86_64, branch32, 6, 0 },
+
+ // Stub Helper-Common size and code
+ 16,
+ { 0x4C, 0x8D, 0x1D, 0x00, 0x00, 0x00, 0x00, // leaq cache(%rip),%r11
+ 0x41, 0x53, // push %r11
+ 0xFF, 0x25, 0x00, 0x00, 0x00, 0x00, // jmp *binder(%rip)
+ 0x90 }, // nop
+ { Reference::KindArch::x86_64, ripRel32, 3, 0 },
+ { Reference::KindArch::x86_64, ripRel32, 11, 0 }
+
+};
+
+bool ArchHandler_x86_64::isCallSite(const Reference &ref) {
+ if (ref.kindNamespace() != Reference::KindNamespace::mach_o)
+ return false;
+ assert(ref.kindArch() == Reference::KindArch::x86_64);
+ return (ref.kindValue() == branch32);
+}
+
+bool ArchHandler_x86_64::isPointer(const Reference &ref) {
+ if (ref.kindNamespace() != Reference::KindNamespace::mach_o)
+ return false;
+ assert(ref.kindArch() == Reference::KindArch::x86_64);
+ Reference::KindValue kind = ref.kindValue();
+ return (kind == pointer64 || kind == pointer64Anon);
+}
+
+bool ArchHandler_x86_64::isPairedReloc(const Relocation &reloc) {
+ return (reloc.type == X86_64_RELOC_SUBTRACTOR);
+}
+
+Reference::KindValue
+ArchHandler_x86_64::kindFromReloc(const Relocation &reloc) {
+ switch(relocPattern(reloc)) {
+ case X86_64_RELOC_BRANCH | rPcRel | rExtern | rLength4:
+ return branch32;
+ case X86_64_RELOC_SIGNED | rPcRel | rExtern | rLength4:
+ return ripRel32;
+ case X86_64_RELOC_SIGNED | rPcRel | rLength4:
+ return ripRel32Anon;
+ case X86_64_RELOC_SIGNED_1 | rPcRel | rExtern | rLength4:
+ return ripRel32Minus1;
+ case X86_64_RELOC_SIGNED_2 | rPcRel | rExtern | rLength4:
+ return ripRel32Minus2;
+ case X86_64_RELOC_SIGNED_4 | rPcRel | rExtern | rLength4:
+ return ripRel32Minus4;
+ case X86_64_RELOC_GOT_LOAD | rPcRel | rExtern | rLength4:
+ return ripRel32GotLoad;
+ case X86_64_RELOC_GOT | rPcRel | rExtern | rLength4:
+ return ripRel32Got;
+ case X86_64_RELOC_UNSIGNED | rExtern | rLength8:
+ return pointer64;
+ case X86_64_RELOC_UNSIGNED | rLength8:
+ return pointer64Anon;
+ default:
+ return invalid;
+ }
+}
+
+std::error_code
+ArchHandler_x86_64::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) {
+ typedef std::error_code E;
+ *kind = kindFromReloc(reloc);
+ if (*kind == invalid)
+ return make_dynamic_error_code(Twine("unknown type"));
+ const uint8_t *fixupContent = &inAtom->rawContent()[offsetInAtom];
+ uint64_t targetAddress;
+ switch (*kind) {
+ case branch32:
+ case ripRel32:
+ if (E ec = atomFromSymbolIndex(reloc.symbol, target))
+ return ec;
+ *addend = readS32(swap, fixupContent);
+ return std::error_code();
+ case ripRel32Minus1:
+ if (E ec = atomFromSymbolIndex(reloc.symbol, target))
+ return ec;
+ *addend = readS32(swap, fixupContent) + 1;
+ return std::error_code();
+ case ripRel32Minus2:
+ if (E ec = atomFromSymbolIndex(reloc.symbol, target))
+ return ec;
+ *addend = readS32(swap, fixupContent) + 2;
+ return std::error_code();
+ case ripRel32Minus4:
+ if (E ec = atomFromSymbolIndex(reloc.symbol, target))
+ return ec;
+ *addend = readS32(swap, fixupContent) + 4;
+ return std::error_code();
+ case ripRel32Anon:
+ targetAddress = fixupAddress + 4 + readS32(swap, fixupContent);
+ return atomFromAddress(reloc.symbol, targetAddress, target, addend);
+ case ripRel32GotLoad:
+ case ripRel32Got:
+ if (E ec = atomFromSymbolIndex(reloc.symbol, target))
+ return ec;
+ *addend = 0;
+ return std::error_code();
+ case pointer64:
+ if (E ec = atomFromSymbolIndex(reloc.symbol, target))
+ return ec;
+ *addend = readS64(swap, fixupContent);
+ return std::error_code();
+ case pointer64Anon:
+ targetAddress = readS64(swap, fixupContent);
+ return atomFromAddress(reloc.symbol, targetAddress, target, addend);
+ default:
+ llvm_unreachable("bad reloc kind");
+ }
+}
+
+Reference::KindValue
+ArchHandler_x86_64::kindFromRelocPair(const normalized::Relocation &reloc1,
+ const normalized::Relocation &reloc2) {
+ switch(relocPattern(reloc1) << 16 | relocPattern(reloc2)) {
+ case ((X86_64_RELOC_SUBTRACTOR | rExtern | rLength8) << 16 |
+ X86_64_RELOC_UNSIGNED | rExtern | rLength8):
+ return delta64;
+ case ((X86_64_RELOC_SUBTRACTOR | rExtern | rLength4) << 16 |
+ X86_64_RELOC_UNSIGNED | rExtern | rLength4):
+ return delta32;
+ case ((X86_64_RELOC_SUBTRACTOR | rExtern | rLength8) << 16 |
+ X86_64_RELOC_UNSIGNED | rLength8):
+ return delta64Anon;
+ case ((X86_64_RELOC_SUBTRACTOR | rExtern | rLength4) << 16 |
+ X86_64_RELOC_UNSIGNED | rLength4):
+ return delta32Anon;
+ default:
+ llvm_unreachable("bad reloc pairs");
+ }
+}
+
+std::error_code
+ArchHandler_x86_64::getPairReferenceInfo(const normalized::Relocation &reloc1,
+ const normalized::Relocation &reloc2,
+ 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) {
+ *kind = kindFromRelocPair(reloc1, reloc2);
+ if (*kind == invalid)
+ return make_dynamic_error_code(Twine("unknown pair"));
+ const uint8_t *fixupContent = &inAtom->rawContent()[offsetInAtom];
+ typedef std::error_code E;
+ uint64_t targetAddress;
+ const lld::Atom *fromTarget;
+ if (E ec = atomFromSymbolIndex(reloc1.symbol, &fromTarget))
+ return ec;
+ if (fromTarget != inAtom)
+ return make_dynamic_error_code(Twine("pointer diff not in base atom"));
+ switch (*kind) {
+ case delta64:
+ if (E ec = atomFromSymbolIndex(reloc2.symbol, target))
+ return ec;
+ *addend = readS64(swap, fixupContent) + offsetInAtom;
+ return std::error_code();
+ case delta32:
+ if (E ec = atomFromSymbolIndex(reloc2.symbol, target))
+ return ec;
+ *addend = readS32(swap, fixupContent) + offsetInAtom;
+ return std::error_code();
+ case delta64Anon:
+ targetAddress = offsetInAtom + readS64(swap, fixupContent);
+ return atomFromAddress(reloc2.symbol, targetAddress, target, addend);
+ case delta32Anon:
+ targetAddress = offsetInAtom + readS32(swap, fixupContent);
+ return atomFromAddress(reloc2.symbol, targetAddress, target, addend);
+ default:
+ llvm_unreachable("bad reloc pair kind");
+ }
+}
+
+void ArchHandler_x86_64::applyFixup(Reference::KindNamespace ns,
+ Reference::KindArch arch,
+ Reference::KindValue kindValue,
+ uint64_t addend, uint8_t *location,
+ uint64_t fixupAddress,
+ uint64_t targetAddress,
+ uint64_t inAtomAddress) {
+ if (ns != Reference::KindNamespace::mach_o)
+ return;
+ assert(arch == Reference::KindArch::x86_64);
+ int32_t *loc32 = reinterpret_cast<int32_t *>(location);
+ uint64_t *loc64 = reinterpret_cast<uint64_t *>(location);
+ switch (kindValue) {
+ case branch32:
+ case ripRel32:
+ case ripRel32Got:
+ case ripRel32GotLoad:
+ write32(*loc32, _swap, (targetAddress - (fixupAddress + 4)) + addend);
+ break;
+ case pointer64:
+ case pointer64Anon:
+ write64(*loc64, _swap, targetAddress + addend);
+ break;
+ case ripRel32Minus1:
+ write32(*loc32, _swap, (targetAddress - (fixupAddress + 5)) + addend);
+ break;
+ case ripRel32Minus2:
+ write32(*loc32, _swap, (targetAddress - (fixupAddress + 6)) + addend);
+ break;
+ case ripRel32Minus4:
+ write32(*loc32, _swap, (targetAddress - (fixupAddress + 8)) + addend);
+ break;
+ case delta32:
+ case delta32Anon:
+ write32(*loc32, _swap, (targetAddress - fixupAddress) + addend);
+ break;
+ case delta64:
+ case delta64Anon:
+ write64(*loc64, _swap, (targetAddress - fixupAddress) + addend);
+ break;
+ case ripRel32GotLoadNowLea:
+ // Change MOVQ to LEA
+ assert(location[-2] == 0x8B);
+ location[-2] = 0x8D;
+ write32(*loc32, _swap, (targetAddress - (fixupAddress + 4)) + addend);
+ break;
+ case lazyPointer:
+ case lazyImmediateLocation:
+ // do nothing
+ break;
+ default:
+ llvm_unreachable("invalid x86_64 Reference Kind");
+ break;
+ }
+}
+
+std::unique_ptr<mach_o::ArchHandler> ArchHandler::create_x86_64() {
+ return std::unique_ptr<mach_o::ArchHandler>(new ArchHandler_x86_64());
+}
+
+} // namespace mach_o
+} // namespace lld
add_lld_library(lldMachO
+ ArchHandler.cpp
+ ArchHandler_arm.cpp
+ ArchHandler_x86.cpp
+ ArchHandler_x86_64.cpp
GOTPass.cpp
MachOLinkingContext.cpp
MachONormalizedFileBinaryReader.cpp
MachONormalizedFileFromAtoms.cpp
MachONormalizedFileToAtoms.cpp
MachONormalizedFileYAML.cpp
- ReferenceKinds.cpp
StubsPass.cpp
WriterMachO.cpp
)
class CRuntimeFile : public SimpleFile {
public:
CRuntimeFile(const MachOLinkingContext &context)
- : SimpleFile("C runtime"), _undefMain(*this, context.entrySymbolName()) {
+ : SimpleFile("C runtime"),
+ _undefMain(*this, context.entrySymbolName()),
+ _undefBinder(*this, context.binderSymbolName()) {
// only main executables need _main
if (context.outputMachOType() == llvm::MachO::MH_EXECUTE) {
this->addAtom(_undefMain);
}
+ // only dynamic binaries use stubs
+ if (context.needsStubsPass()) {
+ this->addAtom(_undefBinder);
+ }
}
private:
SimpleUndefinedAtom _undefMain;
+ SimpleUndefinedAtom _undefBinder;
};
} // namespace mach_o
#ifndef LLD_READER_WRITER_MACHO_FILE_H
#define LLD_READER_WRITER_MACHO_FILE_H
-#include "llvm/ADT/StringMap.h"
-
#include "Atoms.h"
+#include "MachONormalizedFile.h"
#include "lld/Core/Simple.h"
#include "lld/Core/SharedLibraryFile.h"
+#include "llvm/ADT/StringMap.h"
+
#include <unordered_map>
namespace lld {
return pos->second;
}
+ llvm::BumpPtrAllocator &allocator() { return _allocator; }
+
private:
struct SectionOffsetAndAtom { uint64_t offset; MachODefinedAtom *atom; };
///
//===----------------------------------------------------------------------===//
+#include "ArchHandler.h"
+#include "File.h"
+#include "MachOPasses.h"
+
#include "lld/Core/DefinedAtom.h"
#include "lld/Core/File.h"
#include "lld/Core/LLVM.h"
#include "lld/Core/Reference.h"
+#include "lld/Core/Simple.h"
+
#include "llvm/ADT/DenseMap.h"
-#include "MachOPasses.h"
namespace lld {
+namespace mach_o {
+
+
+//
+// GOT Entry Atom created by the GOT pass.
+//
+class GOTEntryAtom : public SimpleDefinedAtom {
+public:
+ GOTEntryAtom(const File &file, bool is64)
+ : SimpleDefinedAtom(file), _is64(is64) { }
-static bool shouldReplaceTargetWithGOTAtom(const Atom *target,
- bool canBypassGOT) {
- // Accesses to shared library symbols must go through GOT.
- if (target->definition() == Atom::definitionSharedLibrary)
- return true;
- // Accesses to interposable symbols in same linkage unit must also go
- // through GOT.
- const DefinedAtom *defTarget = dyn_cast<DefinedAtom>(target);
- if (defTarget != nullptr &&
- defTarget->interposable() != DefinedAtom::interposeNo) {
- assert(defTarget->scope() != DefinedAtom::scopeTranslationUnit);
- return true;
+ ContentType contentType() const override {
+ return DefinedAtom::typeGOT;
}
- // Target does not require indirection. So, if instruction allows GOT to be
- // by-passed, do that optimization and don't create GOT entry.
- return !canBypassGOT;
-}
-static const DefinedAtom *
-findGOTAtom(const Atom *target,
- llvm::DenseMap<const Atom *, const DefinedAtom *> &targetToGOT) {
- auto pos = targetToGOT.find(target);
- return (pos == targetToGOT.end()) ? nullptr : pos->second;
-}
+ Alignment alignment() const override {
+ return Alignment(_is64 ? 3 : 2);
+ }
-void GOTPass::perform(std::unique_ptr<MutableFile> &mergedFile) {
- // Use map so all pointers to same symbol use same GOT entry.
- llvm::DenseMap<const Atom*, const DefinedAtom*> targetToGOT;
-
- // Scan all references in all atoms.
- for (const DefinedAtom *atom : mergedFile->defined()) {
- for (const Reference *ref : *atom) {
- // Look at instructions accessing the GOT.
- bool canBypassGOT;
- if (!isGOTAccess(*ref, canBypassGOT))
- continue;
- const Atom *target = ref->target();
- assert(target != nullptr);
-
- if (!shouldReplaceTargetWithGOTAtom(target, canBypassGOT)) {
- // Update reference kind to reflect that target is a direct accesss.
- updateReferenceToGOT(ref, false);
- continue;
- }
- // Replace the target with a reference to a GOT entry.
- const DefinedAtom *gotEntry = findGOTAtom(target, targetToGOT);
- if (!gotEntry) {
- gotEntry = makeGOTEntry(*target);
- assert(gotEntry != nullptr);
- assert(gotEntry->contentType() == DefinedAtom::typeGOT);
- targetToGOT[target] = gotEntry;
+ uint64_t size() const override {
+ return _is64 ? 8 : 4;
+ }
+
+ ContentPermissions permissions() const override {
+ return DefinedAtom::permRW_;
+ }
+
+ ArrayRef<uint8_t> rawContent() const override {
+ static const uint8_t zeros[] =
+ { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
+ return llvm::makeArrayRef(zeros, size());
+ }
+
+private:
+ const bool _is64;
+};
+
+
+/// Pass for instantiating and optimizing GOT slots.
+///
+class GOTPass : public Pass {
+public:
+ GOTPass(const MachOLinkingContext &context)
+ : _context(context), _archHandler(_context.archHandler()),
+ _file("<mach-o GOT Pass>") { }
+
+private:
+
+ void perform(std::unique_ptr<MutableFile> &mergedFile) override {
+ // Scan all references in all atoms.
+ for (const DefinedAtom *atom : mergedFile->defined()) {
+ for (const Reference *ref : *atom) {
+ // Look at instructions accessing the GOT.
+ bool canBypassGOT;
+ if (!_archHandler.isGOTAccess(*ref, canBypassGOT))
+ continue;
+ const Atom *target = ref->target();
+ assert(target != nullptr);
+
+ if (!shouldReplaceTargetWithGOTAtom(target, canBypassGOT)) {
+ // Update reference kind to reflect that target is a direct accesss.
+ _archHandler.updateReferenceToGOT(ref, false);
+ } else {
+ // Replace the target with a reference to a GOT entry.
+ const DefinedAtom *gotEntry = makeGOTEntry(target);
+ const_cast<Reference *>(ref)->setTarget(gotEntry);
+ // Update reference kind to reflect that target is now a GOT entry.
+ _archHandler.updateReferenceToGOT(ref, true);
+ }
}
- const_cast<Reference *>(ref)->setTarget(gotEntry);
- // Update reference kind to reflect that target is now a GOT entry.
- updateReferenceToGOT(ref, true);
}
+
+ // add all created GOT Atoms to master file
+ for (auto &it : _targetToGOT)
+ mergedFile->addAtom(*it.second);
+ }
+
+ bool shouldReplaceTargetWithGOTAtom(const Atom *target, bool canBypassGOT) {
+ // Accesses to shared library symbols must go through GOT.
+ if (target->definition() == Atom::definitionSharedLibrary)
+ return true;
+ // Accesses to interposable symbols in same linkage unit must also go
+ // through GOT.
+ const DefinedAtom *defTarget = dyn_cast<DefinedAtom>(target);
+ if (defTarget != nullptr &&
+ defTarget->interposable() != DefinedAtom::interposeNo) {
+ assert(defTarget->scope() != DefinedAtom::scopeTranslationUnit);
+ return true;
+ }
+ // Target does not require indirection. So, if instruction allows GOT to be
+ // by-passed, do that optimization and don't create GOT entry.
+ return !canBypassGOT;
+ }
+
+ const DefinedAtom *makeGOTEntry(const Atom *target) {
+ auto pos = _targetToGOT.find(target);
+ if (pos == _targetToGOT.end()) {
+ GOTEntryAtom *gotEntry = new (_file.allocator())
+ GOTEntryAtom(_file, _context.is64Bit());
+ _targetToGOT[target] = gotEntry;
+ const ArchHandler::ReferenceInfo &nlInfo = _archHandler.stubInfo().
+ nonLazyPointerReferenceToBinder;
+ gotEntry->addReference(Reference::KindNamespace::mach_o, nlInfo.arch,
+ nlInfo.kind, 0, target, 0);
+ return gotEntry;
+ }
+ return pos->second;
}
- // add all created GOT Atoms to master file
- for (auto &it : targetToGOT)
- mergedFile->addAtom(*it.second);
+
+ const MachOLinkingContext &_context;
+ mach_o::ArchHandler &_archHandler;
+ MachOFile _file;
+ llvm::DenseMap<const Atom*, const GOTEntryAtom*> _targetToGOT;
+};
+
+
+
+void addGOTPass(PassManager &pm, const MachOLinkingContext &ctx) {
+ assert(ctx.needsGOTPass());
+ pm.add(std::unique_ptr<Pass>(new GOTPass(ctx)));
}
+
+} // end namesapce mach_o
} // end namesapce lld
namespace mach_o {
-class GOTPass : public lld::GOTPass {
-public:
- bool noTextRelocs() override {
- return true;
- }
-
- bool isGOTAccess(const Reference &, bool &canBypassGOT) override {
- return false;
- }
-
- void updateReferenceToGOT(const Reference*, bool targetIsNowGOT) override {
-
- }
-
- const DefinedAtom* makeGOTEntry(const Atom&) override {
- return nullptr;
- }
-
-};
-
-
} // namespace mach_o
} // namespace lld
//===----------------------------------------------------------------------===//
#include "lld/ReaderWriter/MachOLinkingContext.h"
-#include "GOTPass.hpp"
-#include "StubsPass.hpp"
-#include "ReferenceKinds.h"
+
+#include "ArchHandler.h"
+#include "MachOPasses.h"
#include "lld/Core/PassManager.h"
#include "lld/ReaderWriter/Reader.h"
#include "llvm/Support/MachO.h"
#include "llvm/Support/Path.h"
-using lld::mach_o::KindHandler;
+using lld::mach_o::ArchHandler;
using namespace llvm::MachO;
namespace lld {
_doNothing(false), _arch(arch_unknown), _os(OS::macOSX), _osMinVersion(0),
_pageZeroSize(0), _pageSize(4096), _compatibilityVersion(0),
_currentVersion(0), _deadStrippableDylib(false), _printAtoms(false),
- _testingLibResolution(false), _kindHandler(nullptr) {}
+ _testingLibResolution(false), _archHandler(nullptr) {}
MachOLinkingContext::~MachOLinkingContext() {}
}
}
+bool MachOLinkingContext::needsStubsPass() const {
+ switch (_outputMachOType) {
+ case MH_EXECUTE:
+ return !_outputMachOTypeStatic;
+ case MH_DYLIB:
+ case MH_BUNDLE:
+ return true;
+ default:
+ return false;
+ }
+}
+
+bool MachOLinkingContext::needsGOTPass() const {
+ // Only x86_64 uses GOT pass but not in -r mode.
+ if (_arch != arch_x86_64)
+ return false;
+ return (_outputMachOType != MH_OBJECT);
+}
+
+
+StringRef MachOLinkingContext::binderSymbolName() const {
+ return archHandler().stubInfo().binderSymbolName;
+}
+
+
+
+
bool MachOLinkingContext::minOS(StringRef mac, StringRef iOS) const {
uint32_t parsedVersion;
switch (_os) {
}
void MachOLinkingContext::addPasses(PassManager &pm) {
- if (outputMachOType() != MH_OBJECT) {
- pm.add(std::unique_ptr<Pass>(new mach_o::GOTPass));
- pm.add(std::unique_ptr<Pass>(new mach_o::StubsPass(*this)));
- }
pm.add(std::unique_ptr<Pass>(new LayoutPass(registry())));
+ if (needsStubsPass())
+ mach_o::addStubsPass(pm, *this);
+ if (needsGOTPass())
+ mach_o::addGOTPass(pm, *this);
}
Writer &MachOLinkingContext::writer() const {
return *_writer;
}
-KindHandler &MachOLinkingContext::kindHandler() const {
- if (!_kindHandler)
- _kindHandler = KindHandler::create(_arch);
- return *_kindHandler;
+ArchHandler &MachOLinkingContext::archHandler() const {
+ if (!_archHandler)
+ _archHandler = ArchHandler::create(_arch);
+ return *_archHandler;
}
/// +------------+
#include "MachONormalizedFile.h"
+
+#include "ArchHandler.h"
#include "MachONormalizedFileBinaryUtils.h"
-#include "ReferenceKinds.h"
+
#include "lld/Core/Error.h"
#include "lld/Core/LLVM.h"
#include "llvm/ADT/SmallString.h"
} // namespace normalized
} // namespace mach_o
-void Registry::addSupportMachOObjects(StringRef archName) {
- MachOLinkingContext::Arch arch = MachOLinkingContext::archFromName(archName);
+void Registry::addSupportMachOObjects(const MachOLinkingContext &ctx) {
+ MachOLinkingContext::Arch arch = ctx.arch();
add(std::unique_ptr<Reader>(new mach_o::normalized::MachOReader(arch)));
- switch (arch) {
- case MachOLinkingContext::arch_x86_64:
- addKindTable(Reference::KindNamespace::mach_o, Reference::KindArch::x86_64,
- mach_o::KindHandler_x86_64::kindStrings);
- break;
- case MachOLinkingContext::arch_x86:
- addKindTable(Reference::KindNamespace::mach_o, Reference::KindArch::x86,
- mach_o::KindHandler_x86::kindStrings);
- break;
- case MachOLinkingContext::arch_armv6:
- case MachOLinkingContext::arch_armv7:
- case MachOLinkingContext::arch_armv7s:
- addKindTable(Reference::KindNamespace::mach_o, Reference::KindArch::ARM,
- mach_o::KindHandler_arm::kindStrings);
- break;
- default:
- llvm_unreachable("mach-o arch not supported");
- }
+ addKindTable(Reference::KindNamespace::mach_o, ctx.archHandler().kindArch(),
+ ctx.archHandler().kindStrings());
add(std::unique_ptr<YamlIOTaggedDocumentHandler>(
new mach_o::MachOYamlIOTaggedDocumentHandler(arch)));
}
return (swap ? getSwappedBytes(value) : value);
}
+inline void write16(int16_t &loc, bool swap, int16_t value) {
+ loc = (swap ? getSwappedBytes(value) : value);
+}
+
+inline void write32(int32_t &loc, bool swap, int32_t value) {
+ loc = (swap ? getSwappedBytes(value) : value);
+}
+inline void write64(uint64_t &loc, bool swap, uint64_t value) {
+ loc = (swap ? getSwappedBytes(value) : value);
+}
inline uint32_t
bitFieldExtract(uint32_t value, bool isBigEndianBigField, uint8_t firstBit,
/// +-------+
#include "MachONormalizedFile.h"
+
+#include "ArchHandler.h"
#include "MachONormalizedFileBinaryUtils.h"
-#include "ReferenceKinds.h"
+
#include "lld/Core/Error.h"
#include "lld/Core/LLVM.h"
#include "llvm/ADT/StringRef.h"
// FIXME: Need a handler method to update content for .o file
// output and any needed section relocations.
} else {
- _context.kindHandler().applyFixup(
+ _context.archHandler().applyFixup(
ref->kindNamespace(), ref->kindArch(), ref->kindValue(),
ref->addend(), &atomContent[offset], fixupAddress, targetAddress,
atomAddress);
const Atom *Util::targetOfLazyPointer(const DefinedAtom *lpAtom) {
for (const Reference *ref : *lpAtom) {
- if (_context.kindHandler().isLazyTarget(*ref)) {
+ if (_context.archHandler().isLazyPointer(*ref)) {
return ref->target();
}
}
uint64_t segmentOffset = _atomToAddress[atom] + ref->offsetInAtom()
- segmentStartAddr;
const Atom* targ = ref->target();
- if (_context.kindHandler().isPointer(*ref)) {
+ if (_context.archHandler().isPointer(*ref)) {
// A pointer to a DefinedAtom requires rebasing.
if (dyn_cast<DefinedAtom>(targ)) {
RebaseLocation rebase;
nFile.bindingInfo.push_back(bind);
}
}
- if (_context.kindHandler().isLazyTarget(*ref)) {
+ if (_context.archHandler().isLazyPointer(*ref)) {
BindLocation bind;
bind.segIndex = segmentIndex;
bind.segOffset = segmentOffset;
/// +-------+
#include "MachONormalizedFile.h"
-#include "MachONormalizedFileBinaryUtils.h"
-#include "File.h"
+
+#include "ArchHandler.h"
#include "Atoms.h"
-#include "ReferenceKinds.h"
+#include "File.h"
+#include "MachONormalizedFileBinaryUtils.h"
#include "lld/Core/Error.h"
#include "lld/Core/LLVM.h"
std::error_code convertRelocs(const Section §ion,
const NormalizedFile &normalizedFile,
MachOFile &file,
- KindHandler &handler) {
- // Utility function for KindHandler to find atom by its address.
+ ArchHandler &handler) {
+ // Utility function for ArchHandler to find atom by its address.
auto atomByAddr = [&] (uint32_t sectIndex, uint64_t addr,
const lld::Atom **atom, Reference::Addend *addend)
-> std::error_code {
return std::error_code();
};
- // Utility function for KindHandler to find atom by its symbol index.
+ // Utility function for ArchHandler to find atom by its symbol index.
auto atomBySymbol = [&] (uint32_t symbolIndex, const lld::Atom **result)
-> std::error_code {
// Find symbol from index.
&target, &addend);
}
else {
- // Use KindHandler to convert relocation record into information
+ // Use ArchHandler to convert relocation record into information
// needed to instantiate an lld::Reference object.
relocErr = handler.getReferenceInfo(reloc, inAtom, offsetInAtom,
fixupAddress,swap, atomByAddr,
+ ")" );
} else {
// Instantiate an lld::Reference object and add to its atom.
- Reference::KindArch arch = Reference::KindArch::all;
- switch (normalizedFile.arch ) {
- case lld::MachOLinkingContext::arch_x86_64:
- arch = Reference::KindArch::x86_64;
- break;
- case lld::MachOLinkingContext::arch_x86:
- arch = Reference::KindArch::x86;
- break;
- case lld::MachOLinkingContext::arch_ppc:
- arch = Reference::KindArch::PowerPC;
- break;
- case lld::MachOLinkingContext::arch_armv6:
- case lld::MachOLinkingContext::arch_armv7:
- case lld::MachOLinkingContext::arch_armv7s:
- arch = Reference::KindArch::ARM;
- break;
- case lld::MachOLinkingContext::arch_unknown:
- return make_dynamic_error_code(Twine("unknown architecture"));
- }
-
- inAtom->addReference(offsetInAtom, kind, target, addend, arch);
+ inAtom->addReference(offsetInAtom, kind, target, addend,
+ handler.kindArch());
}
}
return std::error_code();
}
// Convert mach-o relocations to References
- std::unique_ptr<mach_o::KindHandler> handler
- = KindHandler::create(normalizedFile.arch);
+ std::unique_ptr<mach_o::ArchHandler> handler
+ = ArchHandler::create(normalizedFile.arch);
for (auto § : normalizedFile.sections) {
if (isDebugInfoSection(sect))
continue;
#ifndef LLD_READER_WRITER_MACHO_PASSES_H
#define LLD_READER_WRITER_MACHO_PASSES_H
-#include "lld/Core/Atom.h"
-#include "lld/Core/File.h"
-#include "lld/Core/Pass.h"
-#include "lld/Core/range.h"
-#include "lld/Core/Reference.h"
-
-#include <vector>
+#include "lld/Core/PassManager.h"
+#include "lld/ReaderWriter/MachOLinkingContext.h"
namespace lld {
-class DefinedAtom;
-class MutableFile;
-
-
-/// Pass for adding stubs (PLT entries) for calls to functions
-/// outside the linkage unit. This class is subclassed by each
-/// file format Writer which implements the pure virtual methods.
-class StubsPass : public Pass {
-public:
- StubsPass() : Pass() {}
-
- /// Scans all Atoms looking for call-site uses of SharedLibraryAtoms
- /// and transfroms the call-site to call a stub instead using the
- /// helper methods below.
- void perform(std::unique_ptr<MutableFile> &mergedFile) override;
-
- /// If true, the pass should use stubs for references
- /// to shared library symbols. If false, the pass
- /// will generate relocations on the text segment which the
- /// runtime loader will use to patch the program at runtime.
- virtual bool noTextRelocs() = 0;
-
- /// Returns whether the Reference kind is for a call site. The pass
- /// uses this to find calls that need to be indirected through a stub.
- virtual bool isCallSite(const Reference &) = 0;
-
- /// Returns a file format specific atom for a stub/PLT entry which contains
- /// instructions which jump to the specified atom. May be called multiple
- /// times for the same target atom, in which case this method should return
- /// the same stub atom.
- virtual const DefinedAtom *getStub(const Atom &target) = 0;
-
- /// After the default implementation of perform() is done calling getStub(),
- /// it will call this method to add all the stub (and support) atoms to the
- /// master file object.
- virtual void addStubAtoms(MutableFile &masterFile) = 0;
-
-private:
- void replaceCalleeWithStub(const Atom *target, const Reference *ref);
-};
-
-/// Pass for adding GOT entries for pointers to functions/data
-/// outside the linkage unit. This class is subclassed by each
-/// file format Writer which implements the pure virtual methods.
-class GOTPass : public Pass {
-public:
- GOTPass() : Pass() {}
-
- /// Scans all Atoms looking for pointer to SharedLibraryAtoms
- /// and transfroms them to a pointer to a GOT entry using the
- /// helper methods below.
- void perform(std::unique_ptr<MutableFile> &mergedFile) override;
-
- /// If true, the pass will use GOT entries for references
- /// to shared library symbols. If false, the pass
- /// will generate relocations on the text segment which the
- /// runtime loader will use to patch the program at runtime.
- virtual bool noTextRelocs() = 0;
-
- /// Returns whether the Reference kind is a pre-instantiated GOT access.
- /// The default implementation of perform() uses this to figure out
- /// what GOT entries to instantiate.
- virtual bool isGOTAccess(const Reference &, bool &canBypassGOT) = 0;
-
- /// The file format Writer needs to alter the reference kind from a
- /// pre-instantiated GOT access to an actual access. If targetIsNowGOT is
- /// true, the pass has instantiated a GOT atom and altered the reference's
- /// target to point to that atom. If targetIsNowGOT is false, the pass
- /// determined a GOT entry is not needed because the reference site can
- /// directly access the target.
- virtual void updateReferenceToGOT(const Reference*, bool targetIsNowGOT) = 0;
+namespace mach_o {
- /// Returns a file format specific atom for a GOT entry targeting
- /// the specified atom.
- virtual const DefinedAtom *makeGOTEntry(const Atom &target) = 0;
-};
+void addStubsPass(PassManager &pm, const MachOLinkingContext &ctx);
+void addGOTPass(PassManager &pm, const MachOLinkingContext &ctx);
+} // namespace mach_o
} // namespace lld
#endif // LLD_READER_WRITER_MACHO_PASSES_H
+++ /dev/null
-//===- lib/FileFormat/MachO/ReferenceKinds.cpp ----------------------===//
-//
-// The LLVM Linker
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-
-
-#include "ReferenceKinds.h"
-#include "MachONormalizedFileBinaryUtils.h"
-#include "Atoms.h"
-
-#include "llvm/ADT/StringRef.h"
-#include "llvm/ADT/StringSwitch.h"
-#include "llvm/ADT/Triple.h"
-
-#include "llvm/Support/ErrorHandling.h"
-
-using namespace llvm::MachO;
-using namespace lld::mach_o::normalized;
-
-namespace lld {
-namespace mach_o {
-
-//===----------------------------------------------------------------------===//
-// KindHandler
-//===----------------------------------------------------------------------===//
-
-KindHandler::KindHandler() {
-}
-
-KindHandler::~KindHandler() {
-}
-
-std::unique_ptr<mach_o::KindHandler>
-KindHandler::create(MachOLinkingContext::Arch arch) {
- switch (arch) {
- case MachOLinkingContext::arch_x86_64:
- return std::unique_ptr<mach_o::KindHandler>(new KindHandler_x86_64());
- case MachOLinkingContext::arch_x86:
- return std::unique_ptr<mach_o::KindHandler>(new KindHandler_x86());
- case MachOLinkingContext::arch_armv6:
- case MachOLinkingContext::arch_armv7:
- case MachOLinkingContext::arch_armv7s:
- return std::unique_ptr<mach_o::KindHandler>(new KindHandler_arm());
- default:
- llvm_unreachable("Unknown arch");
- }
-}
-
-KindHandler::RelocPattern KindHandler::relocPattern(const Relocation &reloc) {
- assert((reloc.type & 0xFFF0) == 0);
- uint16_t result = reloc.type;
- if (reloc.scattered)
- result |= rScattered;
- if (reloc.pcRel)
- result |= rPcRel;
- if (reloc.isExtern)
- result |= rExtern;
- switch(reloc.length) {
- case 0:
- break;
- case 1:
- result |= rLength2;
- break;
- case 2:
- result |= rLength4;
- break;
- case 3:
- result |= rLength8;
- break;
- default:
- llvm_unreachable("bad r_length");
- }
- return result;
-}
-
-int16_t KindHandler::readS16(bool swap, const uint8_t *addr) {
- return read16(swap, *reinterpret_cast<const uint16_t*>(addr));
-}
-
-int32_t KindHandler::readS32(bool swap, const uint8_t *addr) {
- return read32(swap, *reinterpret_cast<const uint32_t*>(addr));
-}
-
-uint32_t KindHandler::readU32(bool swap, const uint8_t *addr) {
- return read32(swap, *reinterpret_cast<const uint32_t*>(addr));
-}
-
-int64_t KindHandler::readS64(bool swap, const uint8_t *addr) {
- return read64(swap, *reinterpret_cast<const uint64_t*>(addr));
-}
-
-
-//===----------------------------------------------------------------------===//
-// KindHandler_x86_64
-//===----------------------------------------------------------------------===//
-
-KindHandler_x86_64::~KindHandler_x86_64() {
-}
-
-const Registry::KindStrings KindHandler_x86_64::kindStrings[] = {
- LLD_KIND_STRING_ENTRY(invalid),
- LLD_KIND_STRING_ENTRY(branch32),
- LLD_KIND_STRING_ENTRY(ripRel32),
- LLD_KIND_STRING_ENTRY(ripRel32Minus1),
- LLD_KIND_STRING_ENTRY(ripRel32Minus2),
- LLD_KIND_STRING_ENTRY(ripRel32Minus4),
- LLD_KIND_STRING_ENTRY(ripRel32Anon),
- LLD_KIND_STRING_ENTRY(ripRel32GotLoad),
- LLD_KIND_STRING_ENTRY(ripRel32GotLoadNowLea),
- LLD_KIND_STRING_ENTRY(ripRel32Got),
- LLD_KIND_STRING_ENTRY(lazyPointer),
- LLD_KIND_STRING_ENTRY(lazyImmediateLocation),
- LLD_KIND_STRING_ENTRY(pointer64),
- LLD_KIND_STRING_ENTRY(pointer64Anon),
- LLD_KIND_STRING_ENTRY(delta32),
- LLD_KIND_STRING_ENTRY(delta64),
- LLD_KIND_STRING_ENTRY(delta32Anon),
- LLD_KIND_STRING_ENTRY(delta64Anon),
- LLD_KIND_STRING_END
-};
-
-bool KindHandler_x86_64::isCallSite(const Reference &ref) {
- if (ref.kindNamespace() != Reference::KindNamespace::mach_o)
- return false;
- assert(ref.kindArch() == Reference::KindArch::x86_64);
- return (ref.kindValue() == branch32);
-}
-
-bool KindHandler_x86_64::isPointer(const Reference &ref) {
- if (ref.kindNamespace() != Reference::KindNamespace::mach_o)
- return false;
- assert(ref.kindArch() == Reference::KindArch::x86_64);
- Reference::KindValue kind = ref.kindValue();
- return (kind == pointer64 || kind == pointer64Anon);
-}
-
-bool KindHandler_x86_64::isLazyImmediate(const Reference &ref) {
- if (ref.kindNamespace() != Reference::KindNamespace::mach_o)
- return false;
- assert(ref.kindArch() == Reference::KindArch::x86_64);
- return (ref.kindValue() == lazyImmediateLocation);
-}
-
-bool KindHandler_x86_64::isLazyTarget(const Reference &ref) {
- if (ref.kindNamespace() != Reference::KindNamespace::mach_o)
- return false;
- assert(ref.kindArch() == Reference::KindArch::x86_64);
- return (ref.kindValue() == lazyPointer);
-}
-
-bool KindHandler_x86_64::isPairedReloc(const Relocation &reloc) {
- return (reloc.type == X86_64_RELOC_SUBTRACTOR);
-}
-
-
-Reference::KindValue
-KindHandler_x86_64::kindFromReloc(const Relocation &reloc) {
- switch(relocPattern(reloc)) {
- case X86_64_RELOC_BRANCH | rPcRel | rExtern | rLength4:
- return branch32;
- case X86_64_RELOC_SIGNED | rPcRel | rExtern | rLength4:
- return ripRel32;
- case X86_64_RELOC_SIGNED | rPcRel | rLength4:
- return ripRel32Anon;
- case X86_64_RELOC_SIGNED_1 | rPcRel | rExtern | rLength4:
- return ripRel32Minus1;
- case X86_64_RELOC_SIGNED_2 | rPcRel | rExtern | rLength4:
- return ripRel32Minus2;
- case X86_64_RELOC_SIGNED_4 | rPcRel | rExtern | rLength4:
- return ripRel32Minus4;
- case X86_64_RELOC_GOT_LOAD | rPcRel | rExtern | rLength4:
- return ripRel32GotLoad;
- case X86_64_RELOC_GOT | rPcRel | rExtern | rLength4:
- return ripRel32Got;
- case X86_64_RELOC_UNSIGNED | rExtern | rLength8:
- return pointer64;
- case X86_64_RELOC_UNSIGNED | rLength8:
- return pointer64Anon;
- default:
- return invalid;
- }
-
-}
-
-
-std::error_code
-KindHandler_x86_64::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) {
- typedef std::error_code E;
- *kind = kindFromReloc(reloc);
- if (*kind == invalid)
- return make_dynamic_error_code(Twine("unknown type"));
- const uint8_t *fixupContent = &inAtom->rawContent()[offsetInAtom];
- uint64_t targetAddress;
- switch (*kind) {
- case branch32:
- case ripRel32:
- if (E ec = atomFromSymbolIndex(reloc.symbol, target))
- return ec;
- *addend = readS32(swap, fixupContent);
- return std::error_code();
- case ripRel32Minus1:
- if (E ec = atomFromSymbolIndex(reloc.symbol, target))
- return ec;
- *addend = readS32(swap, fixupContent) + 1;
- return std::error_code();
- case ripRel32Minus2:
- if (E ec = atomFromSymbolIndex(reloc.symbol, target))
- return ec;
- *addend = readS32(swap, fixupContent) + 2;
- return std::error_code();
- case ripRel32Minus4:
- if (E ec = atomFromSymbolIndex(reloc.symbol, target))
- return ec;
- *addend = readS32(swap, fixupContent) + 4;
- return std::error_code();
- case ripRel32Anon:
- targetAddress = fixupAddress + 4 + readS32(swap, fixupContent);
- return atomFromAddress(reloc.symbol, targetAddress, target, addend);
- case ripRel32GotLoad:
- case ripRel32Got:
- if (E ec = atomFromSymbolIndex(reloc.symbol, target))
- return ec;
- *addend = 0;
- return std::error_code();
- case pointer64:
- if (E ec = atomFromSymbolIndex(reloc.symbol, target))
- return ec;
- *addend = readS64(swap, fixupContent);
- return std::error_code();
- case pointer64Anon:
- targetAddress = readS64(swap, fixupContent);
- return atomFromAddress(reloc.symbol, targetAddress, target, addend);
- default:
- llvm_unreachable("bad reloc kind");
- }
-}
-
-
-Reference::KindValue
-KindHandler_x86_64::kindFromRelocPair(const normalized::Relocation &reloc1,
- const normalized::Relocation &reloc2) {
- switch(relocPattern(reloc1) << 16 | relocPattern(reloc2)) {
- case ((X86_64_RELOC_SUBTRACTOR | rExtern | rLength8) << 16 |
- X86_64_RELOC_UNSIGNED | rExtern | rLength8):
- return delta64;
- case ((X86_64_RELOC_SUBTRACTOR | rExtern | rLength4) << 16 |
- X86_64_RELOC_UNSIGNED | rExtern | rLength4):
- return delta32;
- case ((X86_64_RELOC_SUBTRACTOR | rExtern | rLength8) << 16 |
- X86_64_RELOC_UNSIGNED | rLength8):
- return delta64Anon;
- case ((X86_64_RELOC_SUBTRACTOR | rExtern | rLength4) << 16 |
- X86_64_RELOC_UNSIGNED | rLength4):
- return delta32Anon;
- default:
- llvm_unreachable("bad reloc pairs");
- }
-}
-
-
-std::error_code
-KindHandler_x86_64::getPairReferenceInfo(const normalized::Relocation &reloc1,
- const normalized::Relocation &reloc2,
- 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) {
- *kind = kindFromRelocPair(reloc1, reloc2);
- if (*kind == invalid)
- return make_dynamic_error_code(Twine("unknown pair"));
- const uint8_t *fixupContent = &inAtom->rawContent()[offsetInAtom];
- typedef std::error_code E;
- uint64_t targetAddress;
- const lld::Atom *fromTarget;
- if (E ec = atomFromSymbolIndex(reloc1.symbol, &fromTarget))
- return ec;
- if (fromTarget != inAtom)
- return make_dynamic_error_code(Twine("pointer diff not in base atom"));
- switch (*kind) {
- case delta64:
- if (E ec = atomFromSymbolIndex(reloc2.symbol, target))
- return ec;
- *addend = readS64(swap, fixupContent) + offsetInAtom;
- return std::error_code();
- case delta32:
- if (E ec = atomFromSymbolIndex(reloc2.symbol, target))
- return ec;
- *addend = readS32(swap, fixupContent) + offsetInAtom;
- return std::error_code();
- case delta64Anon:
- targetAddress = offsetInAtom + readS64(swap, fixupContent);
- return atomFromAddress(reloc2.symbol, targetAddress, target, addend);
- case delta32Anon:
- targetAddress = offsetInAtom + readS32(swap, fixupContent);
- return atomFromAddress(reloc2.symbol, targetAddress, target, addend);
- default:
- llvm_unreachable("bad reloc pair kind");
- }
-}
-
-
-
-void KindHandler_x86_64::applyFixup(Reference::KindNamespace ns,
- Reference::KindArch arch,
- Reference::KindValue kindValue,
- uint64_t addend, uint8_t *location,
- uint64_t fixupAddress,
- uint64_t targetAddress,
- uint64_t inAtomAddress) {
- if (ns != Reference::KindNamespace::mach_o)
- return;
- assert(arch == Reference::KindArch::x86_64);
- int32_t *loc32 = reinterpret_cast<int32_t*>(location);
- uint64_t* loc64 = reinterpret_cast<uint64_t*>(location);
- switch (kindValue) {
- case branch32:
- case ripRel32:
- case ripRel32Got:
- case ripRel32GotLoad:
- *loc32 = (targetAddress - (fixupAddress+4)) + addend;
- break;
- case pointer64:
- case pointer64Anon:
- *loc64 = targetAddress + addend;
- break;
- case ripRel32Minus1:
- *loc32 = (targetAddress - (fixupAddress+5)) + addend;
- break;
- case ripRel32Minus2:
- *loc32 = (targetAddress - (fixupAddress+6)) + addend;
- break;
- case ripRel32Minus4:
- *loc32 = (targetAddress - (fixupAddress+8)) + addend;
- break;
- case delta32:
- case delta32Anon:
- *loc32 = (targetAddress - fixupAddress) + addend;
- break;
- case delta64:
- case delta64Anon:
- *loc64 = (targetAddress - fixupAddress) + addend;
- break;
- case ripRel32GotLoadNowLea:
- // Change MOVQ to LEA
- assert(location[-2] == 0x8B);
- location[-2] = 0x8D;
- *loc32 = (targetAddress - (fixupAddress+4)) + addend;
- break;
- case lazyPointer:
- case lazyImmediateLocation:
- // do nothing
- break;
- default:
- llvm_unreachable("invalid x86_64 Reference Kind");
- break;
- }
-}
-
-
-//===----------------------------------------------------------------------===//
-// KindHandler_x86
-//===----------------------------------------------------------------------===//
-
-KindHandler_x86::~KindHandler_x86() {
-}
-
-const Registry::KindStrings KindHandler_x86::kindStrings[] = {
- LLD_KIND_STRING_ENTRY(invalid),
- 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(lazyPointer),
- LLD_KIND_STRING_ENTRY(lazyImmediateLocation),
- LLD_KIND_STRING_END
-};
-
-bool KindHandler_x86::isCallSite(const Reference &ref) {
- return (ref.kindValue() == branch32);
-}
-
-bool KindHandler_x86::isPointer(const Reference &ref) {
- return (ref.kindValue() == pointer32);
-}
-
-bool KindHandler_x86::isLazyImmediate(const Reference &ref) {
- return (ref.kindValue() == lazyImmediateLocation);
-}
-
-bool KindHandler_x86::isLazyTarget(const Reference &ref) {
- return (ref.kindValue() == lazyPointer);
-}
-
-
-bool KindHandler_x86::isPairedReloc(const Relocation &reloc) {
- if (!reloc.scattered)
- return false;
- return (reloc.type == GENERIC_RELOC_LOCAL_SECTDIFF) ||
- (reloc.type == GENERIC_RELOC_SECTDIFF);
-}
-
-
-std::error_code
-KindHandler_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) {
- typedef std::error_code E;
- 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 (E ec = atomFromSymbolIndex(reloc.symbol, target))
- return ec;
- *addend = fixupAddress + 4 + readS32(swap, fixupContent);
- break;
- case GENERIC_RELOC_VANILLA | rPcRel | rLength4:
- // ex: call _foo (and _foo defined)
- *kind = branch32;
- targetAddress = fixupAddress + 4 + readS32(swap, fixupContent);
- return atomFromAddress(reloc.symbol, targetAddress, target, addend);
- break;
- case GENERIC_RELOC_VANILLA | rPcRel | rExtern | rLength2:
- // ex: callw _foo (and _foo undefined)
- *kind = branch16;
- if (E ec = atomFromSymbolIndex(reloc.symbol, target))
- return ec;
- *addend = fixupAddress + 2 + readS16(swap, fixupContent);
- break;
- case GENERIC_RELOC_VANILLA | rPcRel | rLength2:
- // ex: callw _foo (and _foo defined)
- *kind = branch16;
- targetAddress = fixupAddress + 2 + readS16(swap, fixupContent);
- return atomFromAddress(reloc.symbol, targetAddress, target, addend);
- 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 (E ec = atomFromSymbolIndex(reloc.symbol, target))
- return ec;
- *addend = readU32(swap, 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 = readU32(swap, fixupContent);
- return atomFromAddress(reloc.symbol, targetAddress, target, addend);
- break;
- default:
- return make_dynamic_error_code(Twine("unsupported i386 relocation type"));
- }
- return std::error_code();
-}
-
-
-std::error_code
-KindHandler_x86::getPairReferenceInfo(const normalized::Relocation &reloc1,
- const normalized::Relocation &reloc2,
- const DefinedAtom *inAtom,
- uint32_t offsetInAtom,
- uint64_t fixupAddress, bool swap,
- FindAtomBySectionAndAddress atomFromAddr,
- FindAtomBySymbolIndex atomFromSymbolIndex,
- Reference::KindValue *kind,
- const lld::Atom **target,
- Reference::Addend *addend) {
- const uint8_t *fixupContent = &inAtom->rawContent()[offsetInAtom];
- std::error_code ec;
- 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 = readS32(swap, fixupContent);
- ec = atomFromAddr(0, toAddress, target, &offsetInTo);
- if (ec)
- return ec;
- ec = atomFromAddr(0, fromAddress, &fromTarget, &offsetInFrom);
- if (ec)
- return ec;
- if (fromTarget != inAtom)
- return make_dynamic_error_code(Twine("SECTDIFF relocation where "
- "subtrahend label is not in atom"));
- *kind = ((perms & DefinedAtom::permR_X) == DefinedAtom::permR_X)
- ? funcRel32 : delta32;
- if (*kind == funcRel32) {
- // 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.
- uint32_t ta = fromAddress + value - toAddress;
- *addend = ta - offsetInFrom;
- } else {
- *addend = fromAddress + value - toAddress;
- }
- return std::error_code();
- break;
- default:
- return make_dynamic_error_code(Twine("unsupported i386 relocation type"));
- }
-}
-
-void KindHandler_x86::applyFixup(Reference::KindNamespace ns,
- Reference::KindArch arch,
- Reference::KindValue kindValue,
- uint64_t addend, uint8_t *location,
- uint64_t fixupAddress,
- uint64_t targetAddress,
- uint64_t inAtomAddress) {
- if (ns != Reference::KindNamespace::mach_o)
- return;
- assert(arch == Reference::KindArch::x86);
- int32_t *loc32 = reinterpret_cast<int32_t*>(location);
- int16_t *loc16 = reinterpret_cast<int16_t*>(location);
- // FIXME: these writes may need a swap.
- switch (kindValue) {
- case branch32:
- *loc32 = (targetAddress - (fixupAddress+4)) + addend;
- break;
- case branch16:
- *loc16 = (targetAddress - (fixupAddress+4)) + addend;
- break;
- case pointer32:
- case abs32:
- *loc32 = targetAddress + addend;
- break;
- case funcRel32:
- *loc32 = targetAddress - inAtomAddress + addend; // FIXME
- break;
- case delta32:
- *loc32 = targetAddress - fixupAddress + addend;
- break;
- case lazyPointer:
- case lazyImmediateLocation:
- // do nothing
- break;
- default:
- llvm_unreachable("invalid x86 Reference Kind");
- break;
- }
-}
-
-
-//===----------------------------------------------------------------------===//
-// KindHandler_arm
-//===----------------------------------------------------------------------===//
-
-KindHandler_arm::~KindHandler_arm() {
-}
-
-const Registry::KindStrings KindHandler_arm::kindStrings[] = {
- LLD_KIND_STRING_ENTRY(thumb_b22),
- LLD_KIND_STRING_ENTRY(thumb_movw),
- LLD_KIND_STRING_ENTRY(thumb_movt),
- LLD_KIND_STRING_ENTRY(thumb_movw_funcRel),
- LLD_KIND_STRING_ENTRY(thumb_movt_funcRel),
- LLD_KIND_STRING_ENTRY(arm_b24),
- LLD_KIND_STRING_ENTRY(arm_movw),
- LLD_KIND_STRING_ENTRY(arm_movt),
- LLD_KIND_STRING_ENTRY(arm_movw_funcRel),
- LLD_KIND_STRING_ENTRY(arm_movt_funcRel),
- LLD_KIND_STRING_ENTRY(pointer32),
- LLD_KIND_STRING_ENTRY(delta32),
- LLD_KIND_STRING_ENTRY(lazyPointer),
- LLD_KIND_STRING_ENTRY(lazyImmediateLocation),
- LLD_KIND_STRING_END
-};
-
-bool KindHandler_arm::isCallSite(const Reference &ref) {
- return (ref.kindValue() == thumb_b22) ||
- (ref.kindValue() == arm_b24);
-}
-
-bool KindHandler_arm::isPointer(const Reference &ref) {
- return (ref.kindValue() == pointer32);
-}
-
-bool KindHandler_arm::isLazyImmediate(const Reference &ref) {
- return (ref.kindValue() == lazyImmediateLocation);
-}
-
-bool KindHandler_arm::isLazyTarget(const Reference &ref) {
- return (ref.kindValue() == lazyPointer);
-}
-
-bool KindHandler_arm::isPairedReloc(const Relocation &reloc) {
- switch (reloc.type) {
- case ARM_RELOC_SECTDIFF:
- case ARM_RELOC_LOCAL_SECTDIFF:
- case ARM_RELOC_HALF_SECTDIFF:
- case ARM_RELOC_HALF:
- return true;
- default:
- return false;
- }
-}
-
-
-int32_t KindHandler_arm::getDisplacementFromThumbBranch(uint32_t instruction) {
- uint32_t s = (instruction >> 10) & 0x1;
- uint32_t j1 = (instruction >> 29) & 0x1;
- uint32_t j2 = (instruction >> 27) & 0x1;
- uint32_t imm10 = instruction & 0x3FF;
- uint32_t imm11 = (instruction >> 16) & 0x7FF;
- uint32_t i1 = (j1 == s);
- uint32_t i2 = (j2 == s);
- uint32_t dis = (s << 24) | (i1 << 23) | (i2 << 22)
- | (imm10 << 12) | (imm11 << 1);
- int32_t sdis = dis;
- if (s)
- return (sdis | 0xFE000000);
- else
- return sdis;
-}
-
-int32_t KindHandler_arm::getDisplacementFromArmBranch(uint32_t instruction) {
- // Sign-extend imm24
- int32_t displacement = (instruction & 0x00FFFFFF) << 2;
- if ( (displacement & 0x02000000) != 0 )
- displacement |= 0xFC000000;
- // If this is BLX and H bit set, add 2.
- if ((instruction & 0xFF000000) == 0xFB000000)
- displacement += 2;
- return displacement;
-}
-
-
-uint16_t KindHandler_arm::getWordFromThumbMov(uint32_t instruction) {
- uint32_t i = ((instruction & 0x00000400) >> 10);
- uint32_t imm4 = (instruction & 0x0000000F);
- uint32_t imm3 = ((instruction & 0x70000000) >> 28);
- uint32_t imm8 = ((instruction & 0x00FF0000) >> 16);
- return (imm4 << 12) | (i << 11) | (imm3 << 8) | imm8;
-}
-
-uint16_t KindHandler_arm::getWordFromArmMov(uint32_t instruction) {
- uint32_t imm4 = ((instruction & 0x000F0000) >> 16);
- uint32_t imm12 = (instruction & 0x00000FFF);
- return (imm4 << 12) | imm12;
-}
-
-uint32_t KindHandler_arm::clearThumbBit(uint32_t value, const Atom* target) {
- // The assembler often adds one to the address of a thumb function.
- // We need to undo that so it does not look like an addend.
- if (value & 1) {
- if (isa<DefinedAtom>(target)) {
- const MachODefinedAtom *machoTarget = reinterpret_cast<
- const MachODefinedAtom*>(target);
- if (machoTarget->isThumb())
- value &= -2; // mask off thumb-bit
- }
- }
- return value;
-}
-
-std::error_code
-KindHandler_arm::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) {
- typedef std::error_code E;
- const uint8_t *fixupContent = &inAtom->rawContent()[offsetInAtom];
- uint64_t targetAddress;
- uint32_t instruction = readU32(swap, fixupContent);
- int32_t displacement;
- switch (relocPattern(reloc)) {
- case ARM_THUMB_RELOC_BR22 | rPcRel | rExtern | rLength4:
- // ex: bl _foo (and _foo is undefined)
- *kind = thumb_b22;
- if (E ec = atomFromSymbolIndex(reloc.symbol, target))
- return ec;
- // Instruction contains branch to addend.
- displacement = getDisplacementFromThumbBranch(instruction);
- *addend = fixupAddress + 4 + displacement;
- return std::error_code();
- case ARM_THUMB_RELOC_BR22 | rPcRel | rLength4:
- // ex: bl _foo (and _foo is defined)
- *kind = thumb_b22;
- displacement = getDisplacementFromThumbBranch(instruction);
- targetAddress = fixupAddress + 4 + displacement;
- return atomFromAddress(reloc.symbol, targetAddress, target, addend);
- case ARM_THUMB_RELOC_BR22 | rScattered | rPcRel | rLength4:
- // ex: bl _foo+4 (and _foo is defined)
- *kind = thumb_b22;
- displacement = getDisplacementFromThumbBranch(instruction);
- targetAddress = fixupAddress + 4 + displacement;
- if (E ec = atomFromAddress(0, reloc.value, target, addend))
- return ec;
- // reloc.value is target atom's address. Instruction contains branch
- // to atom+addend.
- *addend += (targetAddress - reloc.value);
- return std::error_code();
- case ARM_RELOC_BR24 | rPcRel | rExtern | rLength4:
- // ex: bl _foo (and _foo is undefined)
- *kind = arm_b24;
- if (E ec = atomFromSymbolIndex(reloc.symbol, target))
- return ec;
- // Instruction contains branch to addend.
- displacement = getDisplacementFromArmBranch(instruction);
- *addend = fixupAddress + 8 + displacement;
- return std::error_code();
- case ARM_RELOC_BR24 | rPcRel | rLength4:
- // ex: bl _foo (and _foo is defined)
- *kind = arm_b24;
- displacement = getDisplacementFromArmBranch(instruction);
- targetAddress = fixupAddress + 8 + displacement;
- return atomFromAddress(reloc.symbol, targetAddress, target, addend);
- case ARM_RELOC_BR24 | rScattered | rPcRel | rLength4:
- // ex: bl _foo+4 (and _foo is defined)
- *kind = arm_b24;
- displacement = getDisplacementFromArmBranch(instruction);
- targetAddress = fixupAddress + 8 + displacement;
- if (E ec = atomFromAddress(0, reloc.value, target, addend))
- return ec;
- // reloc.value is target atom's address. Instruction contains branch
- // to atom+addend.
- *addend += (targetAddress - reloc.value);
- return std::error_code();
- case ARM_RELOC_VANILLA | rExtern | rLength4:
- // ex: .long _foo (and _foo is undefined)
- *kind = pointer32;
- if (E ec = atomFromSymbolIndex(reloc.symbol, target))
- return ec;
- *addend = instruction;
- return std::error_code();
- case ARM_RELOC_VANILLA | rLength4:
- // ex: .long _foo (and _foo is defined)
- *kind = pointer32;
- if (E ec = atomFromAddress(reloc.symbol, instruction, target, addend))
- return ec;
- *addend = clearThumbBit((uint32_t)*addend, *target);
- return std::error_code();
- case ARM_RELOC_VANILLA | rScattered | rLength4:
- // ex: .long _foo+a (and _foo is defined)
- *kind = pointer32;
- if (E ec = atomFromAddress(0, reloc.value, target, addend))
- return ec;
- *addend += (clearThumbBit(instruction, *target) - reloc.value);
- return std::error_code();
- default:
- return make_dynamic_error_code(Twine("unsupported arm relocation type"));
- }
- return std::error_code();
-}
-
-
-std::error_code
-KindHandler_arm::getPairReferenceInfo(const normalized::Relocation &reloc1,
- const normalized::Relocation &reloc2,
- const DefinedAtom *inAtom,
- uint32_t offsetInAtom,
- uint64_t fixupAddress, bool swap,
- FindAtomBySectionAndAddress atomFromAddr,
- FindAtomBySymbolIndex atomFromSymbolIndex,
- Reference::KindValue *kind,
- const lld::Atom **target,
- Reference::Addend *addend) {
- bool pointerDiff = false;
- bool funcRel;
- bool top;
- bool thumbReloc;
- switch(relocPattern(reloc1) << 16 | relocPattern(reloc2)) {
- case ((ARM_RELOC_HALF_SECTDIFF | rScattered | rLength4) << 16 |
- ARM_RELOC_PAIR | rScattered | rLength4):
- // ex: movw r1, :lower16:(_x-L1) [thumb mode]
- *kind = thumb_movw_funcRel;
- funcRel = true;
- top = false;
- thumbReloc = true;
- break;
- case ((ARM_RELOC_HALF_SECTDIFF | rScattered | rLength8) << 16 |
- ARM_RELOC_PAIR | rScattered | rLength8):
- // ex: movt r1, :upper16:(_x-L1) [thumb mode]
- *kind = thumb_movt_funcRel;
- funcRel = true;
- top = true;
- thumbReloc = true;
- break;
- case ((ARM_RELOC_HALF_SECTDIFF | rScattered | rLength1) << 16 |
- ARM_RELOC_PAIR | rScattered | rLength1):
- // ex: movw r1, :lower16:(_x-L1) [arm mode]
- *kind = arm_movw_funcRel;
- funcRel = true;
- top = false;
- thumbReloc = false;
- break;
- case ((ARM_RELOC_HALF_SECTDIFF | rScattered | rLength2) << 16 |
- ARM_RELOC_PAIR | rScattered | rLength2):
- // ex: movt r1, :upper16:(_x-L1) [arm mode]
- *kind = arm_movt_funcRel;
- funcRel = true;
- top = true;
- thumbReloc = false;
- break;
- case ((ARM_RELOC_HALF | rLength4) << 16 |
- ARM_RELOC_PAIR | rLength4):
- // ex: movw r1, :lower16:_x [thumb mode]
- *kind = thumb_movw;
- funcRel = false;
- top = false;
- thumbReloc = true;
- break;
- case ((ARM_RELOC_HALF | rLength8) << 16 |
- ARM_RELOC_PAIR | rLength8):
- // ex: movt r1, :upper16:_x [thumb mode]
- *kind = thumb_movt;
- funcRel = false;
- top = true;
- thumbReloc = true;
- break;
- case ((ARM_RELOC_HALF | rLength1) << 16 |
- ARM_RELOC_PAIR | rLength1):
- // ex: movw r1, :lower16:_x [arm mode]
- *kind = arm_movw;
- funcRel = false;
- top = false;
- thumbReloc = false;
- break;
- case ((ARM_RELOC_HALF | rLength2) << 16 |
- ARM_RELOC_PAIR | rLength2):
- // ex: movt r1, :upper16:_x [arm mode]
- *kind = arm_movt;
- funcRel = false;
- top = true;
- thumbReloc = false;
- break;
- case ((ARM_RELOC_HALF | rScattered | rLength4) << 16 |
- ARM_RELOC_PAIR | rLength4):
- // ex: movw r1, :lower16:_x+a [thumb mode]
- *kind = thumb_movw;
- funcRel = false;
- top = false;
- thumbReloc = true;
- break;
- case ((ARM_RELOC_HALF | rScattered | rLength8) << 16 |
- ARM_RELOC_PAIR | rLength8):
- // ex: movt r1, :upper16:_x+a [thumb mode]
- *kind = thumb_movt;
- funcRel = false;
- top = true;
- thumbReloc = true;
- break;
- case ((ARM_RELOC_HALF | rScattered | rLength1) << 16 |
- ARM_RELOC_PAIR | rLength1):
- // ex: movw r1, :lower16:_x+a [arm mode]
- *kind = arm_movw;
- funcRel = false;
- top = false;
- thumbReloc = false;
- break;
- case ((ARM_RELOC_HALF | rScattered | rLength2) << 16 |
- ARM_RELOC_PAIR | rLength2):
- // ex: movt r1, :upper16:_x+a [arm mode]
- *kind = arm_movt;
- funcRel = false;
- top = true;
- thumbReloc = false;
- break;
- case ((ARM_RELOC_HALF | rExtern | rLength4) << 16 |
- ARM_RELOC_PAIR | rLength4):
- // ex: movw r1, :lower16:_undef [thumb mode]
- *kind = thumb_movw;
- funcRel = false;
- top = false;
- thumbReloc = true;
- break;
- case ((ARM_RELOC_HALF | rExtern | rLength8) << 16 |
- ARM_RELOC_PAIR | rLength8):
- // ex: movt r1, :upper16:_undef [thumb mode]
- *kind = thumb_movt;
- funcRel = false;
- top = true;
- thumbReloc = true;
- break;
- case ((ARM_RELOC_HALF | rExtern | rLength1) << 16 |
- ARM_RELOC_PAIR | rLength1):
- // ex: movw r1, :lower16:_undef [arm mode]
- *kind = arm_movw;
- funcRel = false;
- top = false;
- thumbReloc = false;
- break;
- case ((ARM_RELOC_HALF | rExtern | rLength2) << 16 |
- ARM_RELOC_PAIR | rLength2):
- // ex: movt r1, :upper16:_undef [arm mode]
- *kind = arm_movt;
- funcRel = false;
- top = true;
- thumbReloc = false;
- break;
- case ((ARM_RELOC_SECTDIFF | rScattered | rLength4) << 16 |
- ARM_RELOC_PAIR | rScattered | rLength4):
- case ((ARM_RELOC_LOCAL_SECTDIFF | rScattered | rLength4) << 16 |
- ARM_RELOC_PAIR | rScattered | rLength4):
- // ex: .long _foo - .
- pointerDiff = true;
- break;
- default:
- return make_dynamic_error_code(Twine("unsupported arm relocation pair"));
- }
- const uint8_t *fixupContent = &inAtom->rawContent()[offsetInAtom];
- std::error_code ec;
- uint32_t instruction = readU32(swap, fixupContent);
- uint32_t value;
- uint32_t fromAddress;
- uint32_t toAddress;
- uint16_t instruction16;
- uint16_t other16;
- const lld::Atom *fromTarget;
- Reference::Addend offsetInTo;
- Reference::Addend offsetInFrom;
- if (pointerDiff) {
- toAddress = reloc1.value;
- fromAddress = reloc2.value;
- ec = atomFromAddr(0, toAddress, target, &offsetInTo);
- if (ec)
- return ec;
- ec = atomFromAddr(0, fromAddress, &fromTarget, &offsetInFrom);
- if (ec)
- return ec;
- if (fromTarget != inAtom)
- return make_dynamic_error_code(Twine("SECTDIFF relocation where "
- "subtrahend label is not in atom"));
- *kind = delta32;
- value = clearThumbBit(instruction, *target);
- *addend = value - (toAddress - fromAddress);
- } else if (funcRel) {
- toAddress = reloc1.value;
- fromAddress = reloc2.value;
- ec = atomFromAddr(0, toAddress, target, &offsetInTo);
- if (ec)
- return ec;
- ec = atomFromAddr(0, fromAddress, &fromTarget, &offsetInFrom);
- if (ec)
- return ec;
- if (fromTarget != inAtom)
- return make_dynamic_error_code(Twine("ARM_RELOC_HALF_SECTDIFF relocation "
- "where subtrahend label is not in atom"));
- other16 = (reloc2.offset & 0xFFFF);
- if (thumbReloc)
- instruction16 = getWordFromThumbMov(instruction);
- else
- instruction16 = getWordFromArmMov(instruction);
- if (top)
- value = (instruction16 << 16) | other16;
- else
- value = (other16 << 16) | instruction16;
- value = clearThumbBit(value, *target);
- int64_t ta = (int64_t)value - (toAddress - fromAddress);
- *addend = ta - offsetInFrom;
- return std::error_code();
- } else {
- uint32_t sectIndex;
- if (thumbReloc)
- instruction16 = getWordFromThumbMov(instruction);
- else
- instruction16 = getWordFromArmMov(instruction);
- other16 = (reloc2.offset & 0xFFFF);
- if (top)
- value = (instruction16 << 16) | other16;
- else
- value = (other16 << 16) | instruction16;
- if (reloc1.isExtern) {
- ec = atomFromSymbolIndex(reloc1.symbol, target);
- if (ec)
- return ec;
- *addend = value;
- } else {
- if (reloc1.scattered) {
- toAddress = reloc1.value;
- sectIndex = 0;
- } else {
- toAddress = value;
- sectIndex = reloc1.symbol;
- }
- ec = atomFromAddr(sectIndex, toAddress, target, &offsetInTo);
- if (ec)
- return ec;
- *addend = value - toAddress;
- }
- }
-
- return std::error_code();
-}
-
-
-
-void KindHandler_arm::applyFixup(Reference::KindNamespace ns,
- Reference::KindArch arch,
- Reference::KindValue kindValue,
- uint64_t addend, uint8_t *location,
- uint64_t fixupAddress,
- uint64_t targetAddress,
- uint64_t inAtomAddress) {
- if (ns != Reference::KindNamespace::mach_o)
- return;
- assert(arch == Reference::KindArch::ARM);
- //int32_t *loc32 = reinterpret_cast<int32_t*>(location);
- // FIXME: these writes may need a swap.
- switch (kindValue) {
- case thumb_b22:
- // FIXME
- break;
- case thumb_movw:
- // FIXME
- break;
- case thumb_movt:
- // FIXME
- break;
- case thumb_movw_funcRel:
- // FIXME
- break;
- case thumb_movt_funcRel:
- // FIXME
- break;
- case arm_b24:
- // FIXME
- break;
- case arm_movw:
- // FIXME
- break;
- case arm_movt:
- // FIXME
- break;
- case arm_movw_funcRel:
- // FIXME
- break;
- case arm_movt_funcRel:
- // FIXME
- break;
- case pointer32:
- // FIXME
- break;
- case delta32:
- // FIXME
- break;
- case lazyPointer:
- case lazyImmediateLocation:
- // do nothing
- break;
- case invalid:
- llvm_unreachable("invalid ARM Reference Kind");
- break;
- }
-}
-
-
-} // namespace mach_o
-} // namespace lld
-
-
-
+++ /dev/null
-//===- lib/FileFormat/MachO/ReferenceKinds.h ------------------------------===//
-//
-// The LLVM Linker
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-
-
-#include "MachONormalizedFile.h"
-
-#include "lld/Core/LLVM.h"
-#include "lld/Core/Reference.h"
-#include "lld/ReaderWriter/MachOLinkingContext.h"
-
-#include "llvm/ADT/Triple.h"
-
-#ifndef LLD_READER_WRITER_MACHO_REFERENCE_KINDS_H
-#define LLD_READER_WRITER_MACHO_REFERENCE_KINDS_H
-
-namespace lld {
-namespace mach_o {
-
-
-///
-/// The KindHandler class is the abstract interface to Reference::Kind
-/// values for mach-o files. Particular Kind values (e.g. 3) has a different
-/// meaning for each architecture.
-///
-class KindHandler {
-public:
-
- static std::unique_ptr<mach_o::KindHandler> create(MachOLinkingContext::Arch);
- virtual ~KindHandler();
-
- virtual bool isCallSite(const Reference &) = 0;
- virtual bool isPointer(const Reference &) = 0;
- virtual bool isLazyImmediate(const Reference &) = 0;
- virtual bool isLazyTarget(const Reference &) = 0;
-
- /// Returns true if the specified relocation is paired to the next relocation.
- virtual bool isPairedReloc(const normalized::Relocation &) = 0;
-
- /// Prototype for a helper function. Given a sectionIndex and address,
- /// finds the atom and offset with that atom of that address.
- typedef std::function<std::error_code (uint32_t sectionIndex, uint64_t addr,
- const lld::Atom **, Reference::Addend *)>
- FindAtomBySectionAndAddress;
-
- /// Prototype for a helper function. Given a symbolIndex, finds the atom
- /// representing that symbol.
- typedef std::function<std::error_code (uint32_t symbolIndex,
- const lld::Atom **)> FindAtomBySymbolIndex;
-
- /// Analyzes a relocation from a .o file and returns the info
- /// (kind, target, addend) needed to instantiate a Reference.
- /// Two helper functions are passed as parameters to find the target atom
- /// given a symbol index or address.
- virtual std::error_code
- 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) = 0;
-
- /// Analyzes a pair of relocations from a .o file and returns the info
- /// (kind, target, addend) needed to instantiate a Reference.
- /// Two helper functions are passed as parameters to find the target atom
- /// given a symbol index or address.
- virtual std::error_code
- getPairReferenceInfo(const normalized::Relocation &reloc1,
- const normalized::Relocation &reloc2,
- 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) = 0;
-
- /// Fixup an atom when generating a final linked binary.
- virtual void applyFixup(Reference::KindNamespace ns, Reference::KindArch arch,
- Reference::KindValue kindValue, uint64_t addend,
- uint8_t *location, uint64_t fixupAddress,
- uint64_t targetAddress, uint64_t inAtomAddress) = 0;
-
-protected:
- KindHandler();
-
- // Handy way to pack mach-o r_type and other bit fields into one 16-bit value.
- typedef uint16_t RelocPattern;
- enum {
- rScattered = 0x8000,
- rPcRel = 0x4000,
- rExtern = 0x2000,
- rLength1 = 0x0000,
- rLength2 = 0x0100,
- rLength4 = 0x0200,
- rLength8 = 0x0300
- };
- static RelocPattern relocPattern(const normalized::Relocation &reloc);
-
- static int16_t readS16(bool swap, const uint8_t *addr);
- static int32_t readS32(bool swap, const uint8_t *addr);
- static uint32_t readU32(bool swap, const uint8_t *addr);
- static int64_t readS64(bool swap, const uint8_t *addr);
-};
-
-
-
-class KindHandler_x86_64 : public KindHandler {
-public:
- static const Registry::KindStrings kindStrings[];
-
- virtual ~KindHandler_x86_64();
- bool isCallSite(const Reference &) override;
- bool isPointer(const Reference &) override;
- bool isLazyImmediate(const Reference &) override;
- bool isLazyTarget(const Reference &) override;
- bool isPairedReloc(const normalized::Relocation &) override;
- std::error_code 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;
- std::error_code
- getPairReferenceInfo(const normalized::Relocation &reloc1,
- const normalized::Relocation &reloc2,
- 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;
-
- virtual void applyFixup(Reference::KindNamespace ns, Reference::KindArch arch,
- Reference::KindValue kindValue, uint64_t addend,
- uint8_t *location, uint64_t fixupAddress,
- uint64_t targetAddress, uint64_t inAtomAddress)
- override;
-
-private:
- friend class X86_64LazyPointerAtom;
- friend class X86_64StubHelperAtom;
- friend class X86_64StubAtom;
- friend class X86_64StubHelperCommonAtom;
- friend class X86_64NonLazyPointerAtom;
-
- enum : Reference::KindValue {
- invalid, /// for error condition
-
- // Kinds found in mach-o .o files:
- branch32, /// ex: call _foo
- ripRel32, /// ex: movq _foo(%rip), %rax
- ripRel32Minus1, /// ex: movb $0x12, _foo(%rip)
- ripRel32Minus2, /// ex: movw $0x1234, _foo(%rip)
- ripRel32Minus4, /// ex: movl $0x12345678, _foo(%rip)
- ripRel32Anon, /// ex: movq L1(%rip), %rax
- ripRel32GotLoad, /// ex: movq _foo@GOTPCREL(%rip), %rax
- ripRel32Got, /// ex: pushq _foo@GOTPCREL(%rip)
- pointer64, /// ex: .quad _foo
- pointer64Anon, /// ex: .quad L1
- delta64, /// ex: .quad _foo - .
- delta32, /// ex: .long _foo - .
- delta64Anon, /// ex: .quad L1 - .
- delta32Anon, /// ex: .long L1 - .
-
- // Kinds introduced by Passes:
- ripRel32GotLoadNowLea, /// Target of GOT load is in linkage unit so
- /// "movq _foo@GOTPCREL(%rip), %rax" can be changed
- /// to "leaq _foo(%rip), %rax
- lazyPointer, /// Location contains a lazy pointer.
- lazyImmediateLocation, /// Location contains immediate value used in stub.
- };
-
- Reference::KindValue kindFromReloc(const normalized::Relocation &reloc);
- Reference::KindValue kindFromRelocPair(const normalized::Relocation &reloc1,
- const normalized::Relocation &reloc2);
-
-
-};
-
-class KindHandler_x86 : public KindHandler {
-public:
- static const Registry::KindStrings kindStrings[];
-
- virtual ~KindHandler_x86();
- bool isCallSite(const Reference &) override;
- bool isPointer(const Reference &) override;
- bool isLazyImmediate(const Reference &) override;
- bool isLazyTarget(const Reference &) override;
- bool isPairedReloc(const normalized::Relocation &) override;
- std::error_code 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;
- std::error_code
- getPairReferenceInfo(const normalized::Relocation &reloc1,
- const normalized::Relocation &reloc2,
- 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;
-
- void applyFixup(Reference::KindNamespace ns, Reference::KindArch arch,
- Reference::KindValue kindValue, uint64_t addend,
- uint8_t *location, uint64_t fixupAddress,
- uint64_t targetAddress, uint64_t inAtomAddress)
- override;
-
-private:
- friend class X86LazyPointerAtom;
- friend class X86StubHelperAtom;
- friend class X86StubAtom;
- friend class X86StubHelperCommonAtom;
- friend class X86NonLazyPointerAtom;
-
- enum : Reference::KindValue {
- invalid, /// for error condition
-
- // 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 - .
-
- // Kinds introduced by Passes:
- lazyPointer, /// Location contains a lazy pointer.
- lazyImmediateLocation, /// Location contains immediate value used in stub.
- };
-
-
-};
-
-
-
-class KindHandler_arm : public KindHandler {
-public:
- static const Registry::KindStrings kindStrings[];
-
- virtual ~KindHandler_arm();
- bool isCallSite(const Reference &) override;
- bool isPointer(const Reference &) override;
- bool isLazyImmediate(const Reference &) override;
- bool isLazyTarget(const Reference &) override;
- bool isPairedReloc(const normalized::Relocation &) override;
- std::error_code 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;
- std::error_code
- getPairReferenceInfo(const normalized::Relocation &reloc1,
- const normalized::Relocation &reloc2,
- 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;
-
- void applyFixup(Reference::KindNamespace ns, Reference::KindArch arch,
- Reference::KindValue kindValue, uint64_t addend,
- uint8_t *location, uint64_t fixupAddress,
- uint64_t targetAddress, uint64_t inAtomAddress)
- override;
-
-private:
- enum : Reference::KindValue {
- invalid, /// for error condition
-
- // Kinds found in mach-o .o files:
- thumb_b22, /// ex: bl _foo
- thumb_movw, /// ex: movw r1, :lower16:_foo
- thumb_movt, /// ex: movt r1, :lower16:_foo
- thumb_movw_funcRel, /// ex: movw r1, :lower16:(_foo-(L1+4))
- thumb_movt_funcRel, /// ex: movt r1, :upper16:(_foo-(L1+4))
- arm_b24, /// ex: bl _foo
- arm_movw, /// ex: movw r1, :lower16:_foo
- arm_movt, /// ex: movt r1, :lower16:_foo
- arm_movw_funcRel, /// ex: movw r1, :lower16:(_foo-(L1+4))
- arm_movt_funcRel, /// ex: movt r1, :upper16:(_foo-(L1+4))
- pointer32, /// ex: .long _foo
- delta32, /// ex: .long _foo - .
-
- // Kinds introduced by Passes:
- lazyPointer, /// Location contains a lazy pointer.
- lazyImmediateLocation, /// Location contains immediate value used in stub.
- };
-
- int32_t getDisplacementFromThumbBranch(uint32_t instruction);
- int32_t getDisplacementFromArmBranch(uint32_t instruction);
- uint16_t getWordFromThumbMov(uint32_t instruction);
- uint16_t getWordFromArmMov(uint32_t instruction);
- uint32_t clearThumbBit(uint32_t value, const Atom* target);
-
-};
-
-} // namespace mach_o
-} // namespace lld
-
-
-
-#endif // LLD_READER_WRITER_MACHO_REFERENCE_KINDS_H
-
+++ /dev/null
-//===- lib/ReaderWriter/MachO/StubAtoms.hpp -------------------------------===//
-//
-// The LLVM Linker
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-
-#ifndef LLD_READER_WRITER_MACHO_STUB_ATOMS_H
-#define LLD_READER_WRITER_MACHO_STUB_ATOMS_H
-
-#include "llvm/ADT/ArrayRef.h"
-
-#include "lld/Core/DefinedAtom.h"
-#include "lld/Core/File.h"
-#include "lld/Core/Reference.h"
-#include "lld/Core/SharedLibraryAtom.h"
-#include "lld/Core/Simple.h"
-
-#include "ReferenceKinds.h"
-#include "StubAtoms_x86_64.hpp"
-#include "StubAtoms_x86.hpp"
-
-namespace lld {
-namespace mach_o {
-
-
-//
-// StubBinderAtom created by the stubs pass.
-//
-class StubBinderAtom : public SharedLibraryAtom {
-public:
- StubBinderAtom(const File &f) : _file(f) {
- }
-
- const File& file() const override {
- return _file;
- }
-
- StringRef name() const override {
- return StringRef("dyld_stub_binder");
- }
-
- StringRef loadName() const override {
- return StringRef("/usr/lib/libSystem.B.dylib");
- }
-
- bool canBeNullAtRuntime() const override {
- return false;
- }
-
- Type type() const override {
- return Type::Unknown;
- }
-
- uint64_t size() const override {
- return 0;
- }
-
-private:
- const File &_file;
-};
-
-
-
-} // namespace mach_o
-} // namespace lld
-
-
-#endif // LLD_READER_WRITER_MACHO_STUB_ATOMS_H
+++ /dev/null
-//===- lib/ReaderWriter/MachO/StubAtoms_x86.hpp ---------------------------===//
-//
-// The LLVM Linker
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-
-#ifndef LLD_READER_WRITER_MACHO_STUB_ATOMS_X86_H
-#define LLD_READER_WRITER_MACHO_STUB_ATOMS_X86_H
-
-#include "llvm/ADT/ArrayRef.h"
-
-#include "lld/Core/DefinedAtom.h"
-#include "lld/Core/SharedLibraryAtom.h"
-#include "lld/Core/File.h"
-#include "lld/Core/Reference.h"
-
-#include "ReferenceKinds.h"
-
-using llvm::makeArrayRef;
-
-namespace lld {
-namespace mach_o {
-
-//
-// X86 Stub Atom created by the stubs pass.
-//
-class X86StubAtom : public SimpleDefinedAtom {
-public:
- X86StubAtom(const File &file, const Atom &lazyPointer)
- : SimpleDefinedAtom(file) {
- this->addReference(Reference::KindNamespace::mach_o,
- Reference::KindArch::x86, KindHandler_x86::abs32, 2,
- &lazyPointer, 0);
- }
-
- ContentType contentType() const override {
- return DefinedAtom::typeStub;
- }
-
- uint64_t size() const override {
- return 6;
- }
-
- ContentPermissions permissions() const override {
- return DefinedAtom::permR_X;
- }
-
- ArrayRef<uint8_t> rawContent() const override {
- static const uint8_t instructions[] =
- { 0xFF, 0x25, 0x00, 0x00, 0x00, 0x00 }; // jmp *lazyPointer
- assert(sizeof(instructions) == this->size());
- return makeArrayRef(instructions);
- }
-};
-
-
-//
-// X86 Stub Helper Common Atom created by the stubs pass.
-//
-class X86StubHelperCommonAtom : public SimpleDefinedAtom {
-public:
- X86StubHelperCommonAtom(const File &file, const Atom &cache,
- const Atom &binder)
- : SimpleDefinedAtom(file) {
- this->addReference(Reference::KindNamespace::mach_o,
- Reference::KindArch::x86, KindHandler_x86::abs32, 1,
- &cache, 0);
- this->addReference(Reference::KindNamespace::mach_o,
- Reference::KindArch::x86, KindHandler_x86::abs32, 7,
- &binder, 0);
- }
-
- ContentType contentType() const override {
- return DefinedAtom::typeStubHelper;
- }
-
- uint64_t size() const override {
- return 12;
- }
-
- ContentPermissions permissions() const override {
- return DefinedAtom::permR_X;
- }
-
- ArrayRef<uint8_t> rawContent() const override {
- static const uint8_t instructions[] =
- { 0x68, 0x00, 0x00, 0x00, 0x00, // pushl $dyld_ImageLoaderCache
- 0xFF, 0x25, 0x00, 0x00, 0x00, 0x00, // jmp *_fast_lazy_bind
- 0x90 }; // nop
- assert(sizeof(instructions) == this->size());
- return makeArrayRef(instructions);
- }
-};
-
-
-//
-// X86 Stub Helper Atom created by the stubs pass.
-//
-class X86StubHelperAtom : public SimpleDefinedAtom {
-public:
- X86StubHelperAtom(const File &file, const Atom &helperCommon)
- : SimpleDefinedAtom(file) {
- this->addReference(Reference::KindNamespace::mach_o,
- Reference::KindArch::x86,
- KindHandler_x86::lazyImmediateLocation, 1, this, 0);
- this->addReference(Reference::KindNamespace::mach_o,
- Reference::KindArch::x86, KindHandler_x86::branch32, 6,
- &helperCommon, 0);
- }
-
- ContentType contentType() const override {
- return DefinedAtom::typeStubHelper;
- }
-
- uint64_t size() const override {
- return 10;
- }
-
- ContentPermissions permissions() const override {
- return DefinedAtom::permR_X;
- }
-
- ArrayRef<uint8_t> rawContent() const override {
- static const uint8_t instructions[] =
- { 0x68, 0x00, 0x00, 0x00, 0x00, // pushq $lazy-info-offset
- 0xE9, 0x00, 0x00, 0x00, 0x00 }; // jmp helperhelper
- assert(sizeof(instructions) == this->size());
- return makeArrayRef(instructions);
- }
-};
-
-
-//
-// X86 Lazy Pointer Atom created by the stubs pass.
-//
-class X86LazyPointerAtom : public SimpleDefinedAtom {
-public:
- X86LazyPointerAtom(const File &file, const Atom &helper, const Atom &shlib)
- : SimpleDefinedAtom(file) {
- this->addReference(Reference::KindNamespace::mach_o,
- Reference::KindArch::x86, KindHandler_x86::pointer32, 0,
- &helper, 0);
- this->addReference(Reference::KindNamespace::mach_o,
- Reference::KindArch::x86, KindHandler_x86::lazyPointer,
- 0, &shlib, 0);
- }
-
- ContentType contentType() const override {
- return DefinedAtom::typeLazyPointer;
- }
-
- Alignment alignment() const override {
- return Alignment(2);
- }
-
- uint64_t size() const override {
- return 4;
- }
-
- ContentPermissions permissions() const override {
- return DefinedAtom::permRW_;
- }
-
- ArrayRef<uint8_t> rawContent() const override {
- static const uint8_t bytes[] = { 0x00, 0x00, 0x00, 0x00 };
- return makeArrayRef(bytes);
- }
-};
-
-
-//
-// X86 NonLazy (GOT) Pointer Atom created by the stubs pass.
-//
-class X86NonLazyPointerAtom : public SimpleDefinedAtom {
-public:
- X86NonLazyPointerAtom(const File &file)
- : SimpleDefinedAtom(file) {}
-
- X86NonLazyPointerAtom(const File &file, const Atom &shlib)
- : SimpleDefinedAtom(file) {
- this->addReference(Reference::KindNamespace::mach_o,
- Reference::KindArch::x86, KindHandler_x86::pointer32, 0,
- &shlib, 0);
- }
-
- ContentType contentType() const override {
- return DefinedAtom::typeGOT;
- }
-
- Alignment alignment() const override {
- return Alignment(2);
- }
-
- uint64_t size() const override {
- return 4;
- }
-
- ContentPermissions permissions() const override {
- return DefinedAtom::permRW_;
- }
-
- ArrayRef<uint8_t> rawContent() const override {
- static const uint8_t bytes[] = { 0x00, 0x00, 0x00, 0x0 };
- return makeArrayRef(bytes);
- }
-};
-
-} // namespace mach_o
-} // namespace lld
-
-
-#endif // LLD_READER_WRITER_MACHO_STUB_ATOMS_X86_H
+++ /dev/null
-//===- lib/ReaderWriter/MachO/StubAtoms_x86_64.hpp ------------------------===//
-//
-// The LLVM Linker
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-
-#ifndef LLD_READER_WRITER_MACHO_STUB_ATOMS_X86_64_H
-#define LLD_READER_WRITER_MACHO_STUB_ATOMS_X86_64_H
-
-#include "llvm/ADT/ArrayRef.h"
-
-#include "lld/Core/DefinedAtom.h"
-#include "lld/Core/SharedLibraryAtom.h"
-#include "lld/Core/File.h"
-#include "lld/Core/Reference.h"
-
-#include "ReferenceKinds.h"
-
-using llvm::makeArrayRef;
-using namespace llvm::MachO;
-
-namespace lld {
-namespace mach_o {
-
-//
-// X86_64 Stub Atom created by the stubs pass.
-//
-class X86_64StubAtom : public SimpleDefinedAtom {
-public:
- X86_64StubAtom(const File &file, const Atom &lazyPointer)
- : SimpleDefinedAtom(file) {
- this->addReference(Reference::KindNamespace::mach_o,
- Reference::KindArch::x86_64,
- KindHandler_x86_64::ripRel32, 2,
- &lazyPointer, 0);
- }
-
- ContentType contentType() const override {
- return DefinedAtom::typeStub;
- }
-
- uint64_t size() const override {
- return 6;
- }
-
- ContentPermissions permissions() const override {
- return DefinedAtom::permR_X;
- }
-
- ArrayRef<uint8_t> rawContent() const override {
- static const uint8_t instructions[] =
- { 0xFF, 0x25, 0x00, 0x00, 0x00, 0x00 }; // jmp *lazyPointer
- assert(sizeof(instructions) == this->size());
- return makeArrayRef(instructions);
- }
-};
-
-//
-// X86_64 Stub Helper Common Atom created by the stubs pass.
-//
-class X86_64StubHelperCommonAtom : public SimpleDefinedAtom {
-public:
- X86_64StubHelperCommonAtom(const File &file, const Atom &cache,
- const Atom &binder)
- : SimpleDefinedAtom(file) {
- this->addReference(Reference::KindNamespace::mach_o,
- Reference::KindArch::x86_64,
- KindHandler_x86_64::ripRel32, 3, &cache, 0);
- this->addReference(Reference::KindNamespace::mach_o,
- Reference::KindArch::x86_64,
- KindHandler_x86_64::ripRel32, 11, &binder, 0);
- }
-
- ContentType contentType() const override {
- return DefinedAtom::typeStubHelper;
- }
-
- uint64_t size() const override {
- return 16;
- }
-
- ContentPermissions permissions() const override {
- return DefinedAtom::permR_X;
- }
-
- ArrayRef<uint8_t> rawContent() const override {
- static const uint8_t instructions[] =
- { 0x4C, 0x8D, 0x1D, 0x00, 0x00, 0x00, 0x00, // leaq cache(%rip),%r11
- 0x41, 0x53, // push %r11
- 0xFF, 0x25, 0x00, 0x00, 0x00, 0x00, // jmp *binder(%rip)
- 0x90 }; // nop
- assert(sizeof(instructions) == this->size());
- return makeArrayRef(instructions);
- }
-};
-
-//
-// X86_64 Stub Helper Atom created by the stubs pass.
-//
-class X86_64StubHelperAtom : public SimpleDefinedAtom {
-public:
- X86_64StubHelperAtom(const File &file, const Atom &helperCommon)
- : SimpleDefinedAtom(file) {
- this->addReference(Reference::KindNamespace::mach_o,
- Reference::KindArch::x86_64,
- KindHandler_x86_64::lazyImmediateLocation, 1, this, 0);
- this->addReference(Reference::KindNamespace::mach_o,
- Reference::KindArch::x86_64,
- KindHandler_x86_64::ripRel32, 6,
- &helperCommon, 0);
- }
-
- ContentType contentType() const override {
- return DefinedAtom::typeStubHelper;
- }
-
- uint64_t size() const override {
- return 10;
- }
-
- ContentPermissions permissions() const override {
- return DefinedAtom::permR_X;
- }
-
- ArrayRef<uint8_t> rawContent() const override {
- static const uint8_t instructions[] =
- { 0x68, 0x00, 0x00, 0x00, 0x00, // pushq $lazy-info-offset
- 0xE9, 0x00, 0x00, 0x00, 0x00 }; // jmp helperhelper
- assert(sizeof(instructions) == this->size());
- return makeArrayRef(instructions);
- }
-};
-
-//
-// X86_64 Lazy Pointer Atom created by the stubs pass.
-//
-class X86_64LazyPointerAtom : public SimpleDefinedAtom {
-public:
- X86_64LazyPointerAtom(const File &file, const Atom &helper,
- const Atom &shlib)
- : SimpleDefinedAtom(file) {
- this->addReference(Reference::KindNamespace::mach_o,
- Reference::KindArch::x86_64,
- KindHandler_x86_64::pointer64, 0, &helper, 0);
- this->addReference(Reference::KindNamespace::mach_o,
- Reference::KindArch::x86_64,
- KindHandler_x86_64::lazyPointer, 0, &shlib, 0);
- }
-
- ContentType contentType() const override {
- return DefinedAtom::typeLazyPointer;
- }
-
- Alignment alignment() const override {
- return Alignment(3);
- }
-
- uint64_t size() const override {
- return 8;
- }
-
- ContentPermissions permissions() const override {
- return DefinedAtom::permRW_;
- }
-
- ArrayRef<uint8_t> rawContent() const override {
- static const uint8_t bytes[] =
- { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
- return makeArrayRef(bytes);
- }
-};
-
-//
-// X86_64 NonLazy (GOT) Pointer Atom created by the stubs pass.
-//
-class X86_64NonLazyPointerAtom : public SimpleDefinedAtom {
-public:
- X86_64NonLazyPointerAtom(const File &file)
- : SimpleDefinedAtom(file) {}
-
- X86_64NonLazyPointerAtom(const File &file, const Atom &shlib)
- : SimpleDefinedAtom(file) {
- this->addReference(Reference::KindNamespace::mach_o,
- Reference::KindArch::x86_64,
- KindHandler_x86_64::pointer64, 0, &shlib, 0);
- }
-
- ContentType contentType() const override {
- return DefinedAtom::typeGOT;
- }
-
- Alignment alignment() const override {
- return Alignment(3);
- }
-
- uint64_t size() const override {
- return 8;
- }
-
- ContentPermissions permissions() const override {
- return DefinedAtom::permRW_;
- }
-
- ArrayRef<uint8_t> rawContent() const override {
- static const uint8_t bytes[] =
- { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
- return makeArrayRef(bytes);
- }
-};
-
-} // namespace mach_o
-} // namespace lld
-
-
-#endif // LLD_READER_WRITER_MACHO_STUB_ATOMS_X86_64_H
//
//===----------------------------------------------------------------------===//
+#include "ArchHandler.h"
+#include "File.h"
+#include "MachOPasses.h"
+
#include "lld/Core/DefinedAtom.h"
#include "lld/Core/File.h"
#include "lld/Core/LLVM.h"
#include "lld/Core/Reference.h"
+#include "lld/Core/Simple.h"
+#include "lld/ReaderWriter/MachOLinkingContext.h"
+
#include "llvm/ADT/DenseMap.h"
-#include "MachOPasses.h"
namespace lld {
+namespace mach_o {
+
+
+//
+// Lazy Pointer Atom created by the stubs pass.
+//
+class LazyPointerAtom : public SimpleDefinedAtom {
+public:
+ LazyPointerAtom(const File &file, bool is64)
+ : SimpleDefinedAtom(file), _is64(is64) { }
+
+ ContentType contentType() const override {
+ return DefinedAtom::typeLazyPointer;
+ }
+
+ Alignment alignment() const override {
+ return Alignment(_is64 ? 3 : 2);
+ }
+
+ uint64_t size() const override {
+ return _is64 ? 8 : 4;
+ }
+
+ ContentPermissions permissions() const override {
+ return DefinedAtom::permRW_;
+ }
+
+ ArrayRef<uint8_t> rawContent() const override {
+ static const uint8_t zeros[] =
+ { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
+ return llvm::makeArrayRef(zeros, size());
+ }
+
+private:
+ const bool _is64;
+};
+
+
+//
+// NonLazyPointer (GOT) Atom created by the stubs pass.
+//
+class NonLazyPointerAtom : public SimpleDefinedAtom {
+public:
+ NonLazyPointerAtom(const File &file, bool is64)
+ : SimpleDefinedAtom(file), _is64(is64) { }
+
+ ContentType contentType() const override {
+ return DefinedAtom::typeGOT;
+ }
+
+ Alignment alignment() const override {
+ return Alignment(_is64 ? 3 : 2);
+ }
+
+ uint64_t size() const override {
+ return _is64 ? 8 : 4;
+ }
+
+ ContentPermissions permissions() const override {
+ return DefinedAtom::permRW_;
+ }
+
+ ArrayRef<uint8_t> rawContent() const override {
+ static const uint8_t zeros[] =
+ { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
+ return llvm::makeArrayRef(zeros, size());
+ }
+
+private:
+ const bool _is64;
+};
+
+
+
+//
+// Stub Atom created by the stubs pass.
+//
+class StubAtom : public SimpleDefinedAtom {
+public:
+ StubAtom(const File &file, const ArchHandler::StubInfo &stubInfo)
+ : SimpleDefinedAtom(file), _stubInfo(stubInfo) { }
+
+ ContentType contentType() const override {
+ return DefinedAtom::typeStub;
+ }
+
+ Alignment alignment() const override {
+ return Alignment(_stubInfo.codeAlignment);
+ }
+
+ uint64_t size() const override {
+ return _stubInfo.stubSize;
+ }
+
+ ContentPermissions permissions() const override {
+ return DefinedAtom::permR_X;
+ }
+
+ ArrayRef<uint8_t> rawContent() const override {
+ return llvm::makeArrayRef(_stubInfo.stubBytes, _stubInfo.stubSize);
+ }
+
+private:
+ const ArchHandler::StubInfo &_stubInfo;
+};
+
+
+//
+// Stub Helper Atom created by the stubs pass.
+//
+class StubHelperAtom : public SimpleDefinedAtom {
+public:
+ StubHelperAtom(const File &file, const ArchHandler::StubInfo &stubInfo)
+ : SimpleDefinedAtom(file), _stubInfo(stubInfo) { }
+
+ ContentType contentType() const override {
+ return DefinedAtom::typeStubHelper;
+ }
+
+ Alignment alignment() const override {
+ return Alignment(_stubInfo.codeAlignment);
+ }
+
+ uint64_t size() const override {
+ return _stubInfo.stubHelperSize;
+ }
+
+ ContentPermissions permissions() const override {
+ return DefinedAtom::permR_X;
+ }
+
+ ArrayRef<uint8_t> rawContent() const override {
+ return llvm::makeArrayRef(_stubInfo.stubHelperBytes,
+ _stubInfo.stubHelperSize);
+ }
+
+private:
+ const ArchHandler::StubInfo &_stubInfo;
+};
+
+
+//
+// Stub Helper Common Atom created by the stubs pass.
+//
+class StubHelperCommonAtom : public SimpleDefinedAtom {
+public:
+ StubHelperCommonAtom(const File &file, const ArchHandler::StubInfo &stubInfo)
+ : SimpleDefinedAtom(file), _stubInfo(stubInfo) { }
+
+ ContentType contentType() const override {
+ return DefinedAtom::typeStubHelper;
+ }
+
+ Alignment alignment() const override {
+ return Alignment(_stubInfo.codeAlignment);
+ }
+
+ uint64_t size() const override {
+ return _stubInfo.stubHelperCommonSize;
+ }
+
+ ContentPermissions permissions() const override {
+ return DefinedAtom::permR_X;
+ }
+
+ ArrayRef<uint8_t> rawContent() const override {
+ return llvm::makeArrayRef(_stubInfo.stubHelperCommonBytes,
+ _stubInfo.stubHelperCommonSize);
+ }
+
+private:
+ const ArchHandler::StubInfo &_stubInfo;
+};
+
+
+class StubsPass : public Pass {
+public:
+ StubsPass(const MachOLinkingContext &context)
+ : _context(context)
+ , _archHandler(_context.archHandler())
+ , _stubInfo(_archHandler.stubInfo())
+ , _file("<mach-o Stubs pass>")
+ , _helperCommonAtom(nullptr)
+ , _helperCacheNLPAtom(nullptr)
+ , _helperBinderNLPAtom(nullptr) {
+ }
-void StubsPass::perform(std::unique_ptr<MutableFile> &mergedFile) {
- // Skip this pass if output format uses text relocations instead of stubs.
- if (!this->noTextRelocs())
- return;
-
- // Scan all references in all atoms.
- for (const DefinedAtom *atom : mergedFile->defined()) {
- for (const Reference *ref : *atom) {
- // Look at call-sites.
- if (!this->isCallSite(*ref))
- continue;
- const Atom *target = ref->target();
- assert(target != nullptr);
- if (target->definition() == Atom::definitionSharedLibrary) {
- // Calls to shared libraries go through stubs.
- replaceCalleeWithStub(target, ref);
- continue;
+
+ void perform(std::unique_ptr<MutableFile> &mergedFile) override {
+ // Skip this pass if output format uses text relocations instead of stubs.
+ if (!this->noTextRelocs())
+ return;
+
+ // Scan all references in all atoms.
+ for (const DefinedAtom *atom : mergedFile->defined()) {
+ for (const Reference *ref : *atom) {
+ // Look at call-sites.
+ if (!this->isCallSite(*ref))
+ continue;
+ const Atom *target = ref->target();
+ assert(target != nullptr);
+ if (target->definition() == Atom::definitionSharedLibrary) {
+ // Calls to shared libraries go through stubs.
+ replaceCalleeWithStub(target, ref);
+ continue;
+ }
+ const DefinedAtom *defTarget = dyn_cast<DefinedAtom>(target);
+ if (defTarget && defTarget->interposable() != DefinedAtom::interposeNo){
+ // Calls to interposable functions in same linkage unit must also go
+ // through a stub.
+ assert(defTarget->scope() != DefinedAtom::scopeTranslationUnit);
+ replaceCalleeWithStub(target, ref);
+ }
}
- const DefinedAtom *defTarget = dyn_cast<DefinedAtom>(target);
- if (defTarget && defTarget->interposable() != DefinedAtom::interposeNo) {
- // Calls to interposable functions in same linkage unit must also go
- // through a stub.
- assert(defTarget->scope() != DefinedAtom::scopeTranslationUnit);
- replaceCalleeWithStub(target, ref);
+ }
+ // Exit early if no stubs needed.
+ if (_targetToStub.empty())
+ return;
+
+ // Add reference to dyld_stub_binder in libSystem.dylib
+ if (_helperBinderNLPAtom) {
+ bool found = false;
+ for (const SharedLibraryAtom *atom : mergedFile->sharedLibrary()) {
+ if (atom->name().equals(_stubInfo.binderSymbolName)) {
+ addReference(_helperBinderNLPAtom,
+ _stubInfo.nonLazyPointerReferenceToBinder, atom);
+ found = true;
+ break;
+ }
}
+ assert(found && "dyld_stub_binder not found");
+ }
+
+ // Add all stubs to master file.
+ for (auto it : _targetToStub) {
+ mergedFile->addAtom(*it.second);
+ }
+ // Add helper code atoms.
+ mergedFile->addAtom(*_helperCommonAtom);
+ for (const DefinedAtom *lp : _stubHelperAtoms) {
+ mergedFile->addAtom(*lp);
+ }
+ // Add GOT slots used for lazy binding.
+ mergedFile->addAtom(*_helperBinderNLPAtom);
+ mergedFile->addAtom(*_helperCacheNLPAtom);
+ // Add all lazy pointers to master file.
+ for (const DefinedAtom *lp : _lazyPointers) {
+ mergedFile->addAtom(*lp);
}
}
- // Add all created stubs and support Atoms.
- this->addStubAtoms(*mergedFile);
-}
-void StubsPass::replaceCalleeWithStub(const Atom *target,
- const Reference *ref) {
- // Make file-format specific stub and other support atoms.
- const DefinedAtom *stub = this->getStub(*target);
- assert(stub != nullptr);
- // Switch call site to reference stub atom instead.
- const_cast<Reference *>(ref)->setTarget(stub);
+
+private:
+
+ bool noTextRelocs() {
+ return true;
+ }
+
+ bool isCallSite(const Reference &ref) {
+ return _archHandler.isCallSite(ref);
+ }
+
+ void replaceCalleeWithStub(const Atom *target, const Reference *ref) {
+ // Make file-format specific stub and other support atoms.
+ const DefinedAtom *stub = this->getStub(*target);
+ assert(stub != nullptr);
+ // Switch call site to reference stub atom instead.
+ const_cast<Reference *>(ref)->setTarget(stub);
+ }
+
+ const DefinedAtom* getStub(const Atom& target) {
+ auto pos = _targetToStub.find(&target);
+ if ( pos != _targetToStub.end() ) {
+ // Reuse an existing stub.
+ assert(pos->second != nullptr);
+ return pos->second;
+ }
+ else {
+ // There is no existing stub, so create a new one.
+ return this->makeStub(target);
+ }
+ }
+
+ const DefinedAtom* makeStub(const Atom &target) {
+ SimpleDefinedAtom* stub = new (_file.allocator())
+ StubAtom(_file, _stubInfo);
+ SimpleDefinedAtom* lp = new (_file.allocator())
+ LazyPointerAtom(_file, _context.is64Bit());
+ SimpleDefinedAtom* helper = new (_file.allocator())
+ StubHelperAtom(_file, _stubInfo);
+
+ addReference(stub, _stubInfo.stubReferenceToLP, lp);
+ addReference(lp, _stubInfo.lazyPointerReferenceToHelper, helper);
+ addReference(lp, _stubInfo.lazyPointerReferenceToFinal, &target);
+ addReference(helper, _stubInfo.stubHelperReferenceToImm, helper);
+ addReference(helper, _stubInfo.stubHelperReferenceToHelperCommon,
+ helperCommon());
+
+ _stubHelperAtoms.push_back(helper);
+ _targetToStub[&target] = stub;
+ _lazyPointers.push_back(lp);
+
+ return stub;
+ }
+
+ void addReference(SimpleDefinedAtom* atom,
+ const ArchHandler::ReferenceInfo &refInfo,
+ const lld::Atom* target) {
+ atom->addReference(Reference::KindNamespace::mach_o,
+ refInfo.arch, refInfo.kind, refInfo.offset,
+ target, refInfo.addend);
+ }
+
+ const DefinedAtom* helperCommon() {
+ if ( !_helperCommonAtom ) {
+ // Lazily create common helper code and data.
+ _helperCommonAtom = new (_file.allocator())
+ StubHelperCommonAtom(_file, _stubInfo);
+ _helperCacheNLPAtom = new (_file.allocator())
+ NonLazyPointerAtom(_file, _context.is64Bit());
+ _helperBinderNLPAtom = new (_file.allocator())
+ NonLazyPointerAtom(_file, _context.is64Bit());
+ addReference(_helperCommonAtom,
+ _stubInfo.stubHelperCommonReferenceToCache,
+ _helperCacheNLPAtom);
+ addReference(_helperCommonAtom,
+ _stubInfo.stubHelperCommonReferenceToBinder,
+ _helperBinderNLPAtom);
+ }
+ return _helperCommonAtom;
+ }
+
+
+ const MachOLinkingContext &_context;
+ mach_o::ArchHandler &_archHandler;
+ const ArchHandler::StubInfo &_stubInfo;
+ MachOFile _file;
+ llvm::DenseMap<const Atom*, const DefinedAtom*> _targetToStub;
+ std::vector<const DefinedAtom*> _lazyPointers;
+ std::vector<const DefinedAtom*> _stubHelperAtoms;
+ SimpleDefinedAtom *_helperCommonAtom;
+ SimpleDefinedAtom *_helperCacheNLPAtom;
+ SimpleDefinedAtom *_helperBinderNLPAtom;
+};
+
+
+
+void addStubsPass(PassManager &pm, const MachOLinkingContext &ctx) {
+ pm.add(std::unique_ptr<Pass>(new StubsPass(ctx)));
}
+} // end namespace mach_o
} // end namespace lld
+++ /dev/null
-//===- lib/ReaderWriter/MachO/StubsPass.hpp -------------------------------===//
-//
-// The LLVM Linker
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-
-#ifndef LLD_READER_WRITER_MACHO_STUBS_PASS_H
-#define LLD_READER_WRITER_MACHO_STUBS_PASS_H
-
-#include "llvm/ADT/DenseMap.h"
-
-#include "lld/Core/DefinedAtom.h"
-#include "lld/Core/File.h"
-#include "lld/Core/Pass.h"
-#include "lld/Core/Reference.h"
-#include "lld/Core/SharedLibraryAtom.h"
-#include "lld/Core/Simple.h"
-
-#include "MachOPasses.h"
-#include "ReferenceKinds.h"
-#include "StubAtoms.hpp"
-
-namespace lld {
-namespace mach_o {
-
-
-class StubsPass : public lld::StubsPass {
-public:
- StubsPass(const MachOLinkingContext &context)
- : _context(context)
- , _kindHandler(_context.kindHandler())
- , _file(context)
- , _helperCommonAtom(nullptr)
- , _helperCacheAtom(nullptr)
- , _helperBinderAtom(nullptr) {
- }
-
- bool noTextRelocs() override {
- return true;
- }
-
- bool isCallSite(const Reference &ref) override {
- return _kindHandler.isCallSite(ref);
- }
-
- const DefinedAtom* getStub(const Atom& target) override {
- auto pos = _targetToStub.find(&target);
- if ( pos != _targetToStub.end() ) {
- // Reuse an existing stub.
- assert(pos->second != nullptr);
- return pos->second;
- }
- else {
- // There is no existing stub, so create a new one.
- return this->makeStub(target);
- }
- }
-
- const DefinedAtom* makeStub(const Atom& target) {
- switch (_context.arch()) {
- case MachOLinkingContext::arch_x86_64:
- return makeStub_x86_64(target);
- case MachOLinkingContext::arch_x86:
- return makeStub_x86(target);
- case MachOLinkingContext::arch_armv6:
- case MachOLinkingContext::arch_armv7:
- case MachOLinkingContext::arch_armv7s:
- return makeStub_arm(target);
- default:
- llvm_unreachable("Unknown mach-o arch");
- }
- }
-
- const DefinedAtom* makeStub_x86_64(const Atom& target) {
- if ( _helperCommonAtom == nullptr ) {
- // Lazily create common helper code and data.
- _helperCacheAtom = new X86_64NonLazyPointerAtom(_file);
- _binderAtom = new StubBinderAtom(_file);
- _helperBinderAtom = new X86_64NonLazyPointerAtom(_file, *_binderAtom);
- _helperCommonAtom = new X86_64StubHelperCommonAtom(_file,
- *_helperCacheAtom, *_helperBinderAtom);
- }
- const DefinedAtom* helper = new X86_64StubHelperAtom(_file,
- *_helperCommonAtom);
- _stubHelperAtoms.push_back(helper);
- const DefinedAtom* lp = new X86_64LazyPointerAtom(_file, *helper, target);
- assert(lp->contentType() == DefinedAtom::typeLazyPointer);
- _lazyPointers.push_back(lp);
- const DefinedAtom* stub = new X86_64StubAtom(_file, *lp);
- assert(stub->contentType() == DefinedAtom::typeStub);
- _targetToStub[&target] = stub;
- return stub;
- }
-
- const DefinedAtom* makeStub_x86(const Atom& target) {
- if ( _helperCommonAtom == nullptr ) {
- // Lazily create common helper code and data.
- _helperCacheAtom = new X86NonLazyPointerAtom(_file);
- _binderAtom = new StubBinderAtom(_file);
- _helperBinderAtom = new X86NonLazyPointerAtom(_file, *_binderAtom);
- _helperCommonAtom = new X86StubHelperCommonAtom(_file,
- *_helperCacheAtom, *_helperBinderAtom);
- }
- const DefinedAtom* helper = new X86StubHelperAtom(_file,
- *_helperCommonAtom);
- _stubHelperAtoms.push_back(helper);
- const DefinedAtom* lp = new X86LazyPointerAtom(_file, *helper, target);
- assert(lp->contentType() == DefinedAtom::typeLazyPointer);
- _lazyPointers.push_back(lp);
- const DefinedAtom* stub = new X86StubAtom(_file, *lp);
- assert(stub->contentType() == DefinedAtom::typeStub);
- _targetToStub[&target] = stub;
- return stub;
- }
-
- const DefinedAtom* makeStub_arm(const Atom& target) {
- assert(0 && "stubs not yet implemented for arm");
- return nullptr;
- }
-
-
- void addStubAtoms(MutableFile &mergedFile) override {
- // Exit early if no stubs needed.
- if (_targetToStub.empty())
- return;
- // Add all stubs to master file.
- for (auto it : _targetToStub) {
- mergedFile.addAtom(*it.second);
- }
- // Add helper code atoms.
- mergedFile.addAtom(*_helperCommonAtom);
- for (const DefinedAtom *lp : _stubHelperAtoms) {
- mergedFile.addAtom(*lp);
- }
- // Add GOT slots used for lazy binding.
- mergedFile.addAtom(*_helperBinderAtom);
- mergedFile.addAtom(*_helperCacheAtom);
- // Add all lazy pointers to master file.
- for (const DefinedAtom *lp : _lazyPointers) {
- mergedFile.addAtom(*lp);
- }
- // Add sharedlibrary atom
- mergedFile.addAtom(*_binderAtom);
- }
-
-private:
-
- class File : public SimpleFile {
- public:
- File(const MachOLinkingContext &context) : SimpleFile("MachO Stubs pass") {}
- };
-
- const MachOLinkingContext &_context;
- mach_o::KindHandler &_kindHandler;
- File _file;
- llvm::DenseMap<const Atom*, const DefinedAtom*> _targetToStub;
- std::vector<const DefinedAtom*> _lazyPointers;
- std::vector<const DefinedAtom*> _stubHelperAtoms;
- const SharedLibraryAtom *_binderAtom;
- const DefinedAtom* _helperCommonAtom;
- const DefinedAtom* _helperCacheAtom;
- const DefinedAtom* _helperBinderAtom;
-};
-
-
-} // namespace mach_o
-} // namespace lld
-
-
-#endif // LLD_READER_WRITER_MACHO_STUBS_PASS_H
+++ /dev/null
-# RUN: lld -flavor darwin -arch x86_64 -macosx_version_min 10.8 %s -o %t && \
-# RUN: llvm-nm %t | FileCheck %s
-#
-# Test that hello-world can be linked into a mach-o executable
-#
-
---- !native
-defined-atoms:
- - name: _main
- type: code
- scope: global
- content: [ 55, 48, 89, E5, 48, 8D, 3D, 00,
- 00, 00, 00, E8, 00, 00, 00, 00,
- 31, C0, 5D, C3 ]
- references:
- - offset: 7
- kind: ripRel32
- target: LC1
- - offset: 12
- kind: branch32
- target: _printf
-
- - ref-name: LC1
- type: c-string
- merge: by-content
- content: [ 68, 65, 6C, 6C, 6F, 0A, 00 ]
-
-shared-library-atoms:
- - name: _printf
- load-name: /usr/lib/libSystem.B.dylib
-
-...
-
-# CHECK: {{[0-9a-f]+}} T _main
-# CHECK: U _printf
-# CHECK: U dyld_stub_binder
desc: [ ]
value: 0
+--- !mach-o
+arch: x86_64
+file-type: MH_DYLIB
+flags: [ ]
+install-name: /usr/lib/libSystem.B.dylib
+sections:
+ - segment: __TEXT
+ section: __text
+ type: S_REGULAR
+ attributes: [ S_ATTR_PURE_INSTRUCTIONS, S_ATTR_SOME_INSTRUCTIONS ]
+ address: 0x0000000000000000
+ content: [ 0x55 ]
+
+global-symbols:
+ - name: dyld_stub_binder
+ type: N_SECT
+ scope: [ N_EXT ]
+ sect: 1
+ value: 0x0000000000000000
+
+
...
# CHECK: {{[0-9a-f]+}} T _foo
type: data
content: [ 01 ]
+--- !mach-o
+arch: x86_64
+file-type: MH_DYLIB
+flags: [ ]
+install-name: /usr/lib/libSystem.B.dylib
+sections:
+ - segment: __TEXT
+ section: __text
+ type: S_REGULAR
+ attributes: [ S_ATTR_PURE_INSTRUCTIONS, S_ATTR_SOME_INSTRUCTIONS ]
+ address: 0x0000000000000000
+ content: [ 0x55 ]
+
+global-symbols:
+ - name: dyld_stub_binder
+ type: N_SECT
+ scope: [ N_EXT ]
+ sect: 1
+ value: 0x0000000000000000
+
+
+
# CHECK-LABEL: Section {
# CHECK: Name: __text
# CHECK: Segment: __TEXT
section-name: __CUST/__custom
+--- !mach-o
+arch: x86_64
+file-type: MH_DYLIB
+flags: [ ]
+install-name: /usr/lib/libSystem.B.dylib
+sections:
+ - segment: __TEXT
+ section: __text
+ type: S_REGULAR
+ attributes: [ S_ATTR_PURE_INSTRUCTIONS, S_ATTR_SOME_INSTRUCTIONS ]
+ address: 0x0000000000000000
+ content: [ 0x55 ]
+
+global-symbols:
+ - name: dyld_stub_binder
+ type: N_SECT
+ scope: [ N_EXT ]
+ sect: 1
+ value: 0x0000000000000000
+
# CHECK-LABEL: Section {
# CHECK: Name: __text
# CHECK: Segment: __TEXT
scope: [ N_EXT ]
sect: 1
value: 0x0000000000000001
+ - name: dyld_stub_binder
+ type: N_SECT
+ scope: [ N_EXT ]
+ sect: 1
+ value: 0x0000000000000001
...
--- /dev/null
+# RUN: lld -flavor darwin -arch x86_64 -macosx_version_min 10.8 %s -o %t && \
+# RUN: llvm-nm %t | FileCheck %s
+#
+# Test that x86_64 hello-world can be linked into a mach-o executable
+#
+
+--- !mach-o
+arch: x86_64
+file-type: MH_OBJECT
+flags: [ MH_SUBSECTIONS_VIA_SYMBOLS ]
+has-UUID: false
+OS: unknown
+sections:
+ - segment: __TEXT
+ section: __text
+ type: S_REGULAR
+ attributes: [ S_ATTR_PURE_INSTRUCTIONS, S_ATTR_SOME_INSTRUCTIONS ]
+ address: 0x0000000000000000
+ content: [ 0x55, 0x48, 0x89, 0xE5, 0x48, 0x8B, 0x05, 0x00,
+ 0x00, 0x00, 0x00, 0x48, 0x8B, 0x38, 0x48, 0x8D,
+ 0x35, 0x00, 0x00, 0x00, 0x00, 0x31, 0xC0, 0xE8,
+ 0x00, 0x00, 0x00, 0x00, 0x31, 0xC0, 0x5D, 0xC3 ]
+ relocations:
+ - offset: 0x00000018
+ type: X86_64_RELOC_BRANCH
+ length: 2
+ pc-rel: true
+ extern: true
+ symbol: 5
+ - offset: 0x00000011
+ type: X86_64_RELOC_SIGNED
+ length: 2
+ pc-rel: true
+ extern: true
+ symbol: 0
+ - offset: 0x00000007
+ type: X86_64_RELOC_GOT_LOAD
+ length: 2
+ pc-rel: true
+ extern: true
+ symbol: 4
+ - segment: __TEXT
+ section: __cstring
+ type: S_CSTRING_LITERALS
+ attributes: [ ]
+ address: 0x0000000000000020
+ content: [ 0x68, 0x65, 0x6C, 0x6C, 0x6F, 0x0A, 0x00 ]
+ - segment: __LD
+ section: __compact_unwind
+ type: S_REGULAR
+ attributes: [ ]
+ alignment: 3
+ address: 0x0000000000000028
+ content: [ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 ]
+ relocations:
+ - offset: 0x00000000
+ type: X86_64_RELOC_UNSIGNED
+ length: 3
+ pc-rel: false
+ extern: false
+ symbol: 1
+ - segment: __TEXT
+ section: __eh_frame
+ type: S_COALESCED
+ attributes: [ ]
+ alignment: 3
+ address: 0x0000000000000048
+ content: [ 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x01, 0x7A, 0x52, 0x00, 0x01, 0x78, 0x10, 0x01,
+ 0x10, 0x0C, 0x07, 0x08, 0x90, 0x01, 0x00, 0x00,
+ 0x24, 0x00, 0x00, 0x00, 0x1C, 0x00, 0x00, 0x00,
+ 0x98, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x41, 0x0E, 0x10, 0x86, 0x02, 0x43, 0x0D,
+ 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 ]
+local-symbols:
+ - name: L1
+ type: N_SECT
+ sect: 2
+ value: 0x0000000000000020
+ - name: EH_frame0
+ type: N_SECT
+ sect: 4
+ value: 0x0000000000000048
+global-symbols:
+ - name: _main
+ type: N_SECT
+ scope: [ N_EXT ]
+ sect: 1
+ value: 0x0000000000000000
+ - name: _main.eh
+ type: N_SECT
+ scope: [ N_EXT ]
+ sect: 4
+ value: 0x0000000000000060
+undefined-symbols:
+ - name: ___stdoutp
+ type: N_UNDF
+ scope: [ N_EXT ]
+ value: 0x0000000000000000
+ - name: _fprintf
+ type: N_UNDF
+ scope: [ N_EXT ]
+ value: 0x0000000000000000
+
+--- !mach-o
+arch: x86_64
+file-type: MH_DYLIB
+flags: [ ]
+install-name: /usr/lib/libSystem.B.dylib
+sections:
+ - segment: __TEXT
+ section: __text
+ type: S_REGULAR
+ attributes: [ S_ATTR_PURE_INSTRUCTIONS, S_ATTR_SOME_INSTRUCTIONS ]
+ address: 0x0000000000000000
+ content: [ 0x55 ]
+
+global-symbols:
+ - name: _fprintf
+ type: N_SECT
+ scope: [ N_EXT ]
+ sect: 1
+ value: 0x0000000000000000
+ - name: dyld_stub_binder
+ type: N_SECT
+ scope: [ N_EXT ]
+ sect: 1
+ value: 0x0000000000000000
+ - name: ___stdoutp
+ type: N_SECT
+ scope: [ N_EXT ]
+ sect: 1
+ value: 0x0000000000000000
+
+...
+
+# CHECK: U ___stdoutp
+# CHECK: U _fprintf
+# CHECK: {{[0-9a-f]+}} T _main
+# CHECK: U dyld_stub_binder
# CHECK: SectionData (
# CHECK-NEXT: 0000: 0E000000 00000000
# CHECK-NEXT: )
+
+
+--- !mach-o
+arch: x86_64
+file-type: MH_DYLIB
+flags: [ ]
+install-name: /usr/lib/libSystem.B.dylib
+sections:
+ - segment: __TEXT
+ section: __text
+ type: S_REGULAR
+ attributes: [ S_ATTR_PURE_INSTRUCTIONS, S_ATTR_SOME_INSTRUCTIONS ]
+ address: 0x0000000000000000
+ content: [ 0x55 ]
+
+global-symbols:
+ - name: dyld_stub_binder
+ type: N_SECT
+ scope: [ N_EXT ]
+ sect: 1
+ value: 0x0000000000000000
+