<div dir="ltr">What happens if the object file contains 'foo' and '_foo@8' and you /export:foo?<br><div class="gmail_extra"><br><div class="gmail_quote">On Wed, Dec 3, 2014 at 10:09 PM, Rui Ueyama <span dir="ltr"><<a href="mailto:ruiu@google.com" target="_blank">ruiu@google.com</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">Author: ruiu<br>
Date: Thu Dec  4 00:09:39 2014<br>
New Revision: 223341<br>
<br>
URL: <a href="http://llvm.org/viewvc/llvm-project?rev=223341&view=rev" target="_blank">http://llvm.org/viewvc/llvm-project?rev=223341&view=rev</a><br>
Log:<br>
[PECOFF] Improve /export compatibility.<br>
<br>
Looks like the rule of /export is more complicated than<br>
I was thinking. If /export:foo, for example, is given, and<br>
if the actual symbol name in an object file is _foo@<number>,<br>
we need to export that symbol as foo, not as the mangled name.<br>
<br>
If only /export:_foo@<number> is given, the symbol is exported<br>
as _foo@<number>.<br>
<br>
If both /export:foo and /export:_foo@<number> are given,<br>
they are considered as duplicates, and the linker needs to<br>
choose the unmangled name.<br>
<br>
The basic idea seems that the linker needs to export a symbol<br>
with the same name as given as /export.<br>
<br>
We exported mangled symbols. This patch fixes that issue.<br>
<br>
Modified:<br>
    lld/trunk/include/lld/ReaderWriter/PECOFFLinkingContext.h<br>
    lld/trunk/lib/ReaderWriter/PECOFF/EdataPass.cpp<br>
    lld/trunk/lib/ReaderWriter/PECOFF/LinkerGeneratedSymbolFile.h<br>
    lld/trunk/test/pecoff/export.test<br>
<br>
Modified: lld/trunk/include/lld/ReaderWriter/PECOFFLinkingContext.h<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/lld/trunk/include/lld/ReaderWriter/PECOFFLinkingContext.h?rev=223341&r1=223340&r2=223341&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/lld/trunk/include/lld/ReaderWriter/PECOFFLinkingContext.h?rev=223341&r1=223340&r2=223341&view=diff</a><br>
==============================================================================<br>
--- lld/trunk/include/lld/ReaderWriter/PECOFFLinkingContext.h (original)<br>
+++ lld/trunk/include/lld/ReaderWriter/PECOFFLinkingContext.h Thu Dec  4 00:09:39 2014<br>
@@ -65,14 +65,17 @@ public:<br>
       return getExternalName().compare(other.getExternalName()) < 0;<br>
     }<br>
<br>
+    StringRef getRealName() const {<br>
+      return mangledName.empty() ? name : mangledName;<br>
+    }<br>
+<br>
     StringRef getExternalName() const {<br>
-      if (!externalName.empty())<br>
-        return externalName;<br>
-      return name;<br>
+      return externalName.empty() ? name : externalName;<br>
     }<br>
<br>
     std::string name;<br>
     std::string externalName;<br>
+    std::string mangledName;<br>
     int ordinal;<br>
     bool noname;<br>
     bool isData;<br>
