forked from OSchip/llvm-project
Move implementation of WriterOptionsMachO to its own file. Reduced redundant
ivars in WriterOptionsMachO instead have its methods compute ivar interactions. Refactor mach-o Reference Kinds and introduce abstract class KindHandler. Split up StubAtoms.hpp by architecture. Add support for 32-bit x86 stubs. llvm-svn: 158336
This commit is contained in:
parent
130adbc5a3
commit
40b68559e8
|
@ -51,25 +51,27 @@ public:
|
|||
enum Architecture {
|
||||
arch_x86_64,
|
||||
arch_x86,
|
||||
arch_arm,
|
||||
arch_armv6,
|
||||
arch_armv7,
|
||||
};
|
||||
|
||||
OutputKind outputKind() const { return _outputkind; }
|
||||
Architecture architecture() const { return _architecture; }
|
||||
StringRef archName() const { return _archName; }
|
||||
uint64_t pageZeroSize() const { return _pageZeroSize; }
|
||||
uint32_t cpuType() const { return _cpuType; }
|
||||
uint32_t cpuSubtype() const { return _cpuSubtype; }
|
||||
bool noTextRelocations() const { return _noTextRelocations; }
|
||||
|
||||
OutputKind outputKind() const { return _outputkind; }
|
||||
Architecture architecture() const { return _architecture; }
|
||||
StringRef archName() const;
|
||||
uint32_t cpuType() const;
|
||||
uint32_t cpuSubtype() const;
|
||||
uint64_t pageZeroSize() const;
|
||||
bool noTextRelocations() const { return _noTextRelocations; }
|
||||
bool addEntryPointLoadCommand() const;
|
||||
bool addUnixThreadLoadCommand() const;
|
||||
StringRef entryPointName() const;
|
||||
|
||||
protected:
|
||||
OutputKind _outputkind;
|
||||
StringRef _archName;
|
||||
Architecture _architecture;
|
||||
uint64_t _pageZeroSize;
|
||||
uint32_t _cpuType;
|
||||
uint32_t _cpuSubtype;
|
||||
bool _noTextRelocations;
|
||||
StringRef _customEntryPointName;
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
add_lld_library(lldMachO
|
||||
WriterMachO.cpp
|
||||
WriterOptionsMachO.cpp
|
||||
ReferenceKinds.cpp
|
||||
)
|
||||
|
|
|
@ -131,7 +131,7 @@ private:
|
|||
|
||||
};
|
||||
|
||||
void mach_header::recordLoadCommand(const load_command *lc) {
|
||||
inline void mach_header::recordLoadCommand(const load_command *lc) {
|
||||
++ncmds;
|
||||
sizeofcmds += lc->cmdsize;
|
||||
}
|
||||
|
@ -140,6 +140,7 @@ void mach_header::recordLoadCommand(const load_command *lc) {
|
|||
enum {
|
||||
LC_SEGMENT = 0x00000001,
|
||||
LC_SYMTAB = 0x00000002,
|
||||
LC_UNIXTHREAD = 0x00000005,
|
||||
LC_LOAD_DYLIB = 0x0000000C,
|
||||
LC_LOAD_DYLINKER = 0x0000000E,
|
||||
LC_SEGMENT_64 = 0x00000019,
|
||||
|
@ -375,6 +376,95 @@ public:
|
|||
};
|
||||
|
||||
|
||||
//
|
||||
// The thread_command load command holds the set of initial register values
|
||||
// for a dynamic executable. In reality, only the PC and SP are used.
|
||||
//
|
||||
class thread_command : public load_command {
|
||||
public:
|
||||
uint32_t fields_flavor;
|
||||
uint32_t fields_count;
|
||||
private:
|
||||
uint32_t _cpuType;
|
||||
uint8_t *_registerArray;
|
||||
|
||||
public:
|
||||
thread_command(uint32_t cpuType, bool is64)
|
||||
: load_command(LC_UNIXTHREAD, 16+registersBufferSize(cpuType), is64),
|
||||
fields_count(registersBufferSize(cpuType)/4), _cpuType(cpuType) {
|
||||
switch ( cpuType ) {
|
||||
case CPU_TYPE_I386:
|
||||
fields_flavor = 1; // i386_THREAD_STATE
|
||||
break;
|
||||
case CPU_TYPE_X86_64:
|
||||
fields_flavor = 4; // x86_THREAD_STATE64;
|
||||
break;
|
||||
case CPU_TYPE_ARM:
|
||||
fields_flavor = 1; // ARM_THREAD_STATE
|
||||
break;
|
||||
default:
|
||||
assert(0 && "unsupported cpu type");
|
||||
}
|
||||
_registerArray = reinterpret_cast<uint8_t*>(
|
||||
::calloc(registersBufferSize(cpuType), 1));
|
||||
assert(_registerArray);
|
||||
}
|
||||
|
||||
virtual void copyTo(uint8_t *to, bool swap=false) {
|
||||
if ( swap ) {
|
||||
assert(0 && "non-native endianness not supported yet");
|
||||
}
|
||||
else {
|
||||
// in-memory matches on-disk, so copy fixed fields
|
||||
::memcpy(to, (uint8_t*)&cmd, 16);
|
||||
// that register array
|
||||
::memcpy(&to[16], _registerArray, registersBufferSize(_cpuType));
|
||||
}
|
||||
}
|
||||
|
||||
void setPC(uint64_t pc) {
|
||||
uint32_t *regs32 = reinterpret_cast<uint32_t*>(_registerArray);
|
||||
uint64_t *regs64 = reinterpret_cast<uint64_t*>(_registerArray);
|
||||
switch ( _cpuType ) {
|
||||
case CPU_TYPE_I386:
|
||||
regs32[10] = pc;
|
||||
break;
|
||||
case CPU_TYPE_X86_64:
|
||||
regs64[16] = pc;
|
||||
break;
|
||||
case CPU_TYPE_ARM:
|
||||
regs32[15] = pc;
|
||||
break;
|
||||
default:
|
||||
assert(0 && "unsupported cpu type");
|
||||
}
|
||||
}
|
||||
|
||||
virtual ~thread_command() {
|
||||
::free(_registerArray);
|
||||
}
|
||||
|
||||
private:
|
||||
uint32_t registersBufferSize(uint32_t cpuType) {
|
||||
switch ( cpuType ) {
|
||||
case CPU_TYPE_I386:
|
||||
return 64; // i386_THREAD_STATE_COUNT * 4
|
||||
case CPU_TYPE_X86_64:
|
||||
return 168; // x86_THREAD_STATE64_COUNT * 4
|
||||
case CPU_TYPE_ARM:
|
||||
return 68; // ARM_THREAD_STATE_COUNT * 4
|
||||
}
|
||||
assert(0 && "unsupported cpu type");
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
//
|
||||
// The dylib_command load command holds the name/path of a dynamic shared
|
||||
|
|
|
@ -16,85 +16,299 @@
|
|||
namespace lld {
|
||||
namespace mach_o {
|
||||
|
||||
|
||||
struct Mapping {
|
||||
const char* string;
|
||||
Reference::Kind value;
|
||||
uint32_t flags;
|
||||
};
|
||||
//===----------------------------------------------------------------------===//
|
||||
// KindHandler
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
enum {
|
||||
flagsNone = 0x0000,
|
||||
flagsIsCallSite = 0x0001,
|
||||
flagsUsesGOT = 0x0002,
|
||||
flagsisGOTLoad = 0x0006,
|
||||
flags32RipRel = 0x1000,
|
||||
};
|
||||
KindHandler::KindHandler() {
|
||||
}
|
||||
|
||||
KindHandler::~KindHandler() {
|
||||
}
|
||||
|
||||
static const Mapping sKindMappingsx86_64[] = {
|
||||
{ "none", ReferenceKind::x86_64_none, flagsNone },
|
||||
{ "call32", ReferenceKind::x86_64_call32, flagsIsCallSite | flags32RipRel },
|
||||
{ "pcrel32", ReferenceKind::x86_64_pcRel32, flags32RipRel },
|
||||
{ "gotLoad32", ReferenceKind::x86_64_gotLoad32, flagsisGOTLoad | flags32RipRel },
|
||||
{ "gotUse32", ReferenceKind::x86_64_gotUse32, flagsUsesGOT | flags32RipRel },
|
||||
{ "lea32wasGot", ReferenceKind::x86_64_lea32WasGot, flags32RipRel },
|
||||
{ "lazyTarget", ReferenceKind::x86_64_lazyTarget, flagsNone },
|
||||
{ "lazyImm", ReferenceKind::x86_64_lazyImm, flagsNone },
|
||||
{ "gotTarget", ReferenceKind::x86_64_gotTarget, flagsNone },
|
||||
{ "pointer64", ReferenceKind::x86_64_pointer64, flagsNone },
|
||||
{ NULL, ReferenceKind::x86_64_none, flagsNone }
|
||||
};
|
||||
|
||||
|
||||
Reference::Kind ReferenceKind::fromString(StringRef kindName) {
|
||||
for (const Mapping* p = sKindMappingsx86_64; p->string != NULL; ++p) {
|
||||
if ( kindName.equals(p->string) )
|
||||
return p->value;
|
||||
KindHandler *KindHandler::makeHandler(WriterOptionsMachO::Architecture arch) {
|
||||
switch( arch ) {
|
||||
case WriterOptionsMachO::arch_x86_64:
|
||||
return new KindHandler_x86_64();
|
||||
break;
|
||||
case WriterOptionsMachO::arch_x86:
|
||||
return new KindHandler_x86();
|
||||
break;
|
||||
case WriterOptionsMachO::arch_armv6:
|
||||
case WriterOptionsMachO::arch_armv7:
|
||||
return new KindHandler_arm();
|
||||
break;
|
||||
default:
|
||||
assert(0 && "arch not supported");
|
||||
}
|
||||
assert(0 && "unknown darwin reference kind");
|
||||
}
|
||||
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// KindHandler_x86_64
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
KindHandler_x86_64::~KindHandler_x86_64() {
|
||||
}
|
||||
|
||||
Reference::Kind KindHandler_x86_64::stringToKind(StringRef str) {
|
||||
if ( str.equals("none") )
|
||||
return KindHandler_x86_64::none;
|
||||
else if ( str.equals("call32") )
|
||||
return KindHandler_x86_64::call32;
|
||||
else if ( str.equals("ripRel32") )
|
||||
return KindHandler_x86_64::ripRel32;
|
||||
else if ( str.equals("gotLoad32") )
|
||||
return KindHandler_x86_64::gotLoad32;
|
||||
else if ( str.equals("gotUse32") )
|
||||
return KindHandler_x86_64::gotUse32;
|
||||
else if ( str.equals("pointer64") )
|
||||
return KindHandler_x86_64::pointer64;
|
||||
else if ( str.equals("lea32WasGot") )
|
||||
return KindHandler_x86_64::lea32WasGot;
|
||||
else if ( str.equals("lazyTarget") )
|
||||
return KindHandler_x86_64::lazyTarget;
|
||||
else if ( str.equals("lazyImm") )
|
||||
return KindHandler_x86_64::lazyImm;
|
||||
else if ( str.equals("gotTarget") )
|
||||
return KindHandler_x86_64::gotTarget;
|
||||
|
||||
assert(0 && "invalid x86_64 Reference kind");
|
||||
return 0;
|
||||
}
|
||||
|
||||
StringRef ReferenceKind::toString(Reference::Kind kindValue) {
|
||||
for (const Mapping* p = sKindMappingsx86_64; p->string != NULL; ++p) {
|
||||
if ( kindValue == p->value)
|
||||
return p->string;
|
||||
StringRef KindHandler_x86_64::kindToString(Reference::Kind kind) {
|
||||
switch ( (Kinds)kind ) {
|
||||
case none:
|
||||
return StringRef("none");
|
||||
case call32:
|
||||
return StringRef("call32");
|
||||
case ripRel32:
|
||||
return StringRef("ripRel32");
|
||||
case gotLoad32:
|
||||
return StringRef("gotLoad32");
|
||||
case gotUse32:
|
||||
return StringRef("gotUse32");
|
||||
case pointer64:
|
||||
return StringRef("pointer64");
|
||||
case lea32WasGot:
|
||||
return StringRef("lea32WasGot");
|
||||
case lazyTarget:
|
||||
return StringRef("lazyTarget");
|
||||
case lazyImm:
|
||||
return StringRef("lazyImm");
|
||||
case gotTarget:
|
||||
return StringRef("gotTarget");
|
||||
}
|
||||
return StringRef("???");
|
||||
assert(0 && "invalid x86_64 Reference kind");
|
||||
return StringRef();
|
||||
}
|
||||
|
||||
static const Mapping* mappingsForArch(WriterOptionsMachO::Architecture arch) {
|
||||
switch ( arch ) {
|
||||
case WriterOptionsMachO::arch_x86_64:
|
||||
return sKindMappingsx86_64;
|
||||
case WriterOptionsMachO::arch_x86:
|
||||
case WriterOptionsMachO::arch_arm:
|
||||
assert(0 && "references table not yet implemented for arch");
|
||||
return nullptr;
|
||||
bool KindHandler_x86_64::isCallSite(Kind kind) {
|
||||
return (kind == call32);
|
||||
}
|
||||
|
||||
bool KindHandler_x86_64::isPointer(Kind kind) {
|
||||
return (kind == pointer64);
|
||||
}
|
||||
|
||||
|
||||
bool KindHandler_x86_64::isLazyImmediate(Kind kind) {
|
||||
return (kind == lazyImm);
|
||||
}
|
||||
|
||||
|
||||
bool KindHandler_x86_64::isLazyTarget(Kind kind) {
|
||||
return (kind == lazyTarget);
|
||||
}
|
||||
|
||||
|
||||
void KindHandler_x86_64::applyFixup(Kind kind, uint64_t addend, uint8_t *location,
|
||||
uint64_t fixupAddress, uint64_t targetAddress) {
|
||||
int32_t *loc32 = reinterpret_cast<int32_t*>(location);
|
||||
uint64_t* loc64 = reinterpret_cast<uint64_t*>(location);
|
||||
switch ( (Kinds)kind ) {
|
||||
case call32:
|
||||
case ripRel32:
|
||||
case gotLoad32:
|
||||
case gotUse32:
|
||||
*loc32 = (targetAddress - (fixupAddress+4)) + addend;
|
||||
break;
|
||||
case pointer64:
|
||||
*loc64 = targetAddress + addend;
|
||||
break;
|
||||
case lea32WasGot:
|
||||
break;
|
||||
case none:
|
||||
case lazyTarget:
|
||||
case lazyImm:
|
||||
case gotTarget:
|
||||
// do nothing
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
bool ReferenceKind::isCallSite(WriterOptionsMachO::Architecture arch,
|
||||
Reference::Kind kindValue) {
|
||||
for (const Mapping* p = mappingsForArch(arch); p->string != NULL; ++p) {
|
||||
if ( kindValue == p->value )
|
||||
return (p->flags & flagsIsCallSite);
|
||||
}
|
||||
return false;
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// KindHandler_x86
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
KindHandler_x86::~KindHandler_x86() {
|
||||
}
|
||||
|
||||
bool ReferenceKind::isRipRel32(Reference::Kind kindValue) {
|
||||
for (const Mapping* p = sKindMappingsx86_64; p->string != NULL; ++p) {
|
||||
if ( kindValue == p->value )
|
||||
return (p->flags & flags32RipRel);
|
||||
Reference::Kind KindHandler_x86::stringToKind(StringRef str) {
|
||||
if ( str.equals("none") )
|
||||
return KindHandler_x86::none;
|
||||
else if ( str.equals("call32") )
|
||||
return KindHandler_x86::call32;
|
||||
else if ( str.equals("abs32") )
|
||||
return KindHandler_x86::abs32;
|
||||
else if ( str.equals("pointer32") )
|
||||
return KindHandler_x86::pointer32;
|
||||
else if ( str.equals("lazyTarget") )
|
||||
return KindHandler_x86::lazyTarget;
|
||||
else if ( str.equals("lazyImm") )
|
||||
return KindHandler_x86::lazyImm;
|
||||
|
||||
assert(0 && "invalid x86 Reference kind");
|
||||
return 0;
|
||||
}
|
||||
|
||||
StringRef KindHandler_x86::kindToString(Reference::Kind kind) {
|
||||
switch ( (Kinds)kind ) {
|
||||
case none:
|
||||
return StringRef("none");
|
||||
case call32:
|
||||
return StringRef("call32");
|
||||
case abs32:
|
||||
return StringRef("abs32");
|
||||
case pointer32:
|
||||
return StringRef("pointer32");
|
||||
case lazyTarget:
|
||||
return StringRef("lazyTarget");
|
||||
case lazyImm:
|
||||
return StringRef("lazyImm");
|
||||
}
|
||||
assert(0 && "invalid x86 Reference kind");
|
||||
return StringRef();
|
||||
}
|
||||
|
||||
bool KindHandler_x86::isCallSite(Kind kind) {
|
||||
return (kind == call32);
|
||||
}
|
||||
|
||||
bool KindHandler_x86::isPointer(Kind kind) {
|
||||
return (kind == pointer32);
|
||||
}
|
||||
|
||||
|
||||
bool KindHandler_x86::isLazyImmediate(Kind kind) {
|
||||
return (kind == lazyImm);
|
||||
}
|
||||
|
||||
|
||||
bool KindHandler_x86::isLazyTarget(Kind kind) {
|
||||
return (kind == lazyTarget);
|
||||
}
|
||||
|
||||
|
||||
void KindHandler_x86::applyFixup(Kind kind, uint64_t addend, uint8_t *location,
|
||||
uint64_t fixupAddress, uint64_t targetAddress) {
|
||||
int32_t *loc32 = reinterpret_cast<int32_t*>(location);
|
||||
switch ( (Kinds)kind ) {
|
||||
case call32:
|
||||
*loc32 = (targetAddress - (fixupAddress+4)) + addend;
|
||||
break;
|
||||
case pointer32:
|
||||
case abs32:
|
||||
*loc32 = targetAddress + addend;
|
||||
break;
|
||||
case none:
|
||||
case lazyTarget:
|
||||
case lazyImm:
|
||||
// do nothing
|
||||
break;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// KindHandler_arm
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
KindHandler_arm::~KindHandler_arm() {
|
||||
}
|
||||
|
||||
Reference::Kind KindHandler_arm::stringToKind(StringRef str) {
|
||||
if ( str.equals("none") )
|
||||
return KindHandler_arm::none;
|
||||
else if ( str.equals("br22") )
|
||||
return KindHandler_arm::br22;
|
||||
else if ( str.equals("pointer32") )
|
||||
return KindHandler_arm::pointer32;
|
||||
else if ( str.equals("lazyTarget") )
|
||||
return KindHandler_arm::lazyTarget;
|
||||
else if ( str.equals("lazyImm") )
|
||||
return KindHandler_arm::lazyImm;
|
||||
|
||||
assert(0 && "invalid ARM Reference kind");
|
||||
return 0;
|
||||
}
|
||||
|
||||
StringRef KindHandler_arm::kindToString(Reference::Kind kind) {
|
||||
switch ( (Kinds)kind ) {
|
||||
case none:
|
||||
return StringRef("none");
|
||||
case br22:
|
||||
return StringRef("br22");
|
||||
case pointer32:
|
||||
return StringRef("pointer32");
|
||||
case lazyTarget:
|
||||
return StringRef("lazyTarget");
|
||||
case lazyImm:
|
||||
return StringRef("lazyImm");
|
||||
}
|
||||
assert(0 && "invalid ARM Reference kind");
|
||||
return StringRef();
|
||||
}
|
||||
|
||||
bool KindHandler_arm::isCallSite(Kind kind) {
|
||||
return (kind == br22);
|
||||
}
|
||||
|
||||
bool KindHandler_arm::isPointer(Kind kind) {
|
||||
return (kind == pointer32);
|
||||
}
|
||||
|
||||
|
||||
bool KindHandler_arm::isLazyImmediate(Kind kind) {
|
||||
return (kind == lazyImm);
|
||||
}
|
||||
|
||||
|
||||
bool KindHandler_arm::isLazyTarget(Kind kind) {
|
||||
return (kind == lazyTarget);
|
||||
}
|
||||
|
||||
|
||||
void KindHandler_arm::applyFixup(Kind kind, uint64_t addend, uint8_t *location,
|
||||
uint64_t fixupAddress, uint64_t targetAddress) {
|
||||
//int32_t *loc32 = reinterpret_cast<int32_t*>(location);
|
||||
switch ( (Kinds)kind ) {
|
||||
case br22:
|
||||
// FIXME
|
||||
break;
|
||||
case pointer32:
|
||||
// FIXME
|
||||
break;
|
||||
case none:
|
||||
case lazyTarget:
|
||||
case lazyImm:
|
||||
// do nothing
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
} // namespace mach_o
|
||||
} // namespace lld
|
||||
|
|
|
@ -19,51 +19,104 @@ namespace lld {
|
|||
namespace mach_o {
|
||||
|
||||
|
||||
class ReferenceKind {
|
||||
///
|
||||
/// 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:
|
||||
// x86_64 Reference Kinds
|
||||
enum {
|
||||
x86_64_none = 0,
|
||||
x86_64_call32 = 1,
|
||||
x86_64_pcRel32 = 2,
|
||||
x86_64_gotLoad32 = 3,
|
||||
x86_64_gotUse32 = 4,
|
||||
x86_64_lea32WasGot = 5,
|
||||
x86_64_lazyTarget = 6,
|
||||
x86_64_lazyImm = 7,
|
||||
x86_64_gotTarget = 8,
|
||||
x86_64_pointer64 = 9,
|
||||
typedef Reference::Kind Kind;
|
||||
|
||||
static KindHandler *makeHandler(WriterOptionsMachO::Architecture arch);
|
||||
virtual ~KindHandler();
|
||||
virtual Kind stringToKind(StringRef str) = 0;
|
||||
virtual StringRef kindToString(Kind) = 0;
|
||||
virtual bool isCallSite(Kind) = 0;
|
||||
virtual bool isPointer(Kind) = 0;
|
||||
virtual bool isLazyImmediate(Kind) = 0;
|
||||
virtual bool isLazyTarget(Kind) = 0;
|
||||
virtual void applyFixup(Kind kind, uint64_t addend, uint8_t *location,
|
||||
uint64_t fixupAddress, uint64_t targetAddress) = 0;
|
||||
|
||||
protected:
|
||||
KindHandler();
|
||||
};
|
||||
|
||||
|
||||
|
||||
class KindHandler_x86_64 : public KindHandler {
|
||||
public:
|
||||
enum Kinds {
|
||||
none = 0,
|
||||
call32 = 1,
|
||||
ripRel32 = 2,
|
||||
gotLoad32 = 3,
|
||||
gotUse32 = 4,
|
||||
lea32WasGot = 5,
|
||||
lazyTarget = 6,
|
||||
lazyImm = 7,
|
||||
gotTarget = 8,
|
||||
pointer64 = 9
|
||||
};
|
||||
|
||||
// x86 Reference Kinds
|
||||
enum {
|
||||
x86_none = 0,
|
||||
x86_call32 = 1,
|
||||
x86_pointer32 = 2,
|
||||
x86_lazyTarget = 3,
|
||||
x86_lazyImm = 4,
|
||||
virtual ~KindHandler_x86_64();
|
||||
virtual Kind stringToKind(StringRef str);
|
||||
virtual StringRef kindToString(Kind);
|
||||
virtual bool isCallSite(Kind);
|
||||
virtual bool isPointer(Kind);
|
||||
virtual bool isLazyImmediate(Kind);
|
||||
virtual bool isLazyTarget(Kind);
|
||||
virtual void applyFixup(Kind kind, uint64_t addend, uint8_t *location,
|
||||
uint64_t fixupAddress, uint64_t targetAddress);
|
||||
|
||||
};
|
||||
|
||||
|
||||
class KindHandler_x86 : public KindHandler {
|
||||
public:
|
||||
enum Kinds {
|
||||
none = 0,
|
||||
call32 = 1,
|
||||
abs32 = 2,
|
||||
pointer32 = 3,
|
||||
lazyTarget = 4,
|
||||
lazyImm = 5
|
||||
};
|
||||
|
||||
virtual ~KindHandler_x86();
|
||||
virtual Kind stringToKind(StringRef str);
|
||||
virtual StringRef kindToString(Kind);
|
||||
virtual bool isCallSite(Kind);
|
||||
virtual bool isPointer(Kind);
|
||||
virtual bool isLazyImmediate(Kind);
|
||||
virtual bool isLazyTarget(Kind);
|
||||
virtual void applyFixup(Kind kind, uint64_t addend, uint8_t *location,
|
||||
uint64_t fixupAddress, uint64_t targetAddress);
|
||||
|
||||
};
|
||||
|
||||
class KindHandler_arm : public KindHandler {
|
||||
public:
|
||||
enum Kinds {
|
||||
none = 0,
|
||||
br22 = 1,
|
||||
pointer32 = 2,
|
||||
lazyTarget = 3,
|
||||
lazyImm = 4
|
||||
// FIXME
|
||||
};
|
||||
|
||||
// ARM Reference Kinds
|
||||
enum {
|
||||
arm_none = 0,
|
||||
arm_br22 = 1,
|
||||
arm_pointer32 = 2,
|
||||
arm_lazyTarget = 3,
|
||||
arm_lazyImm = 4,
|
||||
// FIXME
|
||||
};
|
||||
virtual ~KindHandler_arm();
|
||||
virtual Kind stringToKind(StringRef str);
|
||||
virtual StringRef kindToString(Kind);
|
||||
virtual bool isCallSite(Kind);
|
||||
virtual bool isPointer(Kind);
|
||||
virtual bool isLazyImmediate(Kind);
|
||||
virtual bool isLazyTarget(Kind);
|
||||
virtual void applyFixup(Kind kind, uint64_t addend, uint8_t *location,
|
||||
uint64_t fixupAddress, uint64_t targetAddress);
|
||||
|
||||
static bool isCallSite(WriterOptionsMachO::Architecture arch,
|
||||
Reference::Kind kindValue);
|
||||
|
||||
static bool isRipRel32(Reference::Kind kindValue);
|
||||
|
||||
|
||||
static Reference::Kind fromString(StringRef kindName);
|
||||
static StringRef toString(Reference::Kind kindValue);
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -19,183 +19,13 @@
|
|||
|
||||
#include "ReferenceKinds.h"
|
||||
#include "SimpleAtoms.hpp"
|
||||
#include "StubAtoms_x86_64.hpp"
|
||||
#include "StubAtoms_x86.hpp"
|
||||
|
||||
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(ReferenceKind::x86_64_pcRel32, 2, &lazyPointer, 0);
|
||||
}
|
||||
|
||||
virtual ContentType contentType() const {
|
||||
return DefinedAtom::typeStub;
|
||||
}
|
||||
|
||||
virtual uint64_t size() const {
|
||||
return 6;
|
||||
}
|
||||
|
||||
virtual ContentPermissions permissions() const {
|
||||
return DefinedAtom::permR_X;
|
||||
}
|
||||
|
||||
virtual ArrayRef<uint8_t> rawContent() const {
|
||||
static const uint8_t instructions[] =
|
||||
{ 0xFF, 0x25, 0x00, 0x00, 0x00, 0x00 }; // jmp *lazyPointer
|
||||
assert(sizeof(instructions) == this->size());
|
||||
return ArrayRef<uint8_t>(instructions, sizeof(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(ReferenceKind::x86_64_pcRel32, 3, &cache, 0);
|
||||
this->addReference(ReferenceKind::x86_64_pcRel32, 11, &binder, 0);
|
||||
}
|
||||
|
||||
virtual ContentType contentType() const {
|
||||
return DefinedAtom::typeStubHelper;
|
||||
}
|
||||
|
||||
virtual uint64_t size() const {
|
||||
return 16;
|
||||
}
|
||||
|
||||
virtual ContentPermissions permissions() const {
|
||||
return DefinedAtom::permR_X;
|
||||
}
|
||||
|
||||
virtual ArrayRef<uint8_t> rawContent() const {
|
||||
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 ArrayRef<uint8_t>(instructions, sizeof(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(ReferenceKind::x86_64_lazyImm, 1, nullptr, 0);
|
||||
this->addReference(ReferenceKind::x86_64_pcRel32, 6, &helperCommon, 0);
|
||||
}
|
||||
|
||||
virtual ContentType contentType() const {
|
||||
return DefinedAtom::typeStubHelper;
|
||||
}
|
||||
|
||||
virtual uint64_t size() const {
|
||||
return 10;
|
||||
}
|
||||
|
||||
virtual ContentPermissions permissions() const {
|
||||
return DefinedAtom::permR_X;
|
||||
}
|
||||
|
||||
virtual ArrayRef<uint8_t> rawContent() const {
|
||||
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 ArrayRef<uint8_t>(instructions, sizeof(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(ReferenceKind::x86_64_pointer64, 0, &helper, 0);
|
||||
this->addReference(ReferenceKind::x86_64_lazyTarget, 0, &shlib, 0);
|
||||
}
|
||||
|
||||
virtual ContentType contentType() const {
|
||||
return DefinedAtom::typeLazyPointer;
|
||||
}
|
||||
|
||||
virtual uint64_t size() const {
|
||||
return 8;
|
||||
}
|
||||
|
||||
virtual ContentPermissions permissions() const {
|
||||
return DefinedAtom::permRW_;
|
||||
}
|
||||
|
||||
virtual ArrayRef<uint8_t> rawContent() const {
|
||||
static const uint8_t bytes[] =
|
||||
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
|
||||
return ArrayRef<uint8_t>(bytes, 8);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
|
||||
//
|
||||
// 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(ReferenceKind::x86_64_pointer64, 0, &shlib, 0);
|
||||
}
|
||||
|
||||
virtual ContentType contentType() const {
|
||||
return DefinedAtom::typeGOT;
|
||||
}
|
||||
|
||||
virtual uint64_t size() const {
|
||||
return 8;
|
||||
}
|
||||
|
||||
virtual ContentPermissions permissions() const {
|
||||
return DefinedAtom::permRW_;
|
||||
}
|
||||
|
||||
virtual ArrayRef<uint8_t> rawContent() const {
|
||||
static const uint8_t bytes[] =
|
||||
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
|
||||
return ArrayRef<uint8_t>(bytes, 8);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
|
||||
//
|
||||
// StubBinderAtom created by the stubs pass.
|
||||
//
|
||||
|
|
|
@ -0,0 +1,201 @@
|
|||
//===- 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_ATOM_X86_H_
|
||||
#define LLD_READER_WRITER_MACHO_STUB_ATOM_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"
|
||||
#include "SimpleAtoms.hpp"
|
||||
|
||||
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(KindHandler_x86::abs32, 2, &lazyPointer, 0);
|
||||
}
|
||||
|
||||
virtual ContentType contentType() const {
|
||||
return DefinedAtom::typeStub;
|
||||
}
|
||||
|
||||
virtual uint64_t size() const {
|
||||
return 6;
|
||||
}
|
||||
|
||||
virtual ContentPermissions permissions() const {
|
||||
return DefinedAtom::permR_X;
|
||||
}
|
||||
|
||||
virtual ArrayRef<uint8_t> rawContent() const {
|
||||
static const uint8_t instructions[] =
|
||||
{ 0xFF, 0x25, 0x00, 0x00, 0x00, 0x00 }; // jmp *lazyPointer
|
||||
assert(sizeof(instructions) == this->size());
|
||||
return ArrayRef<uint8_t>(instructions, sizeof(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(KindHandler_x86::abs32, 1, &cache, 0);
|
||||
this->addReference(KindHandler_x86::abs32, 7, &binder, 0);
|
||||
}
|
||||
|
||||
virtual ContentType contentType() const {
|
||||
return DefinedAtom::typeStubHelper;
|
||||
}
|
||||
|
||||
virtual uint64_t size() const {
|
||||
return 12;
|
||||
}
|
||||
|
||||
virtual ContentPermissions permissions() const {
|
||||
return DefinedAtom::permR_X;
|
||||
}
|
||||
|
||||
virtual ArrayRef<uint8_t> rawContent() const {
|
||||
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 ArrayRef<uint8_t>(instructions, sizeof(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(KindHandler_x86::lazyImm, 1, nullptr, 0);
|
||||
this->addReference(KindHandler_x86::call32, 6, &helperCommon, 0);
|
||||
}
|
||||
|
||||
virtual ContentType contentType() const {
|
||||
return DefinedAtom::typeStubHelper;
|
||||
}
|
||||
|
||||
virtual uint64_t size() const {
|
||||
return 10;
|
||||
}
|
||||
|
||||
virtual ContentPermissions permissions() const {
|
||||
return DefinedAtom::permR_X;
|
||||
}
|
||||
|
||||
virtual ArrayRef<uint8_t> rawContent() const {
|
||||
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 ArrayRef<uint8_t>(instructions, sizeof(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(KindHandler_x86::pointer32, 0, &helper, 0);
|
||||
this->addReference(KindHandler_x86::lazyTarget, 0, &shlib, 0);
|
||||
}
|
||||
|
||||
virtual ContentType contentType() const {
|
||||
return DefinedAtom::typeLazyPointer;
|
||||
}
|
||||
|
||||
virtual uint64_t size() const {
|
||||
return 4;
|
||||
}
|
||||
|
||||
virtual ContentPermissions permissions() const {
|
||||
return DefinedAtom::permRW_;
|
||||
}
|
||||
|
||||
virtual ArrayRef<uint8_t> rawContent() const {
|
||||
static const uint8_t bytes[] = { 0x00, 0x00, 0x00, 0x00 };
|
||||
return ArrayRef<uint8_t>(bytes, 4);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
|
||||
//
|
||||
// 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(KindHandler_x86::pointer32, 0, &shlib, 0);
|
||||
}
|
||||
|
||||
virtual ContentType contentType() const {
|
||||
return DefinedAtom::typeGOT;
|
||||
}
|
||||
|
||||
virtual uint64_t size() const {
|
||||
return 4;
|
||||
}
|
||||
|
||||
virtual ContentPermissions permissions() const {
|
||||
return DefinedAtom::permRW_;
|
||||
}
|
||||
|
||||
virtual ArrayRef<uint8_t> rawContent() const {
|
||||
static const uint8_t bytes[] = { 0x00, 0x00, 0x00, 0x0 };
|
||||
return ArrayRef<uint8_t>(bytes, 4);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
||||
} // namespace mach_o
|
||||
} // namespace lld
|
||||
|
||||
|
||||
#endif // LLD_READER_WRITER_MACHO_STUB_ATOM_X86_H_
|
|
@ -0,0 +1,204 @@
|
|||
//===- 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_ATOM_X86_64_H_
|
||||
#define LLD_READER_WRITER_MACHO_STUB_ATOM_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"
|
||||
#include "SimpleAtoms.hpp"
|
||||
|
||||
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(KindHandler_x86_64::ripRel32, 2, &lazyPointer, 0);
|
||||
}
|
||||
|
||||
virtual ContentType contentType() const {
|
||||
return DefinedAtom::typeStub;
|
||||
}
|
||||
|
||||
virtual uint64_t size() const {
|
||||
return 6;
|
||||
}
|
||||
|
||||
virtual ContentPermissions permissions() const {
|
||||
return DefinedAtom::permR_X;
|
||||
}
|
||||
|
||||
virtual ArrayRef<uint8_t> rawContent() const {
|
||||
static const uint8_t instructions[] =
|
||||
{ 0xFF, 0x25, 0x00, 0x00, 0x00, 0x00 }; // jmp *lazyPointer
|
||||
assert(sizeof(instructions) == this->size());
|
||||
return ArrayRef<uint8_t>(instructions, sizeof(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(KindHandler_x86_64::ripRel32, 3, &cache, 0);
|
||||
this->addReference(KindHandler_x86_64::ripRel32, 11, &binder, 0);
|
||||
}
|
||||
|
||||
virtual ContentType contentType() const {
|
||||
return DefinedAtom::typeStubHelper;
|
||||
}
|
||||
|
||||
virtual uint64_t size() const {
|
||||
return 16;
|
||||
}
|
||||
|
||||
virtual ContentPermissions permissions() const {
|
||||
return DefinedAtom::permR_X;
|
||||
}
|
||||
|
||||
virtual ArrayRef<uint8_t> rawContent() const {
|
||||
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 ArrayRef<uint8_t>(instructions, sizeof(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(KindHandler_x86_64::lazyImm, 1, nullptr, 0);
|
||||
this->addReference(KindHandler_x86_64::ripRel32, 6, &helperCommon, 0);
|
||||
}
|
||||
|
||||
virtual ContentType contentType() const {
|
||||
return DefinedAtom::typeStubHelper;
|
||||
}
|
||||
|
||||
virtual uint64_t size() const {
|
||||
return 10;
|
||||
}
|
||||
|
||||
virtual ContentPermissions permissions() const {
|
||||
return DefinedAtom::permR_X;
|
||||
}
|
||||
|
||||
virtual ArrayRef<uint8_t> rawContent() const {
|
||||
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 ArrayRef<uint8_t>(instructions, sizeof(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(KindHandler_x86_64::pointer64, 0, &helper, 0);
|
||||
this->addReference(KindHandler_x86_64::lazyTarget, 0, &shlib, 0);
|
||||
}
|
||||
|
||||
virtual ContentType contentType() const {
|
||||
return DefinedAtom::typeLazyPointer;
|
||||
}
|
||||
|
||||
virtual uint64_t size() const {
|
||||
return 8;
|
||||
}
|
||||
|
||||
virtual ContentPermissions permissions() const {
|
||||
return DefinedAtom::permRW_;
|
||||
}
|
||||
|
||||
virtual ArrayRef<uint8_t> rawContent() const {
|
||||
static const uint8_t bytes[] =
|
||||
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
|
||||
return ArrayRef<uint8_t>(bytes, 8);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
|
||||
//
|
||||
// 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(KindHandler_x86_64::pointer64, 0, &shlib, 0);
|
||||
}
|
||||
|
||||
virtual ContentType contentType() const {
|
||||
return DefinedAtom::typeGOT;
|
||||
}
|
||||
|
||||
virtual uint64_t size() const {
|
||||
return 8;
|
||||
}
|
||||
|
||||
virtual ContentPermissions permissions() const {
|
||||
return DefinedAtom::permRW_;
|
||||
}
|
||||
|
||||
virtual ArrayRef<uint8_t> rawContent() const {
|
||||
static const uint8_t bytes[] =
|
||||
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
|
||||
return ArrayRef<uint8_t>(bytes, 8);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
||||
} // namespace mach_o
|
||||
} // namespace lld
|
||||
|
||||
|
||||
#endif // LLD_READER_WRITER_MACHO_STUB_ATOM_X86_64_H_
|
|
@ -28,7 +28,9 @@ namespace mach_o {
|
|||
|
||||
class StubsPass : public lld::StubsPass {
|
||||
public:
|
||||
StubsPass(const WriterOptionsMachO &options) : _options(options) {
|
||||
StubsPass(const WriterOptionsMachO &options)
|
||||
: _options(options),
|
||||
_kindHandler(KindHandler::makeHandler(options.architecture())) {
|
||||
}
|
||||
|
||||
virtual bool noTextRelocs() {
|
||||
|
@ -36,7 +38,7 @@ public:
|
|||
}
|
||||
|
||||
virtual bool isCallSite(Reference::Kind kind) {
|
||||
return ReferenceKind::isCallSite(_options.architecture(), kind);
|
||||
return _kindHandler->isCallSite(kind);
|
||||
}
|
||||
|
||||
virtual const DefinedAtom* getStub(const Atom& target) {
|
||||
|
@ -60,7 +62,8 @@ public:
|
|||
case WriterOptionsMachO::arch_x86:
|
||||
return makeStub_x86(target);
|
||||
|
||||
case WriterOptionsMachO::arch_arm:
|
||||
case WriterOptionsMachO::arch_armv6:
|
||||
case WriterOptionsMachO::arch_armv7:
|
||||
return makeStub_arm(target);
|
||||
}
|
||||
}
|
||||
|
@ -87,8 +90,24 @@ public:
|
|||
}
|
||||
|
||||
const DefinedAtom* makeStub_x86(const Atom& target) {
|
||||
assert(0 && "stubs not yet implemented for x86");
|
||||
return nullptr;
|
||||
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) {
|
||||
|
@ -127,6 +146,7 @@ private:
|
|||
};
|
||||
|
||||
const WriterOptionsMachO &_options;
|
||||
KindHandler *_kindHandler;
|
||||
File _file;
|
||||
llvm::DenseMap<const Atom*, const DefinedAtom*> _targetToStub;
|
||||
std::vector<const DefinedAtom*> _lazyPointers;
|
||||
|
|
|
@ -129,10 +129,6 @@ private:
|
|||
const WriterOptionsMachO &options,
|
||||
class MachOWriter &writer);
|
||||
|
||||
void applyFixup(Reference::Kind kind, uint64_t addend,
|
||||
uint8_t* location, uint64_t fixupAddress,
|
||||
uint64_t targetAddress);
|
||||
|
||||
StringRef _segmentName;
|
||||
StringRef _sectionName;
|
||||
const WriterOptionsMachO &_options;
|
||||
|
@ -206,6 +202,7 @@ private:
|
|||
segment_command *_linkEditSegment;
|
||||
symtab_command *_symbolTableLoadCommand;
|
||||
entry_point_command *_entryPointLoadCommand;
|
||||
thread_command *_threadLoadCommand;
|
||||
dyld_info_command *_dyldInfoLoadCommand;
|
||||
std::vector<load_command*> _loadCmds;
|
||||
std::vector<ChunkSegInfo> _sectionInfo;
|
||||
|
@ -354,11 +351,14 @@ public:
|
|||
uint64_t *segStartAddr, uint64_t *segEndAddr);
|
||||
|
||||
const std::vector<Chunk*> chunks() { return _chunks; }
|
||||
KindHandler *kindHandler() { return _referenceKindHandler; }
|
||||
|
||||
bool use64BitMachO() const;
|
||||
|
||||
private:
|
||||
friend class LoadCommandsChunk;
|
||||
friend class LazyBindingInfoChunk;
|
||||
friend class BindingInfoChunk;
|
||||
|
||||
void build(const lld::File &file);
|
||||
void createChunks(const lld::File &file);
|
||||
|
@ -373,6 +373,7 @@ private:
|
|||
typedef llvm::DenseMap<const Atom*, uint64_t> AtomToAddress;
|
||||
|
||||
const WriterOptionsMachO &_options;
|
||||
KindHandler *_referenceKindHandler;
|
||||
StubsPass _stubsPass;
|
||||
GOTPass _gotPass;
|
||||
CRuntimeFile _cRuntimeFile;
|
||||
|
@ -386,7 +387,7 @@ private:
|
|||
LazyBindingInfoChunk *_lazyBindingInfo;
|
||||
SymbolTableChunk *_symbolTableChunk;
|
||||
SymbolStringsChunk *_stringsChunk;
|
||||
const DefinedAtom *_mainAtom;
|
||||
const DefinedAtom *_entryAtom;
|
||||
uint64_t _linkEditStartOffset;
|
||||
uint64_t _linkEditStartAddress;
|
||||
};
|
||||
|
@ -582,34 +583,13 @@ void SectionChunk::write(uint8_t *chunkBuffer) {
|
|||
if ( ref->target() != nullptr )
|
||||
targetAddress = _writer.addressOfAtom(ref->target());
|
||||
uint64_t fixupAddress = _writer.addressOfAtom(atomInfo.atom) + offset;
|
||||
this->applyFixup(ref->kind(), ref->addend(), &atomContent[offset],
|
||||
fixupAddress, targetAddress);
|
||||
_writer.kindHandler()->applyFixup(ref->kind(), ref->addend(),
|
||||
&atomContent[offset], fixupAddress, targetAddress);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void SectionChunk::applyFixup(Reference::Kind kind, uint64_t addend,
|
||||
uint8_t* location, uint64_t fixupAddress,
|
||||
uint64_t targetAddress) {
|
||||
//fprintf(stderr, "applyFixup(kind=%s, addend=0x%0llX, "
|
||||
// "fixupAddress=0x%0llX, targetAddress=0x%0llX\n",
|
||||
// kindToString(kind).data(), addend,
|
||||
// fixupAddress, targetAddress);
|
||||
if ( ReferenceKind::isRipRel32(kind) ) {
|
||||
// compute rip relative value and update.
|
||||
int32_t* loc32 = reinterpret_cast<int32_t*>(location);
|
||||
*loc32 = (targetAddress - (fixupAddress+4)) + addend;
|
||||
}
|
||||
else if ( kind == ReferenceKind::x86_64_pointer64 ) {
|
||||
uint64_t* loc64 = reinterpret_cast<uint64_t*>(location);
|
||||
*loc64 = targetAddress + addend;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// MachHeaderChunk
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
@ -687,7 +667,8 @@ LoadCommandsChunk::LoadCommandsChunk(MachHeaderChunk &mh,
|
|||
MachOWriter& writer)
|
||||
: _mh(mh), _options(options), _writer(writer),
|
||||
_linkEditSegment(nullptr), _symbolTableLoadCommand(nullptr),
|
||||
_entryPointLoadCommand(nullptr), _dyldInfoLoadCommand(nullptr) {
|
||||
_entryPointLoadCommand(nullptr), _threadLoadCommand(nullptr),
|
||||
_dyldInfoLoadCommand(nullptr) {
|
||||
}
|
||||
|
||||
|
||||
|
@ -815,15 +796,19 @@ void LoadCommandsChunk::computeSize(const lld::File &file) {
|
|||
this->addLoadCommand(_dyldInfoLoadCommand);
|
||||
|
||||
// Add entry point load command to main executables
|
||||
if (_options.outputKind() == WriterOptionsMachO::outputDynamicExecutable) {
|
||||
if ( _options.addEntryPointLoadCommand() ) {
|
||||
_entryPointLoadCommand = new entry_point_command(is64);
|
||||
this->addLoadCommand(_entryPointLoadCommand);
|
||||
}
|
||||
else if ( _options.addUnixThreadLoadCommand() ) {
|
||||
_threadLoadCommand = new thread_command(_options.cpuType(), is64);
|
||||
this->addLoadCommand(_threadLoadCommand);
|
||||
}
|
||||
|
||||
// Compute total size.
|
||||
_size = _mh.loadCommandsSize();
|
||||
}
|
||||
|
||||
|
||||
|
||||
void LoadCommandsChunk::updateLoadCommandContent(const lld::File &file) {
|
||||
// Update segment/section information in segment load commands
|
||||
|
@ -887,11 +872,17 @@ void LoadCommandsChunk::updateLoadCommandContent(const lld::File &file) {
|
|||
|
||||
// Update entry point
|
||||
if ( _entryPointLoadCommand != nullptr ) {
|
||||
const Atom *mainAtom = _writer._mainAtom;
|
||||
const Atom *mainAtom = _writer._entryAtom;
|
||||
assert(mainAtom != nullptr);
|
||||
uint32_t entryOffset = _writer.addressOfAtom(mainAtom) - _mh.address();
|
||||
_entryPointLoadCommand->entryoff = entryOffset;
|
||||
}
|
||||
else if ( _threadLoadCommand != nullptr ) {
|
||||
const Atom *startAtom = _writer._entryAtom;
|
||||
assert(startAtom != nullptr);
|
||||
_threadLoadCommand->setPC(_writer.addressOfAtom(startAtom));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
@ -1037,9 +1028,9 @@ void BindingInfoChunk::computeSize(const lld::File &file,
|
|||
const SharedLibraryAtom *shlTarget
|
||||
= dyn_cast<SharedLibraryAtom>(target);
|
||||
if ( shlTarget != nullptr ) {
|
||||
assert(ref->kind() == ReferenceKind::x86_64_pointer64);
|
||||
assert(_writer.kindHandler()->isPointer(ref->kind()));
|
||||
targetName = shlTarget->name();
|
||||
ordinal = 1;
|
||||
ordinal = 1; // FIXME
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1096,15 +1087,22 @@ const char* LazyBindingInfoChunk::info() {
|
|||
return "lazy binding info";
|
||||
}
|
||||
|
||||
//
|
||||
// Called when lazy-binding-info is being laid out in __LINKEDIT. We need
|
||||
// to find the helper atom which contains the instruction which loads an
|
||||
// immediate value that is the offset into the lazy-binding-info, and set
|
||||
// that immediate value to be the offset parameter.
|
||||
void LazyBindingInfoChunk::updateHelper(const DefinedAtom *lazyPointerAtom,
|
||||
uint32_t offset) {
|
||||
for (const Reference *ref : *lazyPointerAtom ) {
|
||||
if ( ref->kind() != ReferenceKind::x86_64_pointer64 )
|
||||
if ( ! _writer.kindHandler()->isPointer(ref->kind() ) )
|
||||
continue;
|
||||
const DefinedAtom *helperAtom = dyn_cast<DefinedAtom>(ref->target());
|
||||
const Atom *targ = ref->target();
|
||||
const DefinedAtom *helperAtom = dyn_cast<DefinedAtom>(targ);
|
||||
assert(helperAtom != nullptr);
|
||||
// Found helper atom. Search it for Reference that is lazy immediate value.
|
||||
for (const Reference *href : *helperAtom ) {
|
||||
if ( href->kind() == ReferenceKind::x86_64_lazyImm ) {
|
||||
if ( _writer.kindHandler()->isLazyImmediate(href->kind()) ) {
|
||||
(const_cast<Reference*>(href))->setAddend(offset);
|
||||
return;
|
||||
}
|
||||
|
@ -1154,7 +1152,7 @@ void LazyBindingInfoChunk::computeSize(const lld::File &file,
|
|||
int flags = 0;
|
||||
StringRef name;
|
||||
for (const Reference *ref : *lazyPointerAtom ) {
|
||||
if ( ref->kind() == ReferenceKind::x86_64_lazyTarget ) {
|
||||
if ( _writer.kindHandler()->isLazyTarget(ref->kind()) ) {
|
||||
const Atom *shlib = ref->target();
|
||||
assert(shlib != nullptr);
|
||||
name = shlib->name();
|
||||
|
@ -1298,9 +1296,11 @@ uint32_t SymbolStringsChunk::stringIndex(StringRef str) {
|
|||
//===----------------------------------------------------------------------===//
|
||||
|
||||
MachOWriter::MachOWriter(const WriterOptionsMachO &options)
|
||||
: _options(options), _stubsPass(options), _cRuntimeFile(options),
|
||||
: _options(options),
|
||||
_referenceKindHandler(KindHandler::makeHandler(_options.architecture())),
|
||||
_stubsPass(options), _cRuntimeFile(options),
|
||||
_bindingInfo(nullptr), _lazyBindingInfo(nullptr),
|
||||
_symbolTableChunk(nullptr), _stringsChunk(nullptr), _mainAtom(nullptr),
|
||||
_symbolTableChunk(nullptr), _stringsChunk(nullptr), _entryAtom(nullptr),
|
||||
_linkEditStartOffset(0), _linkEditStartAddress(0) {
|
||||
}
|
||||
|
||||
|
@ -1388,16 +1388,16 @@ void MachOWriter::addLinkEditChunk(LinkEditChunk *chunk) {
|
|||
void MachOWriter::buildAtomToAddressMap() {
|
||||
DEBUG_WITH_TYPE("WriterMachO-layout", llvm::dbgs()
|
||||
<< "assign atom addresses:\n");
|
||||
const bool lookForMain =
|
||||
const bool lookForEntry =
|
||||
(_options.outputKind() == WriterOptionsMachO::outputDynamicExecutable);
|
||||
for (SectionChunk *chunk : _sectionChunks ) {
|
||||
for (const SectionChunk::AtomInfo &info : chunk->atoms() ) {
|
||||
_atomToAddress[info.atom] = chunk->address() + info.offsetInSection;
|
||||
if ( lookForMain
|
||||
if ( lookForEntry
|
||||
&& (info.atom->contentType() == DefinedAtom::typeCode)
|
||||
&& (info.atom->size() != 0)
|
||||
&& info.atom->name().equals("_main") ) {
|
||||
_mainAtom = info.atom;
|
||||
&& info.atom->name().equals(_options.entryPointName()) ) {
|
||||
_entryAtom = info.atom;
|
||||
}
|
||||
DEBUG_WITH_TYPE("WriterMachO-layout", llvm::dbgs()
|
||||
<< " address="
|
||||
|
@ -1544,23 +1544,10 @@ void MachOWriter::addFiles(InputFiles &inputFiles) {
|
|||
|
||||
} // namespace mach_o
|
||||
|
||||
|
||||
Writer* createWriterMachO(const WriterOptionsMachO &options) {
|
||||
return new lld::mach_o::MachOWriter(options);
|
||||
}
|
||||
|
||||
WriterOptionsMachO::WriterOptionsMachO()
|
||||
: _outputkind(outputDynamicExecutable),
|
||||
_archName("x86_64"),
|
||||
_architecture(arch_x86_64),
|
||||
_pageZeroSize(0x100000000),
|
||||
_cpuType(mach_o::CPU_TYPE_X86_64),
|
||||
_cpuSubtype(mach_o::CPU_SUBTYPE_X86_64_ALL),
|
||||
_noTextRelocations(true) {
|
||||
}
|
||||
|
||||
WriterOptionsMachO::~WriterOptionsMachO() {
|
||||
}
|
||||
|
||||
|
||||
} // namespace lld
|
||||
|
||||
|
|
|
@ -0,0 +1,144 @@
|
|||
//===- lib/ReaderWriter/MachO/WriterOptionsMachO.cpp ----------------------===//
|
||||
//
|
||||
// The LLVM Linker
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "lld/ReaderWriter/WriterMachO.h"
|
||||
|
||||
#include "llvm/Support/Debug.h"
|
||||
#include "llvm/Support/ErrorHandling.h"
|
||||
#include "llvm/Support/system_error.h"
|
||||
|
||||
#include "llvm/ADT/SmallVector.h"
|
||||
#include "llvm/ADT/StringRef.h"
|
||||
|
||||
#include "MachOFormat.hpp"
|
||||
|
||||
namespace lld {
|
||||
|
||||
WriterOptionsMachO::WriterOptionsMachO()
|
||||
: _outputkind(outputDynamicExecutable),
|
||||
_architecture(arch_x86),
|
||||
_pageZeroSize(0x1000),
|
||||
_noTextRelocations(true) {
|
||||
}
|
||||
|
||||
WriterOptionsMachO::~WriterOptionsMachO() {
|
||||
}
|
||||
|
||||
StringRef WriterOptionsMachO::archName() const {
|
||||
switch ( _architecture ) {
|
||||
case arch_x86_64:
|
||||
return StringRef("x86_64");
|
||||
case arch_x86:
|
||||
return StringRef("i386");
|
||||
case arch_armv6:
|
||||
return StringRef("armv6");
|
||||
case arch_armv7:
|
||||
return StringRef("armv7");
|
||||
}
|
||||
assert(0 && "unknown arch");
|
||||
return StringRef("???");
|
||||
}
|
||||
|
||||
uint32_t WriterOptionsMachO::cpuType() const {
|
||||
switch ( _architecture ) {
|
||||
case arch_x86_64:
|
||||
return mach_o::CPU_TYPE_X86_64;
|
||||
case arch_x86:
|
||||
return mach_o::CPU_TYPE_I386;
|
||||
case arch_armv6:
|
||||
case arch_armv7:
|
||||
return mach_o::CPU_TYPE_ARM;
|
||||
}
|
||||
assert(0 && "unknown arch");
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint32_t WriterOptionsMachO::cpuSubtype() const {
|
||||
switch ( _architecture ) {
|
||||
case arch_x86_64:
|
||||
return mach_o::CPU_SUBTYPE_X86_64_ALL;
|
||||
case arch_x86:
|
||||
return mach_o::CPU_SUBTYPE_X86_ALL;
|
||||
case arch_armv6:
|
||||
return mach_o::CPU_SUBTYPE_ARM_V6;
|
||||
case arch_armv7:
|
||||
return mach_o::CPU_SUBTYPE_ARM_V7;
|
||||
}
|
||||
assert(0 && "unknown arch");
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint64_t WriterOptionsMachO::pageZeroSize() const {
|
||||
switch ( _outputkind ) {
|
||||
case outputDynamicExecutable:
|
||||
return _pageZeroSize;
|
||||
case outputDylib:
|
||||
case outputBundle:
|
||||
case outputObjectFile:
|
||||
assert(_pageZeroSize == 0);
|
||||
return 0;
|
||||
}
|
||||
assert(0 && "unknown outputkind");
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool WriterOptionsMachO::addEntryPointLoadCommand() const {
|
||||
switch ( _outputkind ) {
|
||||
case outputDynamicExecutable:
|
||||
// Only main executables have an entry point
|
||||
return false;
|
||||
case outputDylib:
|
||||
case outputBundle:
|
||||
case outputObjectFile:
|
||||
return false;
|
||||
}
|
||||
assert(0 && "unknown outputkind");
|
||||
return false;
|
||||
}
|
||||
|
||||
bool WriterOptionsMachO::addUnixThreadLoadCommand() const {
|
||||
switch ( _outputkind ) {
|
||||
case outputDynamicExecutable:
|
||||
// Only main executables have an entry point
|
||||
return true;
|
||||
case outputDylib:
|
||||
case outputBundle:
|
||||
case outputObjectFile:
|
||||
return false;
|
||||
}
|
||||
assert(0 && "unknown outputkind");
|
||||
return false;
|
||||
}
|
||||
|
||||
StringRef WriterOptionsMachO::entryPointName() const {
|
||||
switch ( _outputkind ) {
|
||||
case outputDynamicExecutable:
|
||||
// Only main executables have an entry point
|
||||
if ( ! _customEntryPointName.empty() ) {
|
||||
return _customEntryPointName;
|
||||
}
|
||||
else {
|
||||
if ( true || this->addEntryPointLoadCommand() )
|
||||
return StringRef("_main");
|
||||
else
|
||||
return StringRef("start");
|
||||
}
|
||||
break;
|
||||
case outputDylib:
|
||||
case outputBundle:
|
||||
case outputObjectFile:
|
||||
return StringRef();
|
||||
}
|
||||
assert(0 && "unknown outputkind");
|
||||
return StringRef();
|
||||
}
|
||||
|
||||
|
||||
} // namespace lld
|
||||
|
|
@ -196,7 +196,6 @@ public:
|
|||
<< spacePadding(strlen("scope"))
|
||||
<< KeyValues::scope(atom.scope())
|
||||
<< "\n";
|
||||
hasDash = true;
|
||||
}
|
||||
|
||||
if ( atom.interposable() != KeyValues::interposableDefault ) {
|
||||
|
|
Loading…
Reference in New Issue