Andrew Kelley via llvm-dev
2017-Jun-14 23:24 UTC
[llvm-dev] Using LLD to create a .lib from a .def
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? (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? Regards, Andrew Kelley ziglang.org -------------- next part -------------- An HTML attachment was scrubbed... URL: <http://lists.llvm.org/pipermail/llvm-dev/attachments/20170614/58a0aef9/attachment.html>
Rui Ueyama via llvm-dev
2017-Jun-14 23:37 UTC
[llvm-dev] Using LLD to create a .lib from a .def
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>
Andrew Kelley via llvm-dev
2017-Jun-15 14:33 UTC
[llvm-dev] Using LLD to create a .lib from a .def
On Wed, Jun 14, 2017 at 7:37 PM, Rui Ueyama <ruiu at google.com> wrote:> 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_UN >> KNOWN; >> 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. >I tested this by setting the machine in the config directly to AMD64.> > >> (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. >OK, thanks. I'll get a build going with latest trunk and see if I can get it to work.> > 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/20170615/1908363e/attachment-0001.html>