forked from OSchip/llvm-project
[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. llvm-svn: 213700
This commit is contained in:
parent
97d7c29fbc
commit
b78ad899e5
|
@ -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);
|
||||
|
|
|
@ -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::setDisplacementInArmBranch(uint32_t instruction,
|
|||
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::getWordFromThumbMov(uint32_t instruction) {
|
|||
}
|
||||
|
||||
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(const normalized::Relocation &reloc1,
|
|||
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(const normalized::Relocation &reloc1,
|
|||
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(const normalized::Relocation &reloc1,
|
|||
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(const Reference &ref, uint8_t *location,
|
|||
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::generateAtomContent(const DefinedAtom &atom,
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
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() {
|
||||
|
|
|
@ -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.
|
||||
#
|
||||
|
|
Loading…
Reference in New Issue