diff options
-rw-r--r-- | lld/COFF/Driver.cpp | 5 | ||||
-rw-r--r-- | lld/COFF/Driver.h | 1 | ||||
-rw-r--r-- | lld/COFF/DriverUtils.cpp | 71 | ||||
-rw-r--r-- | lld/test/COFF/Inputs/import.yaml | 41 | ||||
-rw-r--r-- | lld/test/COFF/dll.test | 19 |
5 files changed, 137 insertions, 0 deletions
diff --git a/lld/COFF/Driver.cpp b/lld/COFF/Driver.cpp index be13aa971b8..af316670197 100644 --- a/lld/COFF/Driver.cpp +++ b/lld/COFF/Driver.cpp @@ -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) diff --git a/lld/COFF/Driver.h b/lld/COFF/Driver.h index 07b76b17b3d..8b43e36abe0 100644 --- a/lld/COFF/Driver.h +++ b/lld/COFF/Driver.h @@ -98,6 +98,7 @@ private: }; std::error_code parseModuleDefs(MemoryBufferRef MB); +std::error_code writeImportLibrary(); // Functions below this line are defined in DriverUtils.cpp. diff --git a/lld/COFF/DriverUtils.cpp b/lld/COFF/DriverUtils.cpp index 662e5822335..c210834faa3 100644 --- a/lld/COFF/DriverUtils.cpp +++ b/lld/COFF/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 diff --git a/lld/test/COFF/Inputs/import.yaml b/lld/test/COFF/Inputs/import.yaml new file mode 100644 index 00000000000..97ccac5b8b4 --- /dev/null +++ b/lld/test/COFF/Inputs/import.yaml @@ -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 +... diff --git a/lld/test/COFF/dll.test b/lld/test/COFF/dll.test new file mode 100644 index 00000000000..75ecaf5b391 --- /dev/null +++ b/lld/test/COFF/dll.test @@ -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 |