Commit 2b624fea84

LemonBoy <thatlemon@gmail.com>
2019-10-12 10:56:16
Add dlltool functionality
Don't need no patched lld --kill-at behaviour now.
1 parent 8b45921
Changed files (3)
src/link.cpp
@@ -2054,27 +2054,12 @@ static const char *get_def_lib(CodeGen *parent, const char *name, Buf *def_in_fi
         lib_final_path = buf_alloc();
         os_path_join(artifact_dir, final_lib_basename, lib_final_path);
 
-        args.resize(0);
-        args.append("link");
-        coff_append_machine_arg(parent, &args);
-        args.append("-lldmingw");
-        args.append("-kill-at");
-
-        args.append(buf_ptr(buf_sprintf("-DEF:%s", buf_ptr(def_final_path))));
-        args.append(buf_ptr(buf_sprintf("-OUT:%s", buf_ptr(lib_final_path))));
-
-        if (parent->verbose_link) {
-            for (size_t i = 0; i < args.length; i += 1) {
-                fprintf(stderr, "%s ", args.at(i));
-            }
-            fprintf(stderr, "\n");
-        }
-
-        Buf diag = BUF_INIT;
-        ZigLLVM_ObjectFormatType target_ofmt = target_object_format(parent->zig_target);
-        if (!zig_lld_link(target_ofmt, args.items, args.length, &diag)) {
-            fprintf(stderr, "%s\n", buf_ptr(&diag));
-            exit(1);
+        if (ZigLLVMWriteImportLibrary(buf_ptr(def_final_path),
+                                      parent->zig_target->arch,
+                                      buf_ptr(lib_final_path),
+                                      /* kill_at */ true))
+        {
+            zig_panic("link: could not emit %s", buf_ptr(lib_final_path));
         }
     } else {
         // cache hit
src/zig_llvm.cpp
@@ -34,6 +34,9 @@
 #include <llvm/MC/SubtargetFeature.h>
 #include <llvm/Object/Archive.h>
 #include <llvm/Object/ArchiveWriter.h>
+#include <llvm/Object/COFF.h>
+#include <llvm/Object/COFFImportFile.h>
+#include <llvm/Object/COFFModuleDefinition.h>
 #include <llvm/PassRegistry.h>
 #include <llvm/Support/FileSystem.h>
 #include <llvm/Support/TargetParser.h>
@@ -938,6 +941,85 @@ class MyOStream: public raw_ostream {
         size_t pos;
 };
 
+bool ZigLLVMWriteImportLibrary(const char *def_path, const ZigLLVM_ArchType arch,
+                               const char *output_lib_path, const bool kill_at)
+{
+    COFF::MachineTypes machine = COFF::IMAGE_FILE_MACHINE_UNKNOWN;
+
+    switch (arch) {
+        case ZigLLVM_x86:
+            machine = COFF::IMAGE_FILE_MACHINE_I386;
+            break;
+        case ZigLLVM_x86_64:
+            machine = COFF::IMAGE_FILE_MACHINE_AMD64;
+            break;
+        case ZigLLVM_arm:
+        case ZigLLVM_armeb:
+        case ZigLLVM_thumb:
+        case ZigLLVM_thumbeb:
+            machine = COFF::IMAGE_FILE_MACHINE_ARMNT;
+            break;
+        case ZigLLVM_aarch64:
+        case ZigLLVM_aarch64_be:
+            machine = COFF::IMAGE_FILE_MACHINE_ARM64;
+            break;
+        default:
+            break;
+    }
+
+    if (machine == COFF::IMAGE_FILE_MACHINE_UNKNOWN) {
+        return true;
+    }
+
+    auto bufOrErr = MemoryBuffer::getFile(def_path);
+    if (!bufOrErr) {
+        return false;
+    }
+
+    MemoryBuffer& buf = *bufOrErr.get();
+    Expected<object::COFFModuleDefinition> def =
+        object::parseCOFFModuleDefinition(buf, machine, /* MingwDef */ true);
+
+    if (!def) {
+        return true;
+    }
+
+    // The exports-juggling code below is ripped from LLVM's DllToolDriver.cpp
+
+    // If ExtName is set (if the "ExtName = Name" syntax was used), overwrite
+    // Name with ExtName and clear ExtName. When only creating an import
+    // library and not linking, the internal name is irrelevant. This avoids
+    // cases where writeImportLibrary tries to transplant decoration from
+    // symbol decoration onto ExtName.
+    for (object::COFFShortExport& E : def->Exports) {
+        if (!E.ExtName.empty()) {
+            E.Name = E.ExtName;
+            E.ExtName.clear();
+        }
+    }
+
+    if (machine == COFF::IMAGE_FILE_MACHINE_I386 && kill_at) {
+        for (object::COFFShortExport& E : def->Exports) {
+            if (!E.AliasTarget.empty() || (!E.Name.empty() && E.Name[0] == '?'))
+                continue;
+            E.SymbolName = E.Name;
+            // Trim off the trailing decoration. Symbols will always have a
+            // starting prefix here (either _ for cdecl/stdcall, @ for fastcall
+            // or ? for C++ functions). Vectorcall functions won't have any
+            // fixed prefix, but the function base name will still be at least
+            // one char.
+            E.Name = E.Name.substr(0, E.Name.find('@', 1));
+            // By making sure E.SymbolName != E.Name for decorated symbols,
+            // writeImportLibrary writes these symbols with the type
+            // IMPORT_NAME_UNDECORATE.
+        }
+    }
+
+    return static_cast<bool>(
+        object::writeImportLibrary(def->OutputFile, output_lib_path,
+                                   def->Exports, machine, /* MinGW */ true));
+}
+
 bool ZigLLVMWriteArchive(const char *archive_name, const char **file_names, size_t file_name_count,
         ZigLLVM_OSType os_type)
 {
src/zig_llvm.h
@@ -465,6 +465,9 @@ ZIG_EXTERN_C bool ZigLLDLink(enum ZigLLVM_ObjectFormatType oformat, const char *
 ZIG_EXTERN_C bool ZigLLVMWriteArchive(const char *archive_name, const char **file_names, size_t file_name_count,
         enum ZigLLVM_OSType os_type);
 
+bool ZigLLVMWriteImportLibrary(const char *def_path, const ZigLLVM_ArchType arch,
+                               const char *output_lib_path, const bool kill_at);
+
 ZIG_EXTERN_C void ZigLLVMGetNativeTarget(enum ZigLLVM_ArchType *arch_type, enum ZigLLVM_SubArchType *sub_arch_type,
         enum ZigLLVM_VendorType *vendor_type, enum ZigLLVM_OSType *os_type, enum ZigLLVM_EnvironmentType *environ_type,
         enum ZigLLVM_ObjectFormatType *oformat);