[llvm-dev] Using LLD to create a .lib from a .def
Andrew Kelley via llvm-dev
llvm-dev at lists.llvm.org
Thu Jun 15 07:33:38 PDT 2017
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>
More information about the llvm-dev
mailing list