[mach-o] Add parsing of arm/thumb relocations

This converts the very complicated mach-o arm
relocations into the simple Reference Kinds in lld.

The next patch will use the internal Reference kinds
to fix up arm/thumb code.

llvm-svn: 212306
This commit is contained in:
Nick Kledzik 2014-07-04 00:11:09 +00:00
parent d7f75eeffc
commit 4576c115ac
6 changed files with 1319 additions and 95 deletions

View File

@ -17,10 +17,10 @@ namespace mach_o {
class MachODefinedAtom : public SimpleDefinedAtom {
public:
MachODefinedAtom(const File &f, const StringRef name, Scope scope,
ContentType type, Merge merge,
ContentType type, Merge merge, bool thumb,
const ArrayRef<uint8_t> content)
: SimpleDefinedAtom(f), _name(name), _content(content),
_contentType(type), _scope(scope), _merge(merge) {}
_contentType(type), _scope(scope), _merge(merge), _thumb(thumb) {}
// Constructor for zero-fill content
MachODefinedAtom(const File &f, const StringRef name, Scope scope,
@ -28,7 +28,7 @@ public:
: SimpleDefinedAtom(f), _name(name),
_content(ArrayRef<uint8_t>(nullptr, size)),
_contentType(DefinedAtom::typeZeroFill),
_scope(scope), _merge(mergeNo) {}
_scope(scope), _merge(mergeNo), _thumb(false) {}
uint64_t size() const override { return _content.size(); }
@ -53,6 +53,8 @@ public:
return _content;
}
bool isThumb() const { return _thumb; }
void addReference(uint32_t offsetInAtom, uint16_t relocType,
const Atom *target, Reference::Addend addend,
Reference::KindArch arch = Reference::KindArch::x86_64,
@ -66,15 +68,16 @@ private:
const ContentType _contentType;
const Scope _scope;
const Merge _merge;
const bool _thumb;
};
class MachODefinedCustomSectionAtom : public MachODefinedAtom {
public:
MachODefinedCustomSectionAtom(const File &f, const StringRef name,
Scope scope, ContentType type, Merge merge,
const ArrayRef<uint8_t> content,
bool thumb, const ArrayRef<uint8_t> content,
StringRef sectionName)
: MachODefinedAtom(f, name, scope, type, merge, content),
: MachODefinedAtom(f, name, scope, type, merge, thumb, content),
_sectionName(sectionName) {}
SectionChoice sectionChoice() const override {

View File

@ -30,7 +30,7 @@ public:
void addDefinedAtom(StringRef name, Atom::Scope scope,
DefinedAtom::ContentType type, DefinedAtom::Merge merge,
uint64_t sectionOffset, uint64_t contentSize,
uint64_t sectionOffset, uint64_t contentSize, bool thumb,
bool copyRefs, const Section *inSection) {
assert(sectionOffset+contentSize <= inSection->content.size());
ArrayRef<uint8_t> content = inSection->content.slice(sectionOffset,
@ -41,14 +41,14 @@ public:
content = content.copy(_allocator);
}
MachODefinedAtom *atom =
new (_allocator) MachODefinedAtom(*this, name, scope, type, merge,
content);
new (_allocator) MachODefinedAtom(*this, name, scope, type, merge,
thumb, content);
addAtomForSection(inSection, atom, sectionOffset);
}
void addDefinedAtomInCustomSection(StringRef name, Atom::Scope scope,
DefinedAtom::ContentType type, DefinedAtom::Merge merge,
uint64_t sectionOffset, uint64_t contentSize,
bool thumb, uint64_t sectionOffset, uint64_t contentSize,
StringRef sectionName, bool copyRefs,
const Section *inSection) {
assert(sectionOffset+contentSize <= inSection->content.size());
@ -61,8 +61,9 @@ public:
sectionName = sectionName.copy(_allocator);
}
MachODefinedCustomSectionAtom *atom =
new (_allocator) MachODefinedCustomSectionAtom(*this, name, scope, type,
merge, content, sectionName);
new (_allocator) MachODefinedCustomSectionAtom(*this, name, scope, type,
merge, thumb, content,
sectionName);
addAtomForSection(inSection, atom, sectionOffset);
}

View File

@ -231,6 +231,7 @@ void atomFromSymbol(DefinedAtom::ContentType atomType, const Section &section,
} else {
DefinedAtom::Merge merge = (symbolDescFlags & N_WEAK_DEF)
? DefinedAtom::mergeAsWeak : DefinedAtom::mergeNo;
bool thumb = (symbolDescFlags & N_ARM_THUMB_DEF);
if (atomType == DefinedAtom::typeUnknown) {
// Mach-O needs a segment and section name. Concatentate those two
// with a / seperator (e.g. "seg/sect") to fit into the lld model
@ -238,15 +239,15 @@ void atomFromSymbol(DefinedAtom::ContentType atomType, const Section &section,
std::string segSectName = section.segmentName.str()
+ "/" + section.sectionName.str();
file.addDefinedAtomInCustomSection(symbolName, symbolScope, atomType,
merge, offset, size, segSectName, true,
&section);
merge, thumb,offset, size, segSectName,
true, &section);
} else {
if ((atomType == lld::DefinedAtom::typeCode) &&
(symbolDescFlags & N_SYMBOL_RESOLVER)) {
atomType = lld::DefinedAtom::typeResolver;
}
file.addDefinedAtom(symbolName, symbolScope, atomType, merge,
offset, size, copyRefs, &section);
offset, size, thumb, copyRefs, &section);
}
}
}
@ -418,7 +419,7 @@ std::error_code processSection(DefinedAtom::ContentType atomType,
"not zero terminated.");
}
file.addDefinedAtom(StringRef(), scope, atomType, merge, offset, size,
copyRefs, &section);
false, copyRefs, &section);
offset += size;
}
}
@ -614,12 +615,6 @@ normalizedObjectToAtoms(const NormalizedFile &normalizedFile, StringRef path,
}
}
// TEMP BEGIN: until all KindHandlers switched to new interface.
if ((normalizedFile.arch != lld::MachOLinkingContext::arch_x86_64) &&
(normalizedFile.arch != lld::MachOLinkingContext::arch_x86))
return std::unique_ptr<File>(std::move(file));
// TEMP END
// Convert mach-o relocations to References
std::unique_ptr<mach_o::KindHandler> handler
= KindHandler::create(normalizedFile.arch);

View File

