[lld] r239937 - COFF: Create import library files.

Rui Ueyama ruiu at google.com
Wed Jun 17 13:40:44 PDT 2015


Author: ruiu
Date: Wed Jun 17 15:40:43 2015
New Revision: 239937

URL: http://llvm.org/viewvc/llvm-project?rev=239937&view=rev
Log:
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.

Added:
    lld/trunk/test/COFF/Inputs/import.yaml
    lld/trunk/test/COFF/dll.test
Modified:
    lld/trunk/COFF/Driver.cpp
    lld/trunk/COFF/Driver.h
    lld/trunk/COFF/DriverUtils.cpp

Modified: lld/trunk/COFF/Driver.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/COFF/Driver.cpp?rev=239937&r1=239936&r2=239937&view=diff
==============================================================================
--- lld/trunk/COFF/Driver.cpp (original)
+++ lld/trunk/COFF/Driver.cpp Wed Jun 17 15:40:43 2015
@@ -500,6 +500,11 @@ bool LinkerDriver::link(int Argc, const
     }
   }
 
+  // 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)

Modified: lld/trunk/COFF/Driver.h
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/COFF/Driver.h?rev=239937&r1=239936&r2=239937&view=diff
==============================================================================
--- lld/trunk/COFF/Driver.h (original)
+++ lld/trunk/COFF/Driver.h Wed Jun 17 15:40:43 2015
@@ -98,6 +98,7 @@ private:
 };
 
 std::error_code parseModuleDefs(MemoryBufferRef MB);
+std::error_code writeImportLibrary();
 
 // Functions below this line are defined in DriverUtils.cpp.
 

Modified: lld/trunk/COFF/DriverUtils.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/COFF/DriverUtils.cpp?rev=239937&r1=239936&r2=239937&view=diff
==============================================================================
--- lld/trunk/COFF/DriverUtils.cpp (original)
+++ lld/trunk/COFF/DriverUtils.cpp Wed Jun 17 15:40:43 2015
@@ -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<Memor
   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

Added: lld/trunk/test/COFF/Inputs/import.yaml
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/COFF/Inputs/import.yaml?rev=239937&view=auto
==============================================================================
--- lld/trunk/test/COFF/Inputs/import.yaml (added)
+++ lld/trunk/test/COFF/Inputs/import.yaml Wed Jun 17 15:40:43 2015
@@ -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
+...

Added: lld/trunk/test/COFF/dll.test
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/COFF/dll.test?rev=239937&view=auto
==============================================================================
--- lld/trunk/test/COFF/dll.test (added)
+++ lld/trunk/test/COFF/dll.test Wed Jun 17 15:40:43 2015
@@ -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





More information about the llvm-commits mailing list