diff options
Diffstat (limited to 'lld/lib/ReaderWriter/ELF/ARM')
| -rw-r--r-- | lld/lib/ReaderWriter/ELF/ARM/ARMRelocationHandler.cpp | 82 |
1 files changed, 81 insertions, 1 deletions
diff --git a/lld/lib/ReaderWriter/ELF/ARM/ARMRelocationHandler.cpp b/lld/lib/ReaderWriter/ELF/ARM/ARMRelocationHandler.cpp index 938210f8f49..c99015275b6 100644 --- a/lld/lib/ReaderWriter/ELF/ARM/ARMRelocationHandler.cpp +++ b/lld/lib/ReaderWriter/ELF/ARM/ARMRelocationHandler.cpp @@ -70,6 +70,13 @@ static Reference::Addend readAddend_ARM_CALL(const uint8_t *location) { return llvm::SignExtend64<26>(result); } +static Reference::Addend readAddend_THM_JUMP11(const uint8_t *location) { + const auto value = read16le(location); + const uint16_t imm11 = value & 0x7FF; + + return llvm::SignExtend32<12>(imm11 << 1); +} + static Reference::Addend readAddend(const uint8_t *location, Reference::KindValue kindValue) { switch (kindValue) { @@ -78,6 +85,8 @@ static Reference::Addend readAddend(const uint8_t *location, case R_ARM_THM_CALL: case R_ARM_THM_JUMP24: return readAddend_THM_CALL(location); + case R_ARM_THM_JUMP11: + return readAddend_THM_JUMP11(location); case R_ARM_CALL: case R_ARM_JUMP24: return readAddend_ARM_CALL(location); @@ -107,6 +116,12 @@ static inline void applyThmReloc(uint8_t *location, uint16_t resHi, write16le(location, (read16le(location) & ~maskLo) | (resLo & maskLo)); } +static inline void applyThumb16Reloc(uint8_t *location, uint16_t result, + uint16_t mask = 0xFFFF) { + assert(!(result & ~mask)); + write16le(location, (read16le(location) & ~mask) | (result & mask)); +} + /// \brief R_ARM_ABS32 - (S + A) | T static void relocR_ARM_ABS32(uint8_t *location, uint64_t P, uint64_t S, int64_t A, bool addressesThumb) { @@ -123,6 +138,42 @@ static void relocR_ARM_ABS32(uint8_t *location, uint64_t P, uint64_t S, applyArmReloc(location, result); } +/// \brief R_ARM_REL32 - ((S + A) | T) - P +static void relocR_ARM_REL32(uint8_t *location, uint64_t P, uint64_t S, + int64_t A, bool addressesThumb) { + uint64_t T = addressesThumb; + uint32_t result = (uint32_t)(((S + A) | T) - P); + + DEBUG_WITH_TYPE( + "ARM", llvm::dbgs() << "\t\tHandle " << LLVM_FUNCTION_NAME << " -"; + llvm::dbgs() << " S: 0x" << Twine::utohexstr(S); + llvm::dbgs() << " A: 0x" << Twine::utohexstr(A); + llvm::dbgs() << " P: 0x" << Twine::utohexstr(P); + llvm::dbgs() << " T: 0x" << Twine::utohexstr(T); + llvm::dbgs() << " result: 0x" << Twine::utohexstr(result) << "\n"); + applyArmReloc(location, result); +} + +/// \brief R_ARM_PREL31 - ((S + A) | T) - P +static void relocR_ARM_PREL31(uint8_t *location, uint64_t P, uint64_t S, + int64_t A, bool addressesThumb) { + uint64_t T = addressesThumb; + uint32_t result = (uint32_t)(((S + A) | T) - P); + const uint32_t mask = 0x7FFFFFFF; + uint32_t rel31 = result & mask; + + DEBUG_WITH_TYPE( + "ARM", llvm::dbgs() << "\t\tHandle " << LLVM_FUNCTION_NAME << " -"; + llvm::dbgs() << " S: 0x" << Twine::utohexstr(S); + llvm::dbgs() << " A: 0x" << Twine::utohexstr(A); + llvm::dbgs() << " P: 0x" << Twine::utohexstr(P); + llvm::dbgs() << " T: 0x" << Twine::utohexstr(T); + llvm::dbgs() << " result: 0x" << Twine::utohexstr(result); + llvm::dbgs() << " rel31: 0x" << Twine::utohexstr(rel31) << "\n"); + + applyArmReloc(location, rel31, mask); +} + /// \brief Relocate B/BL instructions. useJs defines whether J1 & J2 are used static void relocR_ARM_THM_B_L(uint8_t *location, uint32_t result, bool useJs) { result = (result & 0x01FFFFFE) >> 1; @@ -183,6 +234,24 @@ static void relocR_ARM_THM_JUMP24(uint8_t *location, uint64_t P, uint64_t S, relocR_ARM_THM_B_L(location, result, true); } +/// \brief R_ARM_THM_JUMP11 - S + A - P +static void relocR_ARM_THM_JUMP11(uint8_t *location, uint64_t P, uint64_t S, + int64_t A) { + uint32_t result = (uint32_t)(S + A - P); + + DEBUG_WITH_TYPE( + "ARM", llvm::dbgs() << "\t\tHandle " << LLVM_FUNCTION_NAME << " -"; + llvm::dbgs() << " S: 0x" << Twine::utohexstr(S); + llvm::dbgs() << " A: 0x" << Twine::utohexstr(A); + llvm::dbgs() << " P: 0x" << Twine::utohexstr(P); + llvm::dbgs() << " result: 0x" << Twine::utohexstr(result) << "\n"); + + //we cut off first bit because it is always 1 according to p. 4.5.3 + result = (result & 0x0FFE) >> 1; + + applyThumb16Reloc(location, result, 0x7FF); +} + /// \brief R_ARM_CALL - ((S + A) | T) - P static void relocR_ARM_CALL(uint8_t *location, uint64_t P, uint64_t S, int64_t A, bool addressesThumb) { @@ -274,7 +343,7 @@ static void relocR_ARM_THM_MOV(uint8_t *location, uint32_t result) { const uint16_t bitI = (result >> 11) & 0x1; const uint16_t resHi = (bitI << 10) | imm4; - applyThmReloc(location, resHi, resLo, 0x40F, 0x70FF); + applyThmReloc(location, resHi, resLo, 0x40F, 0x70FF); } /// \brief R_ARM_THM_MOVW_ABS_NC - (S + A) | T @@ -340,6 +409,10 @@ std::error_code ARMTargetRelocationHandler::applyRelocation( relocR_ARM_ABS32(location, relocVAddress, targetVAddress, addend, addressesThumb); break; + case R_ARM_REL32: + relocR_ARM_REL32(location, relocVAddress, targetVAddress, addend, + addressesThumb); + break; case R_ARM_THM_CALL: // TODO: consider adding bool variable to disable J1 & J2 for archs // before ARMv6 @@ -358,6 +431,9 @@ std::error_code ARMTargetRelocationHandler::applyRelocation( relocR_ARM_THM_JUMP24(location, relocVAddress, targetVAddress, addend, addressesThumb); break; + case R_ARM_THM_JUMP11: + relocR_ARM_THM_JUMP11(location, relocVAddress, targetVAddress, addend); + break; case R_ARM_MOVW_ABS_NC: relocR_ARM_MOVW_ABS_NC(location, relocVAddress, targetVAddress, addend, addressesThumb); @@ -372,6 +448,10 @@ std::error_code ARMTargetRelocationHandler::applyRelocation( case R_ARM_THM_MOVT_ABS: relocR_ARM_THM_MOVT_ABS(location, relocVAddress, targetVAddress, addend); break; + case R_ARM_PREL31: + relocR_ARM_PREL31(location, relocVAddress, targetVAddress, addend, + addressesThumb); + break; default: return make_unhandled_reloc_error(); } |

