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,
: 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(); }
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,
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 {
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,
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());
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);
}
} 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
std::string segSectName = section.segmentName.str()
+ "/" + section.sectionName.str();
file.addDefinedAtomInCustomSection(symbolName, symbolScope, atomType,
- merge, offset, size, segSectName, true,
- §ion);
+ merge, thumb,offset, size, segSectName,
+ true, §ion);
} else {
if ((atomType == lld::DefinedAtom::typeCode) &&
(symbolDescFlags & N_SYMBOL_RESOLVER)) {
atomType = lld::DefinedAtom::typeResolver;
}
file.addDefinedAtom(symbolName, symbolScope, atomType, merge,
- offset, size, copyRefs, §ion);
+ offset, size, thumb, copyRefs, §ion);
}
}
}
"not zero terminated.");
}
file.addDefinedAtom(StringRef(), scope, atomType, merge, offset, size,
- copyRefs, §ion);
+ false, copyRefs, §ion);
offset += size;
}
}
}
}
- // 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);
#include "ReferenceKinds.h"
#include "MachONormalizedFileBinaryUtils.h"
+#include "Atoms.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/ADT/StringSwitch.h"
}
-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
//===----------------------------------------------------------------------===//
uint32_t ta = fromAddress + value - toAddress;
*addend = ta - offsetInFrom;
} else {
- *addend= fromAddress + value - toAddress;
+ *addend = fromAddress + value - toAddress;
}
return std::error_code();
break;
}
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,
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 thumb_movt:
// FIXME
break;
- case ARM_RELOC_BR24:
+ case thumb_movw_funcRel:
// FIXME
break;
- case LLD_ARM_RELOC_THUMB_ABS_LO16:
+ case thumb_movt_funcRel:
// FIXME
break;
- case LLD_ARM_RELOC_THUMB_ABS_HI16:
+ case arm_b24:
// FIXME
break;
- case LLD_ARM_RELOC_THUMB_REL_LO16:
+ case arm_movw:
// FIXME
break;
- case LLD_ARM_RELOC_THUMB_REL_HI16:
+ case arm_movt:
// FIXME
break;
- case LLD_ARM_RELOC_ABS32:
+ case arm_movw_funcRel:
// FIXME
break;
- case LLD_ARM_RELOC_POINTER32:
+ case arm_movt_funcRel:
// FIXME
break;
- case LLD_ARM_RELOC_LAZY_TARGET:
- case LLD_ARM_RELOC_LAZY_IMMEDIATE:
+ 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;
}
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
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.
/// 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.
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.
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,
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
--- /dev/null
+# 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 - .
+#