[mach-o] add parsing of x86 relocations

llvm-svn: 212239
This commit is contained in:
Nick Kledzik 2014-07-02 23:52:22 +00:00
parent bcb70eee1a
commit de0860aae4
7 changed files with 480 additions and 36 deletions

View File

@ -182,6 +182,9 @@ inline void swapStruct(llvm::MachO::nlist_64 &sym) {
inline uint16_t read16(bool swap, uint16_t value) {
return (swap ? getSwappedBytes(value) : value);
}
inline uint32_t read32(bool swap, uint32_t value) {
return (swap ? getSwappedBytes(value) : value);

View File

@ -438,10 +438,25 @@ std::error_code convertRelocs(const Section &section,
if (sectIndex > normalizedFile.sections.size())
return make_dynamic_error_code(Twine("out of range section "
"index (") + Twine(sectIndex) + ")");
const Section &sect = normalizedFile.sections[sectIndex-1];
const Section *sect = nullptr;
if (sectIndex == 0) {
for (const Section &s : normalizedFile.sections) {
uint64_t sAddr = s.address;
if ((sAddr <= addr) && (addr < sAddr+s.content.size())) {
sect = &s;
break;
}
}
if (!sect) {
return make_dynamic_error_code(Twine("address (" + Twine(addr)
+ ") is not in any section"));
}
} else {
sect = &normalizedFile.sections[sectIndex-1];
}
uint32_t offsetInTarget;
uint64_t offsetInSect = addr - sect.address;
*atom = file.findAtomCoveringAddress(sect, offsetInSect, &offsetInTarget);
uint64_t offsetInSect = addr - sect->address;
*atom = file.findAtomCoveringAddress(*sect, offsetInSect, &offsetInTarget);
*addend = offsetInTarget;
return std::error_code();
};
@ -534,7 +549,7 @@ std::error_code convertRelocs(const Section &section,
+ " (r_address=" + Twine::utohexstr(reloc.offset)
+ ", r_type=" + Twine(reloc.type)
+ ", r_extern=" + Twine(reloc.isExtern)
+ ", r_length=" + Twine(reloc.length)
+ ", r_length=" + Twine((int)reloc.length)
+ ", r_pcrel=" + Twine(reloc.pcRel)
+ (!reloc.scattered ? (Twine(", r_symbolnum=") + Twine(reloc.symbol))
: (Twine(", r_scattered=1, r_value=")
@ -542,7 +557,17 @@ std::error_code convertRelocs(const Section &section,
+ ")" );
} else {
// Instantiate an lld::Reference object and add to its atom.
inAtom->addReference(offsetInAtom, kind, target, addend);
Reference::KindArch arch = Reference::KindArch::all;
switch (normalizedFile.arch ) {
case lld::MachOLinkingContext::arch_x86_64:
arch = Reference::KindArch::x86_64;
break;
case lld::MachOLinkingContext::arch_x86:
arch = Reference::KindArch::x86;
break;
}
inAtom->addReference(offsetInAtom, kind, target, addend, arch);
}
}
return std::error_code();
@ -580,7 +605,8 @@ normalizedObjectToAtoms(const NormalizedFile &normalizedFile, StringRef path,
}
// TEMP BEGIN: until all KindHandlers switched to new interface.
if (normalizedFile.arch != lld::MachOLinkingContext::arch_x86_64)
if ((normalizedFile.arch != lld::MachOLinkingContext::arch_x86_64) &&
(normalizedFile.arch != lld::MachOLinkingContext::arch_x86))
return std::unique_ptr<File>(std::move(file));
// TEMP END

View File

@ -76,6 +76,23 @@ KindHandler::RelocPattern KindHandler::relocPattern(const Relocation &reloc) {
return result;
}
int16_t KindHandler::readS16(bool swap, const uint8_t *addr) {
return read16(swap, *reinterpret_cast<const uint16_t*>(addr));
}
int32_t KindHandler::readS32(bool swap, const uint8_t *addr) {
return read32(swap, *reinterpret_cast<const uint32_t*>(addr));
}
uint32_t KindHandler::readU32(bool swap, const uint8_t *addr) {
return read32(swap, *reinterpret_cast<const uint32_t*>(addr));
}
int64_t KindHandler::readS64(bool swap, const uint8_t *addr) {
return read64(swap, *reinterpret_cast<const uint64_t*>(addr));
}
bool KindHandler::isPairedReloc(const Relocation &reloc) {
llvm_unreachable("abstract");
}
@ -169,13 +186,6 @@ bool KindHandler_x86_64::isPairedReloc(const Relocation &reloc) {
return (reloc.type == X86_64_RELOC_SUBTRACTOR);
}
static int32_t readS32(bool swap, const uint8_t *addr) {
return read32(swap, *reinterpret_cast<const uint32_t*>(addr));
}
static int64_t readS64(bool swap, const uint8_t *addr) {
return read64(swap, *reinterpret_cast<const uint64_t*>(addr));
}
Reference::KindValue
KindHandler_x86_64::kindFromReloc(const Relocation &reloc) {
@ -400,29 +410,166 @@ KindHandler_x86::~KindHandler_x86() {
}
const Registry::KindStrings KindHandler_x86::kindStrings[] = {
LLD_KIND_STRING_ENTRY(LLD_X86_RELOC_BRANCH32),
LLD_KIND_STRING_ENTRY(LLD_X86_RELOC_ABS32),
LLD_KIND_STRING_ENTRY(LLD_X86_RELOC_FUNC_REL32),
LLD_KIND_STRING_ENTRY(LLD_X86_RELOC_POINTER32),
LLD_KIND_STRING_ENTRY(LLD_X86_RELOC_LAZY_TARGET),
LLD_KIND_STRING_ENTRY(LLD_X86_RELOC_LAZY_IMMEDIATE),
LLD_KIND_STRING_ENTRY(invalid),
LLD_KIND_STRING_ENTRY(branch32),
LLD_KIND_STRING_ENTRY(branch16),
LLD_KIND_STRING_ENTRY(abs32),
LLD_KIND_STRING_ENTRY(funcRel32),
LLD_KIND_STRING_ENTRY(pointer32),
LLD_KIND_STRING_ENTRY(delta32),
LLD_KIND_STRING_ENTRY(lazyPointer),
LLD_KIND_STRING_ENTRY(lazyImmediateLocation),
LLD_KIND_STRING_END
};
bool KindHandler_x86::isCallSite(const Reference &ref) {
return (ref.kindValue() == LLD_X86_RELOC_BRANCH32);
return (ref.kindValue() == branch32);
}
bool KindHandler_x86::isPointer(const Reference &ref) {
return (ref.kindValue() == LLD_X86_RELOC_POINTER32);
return (ref.kindValue() == pointer32);
}
bool KindHandler_x86::isLazyImmediate(const Reference &ref) {
return (ref.kindValue() == LLD_X86_RELOC_LAZY_TARGET);
return (ref.kindValue() == lazyImmediateLocation);
}
bool KindHandler_x86::isLazyTarget(const Reference &ref) {
return (ref.kindValue() == LLD_X86_RELOC_LAZY_TARGET);
return (ref.kindValue() == lazyPointer);
}
bool KindHandler_x86::isPairedReloc(const Relocation &reloc) {
if (!reloc.scattered)
return false;
return (reloc.type == GENERIC_RELOC_LOCAL_SECTDIFF) ||
(reloc.type == GENERIC_RELOC_SECTDIFF);
}
std::error_code
KindHandler_x86::getReferenceInfo(const Relocation &reloc,
const DefinedAtom *inAtom,
uint32_t offsetInAtom,
uint64_t fixupAddress, bool swap,
FindAtomBySectionAndAddress atomFromAddress,
FindAtomBySymbolIndex atomFromSymbolIndex,
Reference::KindValue *kind,
const lld::Atom **target,
Reference::Addend *addend) {
typedef std::error_code E;
DefinedAtom::ContentPermissions perms;
const uint8_t *fixupContent = &inAtom->rawContent()[offsetInAtom];
uint64_t targetAddress;
switch (relocPattern(reloc)) {
case GENERIC_RELOC_VANILLA | rPcRel | rExtern | rLength4:
// ex: call _foo (and _foo undefined)
*kind = branch32;
if (E ec = atomFromSymbolIndex(reloc.symbol, target))
return ec;
*addend = fixupAddress + 4 + readS32(swap, fixupContent);
break;
case GENERIC_RELOC_VANILLA | rPcRel | rLength4:
// ex: call _foo (and _foo defined)
*kind = branch32;
targetAddress = fixupAddress + 4 + readS32(swap, fixupContent);
return atomFromAddress(reloc.symbol, targetAddress, target, addend);
break;
case GENERIC_RELOC_VANILLA | rPcRel | rExtern | rLength2:
// ex: callw _foo (and _foo undefined)
*kind = branch16;
if (E ec = atomFromSymbolIndex(reloc.symbol, target))
return ec;
*addend = fixupAddress + 2 + readS16(swap, fixupContent);
break;
case GENERIC_RELOC_VANILLA | rPcRel | rLength2:
// ex: callw _foo (and _foo defined)
*kind = branch16;
targetAddress = fixupAddress + 2 + readS16(swap, fixupContent);
return atomFromAddress(reloc.symbol, targetAddress, target, addend);
break;
case GENERIC_RELOC_VANILLA | rExtern | rLength4:
// ex: movl _foo, %eax (and _foo undefined)
// ex: .long _foo (and _foo undefined)
perms = inAtom->permissions();
*kind = ((perms & DefinedAtom::permR_X) == DefinedAtom::permR_X)
? abs32 : pointer32;
if (E ec = atomFromSymbolIndex(reloc.symbol, target))
return ec;
*addend = readU32(swap, fixupContent);
break;
case GENERIC_RELOC_VANILLA | rLength4:
// ex: movl _foo, %eax (and _foo defined)
// ex: .long _foo (and _foo defined)
perms = inAtom->permissions();
*kind = ((perms & DefinedAtom::permR_X) == DefinedAtom::permR_X)
? abs32 : pointer32;
targetAddress = readU32(swap, fixupContent);
return atomFromAddress(reloc.symbol, targetAddress, target, addend);
break;
default:
return make_dynamic_error_code(Twine("unsupported i386 relocation type"));
}
return std::error_code();
}
std::error_code
KindHandler_x86::getPairReferenceInfo(const normalized::Relocation &reloc1,
const normalized::Relocation &reloc2,
const DefinedAtom *inAtom,
uint32_t offsetInAtom,
uint64_t fixupAddress, bool swap,
FindAtomBySectionAndAddress atomFromAddr,
FindAtomBySymbolIndex atomFromSymbolIndex,
Reference::KindValue *kind,
const lld::Atom **target,
Reference::Addend *addend) {
const uint8_t *fixupContent = &inAtom->rawContent()[offsetInAtom];
std::error_code ec;
DefinedAtom::ContentPermissions perms = inAtom->permissions();
uint32_t fromAddress;
uint32_t toAddress;
uint32_t value;
const lld::Atom *fromTarget;
Reference::Addend offsetInTo;
Reference::Addend offsetInFrom;
switch(relocPattern(reloc1) << 16 | relocPattern(reloc2)) {
case ((GENERIC_RELOC_SECTDIFF | rScattered | rLength4) << 16 |
GENERIC_RELOC_PAIR | rScattered | rLength4):
case ((GENERIC_RELOC_LOCAL_SECTDIFF | rScattered | rLength4) << 16 |
GENERIC_RELOC_PAIR | rScattered | rLength4):
toAddress = reloc1.value;
fromAddress = reloc2.value;
value = readS32(swap, fixupContent);
ec = atomFromAddr(0, toAddress, target, &offsetInTo);
if (ec)
return ec;
ec = atomFromAddr(0, fromAddress, &fromTarget, &offsetInFrom);
if (ec)
return ec;
if (fromTarget != inAtom)
return make_dynamic_error_code(Twine("SECTDIFF relocation where "
"subtrahend label is not in atom"));
*kind = ((perms & DefinedAtom::permR_X) == DefinedAtom::permR_X)
? funcRel32 : delta32;
if (*kind == funcRel32) {
// SECTDIFF relocations are used in i386 codegen where the function
// prolog does a CALL to the next instruction which POPs the return
// address into EBX which becomes the pic-base register. The POP
// instruction is label the used for the subtrahend in expressions.
// The funcRel32 kind represents the 32-bit delta to some symbol from
// the start of the function (atom) containing the funcRel32.
uint32_t ta = fromAddress + value - toAddress;
*addend = ta - offsetInFrom;
} else {
*addend= fromAddress + value - toAddress;
}
return std::error_code();
break;
default:
return make_dynamic_error_code(Twine("unsupported i386 relocation type"));
}
}
void KindHandler_x86::applyFixup(Reference::KindNamespace ns,

View File

@ -126,6 +126,10 @@ protected:
};
static RelocPattern relocPattern(const normalized::Relocation &reloc);
static int16_t readS16(bool swap, const uint8_t *addr);
static int32_t readS32(bool swap, const uint8_t *addr);
static uint32_t readU32(bool swap, const uint8_t *addr);
static int64_t readS64(bool swap, const uint8_t *addr);
};
@ -216,12 +220,61 @@ public:
bool isPointer(const Reference &) override;
bool isLazyImmediate(const Reference &) override;
bool isLazyTarget(const Reference &) override;
virtual void applyFixup(Reference::KindNamespace ns, Reference::KindArch arch,
bool isPairedReloc(const normalized::Relocation &) override;
std::error_code getReferenceInfo(const normalized::Relocation &reloc,
const DefinedAtom *inAtom,
uint32_t offsetInAtom,
uint64_t fixupAddress, bool swap,
FindAtomBySectionAndAddress atomFromAddress,
FindAtomBySymbolIndex atomFromSymbolIndex,
Reference::KindValue *kind,
const lld::Atom **target,
Reference::Addend *addend) override;
std::error_code
getPairReferenceInfo(const normalized::Relocation &reloc1,
const normalized::Relocation &reloc2,
const DefinedAtom *inAtom,
uint32_t offsetInAtom,
uint64_t fixupAddress, bool swap,
FindAtomBySectionAndAddress atomFromAddress,
FindAtomBySymbolIndex atomFromSymbolIndex,
Reference::KindValue *kind,
const lld::Atom **target,
Reference::Addend *addend) override;
void applyFixup(Reference::KindNamespace ns, Reference::KindArch arch,
Reference::KindValue kindValue, uint64_t addend,
uint8_t *location, uint64_t fixupAddress,
uint64_t targetAddress) override;
private:
friend class X86LazyPointerAtom;
friend class X86StubHelperAtom;
friend class X86StubAtom;
friend class X86StubHelperCommonAtom;
friend class X86NonLazyPointerAtom;
enum : Reference::KindValue {
invalid, /// for error condition
// Kinds found in mach-o .o files:
branch32, /// ex: call _foo
branch16, /// ex: callw _foo
abs32, /// ex: movl _foo, %eax
funcRel32, /// ex: movl _foo-L1(%eax), %eax
pointer32, /// ex: .long _foo
delta32, /// ex: .long _foo - .
// Kinds introduced by Passes:
lazyPointer, /// Location contains a lazy pointer.
lazyImmediateLocation, /// Location contains immediate value used in stub.
};
};
class KindHandler_arm : public KindHandler {
public:
static const Registry::KindStrings kindStrings[];

View File

@ -39,7 +39,7 @@ sections:
length: 2
pc-rel: false
extern: true
symbol: 1
symbol: 0
- offset: 0x00000008
type: GENERIC_RELOC_VANILLA
length: 2
@ -51,7 +51,7 @@ sections:
length: 2
pc-rel: false
extern: true
symbol: 1
symbol: 0
undefined-symbols:
- name: ___CFConstantStringClassReference
type: N_UNDF
@ -60,19 +60,35 @@ undefined-symbols:
...
# CHECK: defined-atoms:
# CHECK: - scope: hidden
# CHECK: - ref-name: [[STR1:L[L0-9]+]]
# CHECK: scope: hidden
# CHECK: type: c-string
# CHECK: content: [ 68, 65, 6C, 6C, 6F, 00 ]
# CHECK: merge: by-content
# CHECK: - scope: hidden
# CHECK: - ref-name: [[STR2:L[L0-9]+]]
# CHECK: scope: hidden
# CHECK: type: c-string
# CHECK: content: [ 74, 68, 65, 72, 65, 00 ]
# CHECK: merge: by-content
# CHECK: - scope: hidden
# CHECK: type: cfstring
# CHECK: merge: by-content
# CHECK: references:
# CHECK: - kind: pointer32
# CHECK: offset: 0
# CHECK: target: ___CFConstantStringClassReference
# CHECK: - kind: pointer32
# CHECK: offset: 8
# CHECK: target: [[STR1]]
# CHECK: - scope: hidden
# CHECK: type: cfstring
# CHECK: merge: by-content
# CHECK: references:
# CHECK: - kind: pointer32
# CHECK: offset: 0
# CHECK: target: ___CFConstantStringClassReference
# CHECK: - kind: pointer32
# CHECK: offset: 8
# CHECK: target: [[STR2]]
# CHECK:undefined-atoms:
# CHECK: - name: ___CFConstantStringClassReference

View File

@ -71,11 +71,13 @@ undefined-symbols:
# CHECK:defined-atoms:
# CHECK: - scope: hidden
# CHECK: - ref-name: [[GOT1:L[L0-9]+]]
# CHECK: scope: hidden
# CHECK: type: got
# CHECK: content: [ 00, 00, 00, 00 ]
# CHECK: merge: by-content
# CHECK: - scope: hidden
# CHECK: - ref-name: [[GOT2:L[L0-9]+]]
# CHECK: scope: hidden
# CHECK: type: got
# CHECK: content: [ 00, 00, 00, 00 ]
# CHECK: merge: by-content
@ -83,6 +85,13 @@ undefined-symbols:
# CHECK: scope: global
# CHECK: content: [ 55, 89, E5, E8, 00, 00, 00, 00, 59, 8D, 81, 14,
# CHECK: 00, 00, 00, 8D, 81, 18, 00, 00, 00, 5D, C3 ]
# CHECK: references:
# CHECK: - kind: funcRel32
# CHECK: offset: 11
# CHECK: target: [[GOT1]]
# CHECK: - kind: funcRel32
# CHECK: offset: 17
# CHECK: target: [[GOT2]]
# CHECK: - name: _foo
# CHECK: content: [ 55, 89, E5, 5D, C3 ]

View File

@ -0,0 +1,190 @@
# RUN: lld -flavor darwin -arch i386 -r -print_atoms %s -o %t | FileCheck %s
#
# Test parsing of x86 relocations.
#
# .text
#
#_test:
# call _undef
# call _undef+2
# callw _undef
#L1:
# movl _undef, %eax
# movl _x, %eax
# movl _x-L1(%eax), %eax
# movl _x+4-L1(%eax), %eax
#
# .data
#_x:
# .long _undef
# .long _test - .
# .long _test+3 - .
#
--- !mach-o
arch: x86
file-type: MH_OBJECT
flags: [ ]
OS: unknown
sections:
- segment: __TEXT
section: __text
type: S_REGULAR
attributes: [ S_ATTR_PURE_INSTRUCTIONS, S_ATTR_SOME_INSTRUCTIONS ]
address: 0x0000000000000000
content: [ 0xE8, 0xFB, 0xFF, 0xFF, 0xFF, 0xE8, 0xF8, 0xFF,
0xFF, 0xFF, 0x66, 0xE8, 0xF2, 0xFF, 0xA1, 0x00,
0x00, 0x00, 0x00, 0xA1, 0x24, 0x00, 0x00, 0x00,
0x8B, 0x80, 0x16, 0x00, 0x00, 0x00, 0x8B, 0x80,
0x1A, 0x00, 0x00, 0x00 ]
relocations:
- offset: 0x00000020
scattered: true
type: GENERIC_RELOC_LOCAL_SECTDIFF
length: 2
pc-rel: false
value: 0x00000024
- offset: 0x00000000
scattered: true
type: GENERIC_RELOC_PAIR
length: 2
pc-rel: false
value: 0x0000000E
- offset: 0x0000001A
scattered: true
type: GENERIC_RELOC_LOCAL_SECTDIFF
length: 2
pc-rel: false
value: 0x00000024
- offset: 0x00000000
scattered: true
type: GENERIC_RELOC_PAIR
length: 2
pc-rel: false
value: 0x0000000E
- offset: 0x00000014
type: GENERIC_RELOC_VANILLA
length: 2
pc-rel: false
extern: false
symbol: 2
- offset: 0x0000000F
type: GENERIC_RELOC_VANILLA
length: 2
pc-rel: false
extern: true
symbol: 2
- offset: 0x0000000C
type: GENERIC_RELOC_VANILLA
length: 1
pc-rel: true
extern: true
symbol: 2
- offset: 0x00000006
type: GENERIC_RELOC_VANILLA
length: 2
pc-rel: true
extern: true
symbol: 2
- offset: 0x00000001
type: GENERIC_RELOC_VANILLA
length: 2
pc-rel: true
extern: true
symbol: 2
- segment: __DATA
section: __data
type: S_REGULAR
attributes: [ ]
address: 0x0000000000000024
content: [ 0x00, 0x00, 0x00, 0x00, 0xD8, 0xFF, 0xFF, 0xFF,
0xD7, 0xFF, 0xFF, 0xFF ]
relocations:
- offset: 0x00000008
scattered: true
type: GENERIC_RELOC_LOCAL_SECTDIFF
length: 2
pc-rel: false
value: 0x00000000
- offset: 0x00000000
scattered: true
type: GENERIC_RELOC_PAIR
length: 2
pc-rel: false
value: 0x0000002C
- offset: 0x00000004
scattered: true
type: GENERIC_RELOC_LOCAL_SECTDIFF
length: 2
pc-rel: false
value: 0x00000000
- offset: 0x00000000
scattered: true
type: GENERIC_RELOC_PAIR
length: 2
pc-rel: false
value: 0x00000028
- offset: 0x00000000
type: GENERIC_RELOC_VANILLA
length: 2
pc-rel: false
extern: true
symbol: 2
local-symbols:
- name: _test
type: N_SECT
sect: 1
value: 0x0000000000000000
- name: _x
type: N_SECT
sect: 2
value: 0x0000000000000024
undefined-symbols:
- name: _undef
type: N_UNDF
scope: [ N_EXT ]
value: 0x0000000000000000
...
# CHECK: defined-atoms:
# CHECK: - name: _x
# CHECK: type: data
# CHECK: references:
# CHECK: - kind: pointer32
# CHECK: offset: 0
# CHECK: target: _undef
# CHECK: - kind: delta32
# CHECK: offset: 4
# CHECK: target: _test
# CHECK: - kind: delta32
# CHECK: offset: 8
# CHECK: target: _test
# CHECK: addend: 3
# CHECK: - name: _test
# CHECK: references:
# CHECK: - kind: branch32
# CHECK: offset: 1
# CHECK: target: _undef
# CHECK-NOT: addend:
# CHECK: - kind: branch32
# CHECK: offset: 6
# CHECK: target: _undef
# CHECK: addend: 2
# CHECK: - kind: branch16
# CHECK: offset: 12
# CHECK: target: _undef
# CHECK: - kind: abs32
# CHECK: offset: 15
# CHECK: target: _undef
# CHECK: - kind: abs32
# CHECK: offset: 20
# CHECK: target: _x
# CHECK: - kind: funcRel32
# CHECK: offset: 26
# CHECK: target: _x
# CHECK: addend: -14
# CHECK: - kind: funcRel32
# CHECK: offset: 32
# CHECK: target: _x
# CHECK: addend: -10