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
106 lines
3.3 KiB
C++
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
|