[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