forked from OSchip/llvm-project
[mach-o] Add support for arm64 (AAarch64)
Most of the changes are in the new file ArchHandler_arm64.cpp. But a few things had to be fixed to support 16KB pages (instead of 4KB) which iOS arm64 requires. In addition the StubInfo struct had to be expanded because arm64 uses two instruction (ADRP/LDR) to load a global which requires two relocations. The other mach-o arches just needed one relocation. llvm-svn: 217469
This commit is contained in:
parent
d0f103775a
commit
1bebb2832e
|
@ -43,6 +43,7 @@ public:
|
|||
arch_armv6,
|
||||
arch_armv7,
|
||||
arch_armv7s,
|
||||
arch_arm64,
|
||||
};
|
||||
|
||||
enum class OS {
|
||||
|
|
|
@ -42,6 +42,8 @@ std::unique_ptr<mach_o::ArchHandler> ArchHandler::create(
|
|||
case MachOLinkingContext::arch_armv7:
|
||||
case MachOLinkingContext::arch_armv7s:
|
||||
return create_arm();
|
||||
case MachOLinkingContext::arch_arm64:
|
||||
return create_arm64();
|
||||
default:
|
||||
llvm_unreachable("Unknown arch");
|
||||
}
|
||||
|
|
|
@ -174,6 +174,13 @@ public:
|
|||
int32_t addend;
|
||||
};
|
||||
|
||||
struct OptionalRefInfo {
|
||||
bool used;
|
||||
uint16_t kind;
|
||||
uint32_t offset;
|
||||
int32_t addend;
|
||||
};
|
||||
|
||||
/// Table of architecture specific information for creating stubs.
|
||||
struct StubInfo {
|
||||
const char* binderSymbolName;
|
||||
|
@ -185,16 +192,19 @@ public:
|
|||
uint32_t stubSize;
|
||||
uint8_t stubBytes[16];
|
||||
ReferenceInfo stubReferenceToLP;
|
||||
|
||||
OptionalRefInfo optStubReferenceToLP;
|
||||
|
||||
uint32_t stubHelperSize;
|
||||
uint8_t stubHelperBytes[16];
|
||||
ReferenceInfo stubHelperReferenceToImm;
|
||||
ReferenceInfo stubHelperReferenceToHelperCommon;
|
||||
|
||||
|
||||
uint32_t stubHelperCommonSize;
|
||||
uint8_t stubHelperCommonBytes[36];
|
||||
ReferenceInfo stubHelperCommonReferenceToCache;
|
||||
OptionalRefInfo optStubHelperCommonReferenceToCache;
|
||||
ReferenceInfo stubHelperCommonReferenceToBinder;
|
||||
OptionalRefInfo optStubHelperCommonReferenceToBinder;
|
||||
};
|
||||
|
||||
virtual const StubInfo &stubInfo() = 0;
|
||||
|
@ -205,6 +215,7 @@ protected:
|
|||
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();
|
||||
static std::unique_ptr<mach_o::ArchHandler> create_arm64();
|
||||
|
||||
// Handy way to pack mach-o r_type and other bit fields into one 16-bit value.
|
||||
typedef uint16_t RelocPattern;
|
||||
|
|
|
@ -208,6 +208,7 @@ const ArchHandler::StubInfo ArchHandler_arm::_sStubInfoArmPIC = {
|
|||
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 },
|
||||
{ false, 0, 0, 0 },
|
||||
|
||||
// Stub Helper size and code
|
||||
12,
|
||||
|
@ -232,7 +233,9 @@ const ArchHandler::StubInfo ArchHandler_arm::_sStubInfoArmPIC = {
|
|||
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, 0xC },
|
||||
{ Reference::KindArch::ARM, delta32, 32, 0x04 }
|
||||
{ false, 0, 0, 0 },
|
||||
{ Reference::KindArch::ARM, delta32, 32, 0x04 },
|
||||
{ false, 0, 0, 0 }
|
||||
};
|
||||
|
||||
const ArchHandler::StubInfo &ArchHandler_arm::stubInfo() {
|
||||
|
|
|
@ -0,0 +1,727 @@
|
|||
//===- lib/FileFormat/MachO/ArchHandler_arm64.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"
|
||||
#include "llvm/Support/Format.h"
|
||||
|
||||
using namespace llvm::MachO;
|
||||
using namespace lld::mach_o::normalized;
|
||||
|
||||
namespace lld {
|
||||
namespace mach_o {
|
||||
|
||||
class ArchHandler_arm64 : public ArchHandler {
|
||||
public:
|
||||
ArchHandler_arm64();
|
||||
virtual ~ArchHandler_arm64();
|
||||
|
||||
const Registry::KindStrings *kindStrings() override { return _sKindStrings; }
|
||||
|
||||
Reference::KindArch kindArch() override {
|
||||
return Reference::KindArch::AArch64;
|
||||
}
|
||||
|
||||
/// 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::AArch64);
|
||||
switch (ref.kindValue()) {
|
||||
case gotPage21:
|
||||
case gotOffset12:
|
||||
canBypassGOT = true;
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/// Used by GOTPass to update GOT References.
|
||||
void updateReferenceToGOT(const Reference *ref, bool targetNowGOT) override {
|
||||
// If GOT slot was instanciated, transform:
|
||||
// gotPage21/gotOffset12 -> page21/offset12scale8
|
||||
// If GOT slot optimized away, transform:
|
||||
// gotPage21/gotOffset12 -> page21/addOffset12
|
||||
assert(ref->kindNamespace() == Reference::KindNamespace::mach_o);
|
||||
assert(ref->kindArch() == Reference::KindArch::AArch64);
|
||||
switch (ref->kindValue()) {
|
||||
case gotPage21:
|
||||
const_cast<Reference *>(ref)->setKindValue(page21);
|
||||
break;
|
||||
case gotOffset12:
|
||||
const_cast<Reference *>(ref)->setKindValue(targetNowGOT ?
|
||||
offset12scale8 : addOffset12);
|
||||
break;
|
||||
default:
|
||||
llvm_unreachable("Not a GOT reference");
|
||||
}
|
||||
}
|
||||
|
||||
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 bool needsLocalSymbolInRelocatableFile(const DefinedAtom *atom) {
|
||||
return (atom->contentType() == DefinedAtom::typeCString);
|
||||
}
|
||||
|
||||
void generateAtomContent(const DefinedAtom &atom, bool relocatable,
|
||||
FindAddressForAtom findAddress,
|
||||
uint8_t *atomContentBuffer) override;
|
||||
|
||||
void appendSectionRelocations(const DefinedAtom &atom,
|
||||
uint64_t atomSectionOffset,
|
||||
const Reference &ref,
|
||||
FindSymbolIndexForAtom symbolIndexForAtom,
|
||||
FindSectionIndexForAtom sectionIndexForAtom,
|
||||
FindAddressForAtom addressForAtom,
|
||||
normalized::Relocations &relocs) override;
|
||||
|
||||
private:
|
||||
static const Registry::KindStrings _sKindStrings[];
|
||||
static const StubInfo _sStubInfo;
|
||||
|
||||
enum Arm64_Kinds : Reference::KindValue {
|
||||
invalid, /// for error condition
|
||||
|
||||
// Kinds found in mach-o .o files:
|
||||
branch26, /// ex: bl _foo
|
||||
page21, /// ex: adrp x1, _foo@PAGE
|
||||
offset12, /// ex: ldrb w0, [x1, _foo@PAGEOFF]
|
||||
offset12scale2, /// ex: ldrs w0, [x1, _foo@PAGEOFF]
|
||||
offset12scale4, /// ex: ldr w0, [x1, _foo@PAGEOFF]
|
||||
offset12scale8, /// ex: ldr x0, [x1, _foo@PAGEOFF]
|
||||
offset12scale16, /// ex: ldr q0, [x1, _foo@PAGEOFF]
|
||||
gotPage21, /// ex: adrp x1, _foo@GOTPAGE
|
||||
gotOffset12, /// ex: ldr w0, [x1, _foo@GOTPAGEOFF]
|
||||
tlvPage21, /// ex: adrp x1, _foo@TLVPAGE
|
||||
tlvOffset12, /// ex: ldr w0, [x1, _foo@TLVPAGEOFF]
|
||||
|
||||
pointer64, /// ex: .quad _foo
|
||||
delta64, /// ex: .quad _foo - .
|
||||
delta32, /// ex: .long _foo - .
|
||||
pointer64ToGOT, /// ex: .quad _foo@GOT
|
||||
delta32ToGOT, /// ex: .long _foo@GOT - .
|
||||
|
||||
// Kinds introduced by Passes:
|
||||
addOffset12, /// Location contains LDR to change into ADD.
|
||||
lazyPointer, /// Location contains a lazy pointer.
|
||||
lazyImmediateLocation, /// Location contains immediate value used in stub.
|
||||
};
|
||||
|
||||
void applyFixupFinal(const Reference &ref, uint8_t *location,
|
||||
uint64_t fixupAddress, uint64_t targetAddress,
|
||||
uint64_t inAtomAddress);
|
||||
|
||||
void applyFixupRelocatable(const Reference &ref, uint8_t *location,
|
||||
uint64_t fixupAddress, uint64_t targetAddress,
|
||||
uint64_t inAtomAddress);
|
||||
|
||||
// Utility functions for inspecting/updating instructions.
|
||||
static uint32_t setDisplacementInBranch26(uint32_t instr, int32_t disp);
|
||||
static uint32_t setDisplacementInADRP(uint32_t instr, int64_t disp);
|
||||
static Arm64_Kinds offset12KindFromInstruction(uint32_t instr);
|
||||
static uint32_t setImm12(uint32_t instr, uint32_t offset);
|
||||
|
||||
const bool _swap;
|
||||
};
|
||||
|
||||
ArchHandler_arm64::ArchHandler_arm64()
|
||||
: _swap(!MachOLinkingContext::isHostEndian(MachOLinkingContext::arch_arm64)) {
|
||||
}
|
||||
|
||||
ArchHandler_arm64::~ArchHandler_arm64() {}
|
||||
|
||||
const Registry::KindStrings ArchHandler_arm64::_sKindStrings[] = {
|
||||
LLD_KIND_STRING_ENTRY(invalid),
|
||||
LLD_KIND_STRING_ENTRY(branch26),
|
||||
LLD_KIND_STRING_ENTRY(page21),
|
||||
LLD_KIND_STRING_ENTRY(offset12),
|
||||
LLD_KIND_STRING_ENTRY(offset12scale2),
|
||||
LLD_KIND_STRING_ENTRY(offset12scale4),
|
||||
LLD_KIND_STRING_ENTRY(offset12scale8),
|
||||
LLD_KIND_STRING_ENTRY(offset12scale16),
|
||||
LLD_KIND_STRING_ENTRY(gotPage21),
|
||||
LLD_KIND_STRING_ENTRY(gotOffset12),
|
||||
LLD_KIND_STRING_ENTRY(tlvPage21),
|
||||
LLD_KIND_STRING_ENTRY(tlvOffset12),
|
||||
LLD_KIND_STRING_ENTRY(pointer64),
|
||||
LLD_KIND_STRING_ENTRY(delta64),
|
||||
LLD_KIND_STRING_ENTRY(delta32),
|
||||
LLD_KIND_STRING_ENTRY(pointer64ToGOT),
|
||||
LLD_KIND_STRING_ENTRY(delta32ToGOT),
|
||||
|
||||
LLD_KIND_STRING_ENTRY(addOffset12),
|
||||
LLD_KIND_STRING_ENTRY(lazyPointer),
|
||||
LLD_KIND_STRING_ENTRY(lazyImmediateLocation),
|
||||
LLD_KIND_STRING_ENTRY(pointer64),
|
||||
|
||||
LLD_KIND_STRING_END
|
||||
};
|
||||
|
||||
const ArchHandler::StubInfo ArchHandler_arm64::_sStubInfo = {
|
||||
"dyld_stub_binder",
|
||||
|
||||
// Lazy pointer references
|
||||
{ Reference::KindArch::AArch64, pointer64, 0, 0 },
|
||||
{ Reference::KindArch::AArch64, lazyPointer, 0, 0 },
|
||||
|
||||
// GOT pointer to dyld_stub_binder
|
||||
{ Reference::KindArch::AArch64, pointer64, 0, 0 },
|
||||
|
||||
// arm64 code alignment 2^2
|
||||
2,
|
||||
|
||||
// Stub size and code
|
||||
12,
|
||||
{ 0x10, 0x00, 0x00, 0x90, // ADRP X16, lazy_pointer@page
|
||||
0x10, 0x02, 0x40, 0xF9, // LDR X16, [X16, lazy_pointer@pageoff]
|
||||
0x00, 0x02, 0x1F, 0xD6 }, // BR X16
|
||||
{ Reference::KindArch::AArch64, page21, 0, 0 },
|
||||
{ true, offset12scale8, 4, 0 },
|
||||
|
||||
// Stub Helper size and code
|
||||
12,
|
||||
{ 0x50, 0x00, 0x00, 0x18, // LDR W16, L0
|
||||
0x00, 0x00, 0x00, 0x14, // LDR B helperhelper
|
||||
0x00, 0x00, 0x00, 0x00 }, // L0: .long 0
|
||||
{ Reference::KindArch::AArch64, lazyImmediateLocation, 8, 0 },
|
||||
{ Reference::KindArch::AArch64, branch26, 4, 0 },
|
||||
|
||||
// Stub Helper-Common size and code
|
||||
24,
|
||||
{ 0x11, 0x00, 0x00, 0x90, // ADRP X17, dyld_ImageLoaderCache@page
|
||||
0x31, 0x02, 0x00, 0x91, // ADD X17, X17, dyld_ImageLoaderCache@pageoff
|
||||
0xF0, 0x47, 0xBF, 0xA9, // STP X16/X17, [SP, #-16]!
|
||||
0x10, 0x00, 0x00, 0x90, // ADRP X16, _fast_lazy_bind@page
|
||||
0x10, 0x02, 0x40, 0xF9, // LDR X16, [X16,_fast_lazy_bind@pageoff]
|
||||
0x00, 0x02, 0x1F, 0xD6 }, // BR X16
|
||||
{ Reference::KindArch::AArch64, page21, 0, 0 },
|
||||
{ true, offset12, 4, 0 },
|
||||
{ Reference::KindArch::AArch64, page21, 12, 0 },
|
||||
{ true, offset12scale8, 16, 0 }
|
||||
};
|
||||
|
||||
bool ArchHandler_arm64::isCallSite(const Reference &ref) {
|
||||
if (ref.kindNamespace() != Reference::KindNamespace::mach_o)
|
||||
return false;
|
||||
assert(ref.kindArch() == Reference::KindArch::AArch64);
|
||||
return (ref.kindValue() == branch26);
|
||||
}
|
||||
|
||||
bool ArchHandler_arm64::isPointer(const Reference &ref) {
|
||||
if (ref.kindNamespace() != Reference::KindNamespace::mach_o)
|
||||
return false;
|
||||
assert(ref.kindArch() == Reference::KindArch::AArch64);
|
||||
Reference::KindValue kind = ref.kindValue();
|
||||
return (kind == pointer64);
|
||||
}
|
||||
|
||||
bool ArchHandler_arm64::isPairedReloc(const Relocation &r) {
|
||||
return ((r.type == ARM64_RELOC_ADDEND) || (r.type == ARM64_RELOC_SUBTRACTOR));
|
||||
}
|
||||
|
||||
uint32_t ArchHandler_arm64::setDisplacementInBranch26(uint32_t instr,
|
||||
int32_t displacement) {
|
||||
assert((displacement <= 134217727) && (displacement > (-134217728)) &&
|
||||
"arm64 branch out of range");
|
||||
return (instr & 0xFC000000) | ((uint32_t)(displacement >> 2) & 0x03FFFFFF);
|
||||
}
|
||||
|
||||
uint32_t ArchHandler_arm64::setDisplacementInADRP(uint32_t instruction,
|
||||
int64_t displacement) {
|
||||
assert((displacement <= 0x100000000LL) && (displacement > (-0x100000000LL)) &&
|
||||
"arm64 ADRP out of range");
|
||||
assert(((instruction & 0x9F000000) == 0x90000000) &&
|
||||
"reloc not on ADRP instruction");
|
||||
uint32_t immhi = (displacement >> 9) & (0x00FFFFE0);
|
||||
uint32_t immlo = (displacement << 17) & (0x60000000);
|
||||
return (instruction & 0x9F00001F) | immlo | immhi;
|
||||
}
|
||||
|
||||
ArchHandler_arm64::Arm64_Kinds
|
||||
ArchHandler_arm64::offset12KindFromInstruction(uint32_t instruction) {
|
||||
if (instruction & 0x08000000) {
|
||||
switch ((instruction >> 30) & 0x3) {
|
||||
case 0:
|
||||
if ((instruction & 0x04800000) == 0x04800000)
|
||||
return offset12scale16;
|
||||
return offset12;
|
||||
case 1:
|
||||
return offset12scale2;
|
||||
case 2:
|
||||
return offset12scale4;
|
||||
case 3:
|
||||
return offset12scale8;
|
||||
}
|
||||
}
|
||||
return offset12;
|
||||
}
|
||||
|
||||
uint32_t ArchHandler_arm64::setImm12(uint32_t instruction, uint32_t offset) {
|
||||
assert(((offset & 0xFFFFF000) == 0) && "imm12 offset out of range");
|
||||
uint32_t imm12 = offset << 10;
|
||||
return (instruction & 0xFFC003FF) | imm12;
|
||||
}
|
||||
|
||||
std::error_code ArchHandler_arm64::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];
|
||||
switch (relocPattern(reloc)) {
|
||||
case ARM64_RELOC_BRANCH26 | rPcRel | rExtern | rLength4:
|
||||
// ex: bl _foo
|
||||
*kind = branch26;
|
||||
if (auto ec = atomFromSymbolIndex(reloc.symbol, target))
|
||||
return ec;
|
||||
*addend = 0;
|
||||
return std::error_code();
|
||||
case ARM64_RELOC_PAGE21 | rPcRel | rExtern | rLength4:
|
||||
// ex: adrp x1, _foo@PAGE
|
||||
*kind = page21;
|
||||
if (auto ec = atomFromSymbolIndex(reloc.symbol, target))
|
||||
return ec;
|
||||
*addend = 0;
|
||||
return std::error_code();
|
||||
case ARM64_RELOC_PAGEOFF12 | rExtern | rLength4:
|
||||
// ex: ldr x0, [x1, _foo@PAGEOFF]
|
||||
*kind = offset12KindFromInstruction(readS32(swap, fixupContent));
|
||||
if (auto ec = atomFromSymbolIndex(reloc.symbol, target))
|
||||
return ec;
|
||||
*addend = 0;
|
||||
return std::error_code();
|
||||
case ARM64_RELOC_GOT_LOAD_PAGE21 | rPcRel | rExtern | rLength4:
|
||||
// ex: adrp x1, _foo@GOTPAGE
|
||||
*kind = gotPage21;
|
||||
if (auto ec = atomFromSymbolIndex(reloc.symbol, target))
|
||||
return ec;
|
||||
*addend = 0;
|
||||
return std::error_code();
|
||||
case ARM64_RELOC_GOT_LOAD_PAGEOFF12 | rExtern | rLength4:
|
||||
// ex: ldr x0, [x1, _foo@GOTPAGEOFF]
|
||||
*kind = gotOffset12;
|
||||
if (auto ec = atomFromSymbolIndex(reloc.symbol, target))
|
||||
return ec;
|
||||
*addend = 0;
|
||||
return std::error_code();
|
||||
case ARM64_RELOC_TLVP_LOAD_PAGE21 | rPcRel | rExtern | rLength4:
|
||||
// ex: adrp x1, _foo@TLVPAGE
|
||||
*kind = tlvPage21;
|
||||
if (auto ec = atomFromSymbolIndex(reloc.symbol, target))
|
||||
return ec;
|
||||
*addend = 0;
|
||||
return std::error_code();
|
||||
case ARM64_RELOC_TLVP_LOAD_PAGEOFF12 | rExtern | rLength4:
|
||||
// ex: ldr x0, [x1, _foo@TLVPAGEOFF]
|
||||
*kind = tlvOffset12;
|
||||
if (auto ec = atomFromSymbolIndex(reloc.symbol, target))
|
||||
return ec;
|
||||
*addend = 0;
|
||||
return std::error_code();
|
||||
case X86_64_RELOC_UNSIGNED | rExtern | rLength8:
|
||||
// ex: .quad _foo + N
|
||||
*kind = pointer64;
|
||||
if (auto ec = atomFromSymbolIndex(reloc.symbol, target))
|
||||
return ec;
|
||||
*addend = readS64(swap, fixupContent);
|
||||
return std::error_code();
|
||||
case ARM64_RELOC_POINTER_TO_GOT | rExtern | rLength8:
|
||||
// ex: .quad _foo@GOT
|
||||
*kind = pointer64ToGOT;
|
||||
if (auto ec = atomFromSymbolIndex(reloc.symbol, target))
|
||||
return ec;
|
||||
*addend = 0;
|
||||
return std::error_code();
|
||||
case ARM64_RELOC_POINTER_TO_GOT | rPcRel | rExtern | rLength4:
|
||||
// ex: .long _foo@GOT - .
|
||||
*kind = delta32ToGOT;
|
||||
if (auto ec = atomFromSymbolIndex(reloc.symbol, target))
|
||||
return ec;
|
||||
*addend = 0;
|
||||
return std::error_code();
|
||||
default:
|
||||
return make_dynamic_error_code(Twine("unsupported arm relocation type"));
|
||||
}
|
||||
}
|
||||
|
||||
std::error_code ArchHandler_arm64::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) {
|
||||
const uint8_t *fixupContent = &inAtom->rawContent()[offsetInAtom];
|
||||
const uint32_t *cont32 = reinterpret_cast<const uint32_t *>(fixupContent);
|
||||
switch (relocPattern(reloc1) << 16 | relocPattern(reloc2)) {
|
||||
case ((ARM64_RELOC_ADDEND | rLength4) << 16 |
|
||||
ARM64_RELOC_BRANCH26 | rPcRel | rExtern | rLength4):
|
||||
// ex: bl _foo+8
|
||||
*kind = branch26;
|
||||
if (auto ec = atomFromSymbolIndex(reloc2.symbol, target))
|
||||
return ec;
|
||||
*addend = reloc1.symbol;
|
||||
return std::error_code();
|
||||
case ((ARM64_RELOC_ADDEND | rLength4) << 16 |
|
||||
ARM64_RELOC_PAGE21 | rPcRel | rExtern | rLength4):
|
||||
// ex: adrp x1, _foo@PAGE
|
||||
*kind = page21;
|
||||
if (auto ec = atomFromSymbolIndex(reloc2.symbol, target))
|
||||
return ec;
|
||||
*addend = reloc1.symbol;
|
||||
return std::error_code();
|
||||
case ((ARM64_RELOC_ADDEND | rLength4) << 16 |
|
||||
ARM64_RELOC_PAGEOFF12 | rExtern | rLength4):
|
||||
// ex: ldr w0, [x1, _foo@PAGEOFF]
|
||||
*kind = offset12KindFromInstruction(*cont32);
|
||||
if (auto ec = atomFromSymbolIndex(reloc2.symbol, target))
|
||||
return ec;
|
||||
*addend = reloc1.symbol;
|
||||
return std::error_code();
|
||||
case ((ARM64_RELOC_SUBTRACTOR | rExtern | rLength8) << 16 |
|
||||
ARM64_RELOC_UNSIGNED | rExtern | rLength8):
|
||||
// ex: .quad _foo - .
|
||||
*kind = delta64;
|
||||
if (auto ec = atomFromSymbolIndex(reloc2.symbol, target))
|
||||
return ec;
|
||||
*addend = readS64(swap, fixupContent) + offsetInAtom;
|
||||
return std::error_code();
|
||||
case ((ARM64_RELOC_SUBTRACTOR | rExtern | rLength4) << 16 |
|
||||
ARM64_RELOC_UNSIGNED | rExtern | rLength4):
|
||||
// ex: .quad _foo - .
|
||||
*kind = delta32;
|
||||
if (auto ec = atomFromSymbolIndex(reloc2.symbol, target))
|
||||
return ec;
|
||||
*addend = readS32(swap, fixupContent) + offsetInAtom;
|
||||
return std::error_code();
|
||||
default:
|
||||
return make_dynamic_error_code(Twine("unsupported arm64 relocation pair"));
|
||||
}
|
||||
}
|
||||
|
||||
void ArchHandler_arm64::generateAtomContent(const DefinedAtom &atom,
|
||||
bool relocatable,
|
||||
FindAddressForAtom findAddress,
|
||||
uint8_t *atomContentBuffer) {
|
||||
// Copy raw bytes.
|
||||
memcpy(atomContentBuffer, atom.rawContent().data(), atom.size());
|
||||
// Apply fix-ups.
|
||||
for (const Reference *ref : atom) {
|
||||
uint32_t offset = ref->offsetInAtom();
|
||||
const Atom *target = ref->target();
|
||||
uint64_t targetAddress = 0;
|
||||
if (isa<DefinedAtom>(target))
|
||||
targetAddress = findAddress(*target);
|
||||
uint64_t atomAddress = findAddress(atom);
|
||||
uint64_t fixupAddress = atomAddress + offset;
|
||||
if (relocatable) {
|
||||
applyFixupRelocatable(*ref, &atomContentBuffer[offset], fixupAddress,
|
||||
targetAddress, atomAddress);
|
||||
} else {
|
||||
applyFixupFinal(*ref, &atomContentBuffer[offset], fixupAddress,
|
||||
targetAddress, atomAddress);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ArchHandler_arm64::applyFixupFinal(const Reference &ref, uint8_t *location,
|
||||
uint64_t fixupAddress,
|
||||
uint64_t targetAddress,
|
||||
uint64_t inAtomAddress) {
|
||||
if (ref.kindNamespace() != Reference::KindNamespace::mach_o)
|
||||
return;
|
||||
assert(ref.kindArch() == Reference::KindArch::AArch64);
|
||||
int32_t *loc32 = reinterpret_cast<int32_t *>(location);
|
||||
uint64_t *loc64 = reinterpret_cast<uint64_t *>(location);
|
||||
int32_t displacement;
|
||||
uint32_t instruction;
|
||||
uint32_t value32;
|
||||
switch (static_cast<Arm64_Kinds>(ref.kindValue())) {
|
||||
case branch26:
|
||||
displacement = (targetAddress - fixupAddress) + ref.addend();
|
||||
value32 = setDisplacementInBranch26(*loc32, displacement);
|
||||
write32(*loc32, _swap, value32);
|
||||
return;
|
||||
case page21:
|
||||
case gotPage21:
|
||||
case tlvPage21:
|
||||
displacement =
|
||||
((targetAddress + ref.addend()) & (-4096)) - (fixupAddress & (-4096));
|
||||
value32 = setDisplacementInADRP(*loc32, displacement);
|
||||
write32(*loc32, _swap, value32);
|
||||
return;
|
||||
case offset12:
|
||||
case gotOffset12:
|
||||
case tlvOffset12:
|
||||
displacement = (targetAddress + ref.addend()) & 0x00000FFF;
|
||||
value32 = setImm12(*loc32, displacement);
|
||||
write32(*loc32, _swap, value32);
|
||||
return;
|
||||
case offset12scale2:
|
||||
displacement = (targetAddress + ref.addend()) & 0x00000FFF;
|
||||
assert(((displacement & 0x1) == 0) &&
|
||||
"scaled imm12 not accessing 2-byte aligneds");
|
||||
value32 = setImm12(*loc32, displacement >> 1);
|
||||
write32(*loc32, _swap, value32);
|
||||
return;
|
||||
case offset12scale4:
|
||||
displacement = (targetAddress + ref.addend()) & 0x00000FFF;
|
||||
assert(((displacement & 0x3) == 0) &&
|
||||
"scaled imm12 not accessing 4-byte aligned");
|
||||
value32 = setImm12(*loc32, displacement >> 2);
|
||||
write32(*loc32, _swap, value32);
|
||||
return;
|
||||
case offset12scale8:
|
||||
displacement = (targetAddress + ref.addend()) & 0x00000FFF;
|
||||
assert(((displacement & 0x7) == 0) &&
|
||||
"scaled imm12 not accessing 8-byte aligned");
|
||||
value32 = setImm12(*loc32, displacement >> 3);
|
||||
write32(*loc32, _swap, value32);
|
||||
return;
|
||||
case offset12scale16:
|
||||
displacement = (targetAddress + ref.addend()) & 0x00000FFF;
|
||||
assert(((displacement & 0xF) == 0) &&
|
||||
"scaled imm12 not accessing 16-byte aligned");
|
||||
value32 = setImm12(*loc32, displacement >> 4);
|
||||
write32(*loc32, _swap, value32);
|
||||
return;
|
||||
case addOffset12:
|
||||
instruction = read32(_swap, *loc32);
|
||||
assert(((instruction & 0xFFC00000) == 0xF9400000) &&
|
||||
"GOT reloc is not an LDR instruction");
|
||||
displacement = (targetAddress + ref.addend()) & 0x00000FFF;
|
||||
value32 = 0x91000000 | (instruction & 0x000003FF);
|
||||
instruction = setImm12(value32, displacement);
|
||||
write32(*loc32, _swap, instruction);
|
||||
return;
|
||||
case pointer64:
|
||||
case pointer64ToGOT:
|
||||
write64(*loc64, _swap, targetAddress + ref.addend());
|
||||
return;
|
||||
case delta64:
|
||||
write64(*loc64, _swap, (targetAddress - fixupAddress) + ref.addend());
|
||||
return;
|
||||
case delta32:
|
||||
case delta32ToGOT:
|
||||
write32(*loc32, _swap, (targetAddress - fixupAddress) + ref.addend());
|
||||
return;
|
||||
case lazyPointer:
|
||||
case lazyImmediateLocation:
|
||||
// Do nothing
|
||||
return;
|
||||
case invalid:
|
||||
// Fall into llvm_unreachable().
|
||||
break;
|
||||
}
|
||||
llvm_unreachable("invalid arm64 Reference Kind");
|
||||
}
|
||||
|
||||
void ArchHandler_arm64::applyFixupRelocatable(const Reference &ref,
|
||||
uint8_t *location,
|
||||
uint64_t fixupAddress,
|
||||
uint64_t targetAddress,
|
||||
uint64_t inAtomAddress) {
|
||||
if (ref.kindNamespace() != Reference::KindNamespace::mach_o)
|
||||
return;
|
||||
assert(ref.kindArch() == Reference::KindArch::AArch64);
|
||||
int32_t *loc32 = reinterpret_cast<int32_t *>(location);
|
||||
uint64_t *loc64 = reinterpret_cast<uint64_t *>(location);
|
||||
uint32_t value32;
|
||||
switch (static_cast<Arm64_Kinds>(ref.kindValue())) {
|
||||
case branch26:
|
||||
value32 = setDisplacementInBranch26(*loc32, 0);
|
||||
write32(*loc32, _swap, value32);
|
||||
return;
|
||||
case page21:
|
||||
case gotPage21:
|
||||
case tlvPage21:
|
||||
value32 = setDisplacementInADRP(*loc32, 0);
|
||||
write32(*loc32, _swap, value32);
|
||||
return;
|
||||
case offset12:
|
||||
case offset12scale2:
|
||||
case offset12scale4:
|
||||
case offset12scale8:
|
||||
case offset12scale16:
|
||||
case gotOffset12:
|
||||
case tlvOffset12:
|
||||
value32 = setImm12(*loc32, 0);
|
||||
write32(*loc32, _swap, value32);
|
||||
return;
|
||||
case pointer64:
|
||||
write64(*loc64, _swap, ref.addend());
|
||||
return;
|
||||
case delta64:
|
||||
write64(*loc64, _swap, ref.addend() + inAtomAddress - fixupAddress);
|
||||
return;
|
||||
case delta32:
|
||||
write32(*loc32, _swap, ref.addend() + inAtomAddress - fixupAddress);
|
||||
return;
|
||||
case pointer64ToGOT:
|
||||
write64(*loc64, _swap, 0);
|
||||
return;
|
||||
case delta32ToGOT:
|
||||
write32(*loc32, _swap, -fixupAddress);
|
||||
return;
|
||||
case addOffset12:
|
||||
llvm_unreachable("lazy reference kind implies GOT pass was run");
|
||||
case lazyPointer:
|
||||
case lazyImmediateLocation:
|
||||
llvm_unreachable("lazy reference kind implies Stubs pass was run");
|
||||
case invalid:
|
||||
// Fall into llvm_unreachable().
|
||||
break;
|
||||
}
|
||||
llvm_unreachable("unknown arm64 Reference Kind");
|
||||
}
|
||||
|
||||
void ArchHandler_arm64::appendSectionRelocations(
|
||||
const DefinedAtom &atom, uint64_t atomSectionOffset, const Reference &ref,
|
||||
FindSymbolIndexForAtom symbolIndexForAtom,
|
||||
FindSectionIndexForAtom sectionIndexForAtom,
|
||||
FindAddressForAtom addressForAtom, normalized::Relocations &relocs) {
|
||||
if (ref.kindNamespace() != Reference::KindNamespace::mach_o)
|
||||
return;
|
||||
assert(ref.kindArch() == Reference::KindArch::AArch64);
|
||||
uint32_t sectionOffset = atomSectionOffset + ref.offsetInAtom();
|
||||
switch (static_cast<Arm64_Kinds>(ref.kindValue())) {
|
||||
case branch26:
|
||||
if (ref.addend()) {
|
||||
appendReloc(relocs, sectionOffset, ref.addend(), 0,
|
||||
ARM64_RELOC_ADDEND | rLength4);
|
||||
appendReloc(relocs, sectionOffset, symbolIndexForAtom(*ref.target()), 0,
|
||||
ARM64_RELOC_BRANCH26 | rPcRel | rExtern | rLength4);
|
||||
} else {
|
||||
appendReloc(relocs, sectionOffset, symbolIndexForAtom(*ref.target()), 0,
|
||||
ARM64_RELOC_BRANCH26 | rPcRel | rExtern | rLength4);
|
||||
}
|
||||
return;
|
||||
case page21:
|
||||
if (ref.addend()) {
|
||||
appendReloc(relocs, sectionOffset, ref.addend(), 0,
|
||||
ARM64_RELOC_ADDEND | rLength4);
|
||||
appendReloc(relocs, sectionOffset, symbolIndexForAtom(*ref.target()), 0,
|
||||
ARM64_RELOC_PAGE21 | rPcRel | rExtern | rLength4);
|
||||
} else {
|
||||
appendReloc(relocs, sectionOffset, symbolIndexForAtom(*ref.target()), 0,
|
||||
ARM64_RELOC_PAGE21 | rPcRel | rExtern | rLength4);
|
||||
}
|
||||
return;
|
||||
case offset12:
|
||||
case offset12scale2:
|
||||
case offset12scale4:
|
||||
case offset12scale8:
|
||||
case offset12scale16:
|
||||
if (ref.addend()) {
|
||||
appendReloc(relocs, sectionOffset, ref.addend(), 0,
|
||||
ARM64_RELOC_ADDEND | rLength4);
|
||||
appendReloc(relocs, sectionOffset, symbolIndexForAtom(*ref.target()), 0,
|
||||
ARM64_RELOC_PAGEOFF12 | rExtern | rLength4);
|
||||
} else {
|
||||
appendReloc(relocs, sectionOffset, symbolIndexForAtom(*ref.target()), 0,
|
||||
ARM64_RELOC_PAGEOFF12 | rExtern | rLength4);
|
||||
}
|
||||
return;
|
||||
case gotPage21:
|
||||
assert(ref.addend() == 0);
|
||||
appendReloc(relocs, sectionOffset, symbolIndexForAtom(*ref.target()), 0,
|
||||
ARM64_RELOC_GOT_LOAD_PAGE21 | rPcRel | rExtern | rLength4);
|
||||
return;
|
||||
case gotOffset12:
|
||||
assert(ref.addend() == 0);
|
||||
appendReloc(relocs, sectionOffset, symbolIndexForAtom(*ref.target()), 0,
|
||||
ARM64_RELOC_GOT_LOAD_PAGEOFF12 | rExtern | rLength4);
|
||||
return;
|
||||
case tlvPage21:
|
||||
assert(ref.addend() == 0);
|
||||
appendReloc(relocs, sectionOffset, symbolIndexForAtom(*ref.target()), 0,
|
||||
ARM64_RELOC_TLVP_LOAD_PAGE21 | rPcRel | rExtern | rLength4);
|
||||
return;
|
||||
case tlvOffset12:
|
||||
assert(ref.addend() == 0);
|
||||
appendReloc(relocs, sectionOffset, symbolIndexForAtom(*ref.target()), 0,
|
||||
ARM64_RELOC_TLVP_LOAD_PAGEOFF12 | rExtern | rLength4);
|
||||
return;
|
||||
case pointer64:
|
||||
appendReloc(relocs, sectionOffset, symbolIndexForAtom(*ref.target()), 0,
|
||||
X86_64_RELOC_UNSIGNED | rExtern | rLength8);
|
||||
return;
|
||||
case delta64:
|
||||
appendReloc(relocs, sectionOffset, symbolIndexForAtom(atom), 0,
|
||||
ARM64_RELOC_SUBTRACTOR | rExtern | rLength8);
|
||||
appendReloc(relocs, sectionOffset, symbolIndexForAtom(*ref.target()), 0,
|
||||
ARM64_RELOC_UNSIGNED | rExtern | rLength8);
|
||||
return;
|
||||
case delta32:
|
||||
appendReloc(relocs, sectionOffset, symbolIndexForAtom(atom), 0,
|
||||
ARM64_RELOC_SUBTRACTOR | rExtern | rLength4 );
|
||||
appendReloc(relocs, sectionOffset, symbolIndexForAtom(*ref.target()), 0,
|
||||
ARM64_RELOC_UNSIGNED | rExtern | rLength4 );
|
||||
return;
|
||||
case pointer64ToGOT:
|
||||
assert(ref.addend() == 0);
|
||||
appendReloc(relocs, sectionOffset, symbolIndexForAtom(*ref.target()), 0,
|
||||
ARM64_RELOC_POINTER_TO_GOT | rExtern | rLength8);
|
||||
return;
|
||||
case delta32ToGOT:
|
||||
assert(ref.addend() == 0);
|
||||
appendReloc(relocs, sectionOffset, symbolIndexForAtom(*ref.target()), 0,
|
||||
ARM64_RELOC_POINTER_TO_GOT | rPcRel | rExtern | rLength4);
|
||||
return;
|
||||
case addOffset12:
|
||||
llvm_unreachable("lazy reference kind implies GOT pass was run");
|
||||
case lazyPointer:
|
||||
case lazyImmediateLocation:
|
||||
llvm_unreachable("lazy reference kind implies Stubs pass was run");
|
||||
case invalid:
|
||||
// Fall into llvm_unreachable().
|
||||
break;
|
||||
}
|
||||
llvm_unreachable("unknown arm64 Reference Kind");
|
||||
}
|
||||
|
||||
std::unique_ptr<mach_o::ArchHandler> ArchHandler::create_arm64() {
|
||||
return std::unique_ptr<mach_o::ArchHandler>(new ArchHandler_arm64());
|
||||
}
|
||||
|
||||
} // namespace mach_o
|
||||
} // namespace lld
|
|
@ -170,6 +170,7 @@ const ArchHandler::StubInfo ArchHandler_x86::_sStubInfo = {
|
|||
6,
|
||||
{ 0xff, 0x25, 0x00, 0x00, 0x00, 0x00 }, // jmp *lazyPointer
|
||||
{ Reference::KindArch::x86, abs32, 2, 0 },
|
||||
{ false, 0, 0, 0 },
|
||||
|
||||
// Stub Helper size and code
|
||||
10,
|
||||
|
@ -184,7 +185,9 @@ const ArchHandler::StubInfo ArchHandler_x86::_sStubInfo = {
|
|||
0xFF, 0x25, 0x00, 0x00, 0x00, 0x00, // jmp *_fast_lazy_bind
|
||||
0x90 }, // nop
|
||||
{ Reference::KindArch::x86, abs32, 1, 0 },
|
||||
{ Reference::KindArch::x86, abs32, 7, 0 }
|
||||
{ false, 0, 0, 0 },
|
||||
{ Reference::KindArch::x86, abs32, 7, 0 },
|
||||
{ false, 0, 0, 0 }
|
||||
};
|
||||
|
||||
bool ArchHandler_x86::isCallSite(const Reference &ref) {
|
||||
|
|
|
@ -185,6 +185,7 @@ const ArchHandler::StubInfo ArchHandler_x86_64::_sStubInfo = {
|
|||
6,
|
||||
{ 0xff, 0x25, 0x00, 0x00, 0x00, 0x00 }, // jmp *lazyPointer
|
||||
{ Reference::KindArch::x86_64, ripRel32, 2, 0 },
|
||||
{ false, 0, 0, 0 },
|
||||
|
||||
// Stub Helper size and code
|
||||
10,
|
||||
|
@ -200,7 +201,9 @@ const ArchHandler::StubInfo ArchHandler_x86_64::_sStubInfo = {
|
|||
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 }
|
||||
{ false, 0, 0, 0 },
|
||||
{ Reference::KindArch::x86_64, ripRel32, 11, 0 },
|
||||
{ false, 0, 0, 0 }
|
||||
|
||||
};
|
||||
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
add_lld_library(lldMachO
|
||||
ArchHandler.cpp
|
||||
ArchHandler_arm.cpp
|
||||
ArchHandler_arm64.cpp
|
||||
ArchHandler_x86.cpp
|
||||
ArchHandler_x86_64.cpp
|
||||
GOTPass.cpp
|
||||
|
|
|
@ -79,6 +79,7 @@ MachOLinkingContext::ArchInfo MachOLinkingContext::_s_archInfos[] = {
|
|||
{ "armv6", arch_armv6, true, CPU_TYPE_ARM, CPU_SUBTYPE_ARM_V6 },
|
||||
{ "armv7", arch_armv7, true, CPU_TYPE_ARM, CPU_SUBTYPE_ARM_V7 },
|
||||
{ "armv7s", arch_armv7s, true, CPU_TYPE_ARM, CPU_SUBTYPE_ARM_V7S },
|
||||
{ "arm64", arch_arm64, true, CPU_TYPE_ARM64, CPU_SUBTYPE_ARM64_ALL },
|
||||
{ "", arch_unknown,false, 0, 0 }
|
||||
};
|
||||
|
||||
|
@ -194,6 +195,10 @@ void MachOLinkingContext::configure(HeaderFileType type, Arch arch, OS os,
|
|||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
// Set default segment page sizes based on arch.
|
||||
if (arch == arch_arm64)
|
||||
_pageSize = 4*4096;
|
||||
}
|
||||
|
||||
uint32_t MachOLinkingContext::getCPUType() const {
|
||||
|
@ -264,10 +269,17 @@ bool MachOLinkingContext::needsStubsPass() const {
|
|||
}
|
||||
|
||||
bool MachOLinkingContext::needsGOTPass() const {
|
||||
// Only x86_64 uses GOT pass but not in -r mode.
|
||||
if (_arch != arch_x86_64)
|
||||
// GOT pass not used in -r mode.
|
||||
if (_outputMachOType == MH_OBJECT)
|
||||
return false;
|
||||
return (_outputMachOType != MH_OBJECT);
|
||||
// Only some arches use GOT pass.
|
||||
switch (_arch) {
|
||||
case arch_x86_64:
|
||||
case arch_arm64:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -236,6 +236,7 @@ struct NormalizedFile {
|
|||
Hex32 sdkVersion;
|
||||
|
||||
// Maps to load commands with LINKEDIT content (final linked images only).
|
||||
Hex32 pageSize;
|
||||
std::vector<RebaseLocation> rebasingInfo;
|
||||
std::vector<BindLocation> bindingInfo;
|
||||
std::vector<BindLocation> weakBindingInfo;
|
||||
|
|
|
@ -470,16 +470,21 @@ void MachOFileLayout::buildFileOffsets() {
|
|||
// Assign sections to segments.
|
||||
for (const Section &s : _file.sections) {
|
||||
_sectInfo[&s] = t2;
|
||||
bool foundSegment = false;
|
||||
for (const Segment &sg : _file.segments) {
|
||||
if ((s.address >= sg.address)
|
||||
if (sg.name.equals(s.segmentName)) {
|
||||
if ((s.address >= sg.address)
|
||||
&& (s.address+s.content.size() <= sg.address+sg.size)) {
|
||||
if (!sg.name.equals(s.segmentName)) {
|
||||
_ec = make_error_code(llvm::errc::executable_format_error);
|
||||
return;
|
||||
_segInfo[&sg].sections.push_back(&s);
|
||||
foundSegment = true;
|
||||
break;
|
||||
}
|
||||
_segInfo[&sg].sections.push_back(&s);
|
||||
}
|
||||
}
|
||||
if (!foundSegment) {
|
||||
_ec = make_error_code(llvm::errc::executable_format_error);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Assign file offsets.
|
||||
|
@ -507,9 +512,10 @@ void MachOFileLayout::buildFileOffsets() {
|
|||
<< ", fileOffset=" << fileOffset << "\n");
|
||||
}
|
||||
|
||||
// FIXME: 4096 should be inferred from segments in normalized file.
|
||||
_segInfo[&sg].fileSize = llvm::RoundUpToAlignment(segFileSize, 4096);
|
||||
fileOffset = llvm::RoundUpToAlignment(fileOffset + segFileSize, 4096);
|
||||
_segInfo[&sg].fileSize = llvm::RoundUpToAlignment(segFileSize,
|
||||
_file.pageSize);
|
||||
fileOffset = llvm::RoundUpToAlignment(fileOffset + segFileSize,
|
||||
_file.pageSize);
|
||||
_addressOfLinkEdit = sg.address + sg.size;
|
||||
}
|
||||
_startOfLinkEdit = fileOffset;
|
||||
|
@ -638,15 +644,16 @@ std::error_code MachOFileLayout::writeSegmentLoadCommands(uint8_t *&lc) {
|
|||
lc = reinterpret_cast<uint8_t*>(next);
|
||||
}
|
||||
// Add implicit __LINKEDIT segment
|
||||
size_t linkeditSize = _endOfLinkEdit - _startOfLinkEdit;
|
||||
typename T::command* cmd = reinterpret_cast<typename T::command*>(lc);
|
||||
cmd->cmd = T::LC;
|
||||
cmd->cmdsize = sizeof(typename T::command);
|
||||
uint8_t *next = lc + cmd->cmdsize;
|
||||
setString16("__LINKEDIT", cmd->segname);
|
||||
cmd->vmaddr = _addressOfLinkEdit;
|
||||
cmd->vmsize = _endOfLinkEdit - _startOfLinkEdit;
|
||||
cmd->vmsize = llvm::RoundUpToAlignment(linkeditSize, _file.pageSize);
|
||||
cmd->fileoff = _startOfLinkEdit;
|
||||
cmd->filesize = _endOfLinkEdit - _startOfLinkEdit;
|
||||
cmd->filesize = linkeditSize;
|
||||
cmd->maxprot = VM_PROT_READ;
|
||||
cmd->initprot = VM_PROT_READ;
|
||||
cmd->nsects = 0;
|
||||
|
@ -823,6 +830,8 @@ void MachOFileLayout::writeSectionContent() {
|
|||
// Copy all section content to output buffer.
|
||||
if (s.type == llvm::MachO::S_ZEROFILL)
|
||||
continue;
|
||||
if (s.content.empty())
|
||||
continue;
|
||||
uint32_t offset = _sectInfo[&s].fileOffset;
|
||||
uint8_t *p = &_buffer[offset];
|
||||
memcpy(p, &s.content[0], s.content.size());
|
||||
|
@ -1262,7 +1271,6 @@ std::error_code MachOFileLayout::writeBinary(StringRef path) {
|
|||
}
|
||||
|
||||
|
||||
|
||||
/// Takes in-memory normalized view and writes a mach-o object file.
|
||||
std::error_code writeBinary(const NormalizedFile &file, StringRef path) {
|
||||
MachOFileLayout layout(file);
|
||||
|
|
|
@ -1149,6 +1149,7 @@ normalizedFromAtoms(const lld::File &atomFile,
|
|||
normFile.fileType = context.outputMachOType();
|
||||
normFile.flags = util.fileFlags();
|
||||
normFile.installName = context.installName();
|
||||
normFile.pageSize = context.pageSize();
|
||||
util.addDependentDylibs(atomFile, normFile);
|
||||
util.copySegmentInfo(normFile);
|
||||
util.copySectionInfo(normFile);
|
||||
|
|
|
@ -285,6 +285,12 @@ std::error_code processSymboledSection(DefinedAtom::ContentType atomType,
|
|||
Atom::Scope rScope = atomScope(rhs->scope);
|
||||
if (lScope != rScope)
|
||||
return lScope < rScope;
|
||||
// If same address and scope, see if one might be better as
|
||||
// the alias.
|
||||
bool lPrivate = (lhs->name.front() == 'l');
|
||||
bool rPrivate = (rhs->name.front() == 'l');
|
||||
if (lPrivate != rPrivate)
|
||||
return lPrivate;
|
||||
// If same address and scope, sort by name.
|
||||
return lhs->name < rhs->name;
|
||||
});
|
||||
|
@ -315,8 +321,15 @@ std::error_code processSymboledSection(DefinedAtom::ContentType atomType,
|
|||
const Symbol *lastSym = nullptr;
|
||||
for (const Symbol *sym : symbols) {
|
||||
if (lastSym != nullptr) {
|
||||
atomFromSymbol(atomType, section, file, lastSym->value, lastSym->name,
|
||||
lastSym->desc, atomScope(lastSym->scope), sym->value, copyRefs);
|
||||
// Ignore any assembler added "ltmpNNN" symbol at start of section
|
||||
// if there is another symbol at the start.
|
||||
if ((lastSym->value != sym->value)
|
||||
|| lastSym->value != section.address
|
||||
|| !lastSym->name.startswith("ltmp")) {
|
||||
atomFromSymbol(atomType, section, file, lastSym->value, lastSym->name,
|
||||
lastSym->desc, atomScope(lastSym->scope), sym->value,
|
||||
copyRefs);
|
||||
}
|
||||
}
|
||||
lastSym = sym;
|
||||
}
|
||||
|
|
|
@ -129,6 +129,7 @@ struct ScalarEnumerationTraits<lld::MachOLinkingContext::Arch> {
|
|||
io.enumCase(value, "armv6", lld::MachOLinkingContext::arch_armv6);
|
||||
io.enumCase(value, "armv7", lld::MachOLinkingContext::arch_armv7);
|
||||
io.enumCase(value, "armv7s", lld::MachOLinkingContext::arch_armv7s);
|
||||
io.enumCase(value, "arm64", lld::MachOLinkingContext::arch_arm64);
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -400,6 +401,30 @@ struct ScalarEnumerationTraits<RelocationInfoType> {
|
|||
io.enumCase(value, "ARM_RELOC_HALF_SECTDIFF",
|
||||
llvm::MachO::ARM_RELOC_HALF_SECTDIFF);
|
||||
break;
|
||||
case lld::MachOLinkingContext::arch_arm64:
|
||||
io.enumCase(value, "ARM64_RELOC_UNSIGNED",
|
||||
llvm::MachO::ARM64_RELOC_UNSIGNED);
|
||||
io.enumCase(value, "ARM64_RELOC_SUBTRACTOR",
|
||||
llvm::MachO::ARM64_RELOC_SUBTRACTOR);
|
||||
io.enumCase(value, "ARM64_RELOC_BRANCH26",
|
||||
llvm::MachO::ARM64_RELOC_BRANCH26);
|
||||
io.enumCase(value, "ARM64_RELOC_PAGE21",
|
||||
llvm::MachO::ARM64_RELOC_PAGE21);
|
||||
io.enumCase(value, "ARM64_RELOC_PAGEOFF12",
|
||||
llvm::MachO::ARM64_RELOC_PAGEOFF12);
|
||||
io.enumCase(value, "ARM64_RELOC_GOT_LOAD_PAGE21",
|
||||
llvm::MachO::ARM64_RELOC_GOT_LOAD_PAGE21);
|
||||
io.enumCase(value, "ARM64_RELOC_GOT_LOAD_PAGEOFF12",
|
||||
llvm::MachO::ARM64_RELOC_GOT_LOAD_PAGEOFF12);
|
||||
io.enumCase(value, "ARM64_RELOC_POINTER_TO_GOT",
|
||||
llvm::MachO::ARM64_RELOC_POINTER_TO_GOT);
|
||||
io.enumCase(value, "ARM64_RELOC_TLVP_LOAD_PAGE21",
|
||||
llvm::MachO::ARM64_RELOC_TLVP_LOAD_PAGE21);
|
||||
io.enumCase(value, "ARM64_RELOC_TLVP_LOAD_PAGEOFF12",
|
||||
llvm::MachO::ARM64_RELOC_TLVP_LOAD_PAGEOFF12);
|
||||
io.enumCase(value, "ARM64_RELOC_ADDEND",
|
||||
llvm::MachO::ARM64_RELOC_ADDEND);
|
||||
break;
|
||||
default:
|
||||
llvm_unreachable("unknown architecture");
|
||||
}
|
||||
|
@ -646,6 +671,7 @@ struct MappingTraits<NormalizedFile> {
|
|||
io.mapOptional("local-symbols", file.localSymbols);
|
||||
io.mapOptional("global-symbols", file.globalSymbols);
|
||||
io.mapOptional("undefined-symbols",file.undefinedSymbols);
|
||||
io.mapOptional("page-size", file.pageSize, Hex32(4096));
|
||||
io.mapOptional("rebasings", file.rebasingInfo);
|
||||
io.mapOptional("bindings", file.bindingInfo);
|
||||
io.mapOptional("weak-bindings", file.weakBindingInfo);
|
||||
|
|
|
@ -321,6 +321,8 @@ private:
|
|||
StubHelperAtom(_file, _stubInfo);
|
||||
|
||||
addReference(stub, _stubInfo.stubReferenceToLP, lp);
|
||||
addOptReference(stub, _stubInfo.stubReferenceToLP,
|
||||
_stubInfo.optStubReferenceToLP, lp);
|
||||
addReference(lp, _stubInfo.lazyPointerReferenceToHelper, helper);
|
||||
addReference(lp, _stubInfo.lazyPointerReferenceToFinal, &target);
|
||||
addReference(helper, _stubInfo.stubHelperReferenceToImm, helper);
|
||||
|
@ -334,14 +336,25 @@ private:
|
|||
return stub;
|
||||
}
|
||||
|
||||
void addReference(SimpleDefinedAtom* atom,
|
||||
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);
|
||||
}
|
||||
|
||||
|
||||
void addOptReference(SimpleDefinedAtom* atom,
|
||||
const ArchHandler::ReferenceInfo &refInfo,
|
||||
const ArchHandler::OptionalRefInfo &optRef,
|
||||
const lld::Atom* target) {
|
||||
if (!optRef.used)
|
||||
return;
|
||||
atom->addReference(Reference::KindNamespace::mach_o,
|
||||
refInfo.arch, optRef.kind, optRef.offset,
|
||||
target, optRef.addend);
|
||||
}
|
||||
|
||||
const DefinedAtom* helperCommon() {
|
||||
if ( !_helperCommonAtom ) {
|
||||
// Lazily create common helper code and data.
|
||||
|
@ -352,11 +365,19 @@ private:
|
|||
_helperBinderNLPAtom = new (_file.allocator())
|
||||
NonLazyPointerAtom(_file, _context.is64Bit());
|
||||
addReference(_helperCommonAtom,
|
||||
_stubInfo.stubHelperCommonReferenceToCache,
|
||||
_stubInfo.stubHelperCommonReferenceToCache,
|
||||
_helperCacheNLPAtom);
|
||||
addReference(_helperCommonAtom,
|
||||
_stubInfo.stubHelperCommonReferenceToBinder,
|
||||
addOptReference(_helperCommonAtom,
|
||||
_stubInfo.stubHelperCommonReferenceToCache,
|
||||
_stubInfo.optStubHelperCommonReferenceToCache,
|
||||
_helperCacheNLPAtom);
|
||||
addReference(_helperCommonAtom,
|
||||
_stubInfo.stubHelperCommonReferenceToBinder,
|
||||
_helperBinderNLPAtom);
|
||||
addOptReference(_helperCommonAtom,
|
||||
_stubInfo.stubHelperCommonReferenceToBinder,
|
||||
_stubInfo.optStubHelperCommonReferenceToBinder,
|
||||
_helperBinderNLPAtom);
|
||||
}
|
||||
return _helperCommonAtom;
|
||||
}
|
||||
|
|
|
@ -0,0 +1,104 @@
|
|||
# RUN: lld -flavor darwin -arch arm64 -ios_version_min 7.0 %s -o %t && \
|
||||
# RUN: llvm-nm -m -n %t | FileCheck %s
|
||||
#
|
||||
# Test that arm64 hello-world can be linked into a mach-o executable
|
||||
#
|
||||
|
||||
--- !mach-o
|
||||
arch: arm64
|
||||
file-type: MH_OBJECT
|
||||
flags: [ MH_SUBSECTIONS_VIA_SYMBOLS ]
|
||||
sections:
|
||||
- segment: __TEXT
|
||||
section: __text
|
||||
type: S_REGULAR
|
||||
attributes: [ S_ATTR_PURE_INSTRUCTIONS, S_ATTR_SOME_INSTRUCTIONS ]
|
||||
alignment: 2
|
||||
address: 0x0000000000000000
|
||||
content: [ 0xFD, 0x7B, 0xBF, 0xA9, 0xFD, 0x03, 0x00, 0x91,
|
||||
0x08, 0x00, 0x00, 0x90, 0x08, 0x01, 0x40, 0xF9,
|
||||
0x00, 0x01, 0x40, 0xF9, 0x01, 0x00, 0x00, 0x90,
|
||||
0x21, 0x00, 0x00, 0x91, 0x00, 0x00, 0x00, 0x94,
|
||||
0x00, 0x00, 0x80, 0x52, 0xFD, 0x7B, 0xC1, 0xA8,
|
||||
0xC0, 0x03, 0x5F, 0xD6 ]
|
||||
relocations:
|
||||
- offset: 0x0000001C
|
||||
type: ARM64_RELOC_BRANCH26
|
||||
length: 2
|
||||
pc-rel: true
|
||||
extern: true
|
||||
symbol: 5
|
||||
- offset: 0x00000018
|
||||
type: ARM64_RELOC_PAGEOFF12
|
||||
length: 2
|
||||
pc-rel: false
|
||||
extern: true
|
||||
symbol: 1
|
||||
- offset: 0x00000014
|
||||
type: ARM64_RELOC_PAGE21
|
||||
length: 2
|
||||
pc-rel: true
|
||||
extern: true
|
||||
symbol: 1
|
||||
- offset: 0x0000000C
|
||||
type: ARM64_RELOC_GOT_LOAD_PAGEOFF12
|
||||
length: 2
|
||||
pc-rel: false
|
||||
extern: true
|
||||
symbol: 4
|
||||
- offset: 0x00000008
|
||||
type: ARM64_RELOC_GOT_LOAD_PAGE21
|
||||
length: 2
|
||||
pc-rel: true
|
||||
extern: true
|
||||
symbol: 4
|
||||
- segment: __TEXT
|
||||
section: __cstring
|
||||
type: S_CSTRING_LITERALS
|
||||
attributes: [ ]
|
||||
address: 0x000000000000002C
|
||||
content: [ 0x68, 0x65, 0x6C, 0x6C, 0x6F, 0x0A, 0x00 ]
|
||||
local-symbols:
|
||||
- name: ltmp0
|
||||
type: N_SECT
|
||||
sect: 1
|
||||
value: 0x0000000000000000
|
||||
- name: l_.str
|
||||
type: N_SECT
|
||||
sect: 2
|
||||
value: 0x000000000000002C
|
||||
- name: ltmp1
|
||||
type: N_SECT
|
||||
sect: 2
|
||||
value: 0x000000000000002C
|
||||
global-symbols:
|
||||
- name: _main
|
||||
type: N_SECT
|
||||
scope: [ N_EXT ]
|
||||
sect: 1
|
||||
value: 0x0000000000000000
|
||||
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: arm64
|
||||
file-type: MH_DYLIB
|
||||
install-name: /usr/lib/libSystem.B.dylib
|
||||
exports:
|
||||
- name: _fprintf
|
||||
- name: ___stdoutp
|
||||
- name: dyld_stub_binder
|
||||
...
|
||||
|
||||
# CHECK: {{[0-9a-f]+}} (__TEXT,__text) external _main
|
||||
# CHECK: (undefined) external ___stdoutp (from libSystem)
|
||||
# CHECK: (undefined) external _fprintf (from libSystem)
|
||||
# CHECK: (undefined) external dyld_stub_binder (from libSystem)
|
|
@ -0,0 +1,191 @@
|
|||
# RUN: lld -flavor darwin -arch arm64 -r -print_atoms %s -o %t | FileCheck %s \
|
||||
# RUN: && lld -flavor darwin -arch arm64 -r -print_atoms %t -o %t2 | FileCheck %s
|
||||
#
|
||||
# Test parsing and writing of arm64 data relocations.
|
||||
#
|
||||
# The first step tests if the supplied mach-o file is parsed into the correct
|
||||
# set of references. The second step verifies relocations can be round-tripped
|
||||
# by writing to a new .o file, then parsing that file which should result in
|
||||
# the same references.
|
||||
#
|
||||
#_test:
|
||||
|
||||
|
||||
--- !mach-o
|
||||
arch: arm64
|
||||
file-type: MH_OBJECT
|
||||
flags: [ ]
|
||||
has-UUID: false
|
||||
OS: unknown
|
||||
sections:
|
||||
- segment: __TEXT
|
||||
section: __text
|
||||
type: S_REGULAR
|
||||
attributes: [ S_ATTR_PURE_INSTRUCTIONS ]
|
||||
address: 0x0000000000000000
|
||||
- segment: __DATA
|
||||
section: __data
|
||||
type: S_REGULAR
|
||||
attributes: [ ]
|
||||
alignment: 3
|
||||
address: 0x0000000000000000
|
||||
content: [ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0xE0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
0xDC, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
0xD0, 0xFF, 0xFF, 0xFF, 0xCE, 0xFF, 0xFF, 0xFF,
|
||||
0xC8, 0xFF, 0xFF, 0xFF ]
|
||||
relocations:
|
||||
- offset: 0x00000038
|
||||
type: ARM64_RELOC_POINTER_TO_GOT
|
||||
length: 2
|
||||
pc-rel: true
|
||||
extern: true
|
||||
symbol: 3
|
||||
- offset: 0x00000034
|
||||
type: ARM64_RELOC_SUBTRACTOR
|
||||
length: 2
|
||||
pc-rel: false
|
||||
extern: true
|
||||
symbol: 2
|
||||
- offset: 0x00000034
|
||||
type: ARM64_RELOC_UNSIGNED
|
||||
length: 2
|
||||
pc-rel: false
|
||||
extern: true
|
||||
symbol: 3
|
||||
- offset: 0x00000030
|
||||
type: ARM64_RELOC_SUBTRACTOR
|
||||
length: 2
|
||||
pc-rel: false
|
||||
extern: true
|
||||
symbol: 2
|
||||
- offset: 0x00000030
|
||||
type: ARM64_RELOC_UNSIGNED
|
||||
length: 2
|
||||
pc-rel: false
|
||||
extern: true
|
||||
symbol: 3
|
||||
- offset: 0x00000028
|
||||
type: ARM64_RELOC_SUBTRACTOR
|
||||
length: 3
|
||||
pc-rel: false
|
||||
extern: true
|
||||
symbol: 2
|
||||
- offset: 0x00000028
|
||||
type: ARM64_RELOC_UNSIGNED
|
||||
length: 3
|
||||
pc-rel: false
|
||||
extern: true
|
||||
symbol: 3
|
||||
- offset: 0x00000020
|
||||
type: ARM64_RELOC_SUBTRACTOR
|
||||
length: 3
|
||||
pc-rel: false
|
||||
extern: true
|
||||
symbol: 2
|
||||
- offset: 0x00000020
|
||||
type: ARM64_RELOC_UNSIGNED
|
||||
length: 3
|
||||
pc-rel: false
|
||||
extern: true
|
||||
symbol: 3
|
||||
- offset: 0x00000018
|
||||
type: ARM64_RELOC_SUBTRACTOR
|
||||
length: 3
|
||||
pc-rel: false
|
||||
extern: true
|
||||
symbol: 2
|
||||
- offset: 0x00000018
|
||||
type: ARM64_RELOC_UNSIGNED
|
||||
length: 3
|
||||
pc-rel: false
|
||||
extern: true
|
||||
symbol: 3
|
||||
- offset: 0x00000010
|
||||
type: ARM64_RELOC_POINTER_TO_GOT
|
||||
length: 3
|
||||
pc-rel: false
|
||||
extern: true
|
||||
symbol: 3
|
||||
- offset: 0x00000008
|
||||
type: ARM64_RELOC_UNSIGNED
|
||||
length: 3
|
||||
pc-rel: false
|
||||
extern: true
|
||||
symbol: 3
|
||||
- offset: 0x00000000
|
||||
type: ARM64_RELOC_UNSIGNED
|
||||
length: 3
|
||||
pc-rel: false
|
||||
extern: true
|
||||
symbol: 3
|
||||
local-symbols:
|
||||
- name: ltmp0
|
||||
type: N_SECT
|
||||
sect: 1
|
||||
value: 0x0000000000000000
|
||||
- name: ltmp1
|
||||
type: N_SECT
|
||||
sect: 2
|
||||
value: 0x0000000000000000
|
||||
- name: _v1
|
||||
type: N_SECT
|
||||
sect: 2
|
||||
value: 0x0000000000000000
|
||||
undefined-symbols:
|
||||
- name: _foo
|
||||
type: N_UNDF
|
||||
scope: [ N_EXT ]
|
||||
value: 0x0000000000000000
|
||||
...
|
||||
|
||||
# CHECK: defined-atoms:
|
||||
# CHECK: - name: _v1
|
||||
# CHECK: type: data
|
||||
# CHECK: content: [ 00, 00, 00, 00, 00, 00, 00, 00, 08, 00, 00, 00,
|
||||
# CHECK: 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00,
|
||||
# CHECK: 00, 00, 00, 00, 00, 00, 00, 00, E0, FF, FF, FF,
|
||||
# CHECK: FF, FF, FF, FF, DC, FF, FF, FF, FF, FF, FF, FF,
|
||||
# CHECK: D0, FF, FF, FF, CE, FF, FF, FF, C8, FF, FF, FF ]
|
||||
# CHECK: references:
|
||||
# CHECK: - kind: pointer64
|
||||
# CHECK: offset: 0
|
||||
# CHECK: target: _foo
|
||||
# CHECK-NOT: addend:
|
||||
# CHECK: - kind: pointer64
|
||||
# CHECK: offset: 8
|
||||
# CHECK: target: _foo
|
||||
# CHECK: addend: 8
|
||||
# CHECK: - kind: pointer64ToGOT
|
||||
# CHECK: offset: 16
|
||||
# CHECK: target: _foo
|
||||
# CHECK-NOT: addend:
|
||||
# CHECK: - kind: delta64
|
||||
# CHECK: offset: 24
|
||||
# CHECK: target: _foo
|
||||
# CHECK: addend: 24
|
||||
# CHECK: - kind: delta64
|
||||
# CHECK: offset: 32
|
||||
# CHECK: target: _foo
|
||||
# CHECK-NOT: addend:
|
||||
# CHECK: - kind: delta64
|
||||
# CHECK: offset: 40
|
||||
# CHECK: target: _foo
|
||||
# CHECK: addend: 4
|
||||
# CHECK: - kind: delta32
|
||||
# CHECK: offset: 48
|
||||
# CHECK: target: _foo
|
||||
# CHECK-NOT: addend:
|
||||
# CHECK: - kind: delta32
|
||||
# CHECK: offset: 52
|
||||
# CHECK: target: _foo
|
||||
# CHECK: addend: 2
|
||||
# CHECK: - kind: delta32ToGOT
|
||||
# CHECK: offset: 56
|
||||
# CHECK: target: _foo
|
||||
# CHECK-NOT: addend:
|
||||
# CHECK: undefined-atoms:
|
||||
# CHECK: - name: _foo
|
|
@ -0,0 +1,237 @@
|
|||
# RUN: lld -flavor darwin -arch arm64 -r -print_atoms %s -o %t | FileCheck %s \
|
||||
# RUN: && lld -flavor darwin -arch arm64 -r -print_atoms %t -o %t2 | FileCheck %s
|
||||
#
|
||||
# Test parsing and writing of arm64 text relocations.
|
||||
#
|
||||
# The first step tests if the supplied mach-o file is parsed into the correct
|
||||
# set of references. The second step verifies relocations can be round-tripped
|
||||
# by writing to a new .o file, then parsing that file which should result in
|
||||
# the same references.
|
||||
#
|
||||
#_test:
|
||||
|
||||
|
||||
--- !mach-o
|
||||
arch: arm64
|
||||
file-type: MH_OBJECT
|
||||
flags: [ ]
|
||||
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: [ 0x00, 0x00, 0x00, 0x94, 0x00, 0x00, 0x00, 0x94,
|
||||
0x01, 0x00, 0x00, 0x90, 0x20, 0x00, 0x40, 0x39,
|
||||
0x20, 0x00, 0x40, 0x79, 0x20, 0x00, 0x40, 0xB9,
|
||||
0x20, 0x00, 0x40, 0xF9, 0x20, 0x00, 0xC0, 0x3D,
|
||||
0x01, 0x00, 0x00, 0x90, 0x20, 0x00, 0x40, 0xB9,
|
||||
0x01, 0x00, 0x00, 0x90, 0x20, 0x00, 0x40, 0xF9,
|
||||
0x00, 0x00, 0x00, 0x90, 0x00, 0x00, 0x40, 0xF9 ]
|
||||
relocations:
|
||||
- offset: 0x00000034
|
||||
type: ARM64_RELOC_TLVP_LOAD_PAGEOFF12
|
||||
length: 2
|
||||
pc-rel: false
|
||||
extern: true
|
||||
symbol: 5
|
||||
- offset: 0x00000030
|
||||
type: ARM64_RELOC_TLVP_LOAD_PAGE21
|
||||
length: 2
|
||||
pc-rel: true
|
||||
extern: true
|
||||
symbol: 5
|
||||
- offset: 0x0000002C
|
||||
type: ARM64_RELOC_GOT_LOAD_PAGEOFF12
|
||||
length: 2
|
||||
pc-rel: false
|
||||
extern: true
|
||||
symbol: 6
|
||||
- offset: 0x00000028
|
||||
type: ARM64_RELOC_GOT_LOAD_PAGE21
|
||||
length: 2
|
||||
pc-rel: true
|
||||
extern: true
|
||||
symbol: 6
|
||||
- offset: 0x00000024
|
||||
type: ARM64_RELOC_ADDEND
|
||||
length: 2
|
||||
pc-rel: false
|
||||
extern: false
|
||||
symbol: 16
|
||||
- offset: 0x00000024
|
||||
type: ARM64_RELOC_PAGEOFF12
|
||||
length: 2
|
||||
pc-rel: false
|
||||
extern: true
|
||||
symbol: 2
|
||||
- offset: 0x00000020
|
||||
type: ARM64_RELOC_ADDEND
|
||||
length: 2
|
||||
pc-rel: false
|
||||
extern: false
|
||||
symbol: 16
|
||||
- offset: 0x00000020
|
||||
type: ARM64_RELOC_PAGE21
|
||||
length: 2
|
||||
pc-rel: true
|
||||
extern: true
|
||||
symbol: 2
|
||||
- offset: 0x0000001C
|
||||
type: ARM64_RELOC_PAGEOFF12
|
||||
length: 2
|
||||
pc-rel: false
|
||||
extern: true
|
||||
symbol: 2
|
||||
- offset: 0x00000018
|
||||
type: ARM64_RELOC_PAGEOFF12
|
||||
length: 2
|
||||
pc-rel: false
|
||||
extern: true
|
||||
symbol: 2
|
||||
- offset: 0x00000014
|
||||
type: ARM64_RELOC_PAGEOFF12
|
||||
length: 2
|
||||
pc-rel: false
|
||||
extern: true
|
||||
symbol: 2
|
||||
- offset: 0x00000010
|
||||
type: ARM64_RELOC_PAGEOFF12
|
||||
length: 2
|
||||
pc-rel: false
|
||||
extern: true
|
||||
symbol: 2
|
||||
- offset: 0x0000000C
|
||||
type: ARM64_RELOC_PAGEOFF12
|
||||
length: 2
|
||||
pc-rel: false
|
||||
extern: true
|
||||
symbol: 2
|
||||
- offset: 0x00000008
|
||||
type: ARM64_RELOC_PAGE21
|
||||
length: 2
|
||||
pc-rel: true
|
||||
extern: true
|
||||
symbol: 2
|
||||
- offset: 0x00000004
|
||||
type: ARM64_RELOC_ADDEND
|
||||
length: 2
|
||||
pc-rel: false
|
||||
extern: false
|
||||
symbol: 8
|
||||
- offset: 0x00000004
|
||||
type: ARM64_RELOC_BRANCH26
|
||||
length: 2
|
||||
pc-rel: true
|
||||
extern: true
|
||||
symbol: 4
|
||||
- offset: 0x00000000
|
||||
type: ARM64_RELOC_BRANCH26
|
||||
length: 2
|
||||
pc-rel: true
|
||||
extern: true
|
||||
symbol: 4
|
||||
- segment: __DATA
|
||||
section: __data
|
||||
type: S_REGULAR
|
||||
attributes: [ ]
|
||||
alignment: 2
|
||||
address: 0x0000000000000038
|
||||
content: [ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 ]
|
||||
local-symbols:
|
||||
- name: ltmp0
|
||||
type: N_SECT
|
||||
sect: 1
|
||||
value: 0x0000000000000000
|
||||
- name: _func
|
||||
type: N_SECT
|
||||
sect: 1
|
||||
value: 0x0000000000000000
|
||||
- name: _v1
|
||||
type: N_SECT
|
||||
sect: 2
|
||||
value: 0x0000000000000038
|
||||
- name: ltmp1
|
||||
type: N_SECT
|
||||
sect: 2
|
||||
value: 0x0000000000000038
|
||||
undefined-symbols:
|
||||
- name: _foo
|
||||
type: N_UNDF
|
||||
scope: [ N_EXT ]
|
||||
value: 0x0000000000000000
|
||||
- name: _tlv
|
||||
type: N_UNDF
|
||||
scope: [ N_EXT ]
|
||||
value: 0x0000000000000000
|
||||
- name: _v2
|
||||
type: N_UNDF
|
||||
scope: [ N_EXT ]
|
||||
value: 0x0000000000000000
|
||||
...
|
||||
|
||||
# CHECK: defined-atoms:
|
||||
# CHECK: - name: _v1
|
||||
# CHECK: type: data
|
||||
# CHECK: content: [ 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00,
|
||||
# CHECK: 00, 00, 00, 00 ]
|
||||
# CHECK: - name: _func
|
||||
# CHECK: content: [ 00, 00, 00, 94, 00, 00, 00, 94, 01, 00, 00, 90,
|
||||
# CHECK: 20, 00, 40, 39, 20, 00, 40, 79, 20, 00, 40, B9,
|
||||
# CHECK: 20, 00, 40, F9, 20, 00, C0, 3D, 01, 00, 00, 90,
|
||||
# CHECK: 20, 00, 40, B9, 01, 00, 00, 90, 20, 00, 40, F9,
|
||||
# CHECK: 00, 00, 00, 90, 00, 00, 40, F9 ]
|
||||
# CHECK: references:
|
||||
# CHECK: - kind: branch26
|
||||
# CHECK: offset: 0
|
||||
# CHECK: target: _foo
|
||||
# CHECK: - kind: branch26
|
||||
# CHECK: offset: 4
|
||||
# CHECK: target: _foo
|
||||
# CHECK: addend: 8
|
||||
# CHECK: - kind: page21
|
||||
# CHECK: offset: 8
|
||||
# CHECK: target: _v1
|
||||
# CHECK: - kind: offset12
|
||||
# CHECK: offset: 12
|
||||
# CHECK: target: _v1
|
||||
# CHECK: - kind: offset12scale2
|
||||
# CHECK: offset: 16
|
||||
# CHECK: target: _v1
|
||||
# CHECK: - kind: offset12scale4
|
||||
# CHECK: offset: 20
|
||||
# CHECK: target: _v1
|
||||
# CHECK: - kind: offset12scale8
|
||||
# CHECK: offset: 24
|
||||
# CHECK: target: _v1
|
||||
# CHECK: - kind: offset12scale16
|
||||
# CHECK: offset: 28
|
||||
# CHECK: target: _v1
|
||||
# CHECK: - kind: page21
|
||||
# CHECK: offset: 32
|
||||
# CHECK: target: _v1
|
||||
# CHECK: addend: 16
|
||||
# CHECK: - kind: offset12scale4
|
||||
# CHECK: offset: 36
|
||||
# CHECK: target: _v1
|
||||
# CHECK: addend: 16
|
||||
# CHECK: - kind: gotPage21
|
||||
# CHECK: offset: 40
|
||||
# CHECK: target: _v2
|
||||
# CHECK: - kind: gotOffset12
|
||||
# CHECK: offset: 44
|
||||
# CHECK: target: _v2
|
||||
# CHECK: - kind: tlvPage21
|
||||
# CHECK: offset: 48
|
||||
# CHECK: target: _tlv
|
||||
# CHECK: - kind: tlvOffset12
|
||||
# CHECK: offset: 52
|
||||
# CHECK: target: _tlv
|
||||
# CHECK: undefined-atoms:
|
||||
# CHECK: - name: _foo
|
||||
# CHECK: - name: _tlv
|
||||
# CHECK: - name: _v2
|
||||
|
Loading…
Reference in New Issue