@ -10,6 +10,7 @@
#include "ReferenceKinds.h"
#include "MachONormalizedFileBinaryUtils.h"
#include "Atoms.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/ADT/StringSwitch.h"
@ -93,37 +94,6 @@ int64_t KindHandler::readS64(bool swap, const uint8_t *addr) {
}
bool KindHandler::isPairedReloc(const Relocation &reloc) {
llvm_unreachable("abstract");
}
std::error_code
KindHandler::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) {
llvm_unreachable("abstract");
}
std::error_code
KindHandler::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) {
llvm_unreachable("abstract");
}
//===----------------------------------------------------------------------===//
// KindHandler_x86_64
//===----------------------------------------------------------------------===//
@ -564,7 +534,7 @@ KindHandler_x86::getPairReferenceInfo(const normalized::Relocation &reloc1,
uint32_t ta = fromAddress + value - toAddress;
*addend = ta - offsetInFrom;
} else {
*addend= fromAddress + value - toAddress;
*addend = fromAddress + value - toAddress;
}
return std::error_code();
break;
@ -622,36 +592,447 @@ KindHandler_arm::~KindHandler_arm() {
}
const Registry::KindStrings KindHandler_arm::kindStrings[] = {
LLD_KIND_STRING_ENTRY(ARM_RELOC_BR24),
LLD_KIND_STRING_ENTRY(ARM_THUMB_RELOC_BR22),
LLD_KIND_STRING_ENTRY(LLD_ARM_RELOC_THUMB_ABS_LO16),
LLD_KIND_STRING_ENTRY(LLD_ARM_RELOC_THUMB_ABS_HI16),
LLD_KIND_STRING_ENTRY(LLD_ARM_RELOC_THUMB_REL_LO16),
LLD_KIND_STRING_ENTRY(LLD_ARM_RELOC_THUMB_REL_HI16),
LLD_KIND_STRING_ENTRY(LLD_ARM_RELOC_ABS32),
LLD_KIND_STRING_ENTRY(LLD_ARM_RELOC_POINTER32),
LLD_KIND_STRING_ENTRY(LLD_ARM_RELOC_LAZY_TARGET),
LLD_KIND_STRING_ENTRY(LLD_ARM_RELOC_LAZY_IMMEDIATE),
LLD_KIND_STRING_ENTRY(thumb_b22),
LLD_KIND_STRING_ENTRY(thumb_movw),
LLD_KIND_STRING_ENTRY(thumb_movt),
LLD_KIND_STRING_ENTRY(thumb_movw_funcRel),
LLD_KIND_STRING_ENTRY(thumb_movt_funcRel),
LLD_KIND_STRING_ENTRY(arm_b24),
LLD_KIND_STRING_ENTRY(arm_movw),
LLD_KIND_STRING_ENTRY(arm_movt),
LLD_KIND_STRING_ENTRY(arm_movw_funcRel),
LLD_KIND_STRING_ENTRY(arm_movt_funcRel),
LLD_KIND_STRING_ENTRY(pointer32),
LLD_KIND_STRING_ENTRY(delta32),
LLD_KIND_STRING_ENTRY(lazyPointer),
LLD_KIND_STRING_ENTRY(lazyImmediateLocation),
LLD_KIND_STRING_END
};
bool KindHandler_arm::isCallSite(const Reference &ref) {
return (ref.kindValue() == ARM_THUMB_RELOC_BR22) ||
(ref.kindValue() == ARM_RELOC_BR24);
return (ref.kindValue() == thumb_b22) ||
(ref.kindValue() == arm_b24);
}
bool KindHandler_arm::isPointer(const Reference &ref) {
return (ref.kindValue() == LLD_ARM_RELOC_POINTER32);
return (ref.kindValue() == pointer32);
}
bool KindHandler_arm::isLazyImmediate(const Reference &ref) {
return (ref.kindValue() == LLD_ARM_RELOC_LAZY_IMMEDIATE);
return (ref.kindValue() == lazyImmediateLocation);
}
bool KindHandler_arm::isLazyTarget(const Reference &ref) {
return (ref.kindValue() == LLD_ARM_RELOC_LAZY_TARGET);
return (ref.kindValue() == lazyPointer);
}
bool KindHandler_arm::isPairedReloc(const Relocation &reloc) {
switch (reloc.type) {
case ARM_RELOC_SECTDIFF:
case ARM_RELOC_LOCAL_SECTDIFF:
case ARM_RELOC_HALF_SECTDIFF:
case ARM_RELOC_HALF:
return true;
default:
return false;
}
}
int32_t KindHandler_arm::getDisplacementFromThumbBranch(uint32_t instruction) {
uint32_t s = (instruction >> 10) & 0x1;
uint32_t j1 = (instruction >> 29) & 0x1;
uint32_t j2 = (instruction >> 27) & 0x1;
uint32_t imm10 = instruction & 0x3FF;
uint32_t imm11 = (instruction >> 16) & 0x7FF;
uint32_t i1 = (j1 == s);
uint32_t i2 = (j2 == s);
uint32_t dis = (s << 24) | (i1 << 23) | (i2 << 22)
| (imm10 << 12) | (imm11 << 1);
int32_t sdis = dis;
if (s)
return (sdis | 0xFE000000);
else
return sdis;
}
int32_t KindHandler_arm::getDisplacementFromArmBranch(uint32_t instruction) {
// Sign-extend imm24
int32_t displacement = (instruction & 0x00FFFFFF) << 2;
if ( (displacement & 0x02000000) != 0 )
displacement |= 0xFC000000;
// If this is BLX and H bit set, add 2.
if ((instruction & 0xFF000000) == 0xFB000000)
displacement += 2;
return displacement;
}
uint16_t KindHandler_arm::getWordFromThumbMov(uint32_t instruction) {
uint32_t i = ((instruction & 0x00000400) >> 10);
uint32_t imm4 = (instruction & 0x0000000F);
uint32_t imm3 = ((instruction & 0x70000000) >> 28);
uint32_t imm8 = ((instruction & 0x00FF0000) >> 16);
return (imm4 << 12) | (i << 11) | (imm3 << 8) | imm8;
}
uint16_t KindHandler_arm::getWordFromArmMov(uint32_t instruction) {
uint32_t imm4 = ((instruction & 0x000F0000) >> 16);
uint32_t imm12 = (instruction & 0x00000FFF);
return (imm4 << 12) | imm12;
}
uint32_t KindHandler_arm::clearThumbBit(uint32_t value, const Atom* target) {
// The assembler often adds one to the address of a thumb function.
// We need to undo that so it does not look like an addend.
if (value & 1) {
if (isa<DefinedAtom>(target)) {
const MachODefinedAtom *machoTarget = reinterpret_cast<
const MachODefinedAtom*>(target);
if (machoTarget->isThumb())
value &= -2; // mask off thumb-bit
}
}
return value;
}
std::error_code
KindHandler_arm::getReferenceInfo(const Relocation &reloc,
const DefinedAtom *inAtom,
uint32_t offsetInAtom,
uint64_t fixupAddress, bool swap,
FindAtomBySectionAndAddress atomFromAddress,
FindAtomBySymbolIndex atomFromSymbolIndex,
Reference::KindValue *kind,
const lld::Atom **target,
Reference::Addend *addend) {
typedef std::error_code E;
const uint8_t *fixupContent = &inAtom->rawContent()[offsetInAtom];
uint64_t targetAddress;
uint32_t instruction = readU32(swap, fixupContent);
int32_t displacement;
switch (relocPattern(reloc)) {
case ARM_THUMB_RELOC_BR22 | rPcRel | rExtern | rLength4:
// ex: bl _foo (and _foo is undefined)
*kind = thumb_b22;
if (E ec = atomFromSymbolIndex(reloc.symbol, target))
return ec;
// Instruction contains branch to addend.
displacement = getDisplacementFromThumbBranch(instruction);
*addend = fixupAddress + 4 + displacement;
return std::error_code();
case ARM_THUMB_RELOC_BR22 | rPcRel | rLength4:
// ex: bl _foo (and _foo is defined)
*kind = thumb_b22;
displacement = getDisplacementFromThumbBranch(instruction);
targetAddress = fixupAddress + 4 + displacement;
return atomFromAddress(reloc.symbol, targetAddress, target, addend);
case ARM_THUMB_RELOC_BR22 | rScattered | rPcRel | rLength4:
// ex: bl _foo+4 (and _foo is defined)
*kind = thumb_b22;
displacement = getDisplacementFromThumbBranch(instruction);
targetAddress = fixupAddress + 4 + displacement;
if (E ec = atomFromAddress(0, reloc.value, target, addend))
return ec;
// reloc.value is target atom's address. Instruction contains branch
// to atom+addend.
*addend += (targetAddress - reloc.value);
return std::error_code();
case ARM_RELOC_BR24 | rPcRel | rExtern | rLength4:
// ex: bl _foo (and _foo is undefined)
*kind = arm_b24;
if (E ec = atomFromSymbolIndex(reloc.symbol, target))
return ec;
// Instruction contains branch to addend.
displacement = getDisplacementFromArmBranch(instruction);
*addend = fixupAddress + 8 + displacement;
return std::error_code();
case ARM_RELOC_BR24 | rPcRel | rLength4:
// ex: bl _foo (and _foo is defined)
*kind = arm_b24;
displacement = getDisplacementFromArmBranch(instruction);
targetAddress = fixupAddress + 8 + displacement;
return atomFromAddress(reloc.symbol, targetAddress, target, addend);
case ARM_RELOC_BR24 | rScattered | rPcRel | rLength4:
// ex: bl _foo+4 (and _foo is defined)
*kind = arm_b24;
displacement = getDisplacementFromArmBranch(instruction);
targetAddress = fixupAddress + 8 + displacement;
if (E ec = atomFromAddress(0, reloc.value, target, addend))
return ec;
// reloc.value is target atom's address. Instruction contains branch
// to atom+addend.
*addend += (targetAddress - reloc.value);
return std::error_code();
case ARM_RELOC_VANILLA | rExtern | rLength4:
// ex: .long _foo (and _foo is undefined)
*kind = pointer32;
if (E ec = atomFromSymbolIndex(reloc.symbol, target))
return ec;
*addend = instruction;
return std::error_code();
case ARM_RELOC_VANILLA | rLength4:
// ex: .long _foo (and _foo is defined)
*kind = pointer32;
if (E ec = atomFromAddress(reloc.symbol, instruction, target, addend))
return ec;
*addend = clearThumbBit((uint32_t)*addend, *target);
return std::error_code();
case ARM_RELOC_VANILLA | rScattered | rLength4:
// ex: .long _foo+a (and _foo is defined)
*kind = pointer32;
if (E ec = atomFromAddress(0, reloc.value, target, addend))
return ec;
*addend += (clearThumbBit(instruction, *target) - reloc.value);
return std::error_code();
default:
return make_dynamic_error_code(Twine("unsupported arm relocation type"));
}
return std::error_code();
}
std::error_code
KindHandler_arm::getPairReferenceInfo(const normalized::Relocation &reloc1,
const normalized::Relocation &reloc2,
const DefinedAtom *inAtom,
uint32_t offsetInAtom,
uint64_t fixupAddress, bool swap,
FindAtomBySectionAndAddress atomFromAddr,
FindAtomBySymbolIndex atomFromSymbolIndex,
Reference::KindValue *kind,
const lld::Atom **target,
Reference::Addend *addend) {
bool pointerDiff = false;
bool funcRel;
bool top;
bool thumbReloc;
switch(relocPattern(reloc1) << 16 | relocPattern(reloc2)) {
case ((ARM_RELOC_HALF_SECTDIFF | rScattered | rLength4) << 16 |
ARM_RELOC_PAIR | rScattered | rLength4):
// ex: movw r1, :lower16:(_x-L1) [thumb mode]
*kind = thumb_movw_funcRel;
funcRel = true;
top = false;
thumbReloc = true;
break;
case ((ARM_RELOC_HALF_SECTDIFF | rScattered | rLength8) << 16 |
ARM_RELOC_PAIR | rScattered | rLength8):
// ex: movt r1, :upper16:(_x-L1) [thumb mode]
*kind = thumb_movt_funcRel;
funcRel = true;
top = true;
thumbReloc = true;
break;
case ((ARM_RELOC_HALF_SECTDIFF | rScattered | rLength1) << 16 |
ARM_RELOC_PAIR | rScattered | rLength1):
// ex: movw r1, :lower16:(_x-L1) [arm mode]
*kind = arm_movw_funcRel;
funcRel = true;
top = false;
thumbReloc = false;
break;
case ((ARM_RELOC_HALF_SECTDIFF | rScattered | rLength2) << 16 |
ARM_RELOC_PAIR | rScattered | rLength2):
// ex: movt r1, :upper16:(_x-L1) [arm mode]
*kind = arm_movt_funcRel;
funcRel = true;
top = true;
thumbReloc = false;
break;
case ((ARM_RELOC_HALF | rLength4) << 16 |
ARM_RELOC_PAIR | rLength4):
// ex: movw r1, :lower16:_x [thumb mode]
*kind = thumb_movw;
funcRel = false;
top = false;
thumbReloc = true;
break;
case ((ARM_RELOC_HALF | rLength8) << 16 |
ARM_RELOC_PAIR | rLength8):
// ex: movt r1, :upper16:_x [thumb mode]
*kind = thumb_movt;
funcRel = false;
top = true;
thumbReloc = true;
break;
case ((ARM_RELOC_HALF | rLength1) << 16 |
ARM_RELOC_PAIR | rLength1):
// ex: movw r1, :lower16:_x [arm mode]
*kind = arm_movw;
funcRel = false;
top = false;
thumbReloc = false;
break;
case ((ARM_RELOC_HALF | rLength2) << 16 |
ARM_RELOC_PAIR | rLength2):
// ex: movt r1, :upper16:_x [arm mode]
*kind = arm_movt;
funcRel = false;
top = true;
thumbReloc = false;
break;
case ((ARM_RELOC_HALF | rScattered | rLength4) << 16 |
ARM_RELOC_PAIR | rLength4):
// ex: movw r1, :lower16:_x+a [thumb mode]
*kind = thumb_movw;
funcRel = false;
top = false;
thumbReloc = true;
break;
case ((ARM_RELOC_HALF | rScattered | rLength8) << 16 |
ARM_RELOC_PAIR | rLength8):
// ex: movt r1, :upper16:_x+a [thumb mode]
*kind = thumb_movt;
funcRel = false;
top = true;
thumbReloc = true;
break;
case ((ARM_RELOC_HALF | rScattered | rLength1) << 16 |
ARM_RELOC_PAIR | rLength1):
// ex: movw r1, :lower16:_x+a [arm mode]
*kind = arm_movw;
funcRel = false;
top = false;
thumbReloc = false;
break;
case ((ARM_RELOC_HALF | rScattered | rLength2) << 16 |
ARM_RELOC_PAIR | rLength2):
// ex: movt r1, :upper16:_x+a [arm mode]
*kind = arm_movt;
funcRel = false;
top = true;
thumbReloc = false;
break;
case ((ARM_RELOC_HALF | rExtern | rLength4) << 16 |
ARM_RELOC_PAIR | rLength4):
// ex: movw r1, :lower16:_undef [thumb mode]
*kind = thumb_movw;
funcRel = false;
top = false;
thumbReloc = true;
break;
case ((ARM_RELOC_HALF | rExtern | rLength8) << 16 |
ARM_RELOC_PAIR | rLength8):
// ex: movt r1, :upper16:_undef [thumb mode]
*kind = thumb_movt;
funcRel = false;
top = true;
thumbReloc = true;
break;
case ((ARM_RELOC_HALF | rExtern | rLength1) << 16 |
ARM_RELOC_PAIR | rLength1):
// ex: movw r1, :lower16:_undef [arm mode]
*kind = arm_movw;
funcRel = false;
top = false;
thumbReloc = false;
break;
case ((ARM_RELOC_HALF | rExtern | rLength2) << 16 |
ARM_RELOC_PAIR | rLength2):
// ex: movt r1, :upper16:_undef [arm mode]
*kind = arm_movt;
funcRel = false;
top = true;
thumbReloc = false;
break;
case ((ARM_RELOC_SECTDIFF | rScattered | rLength4) << 16 |
ARM_RELOC_PAIR | rScattered | rLength4):
case ((ARM_RELOC_LOCAL_SECTDIFF | rScattered | rLength4) << 16 |
ARM_RELOC_PAIR | rScattered | rLength4):
// ex: .long _foo - .
pointerDiff = true;
break;
default:
return make_dynamic_error_code(Twine("unsupported arm relocation pair"));
}
const uint8_t *fixupContent = &inAtom->rawContent()[offsetInAtom];
std::error_code ec;
uint32_t instruction = readU32(swap, fixupContent);
uint32_t value;
uint32_t fromAddress;
uint32_t toAddress;
uint16_t instruction16;
uint16_t other16;
const lld::Atom *fromTarget;
Reference::Addend offsetInTo;
Reference::Addend offsetInFrom;
if (pointerDiff) {
toAddress = reloc1.value;
fromAddress = reloc2.value;
ec = atomFromAddr(0, toAddress, target, &offsetInTo);
if (ec)
return ec;
ec = atomFromAddr(0, fromAddress, &fromTarget, &offsetInFrom);
if (ec)
return ec;
if (fromTarget != inAtom)
return make_dynamic_error_code(Twine("SECTDIFF relocation where "
"subtrahend label is not in atom"));
*kind = delta32;
value = clearThumbBit(instruction, *target);
*addend = value - (toAddress - fromAddress);
} else if (funcRel) {
toAddress = reloc1.value;
fromAddress = reloc2.value;
ec = atomFromAddr(0, toAddress, target, &offsetInTo);
if (ec)
return ec;
ec = atomFromAddr(0, fromAddress, &fromTarget, &offsetInFrom);
if (ec)
return ec;
if (fromTarget != inAtom)
return make_dynamic_error_code(Twine("ARM_RELOC_HALF_SECTDIFF relocation "
"where subtrahend label is not in atom"));
other16 = (reloc2.offset & 0xFFFF);
if (thumbReloc)
instruction16 = getWordFromThumbMov(instruction);
else
instruction16 = getWordFromArmMov(instruction);
if (top)
value = (instruction16 << 16) | other16;
else
value = (other16 << 16) | instruction16;
value = clearThumbBit(value, *target);
int64_t ta = (int64_t)value - (toAddress - fromAddress);
*addend = ta - offsetInFrom;
return std::error_code();
} else {
uint32_t sectIndex;
if (thumbReloc)
instruction16 = getWordFromThumbMov(instruction);
else
instruction16 = getWordFromArmMov(instruction);
other16 = (reloc2.offset & 0xFFFF);
if (top)
value = (instruction16 << 16) | other16;
else
value = (other16 << 16) | instruction16;
if (reloc1.isExtern) {
ec = atomFromSymbolIndex(reloc1.symbol, target);
if (ec)
return ec;
*addend = value;
} else {
if (reloc1.scattered) {
toAddress = reloc1.value;
sectIndex = 0;
} else {
toAddress = value;
sectIndex = reloc1.symbol;
}
ec = atomFromAddr(sectIndex, toAddress, target, &offsetInTo);
if (ec)
return ec;
*addend = value - toAddress;
}
}
return std::error_code();
}
void KindHandler_arm::applyFixup(Reference::KindNamespace ns,
Reference::KindArch arch,
Reference::KindValue kindValue,
@ -663,36 +1044,49 @@ void KindHandler_arm::applyFixup(Reference::KindNamespace ns,
return;
assert(arch == Reference::KindArch::ARM);
//int32_t *loc32 = reinterpret_cast<int32_t*>(location);
// FIXME: these writes may need a swap.
switch (kindValue) {
case ARM_THUMB_RELOC_BR22:
case thumb_b22:
// FIXME
break;
case thumb_movw:
// FIXME
break;
case ARM_RELOC_BR24:
case thumb_movt:
// FIXME
break;
case LLD_ARM_RELOC_THUMB_ABS_LO16:
case thumb_movw_funcRel:
// FIXME
break;
case LLD_ARM_RELOC_THUMB_ABS_HI16:
case thumb_movt_funcRel:
// FIXME
break;
case LLD_ARM_RELOC_THUMB_REL_LO16:
case arm_b24:
// FIXME
break;
case LLD_ARM_RELOC_THUMB_REL_HI16:
case arm_movw:
// FIXME
break;
case LLD_ARM_RELOC_ABS32:
case arm_movt:
// FIXME
break;
case LLD_ARM_RELOC_POINTER32:
case arm_movw_funcRel:
// FIXME
break;
case LLD_ARM_RELOC_LAZY_TARGET:
case LLD_ARM_RELOC_LAZY_IMMEDIATE:
case arm_movt_funcRel:
// FIXME
break;
case pointer32:
// FIXME
break;
case delta32:
// FIXME
break;
case lazyPointer:
case lazyImmediateLocation:
// do nothing
break;
default:
case invalid:
llvm_unreachable("invalid ARM Reference Kind");
break;
}

View File

@ -23,18 +23,6 @@ namespace lld {
namespace mach_o {
// Additional Reference Kind values used internally.
enum {
LLD_ARM_RELOC_THUMB_ABS_LO16 = 100, // thumb movw of absolute address
LLD_ARM_RELOC_THUMB_ABS_HI16 = 101, // thumb movt of absolute address
LLD_ARM_RELOC_THUMB_REL_LO16 = 102, // thumb movw of (target - pc)
LLD_ARM_RELOC_THUMB_REL_HI16 = 103, // thumb movt of (target - pc)
LLD_ARM_RELOC_ABS32 = 104, // 32-bit constant pointer
LLD_ARM_RELOC_POINTER32 = 105, // 32-bit data pointer
LLD_ARM_RELOC_LAZY_TARGET = 106,
LLD_ARM_RELOC_LAZY_IMMEDIATE = 107,
};
///
/// The KindHandler class is the abstract interface to Reference::Kind
/// values for mach-o files. Particular Kind values (e.g. 3) has a different
@ -52,7 +40,7 @@ public:
virtual bool isLazyTarget(const Reference &) = 0;
/// Returns true if the specified relocation is paired to the next relocation.
virtual bool isPairedReloc(const normalized::Relocation &);
virtual bool isPairedReloc(const normalized::Relocation &) = 0;
/// Prototype for a helper function. Given a sectionIndex and address,
/// finds the atom and offset with that atom of that address.
@ -63,7 +51,7 @@ public:
/// Prototype for a helper function. Given a symbolIndex, finds the atom
/// representing that symbol.
typedef std::function<std::error_code (uint32_t symbolIndex,
const lld::Atom**)> FindAtomBySymbolIndex;
const lld::Atom **)> FindAtomBySymbolIndex;
/// Analyzes a relocation from a .o file and returns the info
/// (kind, target, addend) needed to instantiate a Reference.
@ -78,7 +66,7 @@ public:
FindAtomBySymbolIndex atomFromSymbolIndex,
Reference::KindValue *kind,
const lld::Atom **target,
Reference::Addend *addend);
Reference::Addend *addend) = 0;
/// Analyzes a pair of relocations from a .o file and returns the info
/// (kind, target, addend) needed to instantiate a Reference.
@ -94,7 +82,7 @@ public:
FindAtomBySymbolIndex atomFromSymbolIndex,
Reference::KindValue *kind,
const lld::Atom **target,
Reference::Addend *addend);
Reference::Addend *addend) = 0;
/// Fixup an atom when generating a final linked binary.
virtual void applyFixup(Reference::KindNamespace ns, Reference::KindArch arch,
@ -278,11 +266,63 @@ public:
bool isPointer(const Reference &) override;
bool isLazyImmediate(const Reference &) override;
bool isLazyTarget(const Reference &) override;
bool isPairedReloc(const normalized::Relocation &) override;
std::error_code getReferenceInfo(const normalized::Relocation &reloc,
const DefinedAtom *inAtom,
uint32_t offsetInAtom,
uint64_t fixupAddress, bool swap,
FindAtomBySectionAndAddress atomFromAddress,
FindAtomBySymbolIndex atomFromSymbolIndex,
Reference::KindValue *kind,
const lld::Atom **target,
Reference::Addend *addend) override;
std::error_code
getPairReferenceInfo(const normalized::Relocation &reloc1,
const normalized::Relocation &reloc2,
const DefinedAtom *inAtom,
uint32_t offsetInAtom,
uint64_t fixupAddress, bool swap,
FindAtomBySectionAndAddress atomFromAddress,
FindAtomBySymbolIndex atomFromSymbolIndex,
Reference::KindValue *kind,
const lld::Atom **target,
Reference::Addend *addend) override;
void applyFixup(Reference::KindNamespace ns, Reference::KindArch arch,
Reference::KindValue kindValue, uint64_t addend,
uint8_t *location, uint64_t fixupAddress,
uint64_t targetAddress, uint64_t inAtomAddress)
override;
private:
enum : Reference::KindValue {
invalid, /// for error condition
// Kinds found in mach-o .o files:
thumb_b22, /// ex: bl _foo
thumb_movw, /// ex: movw r1, :lower16:_foo
thumb_movt, /// ex: movt r1, :lower16:_foo
thumb_movw_funcRel, /// ex: movw r1, :lower16:(_foo-(L1+4))
thumb_movt_funcRel, /// ex: movt r1, :upper16:(_foo-(L1+4))
arm_b24, /// ex: bl _foo
arm_movw, /// ex: movw r1, :lower16:_foo
arm_movt, /// ex: movt r1, :lower16:_foo
arm_movw_funcRel, /// ex: movw r1, :lower16:(_foo-(L1+4))
arm_movt_funcRel, /// ex: movt r1, :upper16:(_foo-(L1+4))
pointer32, /// ex: .long _foo
delta32, /// ex: .long _foo - .
// Kinds introduced by Passes:
lazyPointer, /// Location contains a lazy pointer.
lazyImmediateLocation, /// Location contains immediate value used in stub.
};
int32_t getDisplacementFromThumbBranch(uint32_t instruction);
int32_t getDisplacementFromArmBranch(uint32_t instruction);
uint16_t getWordFromThumbMov(uint32_t instruction);
uint16_t getWordFromArmMov(uint32_t instruction);
uint32_t clearThumbBit(uint32_t value, const Atom* target);
};
} // namespace mach_o

