Index: ELF/Relocations.cpp =================================================================== --- ELF/Relocations.cpp +++ ELF/Relocations.cpp @@ -1001,7 +1001,7 @@ std::pair ThunkCreator::getThunk(SymbolBody &Body, uint32_t Type) { auto res = ThunkedSymbols.insert({&Body, nullptr}); - if (res.second) + if (res.second || !res.first->second->compatibleWith(Type)) res.first->second = addThunk(Type, Body); return std::make_pair(res.first->second, res.second); } Index: ELF/Thunks.h =================================================================== --- ELF/Thunks.h +++ ELF/Thunks.h @@ -41,6 +41,10 @@ // a branch and fall through to the first Symbol in the Target. virtual InputSection *getTargetInputSection() const { return nullptr; } + // To reuse a Thunk the caller as identified by the RelocType must be + // compatible with it. + virtual bool compatibleWith(uint32_t RelocType) const { return true; } + // The alignment requirement for this Thunk, defaults to the size of the // typical code section alignment. const SymbolBody &Destination; Index: ELF/Thunks.cpp =================================================================== --- ELF/Thunks.cpp +++ ELF/Thunks.cpp @@ -57,6 +57,7 @@ uint32_t size() const override { return 12; } void writeTo(uint8_t *Buf, ThunkSection &IS) const override; void addSymbols(ThunkSection &IS) override; + bool compatibleWith(uint32_t RelocType) const override; }; template class ARMV7PILongThunk final : public Thunk { @@ -66,6 +67,7 @@ uint32_t size() const override { return 16; } void writeTo(uint8_t *Buf, ThunkSection &IS) const override; void addSymbols(ThunkSection &IS) override; + bool compatibleWith(uint32_t RelocType) const override; }; template class ThumbV7ABSLongThunk final : public Thunk { @@ -77,6 +79,7 @@ uint32_t size() const override { return 10; } void writeTo(uint8_t *Buf, ThunkSection &IS) const override; void addSymbols(ThunkSection &IS) override; + bool compatibleWith(uint32_t RelocType) const override; }; template class ThumbV7PILongThunk final : public Thunk { @@ -88,6 +91,7 @@ uint32_t size() const override { return 12; } void writeTo(uint8_t *Buf, ThunkSection &IS) const override; void addSymbols(ThunkSection &IS) override; + bool compatibleWith(uint32_t RelocType) const override; }; // MIPS LA25 thunk @@ -131,6 +135,12 @@ } template +bool ARMV7ABSLongThunk::compatibleWith(uint32_t RelocType) const { + // Thumb branch relocations can't use BLX + return RelocType != R_ARM_THM_JUMP19 && RelocType != R_ARM_THM_JUMP24; +} + +template void ThumbV7ABSLongThunk::writeTo(uint8_t *Buf, ThunkSection &IS) const { const uint8_t Data[] = { 0x40, 0xf2, 0x00, 0x0c, // movw ip, :lower16:S @@ -152,6 +162,13 @@ } template +bool ThumbV7ABSLongThunk::compatibleWith(uint32_t RelocType) const { + // ARM branch relocations can't use BLX + return RelocType != R_ARM_JUMP24 && RelocType != R_ARM_PC24 && + RelocType != R_ARM_PLT32; +} + +template void ARMV7PILongThunk::writeTo(uint8_t *Buf, ThunkSection &IS) const { const uint8_t Data[] = { 0xf0, 0xcf, 0x0f, 0xe3, // P: movw ip,:lower16:S - (P + (L1-P) +8) @@ -175,6 +192,12 @@ } template +bool ARMV7PILongThunk::compatibleWith(uint32_t RelocType) const { + // Thumb branch relocations can't use BLX + return RelocType != R_ARM_THM_JUMP19 && RelocType != R_ARM_THM_JUMP24; +} + +template void ThumbV7PILongThunk::writeTo(uint8_t *Buf, ThunkSection &IS) const { const uint8_t Data[] = { 0x4f, 0xf6, 0xf4, 0x7c, // P: movw ip,:lower16:S - (P + (L1-P) + 4) @@ -197,6 +220,13 @@ addSyntheticLocal("$t", STT_NOTYPE, this->Offset, 0, &IS); } +template +bool ThumbV7PILongThunk::compatibleWith(uint32_t RelocType) const { + // ARM branch relocations can't use BLX + return RelocType != R_ARM_JUMP24 && RelocType != R_ARM_PC24 && + RelocType != R_ARM_PLT32; +} + // Write MIPS LA25 thunk code to call PIC function from the non-PIC one. template void MipsThunk::writeTo(uint8_t *Buf, ThunkSection &) const {