Index: lib/ExecutionEngine/RuntimeDyld/RuntimeDyldImpl.h =================================================================== --- lib/ExecutionEngine/RuntimeDyld/RuntimeDyldImpl.h +++ lib/ExecutionEngine/RuntimeDyld/RuntimeDyldImpl.h @@ -149,26 +149,43 @@ /// The size of this relocation (MachO specific). unsigned Size; + // COFF specific. + bool IsRelativeToThumbFunction; + RelocationEntry(unsigned id, uint64_t offset, uint32_t type, int64_t addend) : SectionID(id), Offset(offset), RelType(type), Addend(addend), - SymOffset(0), IsPCRel(false), Size(0) {} + SymOffset(0), IsPCRel(false), Size(0), + IsRelativeToThumbFunction(false) {} RelocationEntry(unsigned id, uint64_t offset, uint32_t type, int64_t addend, uint64_t symoffset) : SectionID(id), Offset(offset), RelType(type), Addend(addend), - SymOffset(symoffset), IsPCRel(false), Size(0) {} + SymOffset(symoffset), IsPCRel(false), Size(0), + IsRelativeToThumbFunction(false) {} RelocationEntry(unsigned id, uint64_t offset, uint32_t type, int64_t addend, bool IsPCRel, unsigned Size) : SectionID(id), Offset(offset), RelType(type), Addend(addend), - SymOffset(0), IsPCRel(IsPCRel), Size(Size) {} + SymOffset(0), IsPCRel(IsPCRel), Size(Size), + IsRelativeToThumbFunction(false) {} RelocationEntry(unsigned id, uint64_t offset, uint32_t type, int64_t addend, unsigned SectionA, uint64_t SectionAOffset, unsigned SectionB, uint64_t SectionBOffset, bool IsPCRel, unsigned Size) : SectionID(id), Offset(offset), RelType(type), Addend(SectionAOffset - SectionBOffset + addend), IsPCRel(IsPCRel), - Size(Size) { + Size(Size), IsRelativeToThumbFunction(false) { + Sections.SectionA = SectionA; + Sections.SectionB = SectionB; + } + + RelocationEntry(unsigned id, uint64_t offset, uint32_t type, int64_t addend, + unsigned SectionA, uint64_t SectionAOffset, unsigned SectionB, + uint64_t SectionBOffset, bool IsPCRel, unsigned Size, + bool IsRelativeToThumbFunction) + : SectionID(id), Offset(offset), RelType(type), + Addend(SectionAOffset - SectionBOffset + addend), IsPCRel(IsPCRel), + Size(Size), IsRelativeToThumbFunction(IsRelativeToThumbFunction) { Sections.SectionA = SectionA; Sections.SectionB = SectionB; } Index: lib/ExecutionEngine/RuntimeDyld/Targets/RuntimeDyldCOFFThumb.h =================================================================== --- lib/ExecutionEngine/RuntimeDyld/Targets/RuntimeDyldCOFFThumb.h +++ lib/ExecutionEngine/RuntimeDyld/Targets/RuntimeDyldCOFFThumb.h @@ -22,6 +22,27 @@ namespace llvm { +static bool isSymbolAThumbFunction(symbol_iterator Symbol, + const ObjectFile &Obj, + section_iterator Section) { + Expected SymTypeOrErr = Symbol->getType(); + if (!SymTypeOrErr) { + std::string Buf; + raw_string_ostream OS(Buf); + logAllUnhandledErrors(SymTypeOrErr.takeError(), OS, ""); + OS.flush(); + report_fatal_error(Buf); + } + + if (*SymTypeOrErr != SymbolRef::ST_Function) + return false; + + // We check the IMAGE_SCN_MEM_16BIT flag in the section of the symbol to tell + // if it's thumb or not + return cast(Obj).getCOFFSection(*Section)->Characteristics & + COFF::IMAGE_SCN_MEM_16BIT; +} + class RuntimeDyldCOFFThumb : public RuntimeDyldCOFF { public: RuntimeDyldCOFFThumb(RuntimeDyld::MemoryManager &MM, @@ -92,12 +113,24 @@ else return TargetSectionIDOrErr.takeError(); + // We need to find out if the relocation is relative to a thumb function + // so that we include the ISA selection bit when resolve the relocation + bool IsRelativeToThumbFunction = + isSymbolAThumbFunction(Symbol, Obj, Section); + switch (RelType) { default: llvm_unreachable("unsupported relocation type"); case COFF::IMAGE_REL_ARM_ABSOLUTE: // This relocation is ignored. break; - case COFF::IMAGE_REL_ARM_ADDR32: + case COFF::IMAGE_REL_ARM_ADDR32: { + RelocationEntry RE = + RelocationEntry(SectionID, Offset, RelType, Addend, TargetSectionID, + getSymbolOffset(*Symbol), 0, 0, false, 0, + IsRelativeToThumbFunction); + addRelocationForSection(RE, TargetSectionID); + break; + } case COFF::IMAGE_REL_ARM_ADDR32NB: { RelocationEntry RE = RelocationEntry(SectionID, Offset, RelType, Addend, TargetSectionID, @@ -120,7 +153,8 @@ case COFF::IMAGE_REL_ARM_MOV32T: { RelocationEntry RE = RelocationEntry(SectionID, Offset, RelType, Addend, TargetSectionID, - getSymbolOffset(*Symbol), 0, 0, false, 0); + getSymbolOffset(*Symbol), 0, 0, false, 0, + IsRelativeToThumbFunction); addRelocationForSection(RE, TargetSectionID); break; } @@ -142,6 +176,7 @@ void resolveRelocation(const RelocationEntry &RE, uint64_t Value) override { const auto Section = Sections[RE.SectionID]; uint8_t *Target = Section.getAddressWithOffset(RE.Offset); + int ISASelectionBit = RE.IsRelativeToThumbFunction ? 1 : 0; switch (RE.RelType) { default: llvm_unreachable("unsupported relocation type"); @@ -154,6 +189,7 @@ RE.Sections.SectionA == static_cast(-1) ? Value : Sections[RE.Sections.SectionA].getLoadAddressWithOffset(RE.Addend); + Result |= ISASelectionBit; assert(static_cast(Result) <= INT32_MAX && "relocation overflow"); assert(static_cast(Result) >= INT32_MIN && @@ -228,7 +264,8 @@ Bytes[3] |= (((Immediate & 0x0700) >> 8) << 4); }; - EncodeImmediate(&Target[0], static_cast(Result) >> 00); + EncodeImmediate(&Target[0], + (static_cast(Result) >> 00) | ISASelectionBit); EncodeImmediate(&Target[4], static_cast(Result) >> 16); break;