Skip to content

Commit

Permalink
[RuntimeDyld][COFF] Build stubs for COFF dllimport symbols.
Browse files Browse the repository at this point in the history
Summary:
Enables JIT-linking by RuntimeDyld of COFF objects that contain references to
dllimport symbols. This is done by recognizing symbols that start with the
reserved "__imp_" prefix and building a pointer entry to the target symbol in
the stubs area of the section. References to the "__imp_" symbol are updated to
point to this pointer.

Work in progress: The generic code is in place, but only RuntimeDyldCOFFX86_64
and RuntimeDyldCOFFI386 have been updated to look for and update references to
dllimport symbols.

Reviewers: compnerd

Subscribers: hiraditya, ributzka, llvm-commits

Tags: #llvm

Differential Revision: https://reviews.llvm.org/D75884
  • Loading branch information
lhames committed Mar 10, 2020
1 parent aed5712 commit 337e131
Show file tree
Hide file tree
Showing 10 changed files with 221 additions and 127 deletions.
36 changes: 36 additions & 0 deletions llvm/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldCOFF.cpp
Expand Up @@ -18,6 +18,7 @@
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/Triple.h"
#include "llvm/Object/ObjectFile.h"
#include "llvm/Support/FormatVariadic.h"

using namespace llvm;
using namespace llvm::object;
Expand Down Expand Up @@ -78,6 +79,41 @@ uint64_t RuntimeDyldCOFF::getSymbolOffset(const SymbolRef &Sym) {
return Sym.getValue();
}

uint64_t RuntimeDyldCOFF::getDLLImportOffset(unsigned SectionID, StubMap &Stubs,
StringRef Name,
bool SetSectionIDMinus1) {
LLVM_DEBUG(dbgs() << "Getting DLLImport entry for " << Name << "... ");
assert(Name.startswith(getImportSymbolPrefix()) && "Not a DLLImport symbol?");
RelocationValueRef Reloc;
Reloc.SymbolName = Name.data();
auto I = Stubs.find(Reloc);
if (I != Stubs.end()) {
LLVM_DEBUG(dbgs() << format("{0:x8}", I->second) << "\n");
return I->second;
}

assert(SectionID < Sections.size() && "SectionID out of range");
auto &Sec = Sections[SectionID];
auto EntryOffset = alignTo(Sec.getStubOffset(), PointerSize);
Sec.advanceStubOffset(EntryOffset + PointerSize - Sec.getStubOffset());
Stubs[Reloc] = EntryOffset;

RelocationEntry RE(SectionID, EntryOffset, PointerReloc, 0, false,
Log2_64(PointerSize));
// Hack to tell I386/Thumb resolveRelocation that this isn't section relative.
if (SetSectionIDMinus1)
RE.Sections.SectionA = -1;
addRelocationForSymbol(RE, Name.drop_front(getImportSymbolPrefix().size()));

LLVM_DEBUG({
dbgs() << "Creating entry at "
<< formatv("{0:x16} + {1:x8} ( {2:x16} )", Sec.getLoadAddress(),
EntryOffset, Sec.getLoadAddress() + EntryOffset)
<< "\n";
});
return EntryOffset;
}

bool RuntimeDyldCOFF::isCompatibleFile(const object::ObjectFile &Obj) const {
return Obj.isCOFF();
}
Expand Down
17 changes: 15 additions & 2 deletions llvm/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldCOFF.h
Expand Up @@ -36,9 +36,22 @@ class RuntimeDyldCOFF : public RuntimeDyldImpl {

protected:
RuntimeDyldCOFF(RuntimeDyld::MemoryManager &MemMgr,
JITSymbolResolver &Resolver)
: RuntimeDyldImpl(MemMgr, Resolver) {}
JITSymbolResolver &Resolver, unsigned PointerSize,
uint32_t PointerReloc)
: RuntimeDyldImpl(MemMgr, Resolver), PointerSize(PointerSize),
PointerReloc(PointerReloc) {
assert((PointerSize == 4 || PointerSize == 8) && "Unexpected pointer size");
}

uint64_t getSymbolOffset(const SymbolRef &Sym);
uint64_t getDLLImportOffset(unsigned SectionID, StubMap &Stubs,
StringRef Name, bool SetSectionIDMinus1 = false);