View File

@ -0,0 +1,791 @@
# RUN: lld -flavor darwin -arch armv7 -r -print_atoms %s -o %t | FileCheck %s
#
# Test parsing of armv7 relocations.
#
#
--- !mach-o
arch: armv7
file-type: MH_OBJECT
flags: [ MH_SUBSECTIONS_VIA_SYMBOLS ]
has-UUID: false
OS: unknown
sections:
- segment: __TEXT
section: __text
type: S_REGULAR
attributes: [ S_ATTR_PURE_INSTRUCTIONS, S_ATTR_SOME_INSTRUCTIONS ]
alignment: 2
address: 0x0000000000000000
content: [ 0x00, 0xF0, 0x4A, 0xF8, 0x00, 0xF0, 0x4A, 0xF8,
0xFF, 0xF7, 0xFA, 0xFF, 0xFF, 0xF7, 0xFA, 0xFF,
0x40, 0xF2, 0x6E, 0x01, 0xC0, 0xF2, 0x00, 0x01,
0x40, 0xF2, 0x76, 0x02, 0xC0, 0xF2, 0x00, 0x02,
0x40, 0xF2, 0x29, 0x01, 0xC0, 0xF2, 0x00, 0x01,
0x79, 0x44, 0x40, 0xF2, 0x98, 0x03, 0xC0, 0xF2,
0x00, 0x03, 0x40, 0xF2, 0xA0, 0x04, 0xC0, 0xF2,
0x00, 0x04, 0x40, 0xF2, 0x53, 0x03, 0xC0, 0xF2,
0x00, 0x03, 0x40, 0xF2, 0x00, 0x05, 0xC0, 0xF2,
0x00, 0x05, 0x40, 0xF2, 0x08, 0x06, 0xC0, 0xF2,
0x00, 0x06, 0xC0, 0x46, 0x0F, 0x00, 0x00, 0xEB,
0x0F, 0x00, 0x00, 0xEB, 0xE7, 0xFF, 0xFF, 0xEB,
0xE7, 0xFF, 0xFF, 0xEB, 0x20, 0x10, 0x00, 0xE3,
0x00, 0x10, 0x40, 0xE3, 0x28, 0x20, 0x00, 0xE3,
0x00, 0x20, 0x40, 0xE3, 0x0F, 0x10, 0x81, 0xE0,
0x98, 0x30, 0x00, 0xE3, 0x00, 0x30, 0x40, 0xE3,
0xA0, 0x40, 0x00, 0xE3, 0x00, 0x40, 0x40, 0xE3,
0x00, 0x50, 0x00, 0xE3, 0x00, 0x50, 0x40, 0xE3,
0x08, 0x60, 0x00, 0xE3, 0x00, 0x60, 0x40, 0xE3 ]
relocations:
- offset: 0x00000094
type: ARM_RELOC_HALF
length: 1
pc-rel: false
extern: true
symbol: 4
- offset: 0x00000008
type: ARM_RELOC_PAIR
length: 1
pc-rel: false
extern: false
symbol: 16777215
- offset: 0x00000090
type: ARM_RELOC_HALF
length: 0
pc-rel: false
extern: true
symbol: 4
- offset: 0x00000000
type: ARM_RELOC_PAIR
length: 0
pc-rel: false
extern: false
symbol: 16777215
- offset: 0x0000008C
type: ARM_RELOC_HALF
length: 1
pc-rel: false
extern: true
symbol: 4
- offset: 0x00000000
type: ARM_RELOC_PAIR
length: 1
pc-rel: false
extern: false
symbol: 16777215
- offset: 0x00000088
type: ARM_RELOC_HALF
length: 0
pc-rel: false
extern: true
symbol: 4
- offset: 0x00000000
type: ARM_RELOC_PAIR
length: 0
pc-rel: false
extern: false
symbol: 16777215
- offset: 0x00000084
scattered: true
type: ARM_RELOC_HALF
length: 1
pc-rel: false
value: 0x00000098
- offset: 0x000000A0
type: ARM_RELOC_PAIR
length: 1
pc-rel: false
extern: false
symbol: 16777215
- offset: 0x00000080
scattered: true
type: ARM_RELOC_HALF
length: 0
pc-rel: false
value: 0x00000098
- offset: 0x00000000
type: ARM_RELOC_PAIR
length: 0
pc-rel: false
extern: false
symbol: 16777215
- offset: 0x0000007C
type: ARM_RELOC_HALF
length: 1
pc-rel: false
extern: false
symbol: 2
- offset: 0x00000098
type: ARM_RELOC_PAIR
length: 1
pc-rel: false
extern: false
symbol: 16777215
- offset: 0x00000078
type: ARM_RELOC_HALF
length: 0
pc-rel: false
extern: false
symbol: 2
- offset: 0x00000000
type: ARM_RELOC_PAIR
length: 0
pc-rel: false
extern: false
symbol: 16777215
- offset: 0x00000070
scattered: true
type: ARM_RELOC_HALF_SECTDIFF
length: 1
pc-rel: false
value: 0x00000098
- offset: 0x00000028
scattered: true
type: ARM_RELOC_PAIR
length: 1
pc-rel: false
value: 0x00000078
- offset: 0x0000006C
scattered: true
type: ARM_RELOC_HALF_SECTDIFF
length: 0
pc-rel: false
value: 0x00000098
- offset: 0x00000000
scattered: true
type: ARM_RELOC_PAIR
length: 0
pc-rel: false
value: 0x00000078
- offset: 0x00000068
scattered: true
type: ARM_RELOC_HALF_SECTDIFF
length: 1
pc-rel: false
value: 0x00000098
- offset: 0x00000020
scattered: true
type: ARM_RELOC_PAIR
length: 1
pc-rel: false
value: 0x00000078
- offset: 0x00000064
scattered: true
type: ARM_RELOC_HALF_SECTDIFF
length: 0
pc-rel: false
value: 0x00000098
- offset: 0x00000000
scattered: true
type: ARM_RELOC_PAIR
length: 0
pc-rel: false
value: 0x00000078
- offset: 0x00000060
type: ARM_RELOC_BR24
length: 2
pc-rel: true
extern: true
symbol: 4
- offset: 0x0000005C
type: ARM_RELOC_BR24
length: 2
pc-rel: true
extern: true
symbol: 4
- offset: 0x00000058
scattered: true
type: ARM_RELOC_BR24
length: 2
pc-rel: true
value: 0x00000098
- offset: 0x00000054
type: ARM_RELOC_BR24
length: 2
pc-rel: true
extern: false
symbol: 2
- offset: 0x0000004E
type: ARM_RELOC_HALF
length: 3
pc-rel: false
extern: true
symbol: 4
- offset: 0x00000008
type: ARM_RELOC_PAIR
length: 3
pc-rel: false
extern: false
symbol: 16777215
- offset: 0x0000004A
type: ARM_RELOC_HALF
length: 2
pc-rel: false
extern: true
symbol: 4
- offset: 0x00000000
type: ARM_RELOC_PAIR
length: 2
pc-rel: false
extern: false
symbol: 16777215
- offset: 0x00000046
type: ARM_RELOC_HALF
length: 3
pc-rel: false
extern: true
symbol: 4
- offset: 0x00000000
type: ARM_RELOC_PAIR
length: 3
pc-rel: false
extern: false
symbol: 16777215
- offset: 0x00000042
type: ARM_RELOC_HALF
length: 2
pc-rel: false
extern: true
symbol: 4
- offset: 0x00000000
type: ARM_RELOC_PAIR
length: 2
pc-rel: false
extern: false
symbol: 16777215
- offset: 0x0000003E
type: ARM_RELOC_HALF
length: 3
pc-rel: false
extern: false
symbol: 1
- offset: 0x00000053
type: ARM_RELOC_PAIR
length: 3
pc-rel: false
extern: false
symbol: 16777215
- offset: 0x0000003A
type: ARM_RELOC_HALF
length: 2
pc-rel: false
extern: false
symbol: 1
- offset: 0x00000000
type: ARM_RELOC_PAIR
length: 2
pc-rel: false
extern: false
symbol: 16777215
- offset: 0x00000036
scattered: true
type: ARM_RELOC_HALF
length: 3
pc-rel: false
value: 0x00000098
- offset: 0x000000A0
type: ARM_RELOC_PAIR
length: 3
pc-rel: false
extern: false
symbol: 16777215
- offset: 0x00000032
scattered: true
type: ARM_RELOC_HALF
length: 2
pc-rel: false
value: 0x00000098
- offset: 0x00000000
type: ARM_RELOC_PAIR
length: 2
pc-rel: false
extern: false
symbol: 16777215
- offset: 0x0000002E
type: ARM_RELOC_HALF
length: 3
pc-rel: false
extern: false
symbol: 2
- offset: 0x00000098
type: ARM_RELOC_PAIR
length: 3
pc-rel: false
extern: false
symbol: 16777215
- offset: 0x0000002A
type: ARM_RELOC_HALF
length: 2
pc-rel: false
extern: false
symbol: 2
- offset: 0x00000000
type: ARM_RELOC_PAIR
length: 2
pc-rel: false
extern: false
symbol: 16777215
- offset: 0x00000024
scattered: true
type: ARM_RELOC_HALF_SECTDIFF
length: 3
pc-rel: false
value: 0x00000052
- offset: 0x00000028
scattered: true
type: ARM_RELOC_PAIR
length: 3
pc-rel: false
value: 0x0000002A
- offset: 0x00000020
scattered: true
type: ARM_RELOC_HALF_SECTDIFF
length: 2
pc-rel: false
value: 0x00000052
- offset: 0x00000000
scattered: true
type: ARM_RELOC_PAIR
length: 2
pc-rel: false
value: 0x0000002A
- offset: 0x0000001C
scattered: true
type: ARM_RELOC_HALF_SECTDIFF
length: 3
pc-rel: false
value: 0x00000098
- offset: 0x00000076
scattered: true
type: ARM_RELOC_PAIR
length: 3
pc-rel: false
value: 0x0000002A
- offset: 0x00000018
scattered: true
type: ARM_RELOC_HALF_SECTDIFF
length: 2
pc-rel: false
value: 0x00000098
- offset: 0x00000000
scattered: true
type: ARM_RELOC_PAIR
length: 2
pc-rel: false
value: 0x0000002A
- offset: 0x00000014
scattered: true
type: ARM_RELOC_HALF_SECTDIFF
length: 3
pc-rel: false
value: 0x00000098
- offset: 0x0000006E
scattered: true
type: ARM_RELOC_PAIR
length: 3
pc-rel: false
value: 0x0000002A
- offset: 0x00000010
scattered: true
type: ARM_RELOC_HALF_SECTDIFF
length: 2
pc-rel: false
value: 0x00000098
- offset: 0x00000000
scattered: true
type: ARM_RELOC_PAIR
length: 2
pc-rel: false
value: 0x0000002A
- offset: 0x0000000C
type: ARM_THUMB_RELOC_BR22
length: 2
pc-rel: true
extern: true
symbol: 4
- offset: 0x00000008
type: ARM_THUMB_RELOC_BR22
length: 2
pc-rel: true
extern: true
symbol: 4
- offset: 0x00000004
scattered: true
type: ARM_THUMB_RELOC_BR22
length: 2
pc-rel: true
value: 0x00000098
- offset: 0x00000000
type: ARM_THUMB_RELOC_BR22
length: 2
pc-rel: true
extern: false
symbol: 2
- segment: __DATA
section: __data
type: S_REGULAR
attributes: [ ]
address: 0x0000000000000098
content: [ 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x04, 0x00, 0x00, 0x00, 0xA8, 0xFF, 0xFF, 0xFF,
0xA8, 0xFF, 0xFF, 0xFF, 0x4D, 0xFF, 0xFF, 0xFF,
0x4D, 0xFF, 0xFF, 0xFF ]
relocations:
- offset: 0x00000020
scattered: true
type: ARM_RELOC_SECTDIFF
length: 2
pc-rel: false
value: 0x00000000
- offset: 0x00000000
scattered: true
type: ARM_RELOC_PAIR
length: 2
pc-rel: false
value: 0x000000B8
- offset: 0x0000001C
scattered: true
type: ARM_RELOC_SECTDIFF
length: 2
pc-rel: false
value: 0x00000000
- offset: 0x00000000
scattered: true
type: ARM_RELOC_PAIR
length: 2
pc-rel: false
value: 0x000000B4
- offset: 0x00000018
scattered: true
type: ARM_RELOC_SECTDIFF
length: 2
pc-rel: false
value: 0x00000054
- offset: 0x00000000
scattered: true
type: ARM_RELOC_PAIR
length: 2
pc-rel: false
value: 0x000000B0
- offset: 0x00000014
scattered: true
type: ARM_RELOC_SECTDIFF
length: 2
pc-rel: false
value: 0x00000054
- offset: 0x00000000
scattered: true
type: ARM_RELOC_PAIR
length: 2
pc-rel: false
value: 0x000000AC
- offset: 0x00000010
type: ARM_RELOC_VANILLA
length: 2
pc-rel: false
extern: true
symbol: 4
- offset: 0x0000000C
type: ARM_RELOC_VANILLA
length: 2
pc-rel: false
extern: true
symbol: 4
- offset: 0x00000008
scattered: true
type: ARM_RELOC_VANILLA
length: 2
pc-rel: false
value: 0x00000000
- offset: 0x00000004
type: ARM_RELOC_VANILLA
length: 2
pc-rel: false
extern: false
symbol: 1
local-symbols:
- name: _foo_thumb
type: N_SECT
sect: 1
desc: [ N_ARM_THUMB_DEF ]
value: 0x0000000000000000
- name: _x
type: N_SECT
sect: 2
value: 0x0000000000000098
- name: _t1
type: N_SECT
sect: 1
desc: [ N_ARM_THUMB_DEF ]
value: 0x0000000000000052
- name: _foo_arm
type: N_SECT
sect: 1
value: 0x0000000000000054
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: 4
# CHECK: target: _foo_thumb
# CHECK-NOT: addend:
# CHECK: - kind: pointer32
# CHECK: offset: 8
# CHECK: target: _foo_thumb
# CHECK: addend: 4
# CHECK: - kind: pointer32
# CHECK: offset: 12
# CHECK: target: _undef
# CHECK-NOT: addend:
# CHECK: - kind: pointer32
# CHECK: offset: 16
# CHECK: target: _undef
# CHECK: addend: 4
# CHECK: - kind: delta32
# CHECK: offset: 20
# CHECK: target: _foo_arm
# CHECK-NOT: addend:
# CHECK: - kind: delta32
# CHECK: offset: 24
# CHECK: target: _foo_arm
# CHECK: addend: 4
# CHECK: - kind: delta32
# CHECK: offset: 28
# CHECK: target: _foo_thumb
# CHECK-NOT: addend:
# CHECK: - kind: delta32
# CHECK: offset: 32
# CHECK: target: _foo_thumb
# CHECK: addend: 4
# CHECK: - name: _foo_thumb
# CHECK: references:
# CHECK: - kind: thumb_b22
# CHECK: offset: 0
# CHECK: target: _x
# CHECK-NOT: addend:
# CHECK: - kind: thumb_b22
# CHECK: offset: 4
# CHECK: target: _x
# CHECK: addend: 4
# CHECK: - kind: thumb_b22
# CHECK: offset: 8
# CHECK: target: _undef
# CHECK-NOT: addend:
# CHECK: - kind: thumb_b22
# CHECK: offset: 12
# CHECK: target: _undef
# CHECK: addend: 4
# CHECK: - kind: thumb_movw_funcRel
# CHECK: offset: 16
# CHECK: target: _x
# CHECK: addend: -42
# CHECK: - kind: thumb_movt_funcRel
# CHECK: offset: 20
# CHECK: target: _x
# CHECK: addend: -42
# CHECK: - kind: thumb_movw_funcRel
# CHECK: offset: 24
# CHECK: target: _x
# CHECK: addend: -34
# CHECK: - kind: thumb_movt_funcRel
# CHECK: offset: 28
# CHECK: target: _x
# CHECK: addend: -34
# CHECK: - kind: thumb_movw_funcRel
# CHECK: offset: 32
# CHECK: target: _t1
# CHECK: addend: -42
# CHECK: - kind: thumb_movt_funcRel
# CHECK: offset: 36
# CHECK: target: _t1
# CHECK: addend: -42
# CHECK: - kind: thumb_movw
# CHECK: offset: 42
# CHECK: target: _x
# CHECK-NOT: addend:
# CHECK: - kind: thumb_movt
# CHECK: offset: 46
# CHECK: target: _x
# CHECK-NOT: addend:
# CHECK: - kind: thumb_movw
# CHECK: offset: 50
# CHECK: target: _x
# CHECK: addend: 8
# CHECK: - kind: thumb_movt
# CHECK: offset: 54
# CHECK: target: _x
# CHECK: addend: 8
# CHECK: - kind: thumb_movw
# CHECK: offset: 58
# CHECK: target: _t1
# CHECK-NOT: addend:
# CHECK: - kind: thumb_movt
# CHECK: offset: 62
# CHECK: target: _t1
# CHECK-NOT: addend:
# CHECK: - kind: thumb_movw
# CHECK: offset: 66
# CHECK: target: _undef
# CHECK-NOT: addend:
# CHECK: - kind: thumb_movt
# CHECK: offset: 70
# CHECK: target: _undef
# CHECK-NOT: addend:
# CHECK: - kind: thumb_movw
# CHECK: offset: 74
# CHECK: target: _undef
# CHECK: addend: 8
# CHECK: - kind: thumb_movt
# CHECK: offset: 78
# CHECK: target: _undef
# CHECK: addend: 8
# CHECK: - name: _t1
# CHECK: content: [ C0, 46 ]
# CHECK: - name: _foo_arm
# CHECK: references:
# CHECK: - kind: arm_b24
# CHECK: offset: 0
# CHECK: target: _x
# CHECK-NOT: addend:
# CHECK: - kind: arm_b24
# CHECK: offset: 4
# CHECK: target: _x
# CHECK: addend: 4
# CHECK: - kind: arm_b24
# CHECK: offset: 8
# CHECK: target: _undef
# CHECK-NOT: addend:
# CHECK: - kind: arm_b24
# CHECK: offset: 12
# CHECK: target: _undef
# CHECK: addend: 4
# CHECK: - kind: arm_movw_funcRel
# CHECK: offset: 16
# CHECK: target: _x
# CHECK: addend: -36
# CHECK: - kind: arm_movt_funcRel
# CHECK: offset: 20
# CHECK: target: _x
# CHECK: addend: -36
# CHECK: - kind: arm_movw_funcRel
# CHECK: offset: 24
# CHECK: target: _x
# CHECK: addend: -28
# CHECK: - kind: arm_movt_funcRel
# CHECK: offset: 28
# CHECK: target: _x
# CHECK: addend: -28
# CHECK: - kind: arm_movw
# CHECK: offset: 36
# CHECK: target: _x
# CHECK-NOT: addend:
# CHECK: - kind: arm_movt
# CHECK: offset: 40
# CHECK: target: _x
# CHECK-NOT: addend:
# CHECK: - kind: arm_movw
# CHECK: offset: 44
# CHECK: target: _x
# CHECK: addend: 8
# CHECK: - kind: arm_movt
# CHECK: offset: 48
# CHECK: target: _x
# CHECK: addend: 8
# CHECK: - kind: arm_movw
# CHECK: offset: 52
# CHECK: target: _undef
# CHECK-NOT: addend:
# CHECK: - kind: arm_movt
# CHECK: offset: 56
# CHECK: target: _undef
# CHECK-NOT: addend:
# CHECK: - kind: arm_movw
# CHECK: offset: 60
# CHECK: target: _undef
# CHECK: addend: 8
# CHECK: - kind: arm_movt
# CHECK: offset: 64
# CHECK: target: _undef
# CHECK: addend: 8
# CHECK: undefined-atoms:
# CHECK: - name: _undef
# .align 2
# .code 16
# .thumb_func _foo_thumb
#_foo_thumb:
# bl _x
# bl _x+4
# bl _undef
# bl _undef+4
# movw r1, :lower16:(_x-L1)
# movt r1, :upper16:(_x-L1)
# movw r2, :lower16:(_x+8-L1)
# movt r2, :upper16:(_x+8-L1)
# movw r1, :lower16:(_t1-L1)
# movt r1, :upper16:(_t1-L1)
# add r1, pc
#L1:
# movw r3, :lower16:_x
# movt r3, :upper16:_x
# movw r4, :lower16:_x+8
# movt r4, :upper16:_x+8
# movw r3, :lower16:_t1
# movt r3, :upper16:_t1
# movw r5, :lower16:_undef
# movt r5, :upper16:_undef
# movw r6, :lower16:_undef+8
# movt r6, :upper16:_undef+8
#
# .thumb_func _t1
#_t1:
# nop
#
#
# .code 32
# .align 2
#_foo_arm:
# bl _x
# bl _x+4
# bl _undef
# bl _undef+4
# movw r1, :lower16:(_x-L2)
# movt r1, :upper16:(_x-L2)
# movw r2, :lower16:(_x+8-L2)
# movt r2, :upper16:(_x+8-L2)
# add r1, pc
#L2:
# movw r3, :lower16:_x
# movt r3, :upper16:_x
# movw r4, :lower16:_x+8
# movt r4, :upper16:_x+8
# movw r5, :lower16:_undef
# movt r5, :upper16:_undef
# movw r6, :lower16:_undef+8
# movt r6, :upper16:_undef+8
#
#
# .data
#_x: .long 0
# .long _foo_thumb
# .long _foo_thumb+4
# .long _undef
# .long _undef+4
# .long _foo_arm - .
# .long _foo_arm+4- .
# .long _foo_thumb - .
# .long _foo_thumb+4 - .
#