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