[lld] r239937 - COFF: Create import library files.
Rui Ueyama
ruiu at google.com
Thu Jul 16 14:57:36 PDT 2015
On Thu, Jul 16, 2015 at 2:53 PM, Filipe Cabecinhas <filcab at gmail.com> wrote:
> Hi Rui,
>
> On Wed, Jun 17, 2015 at 1:40 PM, Rui Ueyama <ruiu at google.com> wrote:
>
>> 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
>>
>
> Shouldn't it REQUIRE winlib, too?
> We have a builder that's failing because it tries to execute lib.exe, but
> that can't be found.
> I think what's happening is that CMake finds all the utilities due to
> having some env var defined pointing at Visual Studio, but then we don't
> have those in the path.
>
Yes, I think we need to add REQUIRES: winlib too. I'm sorry about that, I
should have done that when I submit this patch. In most cases, lib.exe is
available as long as res.exe is available, so I didn't notice that.
Are we going to be able to remove the lib.exe dependency in the future?
>
That's the plan. We already have a lib.exe-compatible command in LLVM, so
it might be as easy as calling it instead of MSVC's lib.exe.
> Thank you,
>
> Filipe
>
>
>
>> +
>> +# 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
>>
>>
>> _______________________________________________
>> llvm-commits mailing list
>> llvm-commits at cs.uiuc.edu
>> http://lists.cs.uiuc.edu/mailman/listinfo/llvm-commits
>>
>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/llvm-commits/attachments/20150716/b8f14387/attachment.html>
More information about the llvm-commits
mailing list