mirror of
https://github.com/capstone-engine/llvm-capstone.git
synced 2025-01-10 18:11:19 +00:00
COFF: Implement DLL symbol forwarding.
DLL export tables usually contain dllexport'ed symbol RVAs so that applications which use the DLLs can find symbols from the DLLs. However, there's a minor feature to "forward" DLL symbols to other DLLs. If you set an RVA to a string whose form is "<dllname>.<symbolname>" (e.g. "KERNEL32.ExitProcess") instead of symbol RVA to the export table, the loader interprets that as a forwarder symbol, and resolve that symbol from the specified DLL. This patch implements that feature. llvm-svn: 257243
This commit is contained in:
parent
22861aeab8
commit
84425d7289
@ -25,6 +25,7 @@ using llvm::COFF::WindowsSubsystem;
|
||||
using llvm::StringRef;
|
||||
class DefinedAbsolute;
|
||||
class DefinedRelative;
|
||||
class StringChunk;
|
||||
class Undefined;
|
||||
|
||||
// Short aliases.
|
||||
@ -42,6 +43,12 @@ struct Export {
|
||||
bool Data = false;
|
||||
bool Private = false;
|
||||
|
||||
// If an export is a form of /export:foo=dllname.bar, that means
|
||||
// that foo should be exported as an alias to bar in the DLL.
|
||||
// ForwardTo is set to "dllname.bar" part. Usually empty.
|
||||
StringRef ForwardTo;
|
||||
StringChunk *ForwardChunk = nullptr;
|
||||
|
||||
// True if this /export option was in .drectves section.
|
||||
bool Directives = false;
|
||||
StringRef SymbolName;
|
||||
|
@ -320,8 +320,12 @@ public:
|
||||
|
||||
void writeTo(uint8_t *Buf) const override {
|
||||
for (Export &E : Config->Exports) {
|
||||
auto *D = cast<Defined>(E.Sym->repl());
|
||||
write32le(Buf + OutputSectionOff + E.Ordinal * 4, D->getRVA());
|
||||
uint8_t *P = Buf + OutputSectionOff + E.Ordinal * 4;
|
||||
if (E.ForwardChunk) {
|
||||
write32le(P, E.ForwardChunk->getRVA());
|
||||
} else {
|
||||
write32le(P, cast<Defined>(E.Sym->repl())->getRVA());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -539,6 +543,15 @@ EdataContents::EdataContents() {
|
||||
for (Export &E : Config->Exports)
|
||||
if (!E.Noname)
|
||||
Names.push_back(new StringChunk(E.ExportName));
|
||||
|
||||
std::vector<Chunk *> Forwards;
|
||||
for (Export &E : Config->Exports) {
|
||||
if (E.ForwardTo.empty())
|
||||
continue;
|
||||
E.ForwardChunk = new StringChunk(E.ForwardTo);
|
||||
Forwards.push_back(E.ForwardChunk);
|
||||
}
|
||||
|
||||
auto *NameTab = new NamePointersChunk(Names);
|
||||
auto *OrdinalTab = new ExportOrdinalChunk(Names.size());
|
||||
auto *Dir = new ExportDirectoryChunk(MaxOrdinal, Names.size(), DLLName,
|
||||
@ -550,6 +563,8 @@ EdataContents::EdataContents() {
|
||||
Chunks.push_back(std::unique_ptr<Chunk>(OrdinalTab));
|
||||
for (Chunk *C : Names)
|
||||
Chunks.push_back(std::unique_ptr<Chunk>(C));
|
||||
for (Chunk *C : Forwards)
|
||||
Chunks.push_back(std::unique_ptr<Chunk>(C));
|
||||
}
|
||||
|
||||
} // namespace coff
|
||||
|
@ -586,6 +586,8 @@ void LinkerDriver::link(llvm::ArrayRef<const char *> ArgsArr) {
|
||||
|
||||
// Windows specific -- Make sure we resolve all dllexported symbols.
|
||||
for (Export &E : Config->Exports) {
|
||||
if (!E.ForwardTo.empty())
|
||||
continue;
|
||||
E.Sym = addUndefined(E.Name);
|
||||
if (!E.Directives)
|
||||
Symtab.mangleMaybe(E.Sym);
|
||||
|
@ -321,7 +321,8 @@ void createSideBySideManifest() {
|
||||
}
|
||||
|
||||
// Parse a string in the form of
|
||||
// "<name>[=<internalname>][,@ordinal[,NONAME]][,DATA][,PRIVATE]".
|
||||
// "<name>[=<internalname>][,@ordinal[,NONAME]][,DATA][,PRIVATE]"
|
||||
// or "<name>=<dllname>.<name>".
|
||||
// Used for parsing /export arguments.
|
||||
Export parseExport(StringRef Arg) {
|
||||
Export E;
|
||||
@ -329,12 +330,25 @@ Export parseExport(StringRef Arg) {
|
||||
std::tie(E.Name, Rest) = Arg.split(",");
|
||||
if (E.Name.empty())
|
||||
goto err;
|
||||
|
||||
if (E.Name.find('=') != StringRef::npos) {
|
||||
std::tie(E.ExtName, E.Name) = E.Name.split("=");
|
||||
StringRef X, Y;
|
||||
std::tie(X, Y) = E.Name.split("=");
|
||||
|
||||
// If "<name>=<dllname>.<name>".
|
||||
if (Y.find(".") != StringRef::npos) {
|
||||
E.Name = X;
|
||||
E.ForwardTo = Y;
|
||||
return E;
|
||||
}
|
||||
|
||||
E.ExtName = X;
|
||||
E.Name = Y;
|
||||
if (E.Name.empty())
|
||||
goto err;
|
||||
}
|
||||
|
||||
// If "<name>=<internalname>[,@ordinal[,NONAME]][,DATA][,PRIVATE]"
|
||||
while (!Rest.empty()) {
|
||||
StringRef Tok;
|
||||
std::tie(Tok, Rest) = Rest.split(",");
|
||||
@ -388,15 +402,22 @@ void fixupExports() {
|
||||
}
|
||||
|
||||
for (Export &E : Config->Exports) {
|
||||
if (Undefined *U = cast_or_null<Undefined>(E.Sym->WeakAlias)) {
|
||||
if (!E.ForwardTo.empty()) {
|
||||
E.SymbolName = E.Name;
|
||||
} else if (Undefined *U = cast_or_null<Undefined>(E.Sym->WeakAlias)) {
|
||||
E.SymbolName = U->getName();
|
||||
} else {
|
||||
E.SymbolName = E.Sym->getName();
|
||||
}
|
||||
}
|
||||
|
||||
for (Export &E : Config->Exports)
|
||||
E.ExportName = undecorate(E.ExtName.empty() ? E.Name : E.ExtName);
|
||||
for (Export &E : Config->Exports) {
|
||||
if (!E.ForwardTo.empty()) {
|
||||
E.ExportName = undecorate(E.Name);
|
||||
} else {
|
||||
E.ExportName = undecorate(E.ExtName.empty() ? E.Name : E.ExtName);
|
||||
}
|
||||
}
|
||||
|
||||
// Uniquefy by name.
|
||||
std::map<StringRef, Export *> Map;
|
||||
|
@ -80,3 +80,14 @@ SYMTAB: __imp_exportfn2 in export.test.tmp.DLL
|
||||
SYMTAB: exportfn2 in export.test.tmp.DLL
|
||||
SYMTAB: __imp_exportfn3 in export.test.tmp.DLL
|
||||
SYMTAB: exportfn3 in export.test.tmp.DLL
|
||||
|
||||
# RUN: lld-link /out:%t.dll /dll %t.obj /export:foo=kernel32.foobar
|
||||
# RUN: llvm-objdump -p %t.dll | FileCheck -check-prefix=FORWARDER %s
|
||||
|
||||
FORWARDER: Export Table:
|
||||
FORWARDER: DLL name: export.test.tmp.dll
|
||||
FORWARDER: Ordinal base: 0
|
||||
FORWARDER: Ordinal RVA Name
|
||||
FORWARDER: 0 0
|
||||
FORWARDER: 1 0x1010 exportfn
|
||||
FORWARDER: 2 0x2062 foo
|
||||
|
Loading…
Reference in New Issue
Block a user