mirror of
https://github.com/RPCS3/llvm-mirror.git
synced 2025-01-31 12:41:49 +01:00
[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
This commit is contained in:
parent
57ceceb3a7
commit
08671757e4
@ -40,6 +40,7 @@ using JITTargetAddress = uint64_t;
|
|||||||
class JITSymbolFlags {
|
class JITSymbolFlags {
|
||||||
public:
|
public:
|
||||||
using UnderlyingType = uint8_t;
|
using UnderlyingType = uint8_t;
|
||||||
|
using TargetFlagsType = uint64_t;
|
||||||
|
|
||||||
enum FlagNames : UnderlyingType {
|
enum FlagNames : UnderlyingType {
|
||||||
None = 0,
|
None = 0,
|
||||||
@ -56,6 +57,11 @@ public:
|
|||||||
/// @brief Construct a JITSymbolFlags instance from the given flags.
|
/// @brief Construct a JITSymbolFlags instance from the given flags.
|
||||||
JITSymbolFlags(FlagNames Flags) : Flags(Flags) {}
|
JITSymbolFlags(FlagNames Flags) : Flags(Flags) {}
|
||||||
|
|
||||||
|
/// @brief Construct a JITSymbolFlags instance from the given flags and target
|
||||||
|
/// flags.
|
||||||
|
JITSymbolFlags(FlagNames Flags, TargetFlagsType TargetFlags)
|
||||||
|
: Flags(Flags), TargetFlags(TargetFlags) {}
|
||||||
|
|
||||||
/// @brief Return true if there was an error retrieving this symbol.
|
/// @brief Return true if there was an error retrieving this symbol.
|
||||||
bool hasError() const {
|
bool hasError() const {
|
||||||
return (Flags & HasError) == HasError;
|
return (Flags & HasError) == HasError;
|
||||||
@ -80,8 +86,12 @@ public:
|
|||||||
return (Flags & Exported) == Exported;
|
return (Flags & Exported) == Exported;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// @brief Implicitly convert to the underlying flags type.
|
||||||
operator UnderlyingType&() { return Flags; }
|
operator UnderlyingType&() { return Flags; }
|
||||||
|
|
||||||
|
/// @brief Return a reference to the target-specific flags.
|
||||||
|
TargetFlagsType& getTargetFlags() { return TargetFlags; }
|
||||||
|
|
||||||
/// Construct a JITSymbolFlags value based on the flags of the given global
|
/// Construct a JITSymbolFlags value based on the flags of the given global
|
||||||
/// value.
|
/// value.
|
||||||
static JITSymbolFlags fromGlobalValue(const GlobalValue &GV);
|
static JITSymbolFlags fromGlobalValue(const GlobalValue &GV);
|
||||||
@ -92,6 +102,26 @@ public:
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
UnderlyingType Flags = None;
|
UnderlyingType Flags = None;
|
||||||
|
TargetFlagsType TargetFlags = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
/// @brief ARM-specific JIT symbol flags.
|
||||||
|
/// FIXME: This should be moved into a target-specific header.
|
||||||
|
class ARMJITSymbolFlags {
|
||||||
|
public:
|
||||||
|
ARMJITSymbolFlags() = default;
|
||||||
|
|
||||||
|
enum FlagNames {
|
||||||
|
None = 0,
|
||||||
|
Thumb = 1 << 0
|
||||||
|
};
|
||||||
|
|
||||||
|
operator JITSymbolFlags::TargetFlagsType&() { return Flags; }
|
||||||
|
|
||||||
|
static ARMJITSymbolFlags fromObjectSymbol(
|
||||||
|
const object::BasicSymbolRef &Symbol);
|
||||||
|
private:
|
||||||
|
JITSymbolFlags::TargetFlagsType Flags = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
/// @brief Represents a symbol that has been evaluated to an address already.
|
/// @brief Represents a symbol that has been evaluated to an address already.
|
||||||
|
@ -39,3 +39,11 @@ llvm::JITSymbolFlags::fromObjectSymbol(const object::BasicSymbolRef &Symbol) {
|
|||||||
Flags |= JITSymbolFlags::Exported;
|
Flags |= JITSymbolFlags::Exported;
|
||||||
return Flags;
|
return Flags;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ARMJITSymbolFlags llvm::ARMJITSymbolFlags::fromObjectSymbol(
|
||||||
|
const object::BasicSymbolRef &Symbol) {
|
||||||
|
ARMJITSymbolFlags Flags;
|
||||||
|
if (Symbol.getFlags() & object::BasicSymbolRef::SF_Thumb)
|
||||||
|
Flags |= ARMJITSymbolFlags::Thumb;
|
||||||
|
return Flags;
|
||||||
|
}
|
||||||
|
@ -233,7 +233,7 @@ RuntimeDyldImpl::loadObjectImpl(const object::ObjectFile &Obj) {
|
|||||||
return NameOrErr.takeError();
|
return NameOrErr.takeError();
|
||||||
|
|
||||||
// Compute JIT symbol flags.
|
// 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 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
|
// 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,
|
Error RuntimeDyldImpl::emitCommonSymbols(const ObjectFile &Obj,
|
||||||
CommonSymbolList &CommonSymbols) {
|
CommonSymbolList &CommonSymbols) {
|
||||||
if (CommonSymbols.empty())
|
if (CommonSymbols.empty())
|
||||||
@ -685,7 +689,7 @@ Error RuntimeDyldImpl::emitCommonSymbols(const ObjectFile &Obj,
|
|||||||
Addr += AlignOffset;
|
Addr += AlignOffset;
|
||||||
Offset += AlignOffset;
|
Offset += AlignOffset;
|
||||||
}
|
}
|
||||||
JITSymbolFlags JITSymFlags = JITSymbolFlags::fromObjectSymbol(Sym);
|
JITSymbolFlags JITSymFlags = getJITSymbolFlags(Sym);
|
||||||
DEBUG(dbgs() << "Allocating common symbol " << Name << " address "
|
DEBUG(dbgs() << "Allocating common symbol " << Name << " address "
|
||||||
<< format("%p", Addr) << "\n");
|
<< format("%p", Addr) << "\n");
|
||||||
GlobalSymbolTable[Name] =
|
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
|
// 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
|
// padding calculations may by incorrect when the section is remapped to a
|
||||||
// higher alignment.
|
// higher alignment.
|
||||||
if (IsCode)
|
if (IsCode) {
|
||||||
Alignment = std::max(Alignment, getStubAlignment());
|
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.
|
// Some sections, such as debug info, don't need to be loaded for execution.
|
||||||
// Process those only if explicitly requested.
|
// Process those only if explicitly requested.
|
||||||
@ -771,8 +778,13 @@ RuntimeDyldImpl::emitSection(const ObjectFile &Obj,
|
|||||||
// Fill in any extra bytes we allocated for padding
|
// Fill in any extra bytes we allocated for padding
|
||||||
if (PaddingSize != 0) {
|
if (PaddingSize != 0) {
|
||||||
memset(Addr + DataSize, 0, PaddingSize);
|
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;
|
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
|
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) {
|
} else if (Arch == Triple::arm || Arch == Triple::armeb) {
|
||||||
// TODO: There is only ARM far stub now. We should add the Thumb stub,
|
// TODO: There is only ARM far stub now. We should add the Thumb stub,
|
||||||
// and stubs for branches Thumb - ARM and ARM - Thumb.
|
// 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;
|
return Addr + 4;
|
||||||
} else if (IsMipsO32ABI) {
|
} else if (IsMipsO32ABI) {
|
||||||
// 0: 3c190000 lui t9,%hi(addr).
|
// 0: 3c190000 lui t9,%hi(addr).
|
||||||
@ -971,15 +983,17 @@ Error RuntimeDyldImpl::resolveExternalSymbols() {
|
|||||||
resolveRelocationList(Relocs, 0);
|
resolveRelocationList(Relocs, 0);
|
||||||
} else {
|
} else {
|
||||||
uint64_t Addr = 0;
|
uint64_t Addr = 0;
|
||||||
|
JITSymbolFlags Flags;
|
||||||
RTDyldSymbolTable::const_iterator Loc = GlobalSymbolTable.find(Name);
|
RTDyldSymbolTable::const_iterator Loc = GlobalSymbolTable.find(Name);
|
||||||
if (Loc == GlobalSymbolTable.end()) {
|
if (Loc == GlobalSymbolTable.end()) {
|
||||||
// This is an external symbol, try to get its address from the symbol
|
// This is an external symbol, try to get its address from the symbol
|
||||||
// resolver.
|
// resolver.
|
||||||
// First search for the symbol in this logical dylib.
|
// First search for the symbol in this logical dylib.
|
||||||
if (auto Sym = Resolver.findSymbolInLogicalDylib(Name.data())) {
|
if (auto Sym = Resolver.findSymbolInLogicalDylib(Name.data())) {
|
||||||
if (auto AddrOrErr = Sym.getAddress())
|
if (auto AddrOrErr = Sym.getAddress()) {
|
||||||
Addr = *AddrOrErr;
|
Addr = *AddrOrErr;
|
||||||
else
|
Flags = Sym.getFlags();
|
||||||
|
} else
|
||||||
return AddrOrErr.takeError();
|
return AddrOrErr.takeError();
|
||||||
} else if (auto Err = Sym.takeError())
|
} else if (auto Err = Sym.takeError())
|
||||||
return Err;
|
return Err;
|
||||||
@ -987,9 +1001,10 @@ Error RuntimeDyldImpl::resolveExternalSymbols() {
|
|||||||
// If that fails, try searching for an external symbol.
|
// If that fails, try searching for an external symbol.
|
||||||
if (!Addr) {
|
if (!Addr) {
|
||||||
if (auto Sym = Resolver.findSymbol(Name.data())) {
|
if (auto Sym = Resolver.findSymbol(Name.data())) {
|
||||||
if (auto AddrOrErr = Sym.getAddress())
|
if (auto AddrOrErr = Sym.getAddress()) {
|
||||||
Addr = *AddrOrErr;
|
Addr = *AddrOrErr;
|
||||||
else
|
Flags = Sym.getFlags();
|
||||||
|
} else
|
||||||
return AddrOrErr.takeError();
|
return AddrOrErr.takeError();
|
||||||
} else if (auto Err = Sym.takeError())
|
} else if (auto Err = Sym.takeError())
|
||||||
return Err;
|
return Err;
|
||||||
@ -1007,6 +1022,7 @@ Error RuntimeDyldImpl::resolveExternalSymbols() {
|
|||||||
const auto &SymInfo = Loc->second;
|
const auto &SymInfo = Loc->second;
|
||||||
Addr = getSectionLoadAddress(SymInfo.getSectionID()) +
|
Addr = getSectionLoadAddress(SymInfo.getSectionID()) +
|
||||||
SymInfo.getOffset();
|
SymInfo.getOffset();
|
||||||
|
Flags = SymInfo.getFlags();
|
||||||
}
|
}
|
||||||
|
|
||||||
// FIXME: Implement error handling that doesn't kill the host program!
|
// 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
|
// If Resolver returned UINT64_MAX, the client wants to handle this symbol
|
||||||
// manually and we shouldn't resolve its relocations.
|
// manually and we shouldn't resolve its relocations.
|
||||||
if (Addr != UINT64_MAX) {
|
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"
|
DEBUG(dbgs() << "Resolving relocations Name: " << Name << "\t"
|
||||||
<< format("0x%lx", Addr) << "\n");
|
<< format("0x%lx", Addr) << "\n");
|
||||||
// This list may have been updated when we called getSymbolAddress, so
|
// This list may have been updated when we called getSymbolAddress, so
|
||||||
|
@ -149,8 +149,8 @@ public:
|
|||||||
/// The size of this relocation (MachO specific).
|
/// The size of this relocation (MachO specific).
|
||||||
unsigned Size;
|
unsigned Size;
|
||||||
|
|
||||||
// COFF specific.
|
// ARM (MachO and COFF) specific.
|
||||||
bool IsTargetThumbFunc;
|
bool IsTargetThumbFunc = false;
|
||||||
|
|
||||||
RelocationEntry(unsigned id, uint64_t offset, uint32_t type, int64_t addend)
|
RelocationEntry(unsigned id, uint64_t offset, uint32_t type, int64_t addend)
|
||||||
: SectionID(id), Offset(offset), RelType(type), Addend(addend),
|
: SectionID(id), Offset(offset), RelType(type), Addend(addend),
|
||||||
@ -195,12 +195,14 @@ public:
|
|||||||
uint64_t Offset;
|
uint64_t Offset;
|
||||||
int64_t Addend;
|
int64_t Addend;
|
||||||
const char *SymbolName;
|
const char *SymbolName;
|
||||||
|
bool IsStubThumb = false;
|
||||||
RelocationValueRef() : SectionID(0), Offset(0), Addend(0),
|
RelocationValueRef() : SectionID(0), Offset(0), Addend(0),
|
||||||
SymbolName(nullptr) {}
|
SymbolName(nullptr) {}
|
||||||
|
|
||||||
inline bool operator==(const RelocationValueRef &Other) const {
|
inline bool operator==(const RelocationValueRef &Other) const {
|
||||||
return SectionID == Other.SectionID && Offset == Other.Offset &&
|
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 {
|
inline bool operator<(const RelocationValueRef &Other) const {
|
||||||
if (SectionID != Other.SectionID)
|
if (SectionID != Other.SectionID)
|
||||||
@ -209,6 +211,8 @@ public:
|
|||||||
return Offset < Other.Offset;
|
return Offset < Other.Offset;
|
||||||
if (Addend != Other.Addend)
|
if (Addend != Other.Addend)
|
||||||
return Addend < Other.Addend;
|
return Addend < Other.Addend;
|
||||||
|
if (IsStubThumb != Other.IsStubThumb)
|
||||||
|
return IsStubThumb < Other.IsStubThumb;
|
||||||
return SymbolName < Other.SymbolName;
|
return SymbolName < Other.SymbolName;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -216,21 +220,21 @@ public:
|
|||||||
/// @brief Symbol info for RuntimeDyld.
|
/// @brief Symbol info for RuntimeDyld.
|
||||||
class SymbolTableEntry {
|
class SymbolTableEntry {
|
||||||
public:
|
public:
|
||||||
SymbolTableEntry()
|
SymbolTableEntry() = default;
|
||||||
: Offset(0), SectionID(0) {}
|
|
||||||
|
|
||||||
SymbolTableEntry(unsigned SectionID, uint64_t Offset, JITSymbolFlags Flags)
|
SymbolTableEntry(unsigned SectionID, uint64_t Offset, JITSymbolFlags Flags)
|
||||||
: Offset(Offset), SectionID(SectionID), Flags(Flags) {}
|
: Offset(Offset), SectionID(SectionID), Flags(Flags) {}
|
||||||
|
|
||||||
unsigned getSectionID() const { return SectionID; }
|
unsigned getSectionID() const { return SectionID; }
|
||||||
uint64_t getOffset() const { return Offset; }
|
uint64_t getOffset() const { return Offset; }
|
||||||
|
void setOffset(uint64_t NewOffset) { Offset = NewOffset; }
|
||||||
|
|
||||||
JITSymbolFlags getFlags() const { return Flags; }
|
JITSymbolFlags getFlags() const { return Flags; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
uint64_t Offset;
|
uint64_t Offset = 0;
|
||||||
unsigned SectionID;
|
unsigned SectionID = 0;
|
||||||
JITSymbolFlags Flags;
|
JITSymbolFlags Flags = JITSymbolFlags::None;
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef StringMap<SymbolTableEntry> RTDyldSymbolTable;
|
typedef StringMap<SymbolTableEntry> RTDyldSymbolTable;
|
||||||
@ -365,6 +369,18 @@ protected:
|
|||||||
/// Dst.
|
/// Dst.
|
||||||
void writeBytesUnaligned(uint64_t Value, uint8_t *Dst, unsigned Size) const;
|
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
|
/// \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
|
/// new section for them and update the symbol mappings in the object and
|
||||||
/// symbol table.
|
/// symbol table.
|
||||||
@ -493,6 +509,12 @@ public:
|
|||||||
if (SymEntry.getSectionID() != AbsoluteSymbolSection)
|
if (SymEntry.getSectionID() != AbsoluteSymbolSection)
|
||||||
SectionAddr = getSectionLoadAddress(SymEntry.getSectionID());
|
SectionAddr = getSectionLoadAddress(SymEntry.getSectionID());
|
||||||
uint64_t TargetAddr = SectionAddr + SymEntry.getOffset();
|
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());
|
return JITEvaluatedSymbol(TargetAddr, SymEntry.getFlags());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -55,7 +55,8 @@ Expected<relocation_iterator>
|
|||||||
RuntimeDyldMachO::processScatteredVANILLA(
|
RuntimeDyldMachO::processScatteredVANILLA(
|
||||||
unsigned SectionID, relocation_iterator RelI,
|
unsigned SectionID, relocation_iterator RelI,
|
||||||
const ObjectFile &BaseObjT,
|
const ObjectFile &BaseObjT,
|
||||||
RuntimeDyldMachO::ObjSectionToIDMap &ObjSectionToID) {
|
RuntimeDyldMachO::ObjSectionToIDMap &ObjSectionToID,
|
||||||
|
bool TargetIsLocalThumbFunc) {
|
||||||
const MachOObjectFile &Obj =
|
const MachOObjectFile &Obj =
|
||||||
static_cast<const MachOObjectFile&>(BaseObjT);
|
static_cast<const MachOObjectFile&>(BaseObjT);
|
||||||
MachO::any_relocation_info RE =
|
MachO::any_relocation_info RE =
|
||||||
@ -85,6 +86,7 @@ RuntimeDyldMachO::processScatteredVANILLA(
|
|||||||
|
|
||||||
Addend -= SectionBaseAddr;
|
Addend -= SectionBaseAddr;
|
||||||
RelocationEntry R(SectionID, Offset, RelocType, Addend, IsPCRel, Size);
|
RelocationEntry R(SectionID, Offset, RelocType, Addend, IsPCRel, Size);
|
||||||
|
R.IsTargetThumbFunc = TargetIsLocalThumbFunc;
|
||||||
|
|
||||||
addRelocationForSection(R, TargetSectionID);
|
addRelocationForSection(R, TargetSectionID);
|
||||||
|
|
||||||
|
@ -83,7 +83,8 @@ protected:
|
|||||||
Expected<relocation_iterator>
|
Expected<relocation_iterator>
|
||||||
processScatteredVANILLA(unsigned SectionID, relocation_iterator RelI,
|
processScatteredVANILLA(unsigned SectionID, relocation_iterator RelI,
|
||||||
const ObjectFile &BaseObjT,
|
const ObjectFile &BaseObjT,
|
||||||
RuntimeDyldMachO::ObjSectionToIDMap &ObjSectionToID);
|
RuntimeDyldMachO::ObjSectionToIDMap &ObjSectionToID,
|
||||||
|
bool TargetIsLocalThumbFunc = false);
|
||||||
|
|
||||||
/// Construct a RelocationValueRef representing the relocation target.
|
/// Construct a RelocationValueRef representing the relocation target.
|
||||||
/// For Symbols in known sections, this will return a RelocationValueRef
|
/// For Symbols in known sections, this will return a RelocationValueRef
|
||||||
|
@ -34,7 +34,20 @@ public:
|
|||||||
|
|
||||||
unsigned getStubAlignment() override { return 4; }
|
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];
|
const SectionEntry &Section = Sections[RE.SectionID];
|
||||||
uint8_t *LocalAddress = Section.getAddressWithOffset(RE.Offset);
|
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.
|
// Now we've got the shifted immediate, shift by 2, sign extend and ret.
|
||||||
return SignExtend32<26>(Temp << 2);
|
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());
|
Obj.getRelocation(RelI->getRawDataRefImpl());
|
||||||
uint32_t RelType = Obj.getAnyRelocationType(RelInfo);
|
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 (Obj.isRelocationScattered(RelInfo)) {
|
||||||
if (RelType == MachO::ARM_RELOC_HALF_SECTDIFF)
|
if (RelType == MachO::ARM_RELOC_HALF_SECTDIFF)
|
||||||
return processHALFSECTDIFFRelocation(SectionID, RelI, Obj,
|
return processHALFSECTDIFFRelocation(SectionID, RelI, Obj,
|
||||||
ObjSectionToID);
|
ObjSectionToID);
|
||||||
else if (RelType == MachO::GENERIC_RELOC_VANILLA)
|
else if (RelType == MachO::GENERIC_RELOC_VANILLA)
|
||||||
return processScatteredVANILLA(SectionID, RelI, Obj, ObjSectionToID);
|
return processScatteredVANILLA(SectionID, RelI, Obj, ObjSectionToID,
|
||||||
|
TargetIsLocalThumbFunc);
|
||||||
else
|
else
|
||||||
return ++RelI;
|
return ++RelI;
|
||||||
}
|
}
|
||||||
@ -77,7 +134,6 @@ public:
|
|||||||
UNIMPLEMENTED_RELOC(MachO::ARM_RELOC_SECTDIFF);
|
UNIMPLEMENTED_RELOC(MachO::ARM_RELOC_SECTDIFF);
|
||||||
UNIMPLEMENTED_RELOC(MachO::ARM_RELOC_LOCAL_SECTDIFF);
|
UNIMPLEMENTED_RELOC(MachO::ARM_RELOC_LOCAL_SECTDIFF);
|
||||||
UNIMPLEMENTED_RELOC(MachO::ARM_RELOC_PB_LA_PTR);
|
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_THUMB_32BIT_BRANCH);
|
||||||
UNIMPLEMENTED_RELOC(MachO::ARM_RELOC_HALF);
|
UNIMPLEMENTED_RELOC(MachO::ARM_RELOC_HALF);
|
||||||
default:
|
default:
|
||||||
@ -89,17 +145,30 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
RelocationEntry RE(getRelocationEntry(SectionID, Obj, RelI));
|
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;
|
RelocationValueRef Value;
|
||||||
if (auto ValueOrErr = getRelocationValueRef(Obj, RelI, RE, ObjSectionToID))
|
if (auto ValueOrErr = getRelocationValueRef(Obj, RelI, RE, ObjSectionToID))
|
||||||
Value = *ValueOrErr;
|
Value = *ValueOrErr;
|
||||||
else
|
else
|
||||||
return ValueOrErr.takeError();
|
return ValueOrErr.takeError();
|
||||||
|
|
||||||
if (RE.IsPCRel)
|
// If this is a branch from a thumb function (BR22) then make sure we mark
|
||||||
makeValueAddendPCRel(Value, RelI, 8);
|
// 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.RelType & 0xf) == MachO::ARM_RELOC_BR24)
|
if (RE.IsPCRel)
|
||||||
|
makeValueAddendPCRel(Value, RelI,
|
||||||
|
(RE.RelType == MachO::ARM_THUMB_RELOC_BR22) ? 4 : 8);
|
||||||
|
|
||||||
|
if (RE.RelType == MachO::ARM_RELOC_BR24 ||
|
||||||
|
RE.RelType == MachO::ARM_THUMB_RELOC_BR22)
|
||||||
processBranchRelocation(RE, Value, Stubs);
|
processBranchRelocation(RE, Value, Stubs);
|
||||||
else {
|
else {
|
||||||
RE.Addend = Value.Offset;
|
RE.Addend = Value.Offset;
|
||||||
@ -124,12 +193,30 @@ public:
|
|||||||
Value -= FinalAddress;
|
Value -= FinalAddress;
|
||||||
// ARM PCRel relocations have an effective-PC offset of two instructions
|
// ARM PCRel relocations have an effective-PC offset of two instructions
|
||||||
// (four bytes in Thumb mode, 8 bytes in ARM mode).
|
// (four bytes in Thumb mode, 8 bytes in ARM mode).
|
||||||
// FIXME: For now, assume ARM mode.
|
Value -= (RE.RelType == MachO::ARM_THUMB_RELOC_BR22) ? 4 : 8;
|
||||||
Value -= 8;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (RE.RelType) {
|
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:
|
case MachO::ARM_RELOC_VANILLA:
|
||||||
|
if (RE.IsTargetThumbFunc)
|
||||||
|
Value |= 0x01;
|
||||||
writeBytesUnaligned(Value + RE.Addend, LocalAddress, 1 << RE.Size);
|
writeBytesUnaligned(Value + RE.Addend, LocalAddress, 1 << RE.Size);
|
||||||
break;
|
break;
|
||||||
case MachO::ARM_RELOC_BR24: {
|
case MachO::ARM_RELOC_BR24: {
|
||||||
@ -158,10 +245,19 @@ public:
|
|||||||
Value = SectionABase - SectionBBase + RE.Addend;
|
Value = SectionABase - SectionBBase + RE.Addend;
|
||||||
if (RE.Size & 0x1) // :upper16:
|
if (RE.Size & 0x1) // :upper16:
|
||||||
Value = (Value >> 16);
|
Value = (Value >> 16);
|
||||||
|
|
||||||
|
bool IsThumb = RE.Size & 0x2;
|
||||||
|
|
||||||
Value &= 0xffff;
|
Value &= 0xffff;
|
||||||
|
|
||||||
uint32_t Insn = readBytesUnaligned(LocalAddress, 4);
|
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);
|
writeBytesUnaligned(Insn, LocalAddress, 4);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -196,17 +292,26 @@ private:
|
|||||||
Addr = Section.getAddressWithOffset(i->second);
|
Addr = Section.getAddressWithOffset(i->second);
|
||||||
} else {
|
} else {
|
||||||
// Create a new stub function.
|
// Create a new stub function.
|
||||||
|
assert(Section.getStubOffset() % 4 == 0 && "Misaligned stub");
|
||||||
Stubs[Value] = Section.getStubOffset();
|
Stubs[Value] = Section.getStubOffset();
|
||||||
uint8_t *StubTargetAddr = createStubFunction(
|
uint32_t StubOpcode = 0;
|
||||||
Section.getAddressWithOffset(Section.getStubOffset()));
|
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(
|
RelocationEntry StubRE(
|
||||||
RE.SectionID, StubTargetAddr - Section.getAddress(),
|
RE.SectionID, StubTargetAddr - Section.getAddress(),
|
||||||
MachO::GENERIC_RELOC_VANILLA, Value.Offset, false, 2);
|
MachO::GENERIC_RELOC_VANILLA, Value.Offset, false, 2);
|
||||||
|
StubRE.IsTargetThumbFunc = RE.IsTargetThumbFunc;
|
||||||
if (Value.SymbolName)
|
if (Value.SymbolName)
|
||||||
addRelocationForSymbol(StubRE, Value.SymbolName);
|
addRelocationForSymbol(StubRE, Value.SymbolName);
|
||||||
else
|
else
|
||||||
addRelocationForSection(StubRE, Value.SectionID);
|
addRelocationForSection(StubRE, Value.SectionID);
|
||||||
Addr = Section.getAddressWithOffset(Section.getStubOffset());
|
|
||||||
Section.advanceStubOffset(getMaxStubSize());
|
Section.advanceStubOffset(getMaxStubSize());
|
||||||
}
|
}
|
||||||
RelocationEntry TargetRE(RE.SectionID, RE.Offset, RE.RelType, 0,
|
RelocationEntry TargetRE(RE.SectionID, RE.Offset, RE.RelType, 0,
|
||||||
@ -223,14 +328,12 @@ private:
|
|||||||
MachO::any_relocation_info RE =
|
MachO::any_relocation_info RE =
|
||||||
MachO.getRelocation(RelI->getRawDataRefImpl());
|
MachO.getRelocation(RelI->getRawDataRefImpl());
|
||||||
|
|
||||||
|
|
||||||
// For a half-diff relocation the length bits actually record whether this
|
// For a half-diff relocation the length bits actually record whether this
|
||||||
// is a movw/movt, and whether this is arm or thumb.
|
// is a movw/movt, and whether this is arm or thumb.
|
||||||
// Bit 0 indicates movw (b0 == 0) or movt (b0 == 1).
|
// Bit 0 indicates movw (b0 == 0) or movt (b0 == 1).
|
||||||
// Bit 1 indicates arm (b1 == 0) or thumb (b1 == 1).
|
// Bit 1 indicates arm (b1 == 0) or thumb (b1 == 1).
|
||||||
unsigned HalfDiffKindBits = MachO.getAnyRelocationLength(RE);
|
unsigned HalfDiffKindBits = MachO.getAnyRelocationLength(RE);
|
||||||
if (HalfDiffKindBits & 0x2)
|
bool IsThumb = HalfDiffKindBits & 0x2;
|
||||||
llvm_unreachable("Thumb not yet supported.");
|
|
||||||
|
|
||||||
SectionEntry &Section = Sections[SectionID];
|
SectionEntry &Section = Sections[SectionID];
|
||||||
uint32_t RelocType = MachO.getAnyRelocationType(RE);
|
uint32_t RelocType = MachO.getAnyRelocationType(RE);
|
||||||
@ -238,7 +341,14 @@ private:
|
|||||||
uint64_t Offset = RelI->getOffset();
|
uint64_t Offset = RelI->getOffset();
|
||||||
uint8_t *LocalAddress = Section.getAddressWithOffset(Offset);
|
uint8_t *LocalAddress = Section.getAddressWithOffset(Offset);
|
||||||
int64_t Immediate = readBytesUnaligned(LocalAddress, 4); // Copy the whole instruction out.
|
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;
|
++RelI;
|
||||||
MachO::any_relocation_info RE2 =
|
MachO::any_relocation_info RE2 =
|
||||||
|
@ -0,0 +1,51 @@
|
|||||||
|
# RUN: llvm-mc -triple=thumbv7s-apple-ios7.0.0 -filetype=obj -o %T/MachO_Thumb.o %s
|
||||||
|
# RUN: llvm-rtdyld -triple=thumbv7s-apple-ios7.0.0 -verify -check=%s %/T/MachO_Thumb.o
|
||||||
|
|
||||||
|
.section __TEXT,__text,regular,pure_instructions
|
||||||
|
.syntax unified
|
||||||
|
|
||||||
|
# Add 'aaa' to the common symbols to make sure 'baz' isn't at the start of the
|
||||||
|
# section. This ensures that we test VANILLA relocation addends correctly.
|
||||||
|
.comm aaa, 4, 2
|
||||||
|
.comm baz, 4, 2
|
||||||
|
|
||||||
|
|
||||||
|
.globl bar
|
||||||
|
.p2align 1
|
||||||
|
.code 16 @ @bar
|
||||||
|
.thumb_func bar
|
||||||
|
|
||||||
|
bar:
|
||||||
|
# Check lower 16-bits of section difference relocation
|
||||||
|
# rtdyld-check: decode_operand(insn1, 1) = (foo-(nextPC+8))[15:0]
|
||||||
|
insn1:
|
||||||
|
movw r0, :lower16:(foo-(nextPC+8))
|
||||||
|
# Check upper 16-bits of section difference relocation
|
||||||
|
# rtdyld-check: decode_operand(insn2, 2) = (foo-(nextPC+8))[31:16]
|
||||||
|
insn2:
|
||||||
|
movt r0, :upper16:(foo-(nextPC+8))
|
||||||
|
nextPC:
|
||||||
|
nop
|
||||||
|
|
||||||
|
# Check stub generation for external symbols by referencing a common symbol, 'baz'.
|
||||||
|
# Check both the content of the stub, and the reference to the stub.
|
||||||
|
# Stub should contain '0xf000f8df' (ldr.w pc, [pc]), followed by the target.
|
||||||
|
#
|
||||||
|
# rtdyld-check: *{4}(stub_addr(MachO_Thumb.o, __text, baz)) = 0xf000f8df
|
||||||
|
# rtdyld-check: *{4}(stub_addr(MachO_Thumb.o, __text, baz) + 4) = baz
|
||||||
|
#
|
||||||
|
# rtdyld-check: decode_operand(insn3, 0) = stub_addr(MachO_Thumb.o, __text, baz) - (insn3 + 4)
|
||||||
|
insn3:
|
||||||
|
bl baz
|
||||||
|
|
||||||
|
# Check stub generation for internal symbols by referencing 'bar'.
|
||||||
|
# rtdyld-check: *{4}(stub_addr(MachO_Thumb.o, __text, bar) + 4) = bar & 0xfffffffffffffffe
|
||||||
|
insn4:
|
||||||
|
bl bar
|
||||||
|
|
||||||
|
.section __DATA,__data
|
||||||
|
.align 2
|
||||||
|
foo:
|
||||||
|
.long 0
|
||||||
|
|
||||||
|
.subsections_via_symbols
|
Loading…
x
Reference in New Issue
Block a user