[lld] r257243 - COFF: Implement DLL symbol forwarding.

Rui Ueyama via llvm-commits llvm-commits at lists.llvm.org
Fri Jan 8 17:22:00 PST 2016


Author: ruiu
Date: Fri Jan  8 19:22:00 2016
New Revision: 257243

URL: http://llvm.org/viewvc/llvm-project?rev=257243&view=rev
Log:
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.

Modified:
    lld/trunk/COFF/Config.h
    lld/trunk/COFF/DLL.cpp
    lld/trunk/COFF/Driver.cpp
    lld/trunk/COFF/DriverUtils.cpp
    lld/trunk/test/COFF/export.test

Modified: lld/trunk/COFF/Config.h
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/COFF/Config.h?rev=257243&r1=257242&r2=257243&view=diff
==============================================================================
--- lld/trunk/COFF/Config.h (original)
+++ lld/trunk/COFF/Config.h Fri Jan  8 19:22:00 2016
@@ -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;

Modified: lld/trunk/COFF/DLL.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/COFF/DLL.cpp?rev=257243&r1=257242&r2=257243&view=diff
==============================================================================
--- lld/trunk/COFF/DLL.cpp (original)
+++ lld/trunk/COFF/DLL.cpp Fri Jan  8 19:22:00 2016
@@ -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

Modified: lld/trunk/COFF/Driver.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/COFF/Driver.cpp?rev=257243&r1=257242&r2=257243&view=diff
==============================================================================
--- lld/trunk/COFF/Driver.cpp (original)
+++ lld/trunk/COFF/Driver.cpp Fri Jan  8 19:22:00 2016
@@ -586,6 +586,8 @@ void LinkerDriver::link(llvm::ArrayRef<c
 
     // 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);

Modified: lld/trunk/COFF/DriverUtils.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/COFF/DriverUtils.cpp?rev=257243&r1=257242&r2=257243&view=diff
==============================================================================
--- lld/trunk/COFF/DriverUtils.cpp (original)
+++ lld/trunk/COFF/DriverUtils.cpp Fri Jan  8 19:22:00 2016
@@ -321,7 +321,8 @@ void createSideBySideManifest() {
 }
 
 // Parse a string in the form of
-// "<name>[=<internalname>][, at ordinal[,NONAME]][,DATA][,PRIVATE]".
+// "<name>[=<internalname>][, at 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>[, at 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;

Modified: lld/trunk/test/COFF/export.test
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/COFF/export.test?rev=257243&r1=257242&r2=257243&view=diff
==============================================================================
--- lld/trunk/test/COFF/export.test (original)
+++ lld/trunk/test/COFF/export.test Fri Jan  8 19:22:00 2016
@@ -80,3 +80,14 @@ SYMTAB: __imp_exportfn2 in export.test.t
 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




More information about the llvm-commits mailing list