static constexpr StringRef getImportSymbolPrefix() { return "__imp_"; }

private:
unsigned PointerSize;
uint32_t PointerReloc;
};

} // end namespace llvm
Expand Down
10 changes: 4 additions & 6 deletions llvm/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldImpl.h
Expand Up @@ -191,13 +191,11 @@ class RelocationEntry {

class RelocationValueRef {
public:
unsigned SectionID;
uint64_t Offset;
int64_t Addend;
const char *SymbolName;
unsigned SectionID = 0;
uint64_t Offset = 0;
int64_t Addend = 0;
const char *SymbolName = nullptr;
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 &&
Expand Down
Expand Up @@ -89,7 +89,8 @@ class RuntimeDyldCOFFAArch64 : public RuntimeDyldCOFF {
public:
RuntimeDyldCOFFAArch64(RuntimeDyld::MemoryManager &MM,
JITSymbolResolver &Resolver)
: RuntimeDyldCOFF(MM, Resolver), ImageBase(0) {}
: RuntimeDyldCOFF(MM, Resolver, 8, COFF::IMAGE_REL_ARM64_ADDR64),
ImageBase(0) {}

unsigned getStubAlignment() override { return 8; }

Expand Down Expand Up @@ -161,14 +162,32 @@ class RuntimeDyldCOFFAArch64 : public RuntimeDyldCOFF {
uint64_t Offset = RelI->getOffset();

// If there is no section, this must be an external reference.
const bool IsExtern = Section == Obj.section_end();
bool IsExtern = Section == Obj.section_end();

// Determine the Addend used to adjust the relocation value.
uint64_t Addend = 0;
SectionEntry &AddendSection = Sections[SectionID];
uintptr_t ObjTarget = AddendSection.getObjAddress() + Offset;
uint8_t *Displacement = (uint8_t *)ObjTarget;

unsigned TargetSectionID = -1;
uint64_t TargetOffset = -1;

if (TargetName.startswith(getImportSymbolPrefix())) {
TargetSectionID = SectionID;
TargetOffset = getDLLImportOffset(SectionID, Stubs, TargetName);
TargetName = StringRef();
IsExtern = false;
} else if (!IsExtern) {
if (auto TargetSectionIDOrErr = findOrEmitSection(
Obj, *Section, Section->isText(), ObjSectionToID))
TargetSectionID = *TargetSectionIDOrErr;
else
return TargetSectionIDOrErr.takeError();

TargetOffset = getSymbolOffset(*Symbol);
}

switch (RelType) {
case COFF::IMAGE_REL_ARM64_ADDR32:
case COFF::IMAGE_REL_ARM64_ADDR32NB:
Expand Down Expand Up @@ -224,18 +243,10 @@ class RuntimeDyldCOFFAArch64 : public RuntimeDyldCOFF {
<< TargetName << " Addend " << Addend << "\n");
#endif

unsigned TargetSectionID = -1;
if (IsExtern) {
RelocationEntry RE(SectionID, Offset, RelType, Addend);
addRelocationForSymbol(RE, TargetName);
} else {
if (auto TargetSectionIDOrErr = findOrEmitSection(
Obj, *Section, Section->isText(), ObjSectionToID)) {
TargetSectionID = *TargetSectionIDOrErr;
} else
return TargetSectionIDOrErr.takeError();

uint64_t TargetOffset = getSymbolOffset(*Symbol);
RelocationEntry RE(SectionID, Offset, RelType, TargetOffset + Addend);
addRelocationForSection(RE, TargetSectionID);
}
Expand Down
35 changes: 23 additions & 12 deletions llvm/lib/ExecutionEngine/RuntimeDyld/Targets/RuntimeDyldCOFFI386.h
Expand Up @@ -25,7 +25,7 @@ class RuntimeDyldCOFFI386 : public RuntimeDyldCOFF {
public:
RuntimeDyldCOFFI386(RuntimeDyld::MemoryManager &MM,
JITSymbolResolver &Resolver)
: RuntimeDyldCOFF(MM, Resolver) {}
: RuntimeDyldCOFF(MM, Resolver, 4, COFF::IMAGE_REL_I386_DIR32) {}

unsigned getMaxStubSize() const override {
return 8; // 2-byte jmp instruction + 32-bit relative address + 2 byte pad
Expand Down Expand Up @@ -53,10 +53,28 @@ class RuntimeDyldCOFFI386 : public RuntimeDyldCOFF {
if (!SectionOrErr)
return SectionOrErr.takeError();
auto Section = *SectionOrErr;
bool IsExtern = Section == Obj.section_end();

uint64_t RelType = RelI->getType();
uint64_t Offset = RelI->getOffset();

unsigned TargetSectionID = -1;
uint64_t TargetOffset = -1;
if (TargetName.startswith(getImportSymbolPrefix())) {
TargetSectionID = SectionID;
TargetOffset = getDLLImportOffset(SectionID, Stubs, TargetName, true);
TargetName = StringRef();
IsExtern = false;
} else if (!IsExtern) {
if (auto TargetSectionIDOrErr = findOrEmitSection(
Obj, *Section, Section->isText(), ObjSectionToID))
TargetSectionID = *TargetSectionIDOrErr;
else
return TargetSectionIDOrErr.takeError();
if (RelType != COFF::IMAGE_REL_I386_SECTION)
TargetOffset = getSymbolOffset(*Symbol);
}

// Determine the Addend used to adjust the relocation value.
uint64_t Addend = 0;
SectionEntry &AddendSection = Sections[SectionID];
Expand All @@ -83,16 +101,10 @@ class RuntimeDyldCOFFI386 : public RuntimeDyldCOFF {
<< " RelType: " << RelTypeName << " TargetName: "
<< TargetName << " Addend " << Addend << "\n");

unsigned TargetSectionID = -1;
if (Section == Obj.section_end()) {
if (IsExtern) {
RelocationEntry RE(SectionID, Offset, RelType, 0, -1, 0, 0, 0, false, 0);
addRelocationForSymbol(RE, TargetName);
} else {
if (auto TargetSectionIDOrErr =
findOrEmitSection(Obj, *Section, Section->isText(), ObjSectionToID))
TargetSectionID = *TargetSectionIDOrErr;
else
return TargetSectionIDOrErr.takeError();

switch (RelType) {
case COFF::IMAGE_REL_I386_ABSOLUTE:
Expand All @@ -103,7 +115,7 @@ class RuntimeDyldCOFFI386 : public RuntimeDyldCOFF {
case COFF::IMAGE_REL_I386_REL32: {
RelocationEntry RE =
RelocationEntry(SectionID, Offset, RelType, Addend, TargetSectionID,
getSymbolOffset(*Symbol), 0, 0, false, 0);
TargetOffset, 0, 0, false, 0);
addRelocationForSection(RE, TargetSectionID);
break;
}
Expand All @@ -114,15 +126,14 @@ class RuntimeDyldCOFFI386 : public RuntimeDyldCOFF {
break;
}
case COFF::IMAGE_REL_I386_SECREL: {
RelocationEntry RE = RelocationEntry(SectionID, Offset, RelType,
getSymbolOffset(*Symbol) + Addend);
RelocationEntry RE =
RelocationEntry(SectionID, Offset, RelType, TargetOffset + Addend);
addRelocationForSection(RE, TargetSectionID);
break;
}
default:
llvm_unreachable("unsupported relocation type");
}

}

return ++RelI;
Expand Down
47 changes: 29 additions & 18 deletions llvm/lib/ExecutionEngine/RuntimeDyld/Targets/RuntimeDyldCOFFThumb.h
Expand Up @@ -48,7 +48,7 @@ class RuntimeDyldCOFFThumb : public RuntimeDyldCOFF {
public:
RuntimeDyldCOFFThumb(RuntimeDyld::MemoryManager &MM,
JITSymbolResolver &Resolver)
: RuntimeDyldCOFF(MM, Resolver) {}
: RuntimeDyldCOFF(MM, Resolver, 4, COFF::IMAGE_REL_ARM_ADDR32) {}

unsigned getMaxStubSize() const override {
return 16; // 8-byte load instructions, 4-byte jump, 4-byte padding
Expand Down Expand Up @@ -103,16 +103,29 @@ class RuntimeDyldCOFFThumb : public RuntimeDyldCOFF {
<< " RelType: " << RelTypeName << " TargetName: "
<< TargetName << " Addend " << Addend << "\n");

bool IsExtern = Section == Obj.section_end();
unsigned TargetSectionID = -1;
if (Section == Obj.section_end()) {
RelocationEntry RE(SectionID, Offset, RelType, 0, -1, 0, 0, 0, false, 0);
addRelocationForSymbol(RE, TargetName);
} else {
uint64_t TargetOffset = -1;

if (TargetName.startswith(getImportSymbolPrefix())) {
TargetSectionID = SectionID;
TargetOffset = getDLLImportOffset(SectionID, Stubs, TargetName, true);
TargetName = StringRef();
IsExtern = false;
} else if (!IsExtern) {
if (auto TargetSectionIDOrErr =
findOrEmitSection(Obj, *Section, Section->isText(), ObjSectionToID))
TargetSectionID = *TargetSectionIDOrErr;
else
return TargetSectionIDOrErr.takeError();
if (RelType != COFF::IMAGE_REL_ARM_SECTION)
TargetOffset = getSymbolOffset(*Symbol);
}

if (IsExtern) {
RelocationEntry RE(SectionID, Offset, RelType, 0, -1, 0, 0, 0, false, 0);
addRelocationForSymbol(RE, TargetName);
} else {

// 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
Expand All @@ -124,16 +137,16 @@ class RuntimeDyldCOFFThumb : public RuntimeDyldCOFF {
// This relocation is ignored.
break;
case COFF::IMAGE_REL_ARM_ADDR32: {
RelocationEntry RE = RelocationEntry(
SectionID, Offset, RelType, Addend, TargetSectionID,
getSymbolOffset(*Symbol), 0, 0, false, 0, IsTargetThumbFunc);
RelocationEntry RE =
RelocationEntry(SectionID, Offset, RelType, Addend, TargetSectionID,
TargetOffset, 0, 0, false, 0, IsTargetThumbFunc);
addRelocationForSection(RE, TargetSectionID);
break;
}
case COFF::IMAGE_REL_ARM_ADDR32NB: {
RelocationEntry RE =
RelocationEntry(SectionID, Offset, RelType, Addend, TargetSectionID,
getSymbolOffset(*Symbol), 0, 0, false, 0);
TargetOffset, 0, 0, false, 0);
addRelocationForSection(RE, TargetSectionID);
break;
}
Expand All @@ -144,24 +157,23 @@ class RuntimeDyldCOFFThumb : public RuntimeDyldCOFF {
break;
}
case COFF::IMAGE_REL_ARM_SECREL: {
RelocationEntry RE = RelocationEntry(SectionID, Offset, RelType,
getSymbolOffset(*Symbol) + Addend);
RelocationEntry RE =
RelocationEntry(SectionID, Offset, RelType, TargetOffset + Addend);
addRelocationForSection(RE, TargetSectionID);
break;
}
case COFF::IMAGE_REL_ARM_MOV32T: {
RelocationEntry RE = RelocationEntry(
SectionID, Offset, RelType, Addend, TargetSectionID,
getSymbolOffset(*Symbol), 0, 0, false, 0, IsTargetThumbFunc);
RelocationEntry RE =
RelocationEntry(SectionID, Offset, RelType, Addend, TargetSectionID,
TargetOffset, 0, 0, false, 0, IsTargetThumbFunc);
addRelocationForSection(RE, TargetSectionID);
break;
}
case COFF::IMAGE_REL_ARM_BRANCH20T:
case COFF::IMAGE_REL_ARM_BRANCH24T:
case COFF::IMAGE_REL_ARM_BLX23T: {
RelocationEntry RE =
RelocationEntry(SectionID, Offset, RelType,
getSymbolOffset(*Symbol) + Addend, true, 0);
RelocationEntry RE = RelocationEntry(SectionID, Offset, RelType,
TargetOffset + Addend, true, 0);
addRelocationForSection(RE, TargetSectionID);
break;
}
Expand Down Expand Up @@ -256,7 +268,6 @@ class RuntimeDyldCOFFThumb : public RuntimeDyldCOFF {
EncodeImmediate(&Target[0],
(static_cast<uint32_t>(Result) >> 00) | ISASelectionBit);
EncodeImmediate(&Target[4], static_cast<uint32_t>(Result) >> 16);

break;
}
case COFF::IMAGE_REL_ARM_BRANCH20T: {
Expand Down

0 comments on commit 337e131

Please sign in to comment.