[lld] r213700 - [mach-o] add support for round tripping all arm/thumb relocations
Nick Kledzik
kledzik at apple.com
Tue Jul 22 16:07:49 PDT 2014
Author: kledzik
Date: Tue Jul 22 18:07:49 2014
New Revision: 213700
URL: http://llvm.org/viewvc/llvm-project?rev=213700&view=rev
Log:
[mach-o] add support for round tripping all arm/thumb relocations
Update the parse-arm-relocs.yaml test case to run the linker back to back
to ensure all relocations round trip in and out of mach-o.
Modified:
lld/trunk/lib/ReaderWriter/MachO/ArchHandler.h
lld/trunk/lib/ReaderWriter/MachO/ArchHandler_arm.cpp
lld/trunk/test/mach-o/parse-arm-relocs.yaml
Modified: lld/trunk/lib/ReaderWriter/MachO/ArchHandler.h
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/lib/ReaderWriter/MachO/ArchHandler.h?rev=213700&r1=213699&r2=213700&view=diff
==============================================================================
--- lld/trunk/lib/ReaderWriter/MachO/ArchHandler.h (original)
+++ lld/trunk/lib/ReaderWriter/MachO/ArchHandler.h Tue Jul 22 18:07:49 2014
@@ -185,7 +185,11 @@ protected:
rLength1 = 0x0000,
rLength2 = 0x0100,
rLength4 = 0x0200,
- rLength8 = 0x0300
+ rLength8 = 0x0300,
+ rLenArmLo = rLength1,
+ rLenArmHi = rLength2,
+ rLenThmbLo = rLength4,
+ rLenThmbHi = rLength8
};
/// Extract RelocPattern from normalized mach-o relocation.
static RelocPattern relocPattern(const normalized::Relocation &reloc);
Modified: lld/trunk/lib/ReaderWriter/MachO/ArchHandler_arm.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/lib/ReaderWriter/MachO/ArchHandler_arm.cpp?rev=213700&r1=213699&r2=213700&view=diff
==============================================================================
--- lld/trunk/lib/ReaderWriter/MachO/ArchHandler_arm.cpp (original)
+++ lld/trunk/lib/ReaderWriter/MachO/ArchHandler_arm.cpp Tue Jul 22 18:07:49 2014
@@ -96,13 +96,23 @@ private:
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);
- uint32_t setDisplacementInArmBranch(uint32_t instruction, int32_t disp);
+ // Utility functions for inspecting/updating instructions.
+ static bool isThumbMovw(uint32_t instruction);
+ static bool isThumbMovt(uint32_t instruction);
+ static bool isArmMovw(uint32_t instruction);
+ static bool isArmMovt(uint32_t instruction);
+ static int32_t getDisplacementFromThumbBranch(uint32_t instruction);
+ static int32_t getDisplacementFromArmBranch(uint32_t instruction);
+ static uint16_t getWordFromThumbMov(uint32_t instruction);
+ static uint16_t getWordFromArmMov(uint32_t instruction);
+ static uint32_t clearThumbBit(uint32_t value, const Atom *target);
+ static uint32_t setDisplacementInArmBranch(uint32_t instr, int32_t disp);
+ static uint32_t setDisplacementInThumbBranch(uint32_t instr, int32_t disp);
+ static uint32_t setWordFromThumbMov(uint32_t instruction, uint16_t word);
+ static uint32_t setWordFromArmMov(uint32_t instruction, uint16_t word);
+ bool useExternalRelocationTo(const Atom &target);
+
void applyFixupFinal(const Reference &ref, uint8_t *location,
uint64_t fixupAddress, uint64_t targetAddress,
uint64_t inAtomAddress);
@@ -250,7 +260,42 @@ uint32_t ArchHandler_arm::setDisplacemen
return newInstruction;
}
+uint32_t ArchHandler_arm::setDisplacementInThumbBranch(uint32_t instruction,
+ int32_t displacement) {
+ // FIXME: handle BLX and out-of-range.
+ uint32_t newInstruction = (instruction & 0xF800D000);
+ uint32_t s = (uint32_t)(displacement >> 24) & 0x1;
+ uint32_t i1 = (uint32_t)(displacement >> 23) & 0x1;
+ uint32_t i2 = (uint32_t)(displacement >> 22) & 0x1;
+ uint32_t imm10 = (uint32_t)(displacement >> 12) & 0x3FF;
+ uint32_t imm11 = (uint32_t)(displacement >> 1) & 0x7FF;
+ uint32_t j1 = (i1 == s);
+ uint32_t j2 = (i2 == s);
+ uint32_t nextDisp = (j1 << 13) | (j2 << 11) | imm11;
+ uint32_t firstDisp = (s << 10) | imm10;
+ newInstruction |= (nextDisp << 16) | firstDisp;
+ return newInstruction;
+}
+
+bool ArchHandler_arm::isThumbMovw(uint32_t instruction) {
+ return (instruction & 0x8000FBF0) == 0x0000F240;
+}
+
+bool ArchHandler_arm::isThumbMovt(uint32_t instruction) {
+ return (instruction & 0x8000FBF0) == 0x0000F2C0;
+}
+
+bool ArchHandler_arm::isArmMovw(uint32_t instruction) {
+ return (instruction & 0x0FF00000) == 0x03000000;
+}
+
+bool ArchHandler_arm::isArmMovt(uint32_t instruction) {
+ return (instruction & 0x0FF00000) == 0x03400000;
+}
+
+
uint16_t ArchHandler_arm::getWordFromThumbMov(uint32_t instruction) {
+ assert(isThumbMovw(instruction) || isThumbMovt(instruction));
uint32_t i = ((instruction & 0x00000400) >> 10);
uint32_t imm4 = (instruction & 0x0000000F);
uint32_t imm3 = ((instruction & 0x70000000) >> 28);
@@ -259,11 +304,30 @@ uint16_t ArchHandler_arm::getWordFromThu
}
uint16_t ArchHandler_arm::getWordFromArmMov(uint32_t instruction) {
+ assert(isArmMovw(instruction) || isArmMovt(instruction));
uint32_t imm4 = ((instruction & 0x000F0000) >> 16);
uint32_t imm12 = (instruction & 0x00000FFF);
return (imm4 << 12) | imm12;
}
+
+uint32_t ArchHandler_arm::setWordFromThumbMov(uint32_t instr, uint16_t word) {
+ assert(isThumbMovw(instr) || isThumbMovt(instr));
+ uint32_t imm4 = (word & 0xF000) >> 12;
+ uint32_t i = (word & 0x0800) >> 11;
+ uint32_t imm3 = (word & 0x0700) >> 8;
+ uint32_t imm8 = word & 0x00FF;
+ return (instr & 0x8F00FBF0) | imm4 | (i << 10) | (imm3 << 28) | (imm8 << 16);
+}
+
+uint32_t ArchHandler_arm::setWordFromArmMov(uint32_t instr, uint16_t word) {
+ assert(isArmMovw(instr) || isArmMovt(instr));
+ uint32_t imm4 = (word & 0xF000) >> 12;
+ uint32_t imm12 = word & 0x0FFF;
+ return (instr & 0xFFF0F000) | (imm4 << 16) | imm12;
+}
+
+
uint32_t ArchHandler_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.
@@ -385,128 +449,128 @@ ArchHandler_arm::getPairReferenceInfo(co
bool top;
bool thumbReloc;
switch(relocPattern(reloc1) << 16 | relocPattern(reloc2)) {
- case ((ARM_RELOC_HALF_SECTDIFF | rScattered | rLength4) << 16 |
- ARM_RELOC_PAIR | rScattered | rLength4):
+ case ((ARM_RELOC_HALF_SECTDIFF | rScattered | rLenThmbLo) << 16 |
+ ARM_RELOC_PAIR | rScattered | rLenThmbLo):
// 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):
+ case ((ARM_RELOC_HALF_SECTDIFF | rScattered | rLenThmbHi) << 16 |
+ ARM_RELOC_PAIR | rScattered | rLenThmbHi):
// 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):
+ case ((ARM_RELOC_HALF_SECTDIFF | rScattered | rLenArmLo) << 16 |
+ ARM_RELOC_PAIR | rScattered | rLenArmLo):
// 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):
+ case ((ARM_RELOC_HALF_SECTDIFF | rScattered | rLenArmHi) << 16 |
+ ARM_RELOC_PAIR | rScattered | rLenArmHi):
// 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):
+ case ((ARM_RELOC_HALF | rLenThmbLo) << 16 |
+ ARM_RELOC_PAIR | rLenThmbLo):
// 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):
+ case ((ARM_RELOC_HALF | rLenThmbHi) << 16 |
+ ARM_RELOC_PAIR | rLenThmbHi):
// 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):
+ case ((ARM_RELOC_HALF | rLenArmLo) << 16 |
+ ARM_RELOC_PAIR | rLenArmLo):
// 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):
+ case ((ARM_RELOC_HALF | rLenArmHi) << 16 |
+ ARM_RELOC_PAIR | rLenArmHi):
// 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):
+ case ((ARM_RELOC_HALF | rScattered | rLenThmbLo) << 16 |
+ ARM_RELOC_PAIR | rLenThmbLo):
// 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):
+ case ((ARM_RELOC_HALF | rScattered | rLenThmbHi) << 16 |
+ ARM_RELOC_PAIR | rLenThmbHi):
// 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):
+ case ((ARM_RELOC_HALF | rScattered | rLenArmLo) << 16 |
+ ARM_RELOC_PAIR | rLenArmLo):
// 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):
+ case ((ARM_RELOC_HALF | rScattered | rLenArmHi) << 16 |
+ ARM_RELOC_PAIR | rLenArmHi):
// 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):
+ case ((ARM_RELOC_HALF | rExtern | rLenThmbLo) << 16 |
+ ARM_RELOC_PAIR | rLenThmbLo):
// 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):
+ case ((ARM_RELOC_HALF | rExtern | rLenThmbHi) << 16 |
+ ARM_RELOC_PAIR | rLenThmbHi):
// 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):
+ case ((ARM_RELOC_HALF | rExtern | rLenArmLo) << 16 |
+ ARM_RELOC_PAIR | rLenArmLo):
// 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):
+ case ((ARM_RELOC_HALF | rExtern | rLenArmHi) << 16 |
+ ARM_RELOC_PAIR | rLenArmHi):
// ex: movt r1, :upper16:_undef [arm mode]
*kind = arm_movt;
funcRel = false;
@@ -563,10 +627,28 @@ ArchHandler_arm::getPairReferenceInfo(co
Twine("ARM_RELOC_HALF_SECTDIFF relocation "
"where subtrahend label is not in atom"));
other16 = (reloc2.offset & 0xFFFF);
- if (thumbReloc)
+ if (thumbReloc) {
+ if (top) {
+ if (!isThumbMovt(instruction))
+ return make_dynamic_error_code(Twine("expected movt instruction"));
+ }
+ else {
+ if (!isThumbMovw(instruction))
+ return make_dynamic_error_code(Twine("expected movw instruction"));
+ }
instruction16 = getWordFromThumbMov(instruction);
- else
+ }
+ else {
+ if (top) {
+ if (!isArmMovt(instruction))
+ return make_dynamic_error_code(Twine("expected movt instruction"));
+ }
+ else {
+ if (!isArmMovw(instruction))
+ return make_dynamic_error_code(Twine("expected movw instruction"));
+ }
instruction16 = getWordFromArmMov(instruction);
+ }
if (top)
value = (instruction16 << 16) | other16;
else
@@ -577,10 +659,28 @@ ArchHandler_arm::getPairReferenceInfo(co
return std::error_code();
} else {
uint32_t sectIndex;
- if (thumbReloc)
+ if (thumbReloc) {
+ if (top) {
+ if (!isThumbMovt(instruction))
+ return make_dynamic_error_code(Twine("expected movt instruction"));
+ }
+ else {
+ if (!isThumbMovw(instruction))
+ return make_dynamic_error_code(Twine("expected movw instruction"));
+ }
instruction16 = getWordFromThumbMov(instruction);
- else
+ }
+ else {
+ if (top) {
+ if (!isArmMovt(instruction))
+ return make_dynamic_error_code(Twine("expected movt instruction"));
+ }
+ else {
+ if (!isArmMovw(instruction))
+ return make_dynamic_error_code(Twine("expected movw instruction"));
+ }
instruction16 = getWordFromArmMov(instruction);
+ }
other16 = (reloc2.offset & 0xFFFF);
if (top)
value = (instruction16 << 16) | other16;
@@ -618,37 +718,47 @@ void ArchHandler_arm::applyFixupFinal(co
assert(ref.kindArch() == Reference::KindArch::ARM);
int32_t *loc32 = reinterpret_cast<int32_t *>(location);
int32_t displacement;
+ uint16_t value16;
switch (ref.kindValue()) {
case thumb_b22:
- // FIXME
+ displacement = (targetAddress - (fixupAddress + 4)) + ref.addend();
+ write32(*loc32, _swap, setDisplacementInThumbBranch(*loc32, displacement));
break;
case thumb_movw:
- // FIXME
+ value16 = (targetAddress + ref.addend()) & 0xFFFF;
+ write32(*loc32, _swap, setWordFromThumbMov(*loc32, value16));
break;
case thumb_movt:
- // FIXME
+ value16 = (targetAddress + ref.addend()) >> 16;
+ write32(*loc32, _swap, setWordFromThumbMov(*loc32, value16));
break;
case thumb_movw_funcRel:
- // FIXME
+ value16 = (targetAddress - inAtomAddress + ref.addend()) & 0xFFFF;
+ write32(*loc32, _swap, setWordFromThumbMov(*loc32, value16));
break;
case thumb_movt_funcRel:
- // FIXME
+ value16 = (targetAddress - inAtomAddress + ref.addend()) >> 16;
+ write32(*loc32, _swap, setWordFromThumbMov(*loc32, value16));
break;
case arm_b24:
displacement = (targetAddress - (fixupAddress + 8)) + ref.addend();
*loc32 = setDisplacementInArmBranch(*loc32, displacement);
break;
case arm_movw:
- // FIXME
+ value16 = (targetAddress + ref.addend()) & 0xFFFF;
+ write32(*loc32, _swap, setWordFromArmMov(*loc32, value16));
break;
case arm_movt:
- // FIXME
+ value16 = (targetAddress + ref.addend()) >> 16;
+ write32(*loc32, _swap, setWordFromArmMov(*loc32, value16));
break;
case arm_movw_funcRel:
- // FIXME
+ value16 = (targetAddress - inAtomAddress + ref.addend()) & 0xFFFF;
+ write32(*loc32, _swap, setWordFromArmMov(*loc32, value16));
break;
case arm_movt_funcRel:
- // FIXME
+ value16 = (targetAddress - inAtomAddress + ref.addend()) >> 16;
+ write32(*loc32, _swap, setWordFromArmMov(*loc32, value16));
break;
case pointer32:
write32(*loc32, _swap, targetAddress + ref.addend());
@@ -693,22 +803,316 @@ void ArchHandler_arm::generateAtomConten
}
}
+
+bool ArchHandler_arm::useExternalRelocationTo(const Atom &target) {
+ // Undefined symbols are referenced via external relocations.
+ if (isa<UndefinedAtom>(&target))
+ return true;
+ if (const DefinedAtom *defAtom = dyn_cast<DefinedAtom>(&target)) {
+ switch (defAtom->merge()) {
+ case DefinedAtom::mergeAsTentative:
+ // Tentative definitions are referenced via external relocations.
+ return true;
+ case DefinedAtom::mergeAsWeak:
+ case DefinedAtom::mergeAsWeakAndAddressUsed:
+ // Global weak-defs are referenced via external relocations.
+ return (defAtom->scope() == DefinedAtom::scopeGlobal);
+ default:
+ break;
+ }
+ }
+ // Everything else is reference via an internal relocation.
+ return false;
+}
+
void ArchHandler_arm::applyFixupRelocatable(const Reference &ref,
uint8_t *location,
uint64_t fixupAddress,
uint64_t targetAddress,
uint64_t inAtomAddress) {
- // FIXME: to do
+ bool useExternalReloc = useExternalRelocationTo(*ref.target());
+ int32_t *loc32 = reinterpret_cast<int32_t *>(location);
+ int32_t displacement;
+ uint16_t value16;
+ switch (ref.kindValue()) {
+ case thumb_b22:
+ if (useExternalReloc)
+ displacement = (ref.addend() - (fixupAddress + 4));
+ else
+ displacement = (targetAddress - (fixupAddress + 4)) + ref.addend();
+ write32(*loc32, _swap, setDisplacementInThumbBranch(*loc32, displacement));
+ break;
+ case thumb_movw:
+ if (useExternalReloc)
+ value16 = ref.addend() & 0xFFFF;
+ else
+ value16 = (targetAddress + ref.addend()) & 0xFFFF;
+ write32(*loc32, _swap, setWordFromThumbMov(*loc32, value16));
+ break;
+ case thumb_movt:
+ if (useExternalReloc)
+ value16 = ref.addend() >> 16;
+ else
+ value16 = (targetAddress + ref.addend()) >> 16;
+ write32(*loc32, _swap, setWordFromThumbMov(*loc32, value16));
+ break;
+ case thumb_movw_funcRel:
+ value16 = (targetAddress - inAtomAddress + ref.addend()) & 0xFFFF;
+ write32(*loc32, _swap, setWordFromThumbMov(*loc32, value16));
+ break;
+ case thumb_movt_funcRel:
+ value16 = (targetAddress - inAtomAddress + ref.addend()) >> 16;
+ write32(*loc32, _swap, setWordFromThumbMov(*loc32, value16));
+ break;
+ case arm_b24:
+ if (useExternalReloc)
+ displacement = (ref.addend() - (fixupAddress + 8));
+ else
+ displacement = (targetAddress - (fixupAddress + 8)) + ref.addend();
+ write32(*loc32, _swap, setDisplacementInArmBranch(*loc32, displacement));
+ break;
+ case arm_movw:
+ if (useExternalReloc)
+ value16 = ref.addend() & 0xFFFF;
+ else
+ value16 = (targetAddress + ref.addend()) & 0xFFFF;
+ write32(*loc32, _swap, setWordFromArmMov(*loc32, value16));
+ break;
+ case arm_movt:
+ if (useExternalReloc)
+ value16 = ref.addend() >> 16;
+ else
+ value16 = (targetAddress + ref.addend()) >> 16;
+ write32(*loc32, _swap, setWordFromArmMov(*loc32, value16));
+ break;
+ case arm_movw_funcRel:
+ value16 = (targetAddress - inAtomAddress + ref.addend()) & 0xFFFF;
+ write32(*loc32, _swap, setWordFromArmMov(*loc32, value16));
+ break;
+ case arm_movt_funcRel:
+ value16 = (targetAddress - inAtomAddress + ref.addend()) >> 16;
+ write32(*loc32, _swap, setWordFromArmMov(*loc32, value16));
+ break;
+ case pointer32:
+ write32(*loc32, _swap, targetAddress + ref.addend());
+ break;
+ case delta32:
+ write32(*loc32, _swap, targetAddress - fixupAddress + ref.addend());
+ break;
+ case lazyPointer:
+ case lazyImmediateLocation:
+ // do nothing
+ break;
+ default:
+ llvm_unreachable("invalid ARM Reference Kind");
+ break;
+ }
}
-void ArchHandler_arm::appendSectionRelocations(const DefinedAtom &atom,
- uint64_t atomSectionOffset,
- const Reference &ref,
- FindSymbolIndexForAtom,
- FindSectionIndexForAtom,
- FindAddressForAtom,
- normalized::Relocations &) {
- // FIXME: to do
+void ArchHandler_arm::appendSectionRelocations(
+ const DefinedAtom &atom,
+ uint64_t atomSectionOffset,
+ const Reference &ref,
+ FindSymbolIndexForAtom symbolIndexForAtom,
+ FindSectionIndexForAtom sectionIndexForAtom,
+ FindAddressForAtom addressForAtom,
+ normalized::Relocations &relocs) {
+ if (ref.kindNamespace() != Reference::KindNamespace::mach_o)
+ return;
+ assert(ref.kindArch() == Reference::KindArch::ARM);
+ uint32_t sectionOffset = atomSectionOffset + ref.offsetInAtom();
+ bool useExternalReloc = useExternalRelocationTo(*ref.target());
+ uint32_t targetAtomAddress;
+ uint32_t fromAtomAddress;
+ uint16_t other16;
+ switch (ref.kindValue()) {
+ case thumb_b22:
+ if (useExternalReloc) {
+ appendReloc(relocs, sectionOffset, symbolIndexForAtom(*ref.target()), 0,
+ ARM_THUMB_RELOC_BR22 | rExtern | rPcRel | rLength4);
+ } else {
+ if (ref.addend() != 0)
+ appendReloc(relocs, sectionOffset, 0, addressForAtom(*ref.target()),
+ ARM_THUMB_RELOC_BR22 | rScattered | rPcRel | rLength4);
+ else
+ appendReloc(relocs, sectionOffset, sectionIndexForAtom(*ref.target()),0,
+ ARM_THUMB_RELOC_BR22 | rPcRel | rLength4);
+ }
+ break;
+ case thumb_movw:
+ if (useExternalReloc) {
+ other16 = ref.addend() >> 16;
+ appendReloc(relocs, sectionOffset, symbolIndexForAtom(*ref.target()), 0,
+ ARM_RELOC_HALF | rExtern | rLenThmbLo);
+ appendReloc(relocs, other16, 0, 0,
+ ARM_RELOC_PAIR | rLenThmbLo);
+ } else {
+ targetAtomAddress = addressForAtom(*ref.target());
+ if (ref.addend() != 0) {
+ other16 = (targetAtomAddress + ref.addend()) >> 16;
+ appendReloc(relocs, sectionOffset, 0, targetAtomAddress,
+ ARM_RELOC_HALF | rScattered | rLenThmbLo);
+ appendReloc(relocs, other16, 0, 0,
+ ARM_RELOC_PAIR | rLenThmbLo);
+ } else {
+ other16 = (targetAtomAddress + ref.addend()) >> 16;
+ appendReloc(relocs, sectionOffset, sectionIndexForAtom(*ref.target()),0,
+ ARM_RELOC_HALF | rLenThmbLo);
+ appendReloc(relocs, other16, 0, 0,
+ ARM_RELOC_PAIR | rLenThmbLo);
+ }
+ }
+ break;
+ case thumb_movt:
+ if (useExternalReloc) {
+ other16 = ref.addend() & 0xFFFF;
+ appendReloc(relocs, sectionOffset, symbolIndexForAtom(*ref.target()), 0,
+ ARM_RELOC_HALF | rExtern | rLenThmbHi);
+ appendReloc(relocs, other16, 0, 0,
+ ARM_RELOC_PAIR | rLenThmbHi);
+ } else {
+ targetAtomAddress = addressForAtom(*ref.target());
+ if (ref.addend() != 0) {
+ other16 = (targetAtomAddress + ref.addend()) & 0xFFFF;
+ appendReloc(relocs, sectionOffset, 0, targetAtomAddress,
+ ARM_RELOC_HALF | rScattered | rLenThmbHi);
+ appendReloc(relocs, other16, 0, 0,
+ ARM_RELOC_PAIR | rLenThmbHi);
+ } else {
+ other16 = (targetAtomAddress + ref.addend()) & 0xFFFF;
+ appendReloc(relocs, sectionOffset, sectionIndexForAtom(*ref.target()),0,
+ ARM_RELOC_HALF | rLenThmbHi);
+ appendReloc(relocs, other16, 0, 0,
+ ARM_RELOC_PAIR | rLenThmbHi);
+ }
+ }
+ break;
+ case thumb_movw_funcRel:
+ fromAtomAddress = addressForAtom(atom);
+ targetAtomAddress = addressForAtom(*ref.target());
+ other16 = (targetAtomAddress - fromAtomAddress + ref.addend()) >> 16;
+ appendReloc(relocs, sectionOffset, 0, targetAtomAddress,
+ ARM_RELOC_HALF_SECTDIFF | rScattered | rLenThmbLo);
+ appendReloc(relocs, other16, 0, fromAtomAddress,
+ ARM_RELOC_PAIR | rScattered | rLenThmbLo);
+ break;
+ case thumb_movt_funcRel:
+ fromAtomAddress = addressForAtom(atom);
+ targetAtomAddress = addressForAtom(*ref.target());
+ other16 = (targetAtomAddress - fromAtomAddress + ref.addend()) & 0xFFFF;
+ appendReloc(relocs, sectionOffset, 0, targetAtomAddress,
+ ARM_RELOC_HALF_SECTDIFF | rScattered | rLenThmbHi);
+ appendReloc(relocs, other16, 0, fromAtomAddress,
+ ARM_RELOC_PAIR | rScattered | rLenThmbHi);
+ break;
+ case arm_b24:
+ if (useExternalReloc) {
+ appendReloc(relocs, sectionOffset, symbolIndexForAtom(*ref.target()), 0,
+ ARM_RELOC_BR24 | rExtern | rPcRel | rLength4);
+ } else {
+ if (ref.addend() != 0)
+ appendReloc(relocs, sectionOffset, 0, addressForAtom(*ref.target()),
+ ARM_RELOC_BR24 | rScattered | rPcRel | rLength4);
+ else
+ appendReloc(relocs, sectionOffset, sectionIndexForAtom(*ref.target()),0,
+ ARM_RELOC_BR24 | rPcRel | rLength4);
+ }
+ break;
+ case arm_movw:
+ if (useExternalReloc) {
+ other16 = ref.addend() >> 16;
+ appendReloc(relocs, sectionOffset, symbolIndexForAtom(*ref.target()), 0,
+ ARM_RELOC_HALF | rExtern | rLenArmLo);
+ appendReloc(relocs, other16, 0, 0,
+ ARM_RELOC_PAIR | rLenArmLo);
+ } else {
+ targetAtomAddress = addressForAtom(*ref.target());
+ if (ref.addend() != 0) {
+ other16 = (targetAtomAddress + ref.addend()) >> 16;
+ appendReloc(relocs, sectionOffset, 0, targetAtomAddress,
+ ARM_RELOC_HALF | rScattered | rLenArmLo);
+ appendReloc(relocs, other16, 0, 0,
+ ARM_RELOC_PAIR | rLenArmLo);
+ } else {
+ other16 = (targetAtomAddress + ref.addend()) >> 16;
+ appendReloc(relocs, sectionOffset, sectionIndexForAtom(*ref.target()),0,
+ ARM_RELOC_HALF | rLenArmLo);
+ appendReloc(relocs, other16, 0, 0,
+ ARM_RELOC_PAIR | rLenArmLo);
+ }
+ }
+ break;
+ case arm_movt:
+ if (useExternalReloc) {
+ other16 = ref.addend() & 0xFFFF;
+ appendReloc(relocs, sectionOffset, symbolIndexForAtom(*ref.target()), 0,
+ ARM_RELOC_HALF | rExtern | rLenArmHi);
+ appendReloc(relocs, other16, 0, 0,
+ ARM_RELOC_PAIR | rLenArmHi);
+ } else {
+ targetAtomAddress = addressForAtom(*ref.target());
+ if (ref.addend() != 0) {
+ other16 = (targetAtomAddress + ref.addend()) & 0xFFFF;
+ appendReloc(relocs, sectionOffset, 0, targetAtomAddress,
+ ARM_RELOC_HALF | rScattered | rLenArmHi);
+ appendReloc(relocs, other16, 0, 0,
+ ARM_RELOC_PAIR | rLenArmHi);
+ } else {
+ other16 = (targetAtomAddress + ref.addend()) & 0xFFFF;
+ appendReloc(relocs, sectionOffset, sectionIndexForAtom(*ref.target()),0,
+ ARM_RELOC_HALF | rLenArmHi);
+ appendReloc(relocs, other16, 0, 0,
+ ARM_RELOC_PAIR | rLenArmHi);
+ }
+ }
+ break;
+ case arm_movw_funcRel:
+ fromAtomAddress = addressForAtom(atom);
+ targetAtomAddress = addressForAtom(*ref.target());
+ other16 = (targetAtomAddress - fromAtomAddress + ref.addend()) >> 16;
+ appendReloc(relocs, sectionOffset, 0, targetAtomAddress,
+ ARM_RELOC_HALF_SECTDIFF | rScattered | rLenArmLo);
+ appendReloc(relocs, other16, 0, fromAtomAddress,
+ ARM_RELOC_PAIR | rScattered | rLenArmLo);
+ break;
+ case arm_movt_funcRel:
+ fromAtomAddress = addressForAtom(atom);
+ targetAtomAddress = addressForAtom(*ref.target());
+ other16 = (targetAtomAddress - fromAtomAddress + ref.addend()) & 0xFFFF;
+ appendReloc(relocs, sectionOffset, 0, targetAtomAddress,
+ ARM_RELOC_HALF_SECTDIFF | rScattered | rLenArmHi);
+ appendReloc(relocs, other16, 0, fromAtomAddress,
+ ARM_RELOC_PAIR | rScattered | rLenArmHi);
+ break;
+ case pointer32:
+ if (useExternalReloc) {
+ appendReloc(relocs, sectionOffset, symbolIndexForAtom(*ref.target()), 0,
+ ARM_RELOC_VANILLA | rExtern | rLength4);
+ }
+ else {
+ if (ref.addend() != 0)
+ appendReloc(relocs, sectionOffset, 0, addressForAtom(*ref.target()),
+ ARM_RELOC_VANILLA | rScattered | rLength4);
+ else
+ appendReloc(relocs, sectionOffset, sectionIndexForAtom(*ref.target()),0,
+ ARM_RELOC_VANILLA | rLength4);
+ }
+ break;
+ case delta32:
+ appendReloc(relocs, sectionOffset, 0, addressForAtom(*ref.target()),
+ ARM_RELOC_SECTDIFF | rScattered | rLength4);
+ appendReloc(relocs, sectionOffset, 0, addressForAtom(atom) +
+ ref.offsetInAtom(),
+ ARM_RELOC_PAIR | rScattered | rLength4);
+ break;
+ case lazyPointer:
+ case lazyImmediateLocation:
+ // do nothing
+ break;
+ default:
+ llvm_unreachable("invalid ARM Reference Kind");
+ break;
+ }
}
std::unique_ptr<mach_o::ArchHandler> ArchHandler::create_arm() {
Modified: lld/trunk/test/mach-o/parse-arm-relocs.yaml
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/mach-o/parse-arm-relocs.yaml?rev=213700&r1=213699&r2=213700&view=diff
==============================================================================
--- lld/trunk/test/mach-o/parse-arm-relocs.yaml (original)
+++ lld/trunk/test/mach-o/parse-arm-relocs.yaml Tue Jul 22 18:07:49 2014
@@ -1,4 +1,5 @@
-# RUN: lld -flavor darwin -arch armv7 -r -print_atoms %s -o %t | FileCheck %s
+# RUN: lld -flavor darwin -arch armv7 -r -print_atoms %s -o %t | FileCheck %s \
+# RUN: && lld -flavor darwin -arch armv7 -r -print_atoms %t -o %t2 | FileCheck %s
#
# Test parsing of armv7 relocations.
#
More information about the llvm-commits
mailing list