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