Index: lld/trunk/ELF/Relocations.cpp =================================================================== --- lld/trunk/ELF/Relocations.cpp +++ lld/trunk/ELF/Relocations.cpp @@ -1050,7 +1050,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->isCompatibleWith(Type)) res.first->second = addThunk(Type, Body); return std::make_pair(res.first->second, res.second); } Index: lld/trunk/ELF/Thunks.h =================================================================== --- lld/trunk/ELF/Thunks.h +++ lld/trunk/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 isCompatibleWith(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: lld/trunk/ELF/Thunks.cpp =================================================================== --- lld/trunk/ELF/Thunks.cpp +++ lld/trunk/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 isCompatibleWith(uint32_t RelocType) const override; }; 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 isCompatibleWith(uint32_t RelocType) const override; }; 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 isCompatibleWith(uint32_t RelocType) const override; }; 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 isCompatibleWith(uint32_t RelocType) const override; }; // MIPS LA25 thunk @@ -128,6 +132,11 @@ addSyntheticLocal("$a", STT_NOTYPE, Offset, 0, &IS); } +bool ARMV7ABSLongThunk::isCompatibleWith(uint32_t RelocType) const { + // Thumb branch relocations can't use BLX + return RelocType != R_ARM_THM_JUMP19 && RelocType != R_ARM_THM_JUMP24; +} + void ThumbV7ABSLongThunk::writeTo(uint8_t *Buf, ThunkSection &IS) const { const uint8_t Data[] = { 0x40, 0xf2, 0x00, 0x0c, // movw ip, :lower16:S @@ -147,6 +156,12 @@ addSyntheticLocal("$t", STT_NOTYPE, Offset, 0, &IS); } +bool ThumbV7ABSLongThunk::isCompatibleWith(uint32_t RelocType) const { + // ARM branch relocations can't use BLX + return RelocType != R_ARM_JUMP24 && RelocType != R_ARM_PC24 && + RelocType != R_ARM_PLT32; +} + 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) @@ -168,6 +183,11 @@ addSyntheticLocal("$a", STT_NOTYPE, Offset, 0, &IS); } +bool ARMV7PILongThunk::isCompatibleWith(uint32_t RelocType) const { + // Thumb branch relocations can't use BLX + return RelocType != R_ARM_THM_JUMP19 && RelocType != R_ARM_THM_JUMP24; +} + 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) @@ -189,6 +209,12 @@ addSyntheticLocal("$t", STT_NOTYPE, Offset, 0, &IS); } +bool ThumbV7PILongThunk::isCompatibleWith(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. void MipsThunk::writeTo(uint8_t *Buf, ThunkSection &) const { uint64_t S = Destination.getVA();