summaryrefslogtreecommitdiffstats
path: root/llvm/lib
diff options
context:
space:
mode:
authorLang Hames <lhames@gmail.com>2017-08-09 20:19:27 +0000
committerLang Hames <lhames@gmail.com>2017-08-09 20:19:27 +0000
commit14a22a442d8aa6bee8c828872b82b7dd722dc7b8 (patch)
treedf3669f3e144a69fb5766c7eac17dfe07e8a2c0f /llvm/lib
parent7d928cc596bdfe3c0f8b60e9a5c605d1b0f4cec2 (diff)
downloadbcm5719-llvm-14a22a442d8aa6bee8c828872b82b7dd722dc7b8.tar.gz
bcm5719-llvm-14a22a442d8aa6bee8c828872b82b7dd722dc7b8.zip
[RuntimeDyld][ORC] Add support for Thumb mode to RuntimeDyldMachOARM.
This patch adds support for thumb relocations to RuntimeDyldMachOARM, and adds a target-specific flags field to JITSymbolFlags (so that on ARM we can record whether each symbol is Thumb-mode code). RuntimeDyldImpl::emitSection is modified to ensure that stubs memory is correctly aligned based on the size returned by getStubAlignment(). llvm-svn: 310517
Diffstat (limited to 'llvm/lib')
-rw-r--r--llvm/lib/ExecutionEngine/RuntimeDyld/JITSymbol.cpp8
-rw-r--r--llvm/lib/ExecutionEngine/RuntimeDyld/RuntimeDyld.cpp40
-rw-r--r--llvm/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldImpl.h38
-rw-r--r--llvm/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldMachO.cpp4
-rw-r--r--llvm/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldMachO.h3
-rw-r--r--llvm/lib/ExecutionEngine/RuntimeDyld/Targets/RuntimeDyldMachOARM.h142
6 files changed, 200 insertions, 35 deletions
diff --git a/llvm/lib/ExecutionEngine/RuntimeDyld/JITSymbol.cpp b/llvm/lib/ExecutionEngine/RuntimeDyld/JITSymbol.cpp
index 8769dcf7374..87059ef2b88 100644
--- a/llvm/lib/ExecutionEngine/RuntimeDyld/JITSymbol.cpp
+++ b/llvm/lib/ExecutionEngine/RuntimeDyld/JITSymbol.cpp
@@ -39,3 +39,11 @@ llvm::JITSymbolFlags::fromObjectSymbol(const object::BasicSymbolRef &Symbol) {
Flags |= JITSymbolFlags::Exported;
return Flags;
}
+
+ARMJITSymbolFlags llvm::ARMJITSymbolFlags::fromObjectSymbol(
+ const object::BasicSymbolRef &Symbol) {
+ ARMJITSymbolFlags Flags;
+ if (Symbol.getFlags() & object::BasicSymbolRef::SF_Thumb)
+ Flags |= ARMJITSymbolFlags::Thumb;
+ return Flags;
+}
diff --git a/llvm/lib/ExecutionEngine/RuntimeDyld/RuntimeDyld.cpp b/llvm/lib/ExecutionEngine/RuntimeDyld/RuntimeDyld.cpp
index 8198836f7a0..4d1d74cf34a 100644
--- a/llvm/lib/ExecutionEngine/RuntimeDyld/RuntimeDyld.cpp
+++ b/llvm/lib/ExecutionEngine/RuntimeDyld/RuntimeDyld.cpp
@@ -233,7 +233,7 @@ RuntimeDyldImpl::loadObjectImpl(const object::ObjectFile &Obj) {
return NameOrErr.takeError();
// Compute JIT symbol flags.
- JITSymbolFlags JITSymFlags = JITSymbolFlags::fromObjectSymbol(*I);
+ JITSymbolFlags JITSymFlags = getJITSymbolFlags(*I);
// If this is a weak definition, check to see if there's a strong one.
// If there is, skip this symbol (we won't be providing it: the strong
@@ -616,6 +616,10 @@ void RuntimeDyldImpl::writeBytesUnaligned(uint64_t Value, uint8_t *Dst,
}
}
+JITSymbolFlags RuntimeDyldImpl::getJITSymbolFlags(const BasicSymbolRef &SR) {
+ return JITSymbolFlags::fromObjectSymbol(SR);
+}
+
Error RuntimeDyldImpl::emitCommonSymbols(const ObjectFile &Obj,
CommonSymbolList &CommonSymbols) {
if (CommonSymbols.empty())
@@ -685,7 +689,7 @@ Error RuntimeDyldImpl::emitCommonSymbols(const ObjectFile &Obj,
Addr += AlignOffset;
Offset += AlignOffset;
}
- JITSymbolFlags JITSymFlags = JITSymbolFlags::fromObjectSymbol(Sym);
+ JITSymbolFlags JITSymFlags = getJITSymbolFlags(Sym);
DEBUG(dbgs() << "Allocating common symbol " << Name << " address "
<< format("%p", Addr) << "\n");
GlobalSymbolTable[Name] =
@@ -746,8 +750,11 @@ RuntimeDyldImpl::emitSection(const ObjectFile &Obj,
// Code section alignment needs to be at least as high as stub alignment or
// padding calculations may by incorrect when the section is remapped to a
// higher alignment.
- if (IsCode)
+ if (IsCode) {
Alignment = std::max(Alignment, getStubAlignment());
+ if (StubBufSize > 0)
+ PaddingSize += getStubAlignment() - 1;
+ }
// Some sections, such as debug info, don't need to be loaded for execution.
// Process those only if explicitly requested.
@@ -771,8 +778,13 @@ RuntimeDyldImpl::emitSection(const ObjectFile &Obj,
// Fill in any extra bytes we allocated for padding
if (PaddingSize != 0) {
memset(Addr + DataSize, 0, PaddingSize);
- // Update the DataSize variable so that the stub offset is set correctly.
+ // Update the DataSize variable to include padding.
DataSize += PaddingSize;
+
+ // Align DataSize to stub alignment if we have any stubs (PaddingSize will
+ // have been increased above to account for this).
+ if (StubBufSize > 0)
+ DataSize &= ~(getStubAlignment() - 1);
}
DEBUG(dbgs() << "emitSection SectionID: " << SectionID << " Name: " << Name
@@ -864,7 +876,7 @@ uint8_t *RuntimeDyldImpl::createStubFunction(uint8_t *Addr,
} else if (Arch == Triple::arm || Arch == Triple::armeb) {
// TODO: There is only ARM far stub now. We should add the Thumb stub,
// and stubs for branches Thumb - ARM and ARM - Thumb.
- writeBytesUnaligned(0xe51ff004, Addr, 4); // ldr pc,<label>
+ writeBytesUnaligned(0xe51ff004, Addr, 4); // ldr pc, [pc, #-4]
return Addr + 4;
} else if (IsMipsO32ABI) {
// 0: 3c190000 lui t9,%hi(addr).
@@ -971,15 +983,17 @@ Error RuntimeDyldImpl::resolveExternalSymbols() {
resolveRelocationList(Relocs, 0);
} else {
uint64_t Addr = 0;
+ JITSymbolFlags Flags;
RTDyldSymbolTable::const_iterator Loc = GlobalSymbolTable.find(Name);
if (Loc == GlobalSymbolTable.end()) {
// This is an external symbol, try to get its address from the symbol
// resolver.
// First search for the symbol in this logical dylib.
if (auto Sym = Resolver.findSymbolInLogicalDylib(Name.data())) {
- if (auto AddrOrErr = Sym.getAddress())
+ if (auto AddrOrErr = Sym.getAddress()) {
Addr = *AddrOrErr;
- else
+ Flags = Sym.getFlags();
+ } else
return AddrOrErr.takeError();
} else if (auto Err = Sym.takeError())
return Err;
@@ -987,9 +1001,10 @@ Error RuntimeDyldImpl::resolveExternalSymbols() {
// If that fails, try searching for an external symbol.
if (!Addr) {
if (auto Sym = Resolver.findSymbol(Name.data())) {
- if (auto AddrOrErr = Sym.getAddress())
+ if (auto AddrOrErr = Sym.getAddress()) {
Addr = *AddrOrErr;
- else
+ Flags = Sym.getFlags();
+ } else
return AddrOrErr.takeError();
} else if (auto Err = Sym.takeError())
return Err;
@@ -1007,6 +1022,7 @@ Error RuntimeDyldImpl::resolveExternalSymbols() {
const auto &SymInfo = Loc->second;
Addr = getSectionLoadAddress(SymInfo.getSectionID()) +
SymInfo.getOffset();
+ Flags = SymInfo.getFlags();
}
// FIXME: Implement error handling that doesn't kill the host program!
@@ -1017,6 +1033,12 @@ Error RuntimeDyldImpl::resolveExternalSymbols() {
// If Resolver returned UINT64_MAX, the client wants to handle this symbol
// manually and we shouldn't resolve its relocations.
if (Addr != UINT64_MAX) {
+
+ // Tweak the address based on the symbol flags if necessary.
+ // For example, this is used by RuntimeDyldMachOARM to toggle the low bit
+ // if the target symbol is Thumb.
+ Addr = modifyAddressBasedOnFlags(Addr, Flags);
+
DEBUG(dbgs() << "Resolving relocations Name: " << Name << "\t"
<< format("0x%lx", Addr) << "\n");
// This list may have been updated when we called getSymbolAddress, so
diff --git a/llvm/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldImpl.h b/llvm/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldImpl.h
index 95b04fd9325..e046a8504e9 100644
--- a/llvm/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldImpl.h
+++ b/llvm/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldImpl.h
@@ -149,8 +149,8 @@ public:
/// The size of this relocation (MachO specific).
unsigned Size;
- // COFF specific.
- bool IsTargetThumbFunc;
+ // ARM (MachO and COFF) specific.
+ bool IsTargetThumbFunc = false;
RelocationEntry(unsigned id, uint64_t offset, uint32_t type, int64_t addend)
: SectionID(id), Offset(offset), RelType(type), Addend(addend),
@@ -195,12 +195,14 @@ public:
uint64_t Offset;
int64_t Addend;
const char *SymbolName;
+ bool IsStubThumb = false;
RelocationValueRef() : SectionID(0), Offset(0), Addend(0),
SymbolName(nullptr) {}
inline bool operator==(const RelocationValueRef &Other) const {
return SectionID == Other.SectionID && Offset == Other.Offset &&
- Addend == Other.Addend && SymbolName == Other.SymbolName;
+ Addend == Other.Addend && SymbolName == Other.SymbolName &&
+ IsStubThumb == Other.IsStubThumb;
}
inline bool operator<(const RelocationValueRef &Other) const {
if (SectionID != Other.SectionID)
@@ -209,6 +211,8 @@ public:
return Offset < Other.Offset;
if (Addend != Other.Addend)
return Addend < Other.Addend;
+ if (IsStubThumb != Other.IsStubThumb)
+ return IsStubThumb < Other.IsStubThumb;
return SymbolName < Other.SymbolName;
}
};
@@ -216,21 +220,21 @@ public:
/// @brief Symbol info for RuntimeDyld.
class SymbolTableEntry {
public:
- SymbolTableEntry()
- : Offset(0), SectionID(0) {}
+ SymbolTableEntry() = default;
SymbolTableEntry(unsigned SectionID, uint64_t Offset, JITSymbolFlags Flags)
: Offset(Offset), SectionID(SectionID), Flags(Flags) {}
unsigned getSectionID() const { return SectionID; }
uint64_t getOffset() const { return Offset; }
+ void setOffset(uint64_t NewOffset) { Offset = NewOffset; }
JITSymbolFlags getFlags() const { return Flags; }
private:
- uint64_t Offset;
- unsigned SectionID;
- JITSymbolFlags Flags;
+ uint64_t Offset = 0;
+ unsigned SectionID = 0;
+ JITSymbolFlags Flags = JITSymbolFlags::None;
};
typedef StringMap<SymbolTableEntry> RTDyldSymbolTable;
@@ -365,6 +369,18 @@ protected:
/// Dst.
void writeBytesUnaligned(uint64_t Value, uint8_t *Dst, unsigned Size) const;
+ /// Generate JITSymbolFlags from a libObject symbol.
+ virtual JITSymbolFlags getJITSymbolFlags(const BasicSymbolRef &Sym);
+
+ /// Modify the given target address based on the given symbol flags.
+ /// This can be used by subclasses to tweak addresses based on symbol flags,
+ /// For example: the MachO/ARM target uses it to set the low bit if the target
+ /// is a thumb symbol.
+ virtual uint64_t modifyAddressBasedOnFlags(uint64_t Addr,
+ JITSymbolFlags Flags) const {
+ return Addr;
+ }
+
/// \brief Given the common symbols discovered in the object file, emit a
/// new section for them and update the symbol mappings in the object and
/// symbol table.
@@ -493,6 +509,12 @@ public:
if (SymEntry.getSectionID() != AbsoluteSymbolSection)
SectionAddr = getSectionLoadAddress(SymEntry.getSectionID());
uint64_t TargetAddr = SectionAddr + SymEntry.getOffset();
+
+ // FIXME: Have getSymbol should return the actual address and the client
+ // modify it based on the flags. This will require clients to be
+ // aware of the target architecture, which we should build
+ // infrastructure for.
+ TargetAddr = modifyAddressBasedOnFlags(TargetAddr, SymEntry.getFlags());
return JITEvaluatedSymbol(TargetAddr, SymEntry.getFlags());
}
diff --git a/llvm/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldMachO.cpp b/llvm/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldMachO.cpp
index 80e9c7ac18a..b0561f68edb 100644
--- a/llvm/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldMachO.cpp
+++ b/llvm/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldMachO.cpp
@@ -55,7 +55,8 @@ Expected<relocation_iterator>
RuntimeDyldMachO::processScatteredVANILLA(
unsigned SectionID, relocation_iterator RelI,
const ObjectFile &BaseObjT,
- RuntimeDyldMachO::ObjSectionToIDMap &ObjSectionToID) {
+ RuntimeDyldMachO::ObjSectionToIDMap &ObjSectionToID,
+ bool TargetIsLocalThumbFunc) {
const MachOObjectFile &Obj =
static_cast<const MachOObjectFile&>(BaseObjT);
MachO::any_relocation_info RE =
@@ -85,6 +86,7 @@ RuntimeDyldMachO::processScatteredVANILLA(
Addend -= SectionBaseAddr;
RelocationEntry R(SectionID, Offset, RelocType, Addend, IsPCRel, Size);
+ R.IsTargetThumbFunc = TargetIsLocalThumbFunc;
addRelocationForSection(R, TargetSectionID);
diff --git a/llvm/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldMachO.h b/llvm/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldMachO.h
index 67a5020fc4f..d71ca4e5495 100644
--- a/llvm/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldMachO.h
+++ b/llvm/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldMachO.h
@@ -83,7 +83,8 @@ protected:
Expected<relocation_iterator>
processScatteredVANILLA(unsigned SectionID, relocation_iterator RelI,
const ObjectFile &BaseObjT,
- RuntimeDyldMachO::ObjSectionToIDMap &ObjSectionToID);
+ RuntimeDyldMachO::ObjSectionToIDMap &ObjSectionToID,
+ bool TargetIsLocalThumbFunc = false);
/// Construct a RelocationValueRef representing the relocation target.
/// For Symbols in known sections, this will return a RelocationValueRef
diff --git a/llvm/lib/ExecutionEngine/RuntimeDyld/Targets/RuntimeDyldMachOARM.h b/llvm/lib/ExecutionEngine/RuntimeDyld/Targets/RuntimeDyldMachOARM.h
index 43461de4c49..990629de2f1 100644
--- a/llvm/lib/ExecutionEngine/RuntimeDyld/Targets/RuntimeDyldMachOARM.h
+++ b/llvm/lib/ExecutionEngine/RuntimeDyld/Targets/RuntimeDyldMachOARM.h
@@ -34,7 +34,20 @@ public:
unsigned getStubAlignment() override { return 4; }
- int64_t decodeAddend(const RelocationEntry &RE) const {
+ JITSymbolFlags getJITSymbolFlags(const BasicSymbolRef &SR) override {
+ auto Flags = RuntimeDyldImpl::getJITSymbolFlags(SR);
+ Flags.getTargetFlags() = ARMJITSymbolFlags::fromObjectSymbol(SR);
+ return Flags;
+ }
+
+ uint64_t modifyAddressBasedOnFlags(uint64_t Addr,
+ JITSymbolFlags Flags) const override {
+ if (Flags.getTargetFlags() & ARMJITSymbolFlags::Thumb)
+ Addr |= 0x1;
+ return Addr;
+ }
+
+ Expected<int64_t> decodeAddend(const RelocationEntry &RE) const {
const SectionEntry &Section = Sections[RE.SectionID];
uint8_t *LocalAddress = Section.getAddressWithOffset(RE.Offset);
@@ -47,6 +60,27 @@ public:
// Now we've got the shifted immediate, shift by 2, sign extend and ret.
return SignExtend32<26>(Temp << 2);
}
+
+ case MachO::ARM_THUMB_RELOC_BR22: {
+ // This is a pair of instructions whose operands combine to provide 22
+ // bits of displacement:
+ // Encoding for high bits 1111 0XXX XXXX XXXX
+ // Encoding for low bits 1111 1XXX XXXX XXXX
+ uint16_t HighInsn = readBytesUnaligned(LocalAddress, 2);
+ if ((HighInsn & 0xf800) != 0xf000)
+ return make_error<StringError>("Unrecognized thumb branch encoding "
+ "(BR22 high bits)",
+ inconvertibleErrorCode());
+
+ uint16_t LowInsn = readBytesUnaligned(LocalAddress + 2, 2);
+ if ((LowInsn & 0xf800) != 0xf800)
+ return make_error<StringError>("Unrecognized thumb branch encoding "
+ "(BR22 low bits)",
+ inconvertibleErrorCode());
+
+ return SignExtend64<23>(((HighInsn & 0x7ff) << 12) |
+ ((LowInsn & 0x7ff) << 1));
+ }
}
}
@@ -61,12 +95,35 @@ public:
Obj.getRelocation(RelI->getRawDataRefImpl());
uint32_t RelType = Obj.getAnyRelocationType(RelInfo);
+ // Set to true for thumb functions in this (or previous) TUs.
+ // Will be used to set the TargetIsThumbFunc member on the relocation entry.
+ bool TargetIsLocalThumbFunc = false;
+ if (Obj.getPlainRelocationExternal(RelInfo)) {
+ auto Symbol = RelI->getSymbol();
+ StringRef TargetName;
+ if (auto TargetNameOrErr = Symbol->getName())
+ TargetName = *TargetNameOrErr;
+ else
+ return TargetNameOrErr.takeError();
+
+ // If the target is external but the value doesn't have a name then we've
+ // converted the value to a section/offset pair, but we still need to set
+ // the IsTargetThumbFunc bit, so look the value up in the globla symbol table.
+ auto EntryItr = GlobalSymbolTable.find(TargetName);
+ if (EntryItr != GlobalSymbolTable.end()) {
+ TargetIsLocalThumbFunc =
+ EntryItr->second.getFlags().getTargetFlags() &
+ ARMJITSymbolFlags::Thumb;
+ }
+ }
+
if (Obj.isRelocationScattered(RelInfo)) {
if (RelType == MachO::ARM_RELOC_HALF_SECTDIFF)
return processHALFSECTDIFFRelocation(SectionID, RelI, Obj,
ObjSectionToID);
else if (RelType == MachO::GENERIC_RELOC_VANILLA)
- return processScatteredVANILLA(SectionID, RelI, Obj, ObjSectionToID);
+ return processScatteredVANILLA(SectionID, RelI, Obj, ObjSectionToID,
+ TargetIsLocalThumbFunc);
else
return ++RelI;
}
@@ -77,7 +134,6 @@ public:
UNIMPLEMENTED_RELOC(MachO::ARM_RELOC_SECTDIFF);
UNIMPLEMENTED_RELOC(MachO::ARM_RELOC_LOCAL_SECTDIFF);
UNIMPLEMENTED_RELOC(MachO::ARM_RELOC_PB_LA_PTR);
- UNIMPLEMENTED_RELOC(MachO::ARM_THUMB_RELOC_BR22);
UNIMPLEMENTED_RELOC(MachO::ARM_THUMB_32BIT_BRANCH);
UNIMPLEMENTED_RELOC(MachO::ARM_RELOC_HALF);
default:
@@ -89,17 +145,30 @@ public:
}
RelocationEntry RE(getRelocationEntry(SectionID, Obj, RelI));
- RE.Addend = decodeAddend(RE);
+ if (auto AddendOrErr = decodeAddend(RE))
+ RE.Addend = *AddendOrErr;
+ else
+ return AddendOrErr.takeError();
+ RE.IsTargetThumbFunc = TargetIsLocalThumbFunc;
+
RelocationValueRef Value;
if (auto ValueOrErr = getRelocationValueRef(Obj, RelI, RE, ObjSectionToID))
Value = *ValueOrErr;
else
return ValueOrErr.takeError();
+ // If this is a branch from a thumb function (BR22) then make sure we mark
+ // the value as being a thumb stub: we don't want to mix it up with an ARM
+ // stub targeting the same function.
+ if (RE.RelType == MachO::ARM_THUMB_RELOC_BR22)
+ Value.IsStubThumb = TargetIsLocalThumbFunc;
+
if (RE.IsPCRel)
- makeValueAddendPCRel(Value, RelI, 8);
+ makeValueAddendPCRel(Value, RelI,
+ (RE.RelType == MachO::ARM_THUMB_RELOC_BR22) ? 4 : 8);
- if ((RE.RelType & 0xf) == MachO::ARM_RELOC_BR24)
+ if (RE.RelType == MachO::ARM_RELOC_BR24 ||
+ RE.RelType == MachO::ARM_THUMB_RELOC_BR22)
processBranchRelocation(RE, Value, Stubs);
else {
RE.Addend = Value.Offset;
@@ -124,12 +193,30 @@ public:
Value -= FinalAddress;
// ARM PCRel relocations have an effective-PC offset of two instructions
// (four bytes in Thumb mode, 8 bytes in ARM mode).
- // FIXME: For now, assume ARM mode.
- Value -= 8;
+ Value -= (RE.RelType == MachO::ARM_THUMB_RELOC_BR22) ? 4 : 8;
}
switch (RE.RelType) {
+ case MachO::ARM_THUMB_RELOC_BR22: {
+ Value += RE.Addend;
+ uint16_t HighInsn = readBytesUnaligned(LocalAddress, 2);
+ assert((HighInsn & 0xf800) == 0xf000 &&
+ "Unrecognized thumb branch encoding (BR22 high bits)");
+ HighInsn = (HighInsn & 0xf800) | ((Value >> 12) & 0x7ff);
+
+ uint16_t LowInsn = readBytesUnaligned(LocalAddress + 2, 2);
+ assert((LowInsn & 0xf800) != 0xf8000 &&
+ "Unrecognized thumb branch encoding (BR22 low bits)");
+ LowInsn = (LowInsn & 0xf800) | ((Value >> 1) & 0x7ff);
+
+ writeBytesUnaligned(HighInsn, LocalAddress, 2);
+ writeBytesUnaligned(LowInsn, LocalAddress + 2, 2);
+ break;
+ }
+
case MachO::ARM_RELOC_VANILLA:
+ if (RE.IsTargetThumbFunc)
+ Value |= 0x01;
writeBytesUnaligned(Value + RE.Addend, LocalAddress, 1 << RE.Size);
break;
case MachO::ARM_RELOC_BR24: {
@@ -158,10 +245,19 @@ public:
Value = SectionABase - SectionBBase + RE.Addend;
if (RE.Size & 0x1) // :upper16:
Value = (Value >> 16);
+
+ bool IsThumb = RE.Size & 0x2;
+
Value &= 0xffff;
uint32_t Insn = readBytesUnaligned(LocalAddress, 4);
- Insn = (Insn & 0xfff0f000) | ((Value & 0xf000) << 4) | (Value & 0x0fff);
+
+ if (IsThumb)
+ Insn = (Insn & 0x8f00fbf0) | ((Value & 0xf000) >> 12) |
+ ((Value & 0x0800) >> 1) | ((Value & 0x0700) << 20) |
+ ((Value & 0x00ff) << 16);
+ else
+ Insn = (Insn & 0xfff0f000) | ((Value & 0xf000) << 4) | (Value & 0x0fff);
writeBytesUnaligned(Insn, LocalAddress, 4);
break;
}
@@ -196,17 +292,26 @@ private:
Addr = Section.getAddressWithOffset(i->second);
} else {
// Create a new stub function.
+ assert(Section.getStubOffset() % 4 == 0 && "Misaligned stub");
Stubs[Value] = Section.getStubOffset();
- uint8_t *StubTargetAddr = createStubFunction(
- Section.getAddressWithOffset(Section.getStubOffset()));
+ uint32_t StubOpcode = 0;
+ if (RE.RelType == MachO::ARM_RELOC_BR24)
+ StubOpcode = 0xe51ff004; // ldr pc, [pc, #-4]
+ else if (RE.RelType == MachO::ARM_THUMB_RELOC_BR22)
+ StubOpcode = 0xf000f8df; // ldr pc, [pc]
+ else
+ llvm_unreachable("Unrecognized relocation");
+ Addr = Section.getAddressWithOffset(Section.getStubOffset());
+ writeBytesUnaligned(StubOpcode, Addr, 4);
+ uint8_t *StubTargetAddr = Addr + 4;
RelocationEntry StubRE(
RE.SectionID, StubTargetAddr - Section.getAddress(),
MachO::GENERIC_RELOC_VANILLA, Value.Offset, false, 2);
+ StubRE.IsTargetThumbFunc = RE.IsTargetThumbFunc;
if (Value.SymbolName)
addRelocationForSymbol(StubRE, Value.SymbolName);
else
addRelocationForSection(StubRE, Value.SectionID);
- Addr = Section.getAddressWithOffset(Section.getStubOffset());
Section.advanceStubOffset(getMaxStubSize());
}
RelocationEntry TargetRE(RE.SectionID, RE.Offset, RE.RelType, 0,
@@ -223,14 +328,12 @@ private:
MachO::any_relocation_info RE =
MachO.getRelocation(RelI->getRawDataRefImpl());
-
// For a half-diff relocation the length bits actually record whether this
// is a movw/movt, and whether this is arm or thumb.
// Bit 0 indicates movw (b0 == 0) or movt (b0 == 1).
// Bit 1 indicates arm (b1 == 0) or thumb (b1 == 1).
unsigned HalfDiffKindBits = MachO.getAnyRelocationLength(RE);
- if (HalfDiffKindBits & 0x2)
- llvm_unreachable("Thumb not yet supported.");
+ bool IsThumb = HalfDiffKindBits & 0x2;
SectionEntry &Section = Sections[SectionID];
uint32_t RelocType = MachO.getAnyRelocationType(RE);
@@ -238,7 +341,14 @@ private:
uint64_t Offset = RelI->getOffset();
uint8_t *LocalAddress = Section.getAddressWithOffset(Offset);
int64_t Immediate = readBytesUnaligned(LocalAddress, 4); // Copy the whole instruction out.
- Immediate = ((Immediate >> 4) & 0xf000) | (Immediate & 0xfff);
+
+ if (IsThumb)
+ Immediate = ((Immediate & 0x0000000f) << 12) |
+ ((Immediate & 0x00000400) << 1) |
+ ((Immediate & 0x70000000) >> 20) |
+ ((Immediate & 0x00ff0000) >> 16);
+ else
+ Immediate = ((Immediate >> 4) & 0xf000) | (Immediate & 0xfff);
++RelI;
MachO::any_relocation_info RE2 =
OpenPOWER on IntegriCloud