Files
clang-p2996/lld/lib/ReaderWriter/PECOFF/WriterImportLibrary.cpp
Rui Ueyama 8bae8189b2 [PECOFF] Fix exported symbol in the import library
There are two ways to specify a symbol to be exported in the module
definition file.

1) EXPORT <external name> = <symbol>
2) EXPORT <symbol>

In (1), you give both external name and internal name. In that case,
the linker tries to find a symbol using the internal name, and write
that address to the export table with the external name. Thus, from
the outer world, the symbol seems to be exported as the external name.

In (2), internal name is basically the same as the external name
with an exception: if you give an undecorated symbol to the EXPORT
directive, and if the linker finds a decorated symbol, the external
name for the symbol will become the decorated symbol.

LLD didn't implement that exception correctly. This patch fixes that.

llvm-svn: 220333
2014-10-21 21:41:28 +00:00

106 lines
3.3 KiB
C++

//===- lib/ReaderWriter/PECOFF/WriterImportLibrary.cpp --------------------===//
//
// The LLVM Linker
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
///
/// This file is responsible for creating the Import Library file.
///
//===----------------------------------------------------------------------===//
#include "lld/ReaderWriter/PECOFFLinkingContext.h"
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/FileUtilities.h"
#include "llvm/Support/Path.h"
#include "llvm/Support/Program.h"
#include "llvm/Support/raw_ostream.h"
namespace lld {
namespace pecoff {
/// Creates a .def file containing the list of exported symbols.
static std::string
createModuleDefinitionFile(const PECOFFLinkingContext &ctx) {
std::string ret;
llvm::raw_string_ostream os(ret);
os << "LIBRARY \"" << llvm::sys::path::filename(ctx.outputPath()) << "\"\n"
<< "EXPORTS\n";
for (const PECOFFLinkingContext::ExportDesc &desc : ctx.getDllExports()) {
os << " " << desc.getExternalName();
if (!desc.isPrivate)
os << " @" << desc.ordinal;
if (desc.noname)
os << " NONAME";
if (desc.isData)
os << " DATA";
if (desc.isPrivate)
os << " PRIVATE";
os << "\n";
}
os.flush();
return ret;
}
static std::string writeToTempFile(StringRef contents) {
SmallString<128> path;
int fd;
if (llvm::sys::fs::createTemporaryFile("tmp", "def", fd, path)) {
llvm::errs() << "Failed to create temporary file\n";
return "";
}
llvm::raw_fd_ostream os(fd, /*shouldClose*/ true);
os << contents;
return path.str();
}
static void writeTo(StringRef path, StringRef contents) {
int fd;
if (llvm::sys::fs::openFileForWrite(path, fd, llvm::sys::fs::F_Text)) {
llvm::errs() << "Failed to open " << path << "\n";
return;
}
llvm::raw_fd_ostream os(fd, /*shouldClose*/ true);
os << contents;
}
/// Creates a .def file and runs lib.exe on it to create an import library.
void writeImportLibrary(const PECOFFLinkingContext &ctx) {
std::string program = "lib.exe";
std::string programPath = llvm::sys::FindProgramByName(program);
std::string fileContents = createModuleDefinitionFile(ctx);
std::string defPath = writeToTempFile(fileContents);
llvm::FileRemover tmpFile(defPath);
std::string defArg = "/def:";
defArg.append(defPath);
std::string outputArg = "/out:";
outputArg.append(ctx.getOutputImportLibraryPath());
std::vector<const char *> args;
args.push_back(programPath.c_str());
args.push_back("/nologo");
args.push_back(ctx.is64Bit() ? "/machine:x64" : "/machine:x86");
args.push_back(defArg.c_str());
args.push_back(outputArg.c_str());
args.push_back(nullptr);
if (programPath.empty()) {
llvm::errs() << "Unable to find " << program << " in PATH\n";
} else if (llvm::sys::ExecuteAndWait(programPath.c_str(), &args[0]) != 0) {
llvm::errs() << program << " failed\n";
}
// If /lldmoduledeffile:<filename> is given, make a copy of the
// temporary module definition file. This feature is for unit tests.
if (!ctx.getModuleDefinitionFile().empty())
writeTo(ctx.getModuleDefinitionFile(), fileContents);
}
} // end namespace pecoff
} // end namespace lld