forked from OSchip/llvm-project
COFF: Create import library files.
On Windows, we have to create a .lib file for each .dll. When linking against DLLs, the linker doesn't use the DLL files, but instead read a list of dllexported symbols from corresponding lib files. A library file containing descriptors of a DLL is called an import library file. lib.exe has a feature to create an import library file from a module-definition file. In this patch, we create a module-definition file and pass that to lib.exe. We eventually want to create an import library file by ourselves to eliminate dependency to lib.exe. For now, we just use the MSVC tool. llvm-svn: 239937
This commit is contained in:
parent
63e09bf70b
commit
151d862d97
|
@ -500,6 +500,11 @@ bool LinkerDriver::link(int Argc, const char *Argv[]) {
|
|||
}
|
||||
}
|
||||
|
||||
// Windows specific -- when we are creating a .dll file, we also
|
||||
// need to create a .lib file.
|
||||
if (!Config->Exports.empty())
|
||||
writeImportLibrary();
|
||||
|
||||
// Windows specific -- fix up dllexported symbols.
|
||||
if (!Config->Exports.empty()) {
|
||||
for (Export &E : Config->Exports)
|
||||
|
|
|
@ -98,6 +98,7 @@ private:
|
|||
};
|
||||
|
||||
std::error_code parseModuleDefs(MemoryBufferRef MB);
|
||||
std::error_code writeImportLibrary();
|
||||
|
||||
// Functions below this line are defined in DriverUtils.cpp.
|
||||
|
||||
|
|
|
@ -24,6 +24,8 @@
|
|||
#include "llvm/Option/ArgList.h"
|
||||
#include "llvm/Option/Option.h"
|
||||
#include "llvm/Support/CommandLine.h"
|
||||
#include "llvm/Support/FileUtilities.h"
|
||||
#include "llvm/Support/Path.h"
|
||||
#include "llvm/Support/Process.h"
|
||||
#include "llvm/Support/Program.h"
|
||||
#include "llvm/Support/raw_ostream.h"
|
||||
|
@ -269,6 +271,75 @@ convertResToCOFF(const std::vector<MemoryBufferRef> &MBs) {
|
|||
return MemoryBuffer::getFile(Path);
|
||||
}
|
||||
|
||||
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 a temporary file\n";
|
||||
return "";
|
||||
}
|
||||
llvm::raw_fd_ostream OS(FD, /*shouldClose*/ true);
|
||||
OS << Contents;
|
||||
return Path.str();
|
||||
}
|
||||
|
||||
/// Creates a .def file containing the list of exported symbols.
|
||||
static std::string createModuleDefinitionFile() {
|
||||
std::string S;
|
||||
llvm::raw_string_ostream OS(S);
|
||||
OS << "LIBRARY \"" << llvm::sys::path::filename(Config->OutputFile) << "\"\n"
|
||||
<< "EXPORTS\n";
|
||||
for (Export &E : Config->Exports) {
|
||||
OS << " " << E.ExtName;
|
||||
if (E.Ordinal > 0)
|
||||
OS << " @" << E.Ordinal;
|
||||
if (E.Noname)
|
||||
OS << " NONAME";
|
||||
if (E.Data)
|
||||
OS << " DATA";
|
||||
if (E.Private)
|
||||
OS << " PRIVATE";
|
||||
OS << "\n";
|
||||
}
|
||||
OS.flush();
|
||||
return S;
|
||||
}
|
||||
|
||||
// Creates a .def file and runs lib.exe on it to create an import library.
|
||||
std::error_code writeImportLibrary() {
|
||||
std::string Prog = "lib.exe";
|
||||
ErrorOr<std::string> ExeOrErr = llvm::sys::findProgramByName(Prog);
|
||||
if (auto EC = ExeOrErr.getError()) {
|
||||
llvm::errs() << "unable to find " << Prog << " in PATH: "
|
||||
<< EC.message() << "\n";
|
||||
return make_error_code(LLDError::InvalidOption);
|
||||
}
|
||||
llvm::BumpPtrAllocator Alloc;
|
||||
llvm::BumpPtrStringSaver S(Alloc);
|
||||
const char *Exe = S.save(ExeOrErr.get());
|
||||
|
||||
std::string Contents = createModuleDefinitionFile();
|
||||
StringRef Def = S.save(StringRef(writeToTempFile(Contents)));
|
||||
llvm::FileRemover TempFile(Def);
|
||||
|
||||
SmallString<128> Out = StringRef(Config->OutputFile);
|
||||
sys::path::replace_extension(Out, ".lib");
|
||||
|
||||
std::vector<const char *> Args;
|
||||
Args.push_back(Exe);
|
||||
Args.push_back("/nologo");
|
||||
Args.push_back("/machine:x64");
|
||||
Args.push_back(S.save("/def:" + Def));
|
||||
Args.push_back(S.save("/out:" + Out));
|
||||
Args.push_back(nullptr);
|
||||
|
||||
if (sys::ExecuteAndWait(Exe, Args.data()) != 0) {
|
||||
llvm::errs() << Exe << " failed\n";
|
||||
return make_error_code(LLDError::InvalidOption);
|
||||
}
|
||||
return std::error_code();
|
||||
}
|
||||
|
||||
// Create OptTable
|
||||
|
||||
// Create prefix string literals used in Options.td
|
||||
|
|
|
@ -0,0 +1,41 @@
|
|||
---
|
||||
header:
|
||||
Machine: IMAGE_FILE_MACHINE_AMD64
|
||||
Characteristics: []
|
||||
sections:
|
||||
- Name: .text
|
||||
Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ]
|
||||
Alignment: 4
|
||||
SectionData: 0000000000000000
|
||||
symbols:
|
||||
- Name: .text
|
||||
Value: 0
|
||||
SectionNumber: 1
|
||||
SimpleType: IMAGE_SYM_TYPE_NULL
|
||||
ComplexType: IMAGE_SYM_DTYPE_NULL
|
||||
StorageClass: IMAGE_SYM_CLASS_STATIC
|
||||
SectionDefinition:
|
||||
Length: 8
|
||||
NumberOfRelocations: 0
|
||||
NumberOfLinenumbers: 0
|
||||
CheckSum: 0
|
||||
Number: 0
|
||||
- Name: mainCRTStartup
|
||||
Value: 0
|
||||
SectionNumber: 1
|
||||
SimpleType: IMAGE_SYM_TYPE_NULL
|
||||
ComplexType: IMAGE_SYM_DTYPE_FUNCTION
|
||||
StorageClass: IMAGE_SYM_CLASS_EXTERNAL
|
||||
- Name: exportfn1
|
||||
Value: 0
|
||||
SectionNumber: 0
|
||||
SimpleType: IMAGE_SYM_TYPE_NULL
|
||||
ComplexType: IMAGE_SYM_DTYPE_NULL
|
||||
StorageClass: IMAGE_SYM_CLASS_EXTERNAL
|
||||
- Name: exportfn2
|
||||
Value: 0
|
||||
SectionNumber: 0
|
||||
SimpleType: IMAGE_SYM_TYPE_NULL
|
||||
ComplexType: IMAGE_SYM_DTYPE_NULL
|
||||
StorageClass: IMAGE_SYM_CLASS_EXTERNAL
|
||||
...
|
|
@ -0,0 +1,19 @@
|
|||
# REQUIRES: winres
|
||||
|
||||
# RUN: yaml2obj < %p/Inputs/export.yaml > %t.obj
|
||||
# RUN: lld -flavor link2 /out:%t.dll /dll %t.obj /export:exportfn1 /export:exportfn2
|
||||
# RUN: llvm-objdump -p %t.dll | FileCheck -check-prefix=EXPORT %s
|
||||
|
||||
EXPORT: Export Table:
|
||||
EXPORT: DLL name: dll.test.tmp.dll
|
||||
EXPORT: Ordinal RVA Name
|
||||
EXPORT-NEXT: 0 0
|
||||
EXPORT-NEXT: 1 0x1008 exportfn1
|
||||
EXPORT-NEXT: 2 0x1010 exportfn2
|
||||
|
||||
# RUN: yaml2obj < %p/Inputs/import.yaml > %t2.obj
|
||||
# RUN: lld -flavor link2 /out:%t2.exe %t2.obj %t.lib
|
||||
# RUN: llvm-readobj -coff-imports %t2.exe | FileCheck -check-prefix=IMPORT %s
|
||||
|
||||
IMPORT: Symbol: exportfn1
|
||||
IMPORT: Symbol: exportfn2
|
Loading…
Reference in New Issue