/// 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;
}
namespace llvm {
+static bool isThumbFunc(symbol_iterator Symbol, const ObjectFile &Obj,
+ section_iterator Section) {
+ Expected<SymbolRef::Type> 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<COFFObjectFile>(Obj).getCOFFSection(*Section)->Characteristics &
+ COFF::IMAGE_SCN_MEM_16BIT;
+}
+
class RuntimeDyldCOFFThumb : public RuntimeDyldCOFF {
public:
RuntimeDyldCOFFThumb(RuntimeDyld::MemoryManager &MM,
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,
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;
}
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");
RE.Sections.SectionA == static_cast<uint32_t>(-1)
? Value
: Sections[RE.Sections.SectionA].getLoadAddressWithOffset(RE.Addend);
+ Result |= ISASelectionBit;
assert(static_cast<int32_t>(Result) <= INT32_MAX &&
"relocation overflow");
assert(static_cast<int32_t>(Result) >= INT32_MIN &&
<< " RelType: IMAGE_REL_ARM_ADDR32NB"
<< " TargetSection: " << RE.Sections.SectionA
<< " Value: " << format("0x%08" PRIx32, Result) << '\n');
+ Result |= ISASelectionBit;
writeBytesUnaligned(Result, Target, 4);
break;
}
Bytes[3] |= (((Immediate & 0x0700) >> 8) << 4);
};
- EncodeImmediate(&Target[0], static_cast<uint32_t>(Result) >> 00);
+ EncodeImmediate(&Target[0],
+ (static_cast<uint32_t>(Result) >> 00) | ISASelectionBit);
EncodeImmediate(&Target[4], static_cast<uint32_t>(Result) >> 16);
break;
// 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
__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:
__imp_OutputDebugStringW:
@ rel13:
.long OutputDebugStringW @ IMAGE_REL_ARM_ADDR32
-# rtdyld-check: *{4}__imp_OutputDebugStringW = 0x01310060
+# rtdyld-check: *{4}__imp_OutputDebugStringW = 0x01310061
.p2align 2
+
+branch_to_thumb_func:
+@ rel14: @ IMAGE_REL_ARM_MOV32T
+ movw r0, :lower16:function
+# rtdyld-check: decode_operand(branch_to_thumb_func, 1) = (function&0x0000ffff|1)
+ movt r0, :upper16:function
+# TODO rtdyld-check: decode_operand(branch_to_thumb_func, 1) = (function&0xffff0000>>16)
+ bx r0
+ trap
+
+ .data
+
+ .p2align 2
+a_data_symbol:
+ .long 1073741822
+
+ .p2align 2
+
+ .text
+
+ref_to_data_symbol_addr:
+@ rel15: @ IMAGE_REL_ARM_MOV32T
+ movw r0, :lower16:a_data_symbol
+# rtdyld-check: decode_operand(ref_to_data_symbol_addr, 1) = (a_data_symbol&0x0000ffff)
+ movt r0, :upper16:a_data_symbol
+# TODO rtdyld-check: decode_operand(ref_to_data_symbol_addr, 1) = (a_data_symbol&0xffff0000>>16)