[lld] r208754 - [PECOFF] Find symbols with @number suffix for dllexported symbols
Rui Ueyama
ruiu at google.com
Tue May 13 23:29:33 PDT 2014
Author: ruiu
Date: Wed May 14 01:29:32 2014
New Revision: 208754
URL: http://llvm.org/viewvc/llvm-project?rev=208754&view=rev
Log:
[PECOFF] Find symbols with @number suffix for dllexported symbols
As written in the comment in this patch, symbol names specified with
/export option is resolved in a special way; for /export:foo, linker
finds a foo@<number> symbol if such symbols exists.
On Windows, a function in stdcall calling convention is mangled with
a leading underscore and following "@" and numbers. This name
mangling is kind of automatic, so you can sometimes omit _ and @number
when specifying a symbol. /export option is that case.
Previously, if a file in an archive file foo.lib provides a symbol
_fn at 8, and /export:fn is specified, LLD failed to resolve the symbol.
It only tried to find _fn, and failed to find _fn at 8. With this patch,
_fn at 8 will be searched on the second iteration.
Differential Revision: http://reviews.llvm.org/D3736
Modified:
lld/trunk/lib/ReaderWriter/PECOFF/LinkerGeneratedSymbolFile.h
lld/trunk/lib/ReaderWriter/PECOFF/PECOFFLinkingContext.cpp
lld/trunk/test/pecoff/Inputs/export.obj.yaml
lld/trunk/test/pecoff/export.test
Modified: lld/trunk/lib/ReaderWriter/PECOFF/LinkerGeneratedSymbolFile.h
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/lib/ReaderWriter/PECOFF/LinkerGeneratedSymbolFile.h?rev=208754&r1=208753&r2=208754&view=diff
==============================================================================
--- lld/trunk/lib/ReaderWriter/PECOFF/LinkerGeneratedSymbolFile.h (original)
+++ lld/trunk/lib/ReaderWriter/PECOFF/LinkerGeneratedSymbolFile.h Wed May 14 01:29:32 2014
@@ -14,6 +14,8 @@
#include "lld/ReaderWriter/Simple.h"
#include "llvm/Support/Allocator.h"
+#include <mutex>
+
namespace lld {
namespace pecoff {
@@ -86,6 +88,22 @@ private:
atom_collection_vector<AbsoluteAtom> _absoluteAtoms;
};
+// A file to make Resolver to resolve a symbol TO instead of a symbol FROM,
+// using fallback mechanism for an undefined symbol. One can virtually rename an
+// undefined symbol using this file.
+class SymbolRenameFile : public SimpleFile {
+public:
+ SymbolRenameFile(StringRef from, StringRef to)
+ : SimpleFile("<symbol-rename>"), _to(*this, to),
+ _from(*this, from, &_to) {
+ addAtom(_from);
+ };
+
+private:
+ COFFUndefinedAtom _to;
+ COFFUndefinedAtom _from;
+};
+
} // anonymous namespace
// A virtual file containing absolute symbol __ImageBase. __ImageBase (or
@@ -141,5 +159,94 @@ private:
mutable llvm::BumpPtrAllocator _alloc;
};
+// A ExportedSymbolRenameFile is a virtual archive file for dllexported symbols.
+//
+// One usually has to specify the exact symbol name to resolve it. That's true
+// in most cases for PE/COFF, except the one described below.
+//
+// DLLExported symbols can be specified using a module definition file. In a
+// file, one can write an EXPORT directive followed by symbol names. Such
+// symbols may not be fully decorated -- one can omit "@" and the following
+// number suffix for the stdcall function.
+//
+// If a symbol FOO is specified to be dllexported by a module definition file,
+// linker has to search not only for FOO but also for FOO@[0-9]+. This ambiguous
+// matching semantics does not fit well with Resolver.
+//
+// We could probably modify Resolver to resolve ambiguous symbols, but I think
+// we don't want to do that because it'd be rarely used, and only this Windows
+// specific feature would use it. It's probably not a good idea to make the core
+// linker to be able to deal with it.
+//
+// So, instead of tweaking Resolver, we chose to do some hack here. An
+// ExportedSymbolRenameFile maintains a set containing all possibly defined
+// symbol names. That set would be a union of (1) all the defined symbols that
+// are already parsed and read and (2) all the defined symbols in archive files
+// that are not yet be parsed.
+//
+// If Resolver asks this file to return an atom for a dllexported symbol, find()
+// looks up the set, doing ambiguous matching. If there's a symbol with @
+// prefix, it returns an atom to rename the dllexported symbol, hoping that
+// Resolver will find the new symbol with atsign from an archive file at the
+// next visit.
+class ExportedSymbolRenameFile : public VirtualArchiveLibraryFile {
+public:
+ ExportedSymbolRenameFile(const PECOFFLinkingContext &ctx)
+ : VirtualArchiveLibraryFile("<export>") {
+ for (const PECOFFLinkingContext::ExportDesc &desc : ctx.getDllExports())
+ _exportedSyms.insert(desc.name);
+ }
+
+ void addResolvableSymbols(File *file) {
+ std::lock_guard<std::mutex> lock(_mutex);
+ if (_seen.count(file) > 0)
+ return;
+ _seen.insert(file);
+ if (auto *archive = dyn_cast<ArchiveLibraryFile>(file)) {
+ for (const std::string &sym : archive->getDefinedSymbols())
+ _defined.insert(sym);
+ return;
+ }
+ for (const DefinedAtom *atom : file->defined())
+ if (!atom->name().empty())
+ _defined.insert(atom->name());
+ }
+
+ const File *find(StringRef sym, bool dataSymbolOnly) const override {
+ if (_exportedSyms.count(sym) == 0)
+ return nullptr;
+ std::string replace;
+ if (!findSymbolWithAtsignSuffix(sym.str(), replace))
+ return nullptr;
+ return new (_alloc) SymbolRenameFile(sym, replace);
+ }
+
+private:
+ // Find a symbol that starts with a given symbol name followed
+ // by @number suffix.
+ bool findSymbolWithAtsignSuffix(std::string sym, std::string &res) const {
+ sym.append("@");
+ auto it = _defined.lower_bound(sym);
+ for (auto e = _defined.end(); it != e; ++it) {
+ if (!StringRef(*it).startswith(sym))
+ return false;
+ if (it->size() == sym.size())
+ continue;
+ StringRef suffix = it->substr(sym.size());
+ if (suffix.find_first_not_of("0123456789") != StringRef::npos)
+ continue;
+ res = *it;
+ return true;
+ }
+ return false;
+ }
+
+ std::set<std::string> _exportedSyms;
+ std::set<std::string> _defined;
+ std::set<File *> _seen;
+ mutable std::mutex _mutex;
+ mutable llvm::BumpPtrAllocator _alloc;
+};
+
} // end namespace pecoff
} // end namespace lld
Modified: lld/trunk/lib/ReaderWriter/PECOFF/PECOFFLinkingContext.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/lib/ReaderWriter/PECOFF/PECOFFLinkingContext.cpp?rev=208754&r1=208753&r2=208754&view=diff
==============================================================================
--- lld/trunk/lib/ReaderWriter/PECOFF/PECOFFLinkingContext.cpp (original)
+++ lld/trunk/lib/ReaderWriter/PECOFF/PECOFFLinkingContext.cpp Wed May 14 01:29:32 2014
@@ -101,8 +101,23 @@ std::unique_ptr<File> PECOFFLinkingConte
"<command line option /include>");
}
+namespace {
+// As per policy, we cannot use std::function.
+class ObserverCallback {
+public:
+ explicit ObserverCallback(pecoff::ExportedSymbolRenameFile *f)
+ : _renameFile(f) {}
+
+ void operator()(File *file) { _renameFile->addResolvableSymbols(file); }
+
+private:
+ pecoff::ExportedSymbolRenameFile *_renameFile;
+};
+} // end anonymous namespace
+
bool PECOFFLinkingContext::createImplicitFiles(
- std::vector<std::unique_ptr<File> > &) const {
+ std::vector<std::unique_ptr<File>> &) const {
+ // Create a file for __ImageBase.
std::unique_ptr<SimpleFileNode> fileNode(
new SimpleFileNode("Implicit Files"));
std::unique_ptr<File> linkerGeneratedSymFile(
@@ -111,11 +126,21 @@ bool PECOFFLinkingContext::createImplici
getInputGraph().insertElementAt(std::move(fileNode),
InputGraph::Position::END);
+ // Create a file for _imp_ symbols.
std::unique_ptr<SimpleFileNode> impFileNode(new SimpleFileNode("imp"));
impFileNode->appendInputFile(
std::unique_ptr<File>(new pecoff::LocallyImportedSymbolFile(*this)));
getInputGraph().insertElementAt(std::move(impFileNode),
InputGraph::Position::END);
+
+ // Create a file for dllexported symbols.
+ std::unique_ptr<SimpleFileNode> exportNode(new SimpleFileNode("<export>"));
+ pecoff::ExportedSymbolRenameFile *renameFile =
+ new pecoff::ExportedSymbolRenameFile(*this);
+ exportNode->appendInputFile(std::unique_ptr<File>(renameFile));
+ getLibraryGroup()->addFile(std::move(exportNode));
+ getInputGraph().registerObserver(
+ *(new (_allocator) ObserverCallback(renameFile)));
return true;
}
Modified: lld/trunk/test/pecoff/Inputs/export.obj.yaml
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/pecoff/Inputs/export.obj.yaml?rev=208754&r1=208753&r2=208754&view=diff
==============================================================================
--- lld/trunk/test/pecoff/Inputs/export.obj.yaml (original)
+++ lld/trunk/test/pecoff/Inputs/export.obj.yaml Wed May 14 01:29:32 2014
@@ -54,4 +54,10 @@ symbols:
SimpleType: IMAGE_SYM_TYPE_NULL
ComplexType: IMAGE_SYM_DTYPE_NULL
StorageClass: IMAGE_SYM_CLASS_EXTERNAL
+ - Name: _exportfn7 at 8
+ Value: 16
+ SectionNumber: 1
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_NULL
+ StorageClass: IMAGE_SYM_CLASS_EXTERNAL
...
Modified: lld/trunk/test/pecoff/export.test
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/pecoff/export.test?rev=208754&r1=208753&r2=208754&view=diff
==============================================================================
--- lld/trunk/test/pecoff/export.test (original)
+++ lld/trunk/test/pecoff/export.test Wed May 14 01:29:32 2014
@@ -41,3 +41,12 @@ CHECK4-NEXT: 5 0x2008 exportfn
CHECK4-NEXT: 6 0x2010 exportfn2
CHECK4-NEXT: 7 0x2010 exportfn5
CHECK4-NEXT: 8 0x2010 exportfn3 at 256
+
+# RUN: lld -flavor link /out:%t5.dll /dll /entry:init \
+# RUN: /export:exportfn7 -- %t.obj
+# RUN: llvm-objdump -p %t5.dll | FileCheck -check-prefix=CHECK5 %s
+
+CHECK5: Export Table:
+CHECK5: DLL name: export.test.tmp5.dll
+CHECK5: Ordinal RVA Name
+CHECK5-NEXT: 1 0x2010 exportfn7
More information about the llvm-commits
mailing list