Index: lib/ExecutionEngine/RuntimeDyld/RuntimeDyldImpl.h =================================================================== --- lib/ExecutionEngine/RuntimeDyld/RuntimeDyldImpl.h +++ lib/ExecutionEngine/RuntimeDyld/RuntimeDyldImpl.h @@ -149,26 +149,41 @@ /// The size of this relocation (MachO specific). unsigned Size; + // COFF specific. + bool IsTargetThumbFunc; + 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), IsTargetThumbFunc(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), + IsTargetThumbFunc(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), IsTargetThumbFunc(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), IsTargetThumbFunc(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 IsTargetThumbFunc) + : SectionID(id), Offset(offset), RelType(type), + Addend(SectionAOffset - SectionBOffset + addend), IsPCRel(IsPCRel), + Size(Size), IsTargetThumbFunc(IsTargetThumbFunc) { 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,26 @@ namespace llvm { +static bool isThumbFunc(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 +112,22 @@ 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 IsTargetThumbFunc = isThumbFunc(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, IsTargetThumbFunc); + addRelocationForSection(RE, TargetSectionID); + break; + } case COFF::IMAGE_REL_ARM_ADDR32NB: { RelocationEntry RE = RelocationEntry(SectionID, Offset, RelType, Addend, TargetSectionID, @@ -118,9 +148,9 @@ break; } case COFF::IMAGE_REL_ARM_MOV32T: { - RelocationEntry RE = - RelocationEntry(SectionID, Offset, RelType, Addend, TargetSectionID, - getSymbolOffset(*Symbol), 0, 0, false, 0); + RelocationEntry RE = RelocationEntry( + SectionID, Offset, RelType, Addend, TargetSectionID, + getSymbolOffset(*Symbol), 0, 0, false, 0, IsTargetThumbFunc); addRelocationForSection(RE, TargetSectionID); break; } @@ -142,6 +172,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.IsTargetThumbFunc ? 1 : 0; switch (RE.RelType) { default: llvm_unreachable("unsupported relocation type"); @@ -154,6 +185,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 && @@ -178,6 +210,7 @@ << " RelType: IMAGE_REL_ARM_ADDR32NB" << " TargetSection: " << RE.Sections.SectionA << " Value: " << format("0x%08" PRIx32, Result) << '\n'); + Result |= ISASelectionBit; writeBytesUnaligned(Result, Target, 4); break; } @@ -228,7 +261,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; Index: test/ExecutionEngine/RuntimeDyld/ARM/COFF_Thumb.s =================================================================== --- test/ExecutionEngine/RuntimeDyld/ARM/COFF_Thumb.s +++ test/ExecutionEngine/RuntimeDyld/ARM/COFF_Thumb.s @@ -1,5 +1,5 @@ // RUN: llvm-mc -triple thumbv7-windows-itanium -filetype obj -o %t.obj %s -// RUN: llvm-rtdyld -triple thumbv7-windows -dummy-extern OutputDebugStringW=0x01310060 -dummy-extern OutputDebugStringA=0x78563412 -dummy-extern ExitProcess=0x54769890 -dummy-extern unnamed_addr=0x00001024 -verify -check %s %t.obj +// RUN: llvm-rtdyld -triple thumbv7-windows -dummy-extern OutputDebugStringW=0x01310061 -dummy-extern OutputDebugStringA=0x78563413 -dummy-extern ExitProcess=0x54769891 -dummy-extern unnamed_addr=0x00001024 -verify -check %s %t.obj .text .syntax unified @@ -82,13 +82,13 @@ __imp_OutputDebugStringA: @ rel6: .long OutputDebugStringA @ IMAGE_REL_ARM_ADDR32 -# rtdyld-check: *{4}__imp_OutputDebugStringA = 0x78563412 +# rtdyld-check: *{4}__imp_OutputDebugStringA = 0x78563413 .p2align 2 __imp_ExitProcess: @ rel7: .long ExitProcess @ IMAGE_REL_ARM_ADDR32 -# rtdyld-check: *{4}__imp_ExitProcess = 0x54769890 +# rtdyld-check: *{4}__imp_ExitProcess = 0x54769891 .global relocations relocations: @@ -118,6 +118,26 @@ __imp_OutputDebugStringW: @ rel13: .long OutputDebugStringW @ IMAGE_REL_ARM_ADDR32 -# rtdyld-check: *{4}__imp_OutputDebugStringW = 0x01310060 +# rtdyld-check: *{4}__imp_OutputDebugStringW = 0x01310061 .p2align 2 + +rel14: @ IMAGE_REL_ARM_MOV32T + movw r0, :lower16:function +# rtdyld-check: decode_operand(rel14, 1) = (function&0x0000ffff|1) + movt r0, :upper16:function +# TODO rtdyld-check: decode_operand(rel14, 1) = (function&0xffff0000>>16) + bx r0 + trap + + + .bss + .lcomm a_data_symbol, 1073741822 + + .text + +rel15: @ IMAGE_REL_ARM_MOV32T + movw r0, :lower16:a_data_symbol +# rtdyld-check: decode_operand(rel15, 1) = (a_data_symbol&0x0000ffff) + movt r0, :upper16:a_data_symbol +# TODO rtdyld-check: decode_operand(rel15, 1) = (a_data_symbol&0xffff0000>>16)