diff options
-rw-r--r-- | lld/COFF/Config.h | 7 | ||||
-rw-r--r-- | lld/COFF/DLL.cpp | 19 | ||||
-rw-r--r-- | lld/COFF/Driver.cpp | 2 | ||||
-rw-r--r-- | lld/COFF/DriverUtils.cpp | 31 | ||||
-rw-r--r-- | lld/test/COFF/export.test | 11 |
5 files changed, 63 insertions, 7 deletions
diff --git a/lld/COFF/Config.h b/lld/COFF/Config.h index 409ede64863..9cfccadba5f 100644 --- a/lld/COFF/Config.h +++ b/lld/COFF/Config.h @@ -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; diff --git a/lld/COFF/DLL.cpp b/lld/COFF/DLL.cpp index cc99f9a2f8d..8f3383d75c7 100644 --- a/lld/COFF/DLL.cpp +++ b/lld/COFF/DLL.cpp @@ -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 diff --git a/lld/COFF/Driver.cpp b/lld/COFF/Driver.cpp index f528dafd985..4cacf0ff552 100644 --- a/lld/COFF/Driver.cpp +++ b/lld/COFF/Driver.cpp @@ -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); diff --git a/lld/COFF/DriverUtils.cpp b/lld/COFF/DriverUtils.cpp index 391a8ab6642..014fee7fefd 100644 --- a/lld/COFF/DriverUtils.cpp +++ b/lld/COFF/DriverUtils.cpp @@ -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; diff --git a/lld/test/COFF/export.test b/lld/test/COFF/export.test index a3ea0ab9bca..abc94de9882 100644 --- a/lld/test/COFF/export.test +++ b/lld/test/COFF/export.test @@ -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 |