[llvm-dev] Using LLD to create a .lib from a .def

Rui Ueyama via llvm-dev llvm-dev at lists.llvm.org
Wed Jun 14 16:37:48 PDT 2017


On Wed, Jun 14, 2017 at 4:24 PM, Andrew Kelley via llvm-dev <
llvm-dev at lists.llvm.org> wrote:

> I'm copying some LLD code into my codebase like this:
>
> // workaround for LLD not exposing ability to convert .def to .lib
>
> #include <set>
>
> namespace lld {
> namespace coff {
>
> class SymbolBody;
> class StringChunk;
> struct Symbol;
>
> struct Export {
>   StringRef Name;       // N in /export:N or /export:E=N
>   StringRef ExtName;    // E in /export:E=N
>   SymbolBody *Sym = nullptr;
>   uint16_t Ordinal = 0;
>   bool Noname = false;
>   bool Data = false;
>   bool Private = false;
>
>   // If an export is a form of /export:foo=dllname.bar, that means
>   // that foo should be exported as an alias to bar in the DLL.
>   // ForwardTo is set to "dllname.bar" part. Usually empty.
>   StringRef ForwardTo;
>   StringChunk *ForwardChunk = nullptr;
>
>   // True if this /export option was in .drectves section.
>   bool Directives = false;
>   StringRef SymbolName;
>   StringRef ExportName; // Name in DLL
>
>   bool operator==(const Export &E) {
>     return (Name == E.Name && ExtName == E.ExtName &&
>             Ordinal == E.Ordinal && Noname == E.Noname &&
>             Data == E.Data && Private == E.Private);
>   }
> };
>
> enum class DebugType {
>   None  = 0x0,
>   CV    = 0x1,  /// CodeView
>   PData = 0x2,  /// Procedure Data
>   Fixup = 0x4,  /// Relocation Table
> };
>
> struct Configuration {
>   enum ManifestKind { SideBySide, Embed, No };
>   llvm::COFF::MachineTypes Machine = llvm::COFF::IMAGE_FILE_
> MACHINE_UNKNOWN;
>   bool Verbose = false;
>   llvm::COFF::WindowsSubsystem Subsystem = llvm::COFF::IMAGE_SUBSYSTEM_
> UNKNOWN;
>   SymbolBody *Entry = nullptr;
>   bool NoEntry = false;
>   std::string OutputFile;
>   bool DoGC = true;
>   bool DoICF = true;
>   bool Relocatable = true;
>   bool Force = false;
>   bool Debug = false;
>   bool WriteSymtab = true;
>   unsigned DebugTypes = static_cast<unsigned>(DebugType::None);
>   StringRef PDBPath;
>
>   // Symbols in this set are considered as live by the garbage collector.
>   std::set<SymbolBody *> GCRoot;
>
>   std::set<StringRef> NoDefaultLibs;
>   bool NoDefaultLibAll = false;
>
>   // True if we are creating a DLL.
>   bool DLL = false;
>   StringRef Implib;
>   std::vector<Export> Exports;
>   std::set<std::string> DelayLoads;
>   std::map<std::string, int> DLLOrder;
>   SymbolBody *DelayLoadHelper = nullptr;
>
>   // Used for SafeSEH.
>   Symbol *SEHTable = nullptr;
>   Symbol *SEHCount = nullptr;
>
>   // Used for /opt:lldlto=N
>   unsigned LTOOptLevel = 2;
>
>   // Used for /opt:lldltojobs=N
>   unsigned LTOJobs = 1;
>
>   // Used for /merge:from=to (e.g. /merge:.rdata=.text)
>   std::map<StringRef, StringRef> Merge;
>
>   // Used for /section=.name,{DEKPRSW} to set section attributes.
>   std::map<StringRef, uint32_t> Section;
>
>   // Options for manifest files.
>   ManifestKind Manifest = SideBySide;
>   int ManifestID = 1;
>   StringRef ManifestDependency;
>   bool ManifestUAC = true;
>   std::vector<std::string> ManifestInput;
>   StringRef ManifestLevel = "'asInvoker'";
>   StringRef ManifestUIAccess = "'false'";
>   StringRef ManifestFile;
>
>   // Used for /failifmismatch.
>   std::map<StringRef, StringRef> MustMatch;
>
>   // Used for /alternatename.
>   std::map<StringRef, StringRef> AlternateNames;
>
>   uint64_t ImageBase = -1;
>   uint64_t StackReserve = 1024 * 1024;
>   uint64_t StackCommit = 4096;
>   uint64_t HeapReserve = 1024 * 1024;
>   uint64_t HeapCommit = 4096;
>   uint32_t MajorImageVersion = 0;
>   uint32_t MinorImageVersion = 0;
>   uint32_t MajorOSVersion = 6;
>   uint32_t MinorOSVersion = 0;
>   bool DynamicBase = true;
>   bool AllowBind = true;
>   bool NxCompat = true;
>   bool AllowIsolation = true;
>   bool TerminalServerAware = true;
>   bool LargeAddressAware = false;
>   bool HighEntropyVA = false;
>
>   // This is for debugging.
>   bool DebugPdb = false;
>   bool DumpPdb = false;
> };
>
> extern Configuration *Config;
>
> void writeImportLibrary();
> void parseModuleDefs(MemoryBufferRef MB);
>
> } // namespace coff
> } // namespace lld
>
> //==========================================================
> ===============
>
>
>
>
> This is so that I can write the following user code:
>
>
>
> // writes the output to dll_path with .dll replaced with .lib
> void ZigLLDDefToLib(Buf *def_contents, Buf *dll_path) {
>     lld::coff::Config = new lld::coff::Configuration;
>     auto mem_buf = MemoryBuffer::getMemBuffer(buf_ptr(def_contents));
>     MemoryBufferRef mbref(*mem_buf);
>     lld::coff::parseModuleDefs(mbref);
>     lld::coff::Config->OutputFile = buf_ptr(dll_path);
>     lld::coff::writeImportLibrary();
> }
>
>
> Then I give it def_contents that looks like:
> LIBRARY kernel32
> EXPORTS
> ExitProcess
> GetConsoleMode
> GetStdHandle
> GetFileInformationByHandleEx
> WriteFile
> GetLastError
>
>
> with dll_path set to ./zig-cache/all.dll. This generates
> ./zig-cache/all.lib.
>
> The generated LLVM IR looks like:
>
> ; Function Attrs: noreturn nounwind
> declare void @ExitProcess(i32) #6
> ; Function Attrs: nounwind
> declare i1 @GetConsoleMode(i8* nonnull, i32* nonnull) #3
> ; Function Attrs: nounwind
> declare i8* @GetStdHandle(i32) #3
> ; Function Attrs: nounwind
> declare i1 @GetFileInformationByHandleEx(i8* nonnull, i32, i8* nonnull,
> i32) #3
> ; Function Attrs: nounwind
> declare i1 @WriteFile(i8* nonnull, i8* nonnull readonly, i32, i32*,
> %OVERLAPPED*) #3
> ; Function Attrs: nounwind
> declare i32 @GetLastError() #3
>
> ...with code you would expect to call these functions.
>
> Then I link with
> lld -NOLOGO -MACHINE:X64 -OUT:hello.exe -NODEFAULTLIB -ENTRY:_start
> ./zig-cache/hello.obj ./zig-cache/builtin.obj ./zig-cache/compiler_rt.obj
> ./zig-cache/all.lib
>
>
> and I get the following errors:
> ./zig-cache/hello.obj: undefined symbol: ExitProcess
> ./zig-cache/hello.obj: undefined symbol: GetConsoleMode
> ./zig-cache/hello.obj: undefined symbol: GetStdHandle
> ./zig-cache/hello.obj: undefined symbol: GetFileInformationByHandleEx
> ./zig-cache/hello.obj: undefined symbol: GetLastError
> ./zig-cache/hello.obj: undefined symbol: WriteFile
> error: link failed
>
>
>
> 1. Is there something else I need to be doing to make this work correctly?
>

The first thing I would check is to make sure that you created your .lib
file for x86-64. Windows uses different name mangling scheme for x86 and
x86-64, so if you mix the two, it could result in an "undefined symbol"
error.


> (Note: I already tried renaming "all" to "kernel32". Ideally I could
> generate 1 .lib file for all the DLL calls needed.)
> 2. Can LLD expose this ability directly so I don't have to copy paste a
> bunch of LLD internal stuff?
>

Martell recently factored out the code to parse and generate module
definition files. You might be able to use that. See
llvm/Object/COFFModuleDefinition.h.

The location at where LLD uses COFFModuleDefinition.h is in parseModuleDefs
and createImportLibrary in COFF/Driver.cpp.

Regards,
> Andrew Kelley
> ziglang.org
>
>
> _______________________________________________
> LLVM Developers mailing list
> llvm-dev at lists.llvm.org
> http://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-dev
>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/llvm-dev/attachments/20170614/90cab393/attachment-0001.html>


More information about the llvm-dev mailing list