<br>
Modified: lld/trunk/lib/ReaderWriter/PECOFF/EdataPass.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/lld/trunk/lib/ReaderWriter/PECOFF/EdataPass.cpp?rev=223341&r1=223340&r2=223341&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/lld/trunk/lib/ReaderWriter/PECOFF/EdataPass.cpp?rev=223341&r1=223340&r2=223341&view=diff</a><br>
==============================================================================<br>
--- lld/trunk/lib/ReaderWriter/PECOFF/EdataPass.cpp (original)<br>
+++ lld/trunk/lib/ReaderWriter/PECOFF/EdataPass.cpp Thu Dec  4 00:09:39 2014<br>
@@ -26,20 +26,54 @@ using llvm::object::export_directory_tab<br>
 namespace lld {<br>
 namespace pecoff {<br>
<br>
+typedef PECOFFLinkingContext::ExportDesc ExportDesc;<br>
+<br>
+// dedupExports removes duplicate export entries. If two exports are<br>
+// referring the same symbol, they are considered duplicates.<br>
+// This could happen if the same symbol name is specified as an argument<br>
+// to /export more than once, or an unmangled and mangled name of the<br>
+// same symbol are given to /export. In the latter case, we choose<br>
+// unmangled (shorter) name.<br>
+static void dedupExports(PECOFFLinkingContext &ctx) {<br>
+  std::vector<ExportDesc> &exports = ctx.getDllExports();<br>
+  // Pass 1: find duplicate entries<br>
+  std::set<const ExportDesc *> dup;<br>
+  std::map<StringRef, ExportDesc *> map;<br>
+  for (ExportDesc &exp : exports) {<br>
+    if (!exp.externalName.empty())<br>
+      continue;;<br></blockquote><div><br></div><div>Extra semi-colon?</div><div> </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
+    StringRef symbol = exp.getRealName();<br>
+    auto it = map.find(symbol);<br>
+    if (it == map.end()) {<br>
+      map[symbol] = &exp;<br>
+    } else if (symbol.size() < it->second->getRealName().size()) {<br>
+      map[symbol] = &exp;<br>
+      dup.insert(it->second);<br>
+    } else {<br>
+      dup.insert(&exp);<br>
+    }<br>
+  }<br>
+  // Pass 2: remove duplicate entries<br>
+  auto pred = [&](const ExportDesc &exp) {<br>
+    return dup.count(&exp) == 1;<br>
+  };<br>
+  exports.erase(std::remove_if(exports.begin(), exports.end(), pred),<br>
+                exports.end());<br>
+}<br>
+<br>
 static void assignOrdinals(PECOFFLinkingContext &ctx) {<br>
-  std::vector<PECOFFLinkingContext::ExportDesc> &exports = ctx.getDllExports();<br>
+  std::vector<ExportDesc> &exports = ctx.getDllExports();<br>
   int maxOrdinal = -1;<br>
-  for (PECOFFLinkingContext::ExportDesc &desc : exports)<br>
+  for (ExportDesc &desc : exports)<br>
     maxOrdinal = std::max(maxOrdinal, desc.ordinal);<br>
<br>
   std::sort(exports.begin(), exports.end(),<br>
-            [](const PECOFFLinkingContext::ExportDesc &a,<br>
-               const PECOFFLinkingContext::ExportDesc &b) {<br>
+            [](const ExportDesc &a, const ExportDesc &b) {<br>
     return a.getExternalName().compare(b.getExternalName()) < 0;<br>
   });<br>
<br>
   int nextOrdinal = (maxOrdinal == -1) ? 1 : (maxOrdinal + 1);<br>
-  for (PECOFFLinkingContext::ExportDesc &desc : exports)<br>
+  for (ExportDesc &desc : exports)<br>
     if (desc.ordinal == -1)<br>
       desc.ordinal = nextOrdinal++;<br>
 }<br>
@@ -51,7 +85,7 @@ static bool getExportedAtoms(PECOFFLinki<br>
     definedAtoms[atom->name()] = atom;<br>
<br>
   for (PECOFFLinkingContext::ExportDesc &desc : ctx.getDllExports()) {<br>
-    auto it = definedAtoms.find(<a href="http://desc.name" target="_blank">desc.name</a>);<br>
+    auto it = definedAtoms.find(desc.getRealName());<br>
     if (it == definedAtoms.end()) {<br>
       llvm::errs() << "Symbol <" << <a href="http://desc.name" target="_blank">desc.name</a><br>
                    << "> is exported but not defined.\n";<br>
@@ -142,6 +176,7 @@ EdataPass::createOrdinalTable(const std:<br>
 }<br>
<br>
 void EdataPass::perform(std::unique_ptr<MutableFile> &file) {<br>
+  dedupExports(_ctx);<br>
   assignOrdinals(_ctx);<br>
<br>
   std::vector<TableEntry> entries;<br>
<br>
Modified: lld/trunk/lib/ReaderWriter/PECOFF/LinkerGeneratedSymbolFile.h<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/lld/trunk/lib/ReaderWriter/PECOFF/LinkerGeneratedSymbolFile.h?rev=223341&r1=223340&r2=223341&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/lld/trunk/lib/ReaderWriter/PECOFF/LinkerGeneratedSymbolFile.h?rev=223341&r1=223340&r2=223341&view=diff</a><br>
==============================================================================<br>
--- lld/trunk/lib/ReaderWriter/PECOFF/LinkerGeneratedSymbolFile.h (original)<br>
+++ lld/trunk/lib/ReaderWriter/PECOFF/LinkerGeneratedSymbolFile.h Thu Dec  4 00:09:39 2014<br>
@@ -261,29 +261,11 @@ public:<br>
     if (!findDecoratedSymbol(_ctx, _syms.get(), sym.str(), replace))<br>
       return nullptr;<br>
<br>
-    // We found a decorated symbol. There may be another symbol that<br>
-    // has the same decorated name. If that's the case, we remove the<br>
-    // duplicate item.<br>
-    std::vector<ExportDesc> &exp = _ctx->getDllExports();<br>
-    auto isFound = std::find_if(<br>
-        exp.begin(), exp.end(),<br>
-        [&](ExportDesc &e) { return e.getExternalName().equals(replace); });<br>
-    if (isFound != exp.end()) {<br>
-      exp.erase(<br>
-          std::remove_if(exp.begin(), exp.end(),<br>
-                         [&](ExportDesc &e) { return <a href="http://e.name" target="_blank">e.name</a> == sym; }),<br>
-          exp.end());<br>
-    } else {<br>
-      for (ExportDesc &e : exp) {<br>
-        if (<a href="http://e.name" target="_blank">e.name</a> == sym) {<br>
-          <a href="http://e.name" target="_blank">e.name</a> = replace;<br>
-          break;<br>
-        }<br>
-      }<br>
-      if (_ctx->deadStrip())<br>
-        _ctx->addDeadStripRoot(_ctx->allocate(replace));<br>
-    }<br>
-<br>
+    for (ExportDesc &exp : _ctx->getDllExports())<br>
+      if (<a href="http://exp.name" target="_blank">exp.name</a> == sym)<br>
+        exp.mangledName = replace;<br>
+    if (_ctx->deadStrip())<br>
+      _ctx->addDeadStripRoot(_ctx->allocate(replace));<br>
     return new (_alloc) impl::SymbolRenameFile(sym, replace);<br>
   }<br>
<br>
<br>
Modified: lld/trunk/test/pecoff/export.test<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/lld/trunk/test/pecoff/export.test?rev=223341&r1=223340&r2=223341&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/lld/trunk/test/pecoff/export.test?rev=223341&r1=223340&r2=223341&view=diff</a><br>
==============================================================================<br>
--- lld/trunk/test/pecoff/export.test (original)<br>
+++ lld/trunk/test/pecoff/export.test Thu Dec  4 00:09:39 2014<br>
@@ -59,30 +59,31 @@ CHECK5-NEXT:        2   0x2010  exportfn<br>
 CHECK6:      Export Table:<br>
 CHECK6:      DLL name: export.test.tmp6.dll<br>
 CHECK6:       Ordinal      RVA  Name<br>
-CHECK6-NEXT:        1   0x2010  ?exportfn8@@YAXXZ<br>
+CHECK6-NEXT:        1   0x2010  exportfn3@256<br>
+CHECK6-NEXT:        2   0x2010  exportfn8<br>
<br>
-# RUN: lld -flavor link /out:%t6.dll /dll /entry:init \<br>
+# RUN: lld -flavor link /out:%t7.dll /dll /entry:init \<br>
 # RUN:   /export:exportfn7 /export:exportfn7@8 \<br>
 # RUN:   /export:exportfn8 /export:exportfn8 /export:exportfn3 -- %t.obj<br>
-# RUN: llvm-objdump -p %t6.dll | FileCheck -check-prefix=DUP %s<br>
+# RUN: llvm-objdump -p %t7.dll | FileCheck -check-prefix=DUP %s<br>
<br>
 DUP:      Export Table:<br>
-DUP:      DLL name: export.test.tmp6.dll<br>
+DUP:      DLL name: export.test.tmp7.dll<br>
 DUP:       Ordinal      RVA  Name<br>
-DUP-NEXT:        1   0x2010  ?exportfn8@@YAXXZ<br>
-DUP-NEXT:        2   0x2010  exportfn3@256<br>
-DUP-NEXT:        3   0x2010  exportfn7@8<br>
+DUP-NEXT:        1   0x2010  exportfn3<br>
+DUP-NEXT:        2   0x2010  exportfn7<br>
+DUP-NEXT:        3   0x2010  exportfn8<br>
 DUP-NOT:  ?exportfn8@@YAXXZ<br>
 DUP-NOT:  exportfn3@256<br>
<br>
 # RUN: yaml2obj %p/Inputs/export.obj.yaml > %t.obj<br>
 #<br>
-# RUN: lld -flavor link /out:%t1.dll /dll /entry:init \<br>
+# RUN: lld -flavor link /out:%t8.dll /dll /entry:init \<br>
 # RUN:   /export:f1=exportfn1 /export:f2@4=exportfn2,private -- %t.obj<br>
-# RUN: llvm-objdump -p %t1.dll | FileCheck -check-prefix=EQUAL %s<br>
+# RUN: llvm-objdump -p %t8.dll | FileCheck -check-prefix=EQUAL %s<br>
<br>
 EQUAL:      Export Table:<br>
-EQUAL:      DLL name: export.test.tmp1.dll<br>
+EQUAL:      DLL name: export.test.tmp8.dll<br>
 EQUAL:       Ordinal      RVA  Name<br>
 EQUAL-NEXT:       1   0x2010  exportfn3@256<br>
 EQUAL-NEXT:       2   0x2008  f1<br>
<br>
<br>
_______________________________________________<br>
llvm-commits mailing list<br>
<a href="mailto:llvm-commits@cs.uiuc.edu">llvm-commits@cs.uiuc.edu</a><br>
<a href="http://lists.cs.uiuc.edu/mailman/listinfo/llvm-commits" target="_blank">http://lists.cs.uiuc.edu/mailman/listinfo/llvm-commits</a><br>
</blockquote></div><br></div></div>