diff options
Diffstat (limited to 'src/link.cpp')
| -rw-r--r-- | src/link.cpp | 308 |
1 files changed, 191 insertions, 117 deletions
diff --git a/src/link.cpp b/src/link.cpp index d6093581f7..8900d0351b 100644 --- a/src/link.cpp +++ b/src/link.cpp @@ -25,6 +25,7 @@ static CodeGen *create_child_codegen(CodeGen *parent_gen, Buf *root_src_path, Ou CodeGen *child_gen = codegen_create(nullptr, root_src_path, parent_gen->zig_target, out_type, parent_gen->build_mode, parent_gen->zig_lib_dir, parent_gen->zig_std_dir, libc, get_stage1_cache_path()); child_gen->disable_gen_h = true; + child_gen->disable_stack_probing = true; child_gen->verbose_tokenize = parent_gen->verbose_tokenize; child_gen->verbose_ast = parent_gen->verbose_ast; child_gen->verbose_link = parent_gen->verbose_link; @@ -772,17 +773,15 @@ static const char *get_libc_crt_file(CodeGen *parent, const char *file) { } } -static Buf *build_a_raw(CodeGen *parent_gen, const char *aname, Buf *full_path) { +static Buf *build_a_raw(CodeGen *parent_gen, const char *aname, Buf *full_path, OutType child_out_type) { // The Mach-O LLD code is not well maintained, and trips an assertion // when we link compiler_rt and builtin as libraries rather than objects. // Here we workaround this by having compiler_rt and builtin be objects. // TODO write our own linker. https://github.com/ziglang/zig/issues/1535 - OutType child_out_type = OutTypeLib; if (parent_gen->zig_target->os == OsMacOSX) { child_out_type = OutTypeObj; } - CodeGen *child_gen = create_child_codegen(parent_gen, full_path, child_out_type, parent_gen->libc); codegen_set_out_name(child_gen, buf_create_from_str(aname)); @@ -804,14 +803,14 @@ static Buf *build_a(CodeGen *parent_gen, const char *aname) { Buf *full_path = buf_alloc(); os_path_join(parent_gen->zig_std_special_dir, source_basename, full_path); - return build_a_raw(parent_gen, aname, full_path); + return build_a_raw(parent_gen, aname, full_path, OutTypeLib); } -static Buf *build_compiler_rt(CodeGen *parent_gen) { +static Buf *build_compiler_rt(CodeGen *parent_gen, OutType child_out_type) { Buf *full_path = buf_alloc(); os_path_join(parent_gen->zig_std_special_dir, buf_create_from_str("compiler_rt.zig"), full_path); - return build_a_raw(parent_gen, "compiler_rt", full_path); + return build_a_raw(parent_gen, "compiler_rt", full_path, child_out_type); } static const char *get_darwin_arch_string(const ZigTarget *t) { @@ -1006,7 +1005,7 @@ static void construct_linker_job_elf(LinkJob *lj) { lj->args.append(buf_ptr(builtin_a_path)); } - Buf *compiler_rt_o_path = build_compiler_rt(g); + Buf *compiler_rt_o_path = build_compiler_rt(g, OutTypeLib); lj->args.append(buf_ptr(compiler_rt_o_path)); } @@ -1091,16 +1090,35 @@ static void construct_linker_job_wasm(LinkJob *lj) { CodeGen *g = lj->codegen; lj->args.append("-error-limit=0"); - lj->args.append("--no-entry"); // So lld doesn't look for _start. + + if (g->zig_target->os != OsWASI) { + lj->args.append("--no-entry"); // So lld doesn't look for _start. + } lj->args.append("--allow-undefined"); - lj->args.append("--export-all"); lj->args.append("-o"); lj->args.append(buf_ptr(&g->output_file_path)); + auto export_it = g->exported_symbol_names.entry_iterator(); + decltype(g->exported_symbol_names)::Entry *curr_entry = nullptr; + while ((curr_entry = export_it.next()) != nullptr) { + Buf *arg = buf_sprintf("--export=%s", buf_ptr(curr_entry->key)); + lj->args.append(buf_ptr(arg)); + } + // .o files for (size_t i = 0; i < g->link_objects.length; i += 1) { lj->args.append((const char *)buf_ptr(g->link_objects.at(i))); } + + if (g->out_type == OutTypeExe) { + if (g->libc_link_lib == nullptr) { + Buf *builtin_a_path = build_a(g, "builtin"); + lj->args.append(buf_ptr(builtin_a_path)); + } + + Buf *compiler_rt_o_path = build_compiler_rt(g, OutTypeLib); + lj->args.append(buf_ptr(compiler_rt_o_path)); + } } static void coff_append_machine_arg(CodeGen *g, ZigList<const char *> *list) { @@ -1124,53 +1142,121 @@ static bool zig_lld_link(ZigLLVM_ObjectFormatType oformat, const char **args, si } static void add_uefi_link_args(LinkJob *lj) { - lj->args.append("/BASE:0"); - lj->args.append("/ENTRY:EfiMain"); - lj->args.append("/OPT:REF"); - lj->args.append("/SAFESEH:NO"); - lj->args.append("/MERGE:.rdata=.data"); - lj->args.append("/ALIGN:32"); - lj->args.append("/NODEFAULTLIB"); - lj->args.append("/SECTION:.xdata,D"); + lj->args.append("-BASE:0"); + lj->args.append("-ENTRY:EfiMain"); + lj->args.append("-OPT:REF"); + lj->args.append("-SAFESEH:NO"); + lj->args.append("-MERGE:.rdata=.data"); + lj->args.append("-ALIGN:32"); + lj->args.append("-NODEFAULTLIB"); + lj->args.append("-SECTION:.xdata,D"); } -static void add_nt_link_args(LinkJob *lj, bool is_library) { +static void add_msvc_link_args(LinkJob *lj, bool is_library) { CodeGen *g = lj->codegen; - if (lj->link_in_crt) { - // TODO: https://github.com/ziglang/zig/issues/2064 - bool is_dynamic = true; // g->is_dynamic; - const char *lib_str = is_dynamic ? "" : "lib"; - const char *d_str = (g->build_mode == BuildModeDebug) ? "d" : ""; - - if (!is_dynamic) { - Buf *cmt_lib_name = buf_sprintf("libcmt%s.lib", d_str); - lj->args.append(buf_ptr(cmt_lib_name)); - } else { - Buf *msvcrt_lib_name = buf_sprintf("msvcrt%s.lib", d_str); - lj->args.append(buf_ptr(msvcrt_lib_name)); - } + // TODO: https://github.com/ziglang/zig/issues/2064 + bool is_dynamic = true; // g->is_dynamic; + const char *lib_str = is_dynamic ? "" : "lib"; + const char *d_str = (g->build_mode == BuildModeDebug) ? "d" : ""; + + if (!is_dynamic) { + Buf *cmt_lib_name = buf_sprintf("libcmt%s.lib", d_str); + lj->args.append(buf_ptr(cmt_lib_name)); + } else { + Buf *msvcrt_lib_name = buf_sprintf("msvcrt%s.lib", d_str); + lj->args.append(buf_ptr(msvcrt_lib_name)); + } + + Buf *vcruntime_lib_name = buf_sprintf("%svcruntime%s.lib", lib_str, d_str); + lj->args.append(buf_ptr(vcruntime_lib_name)); - Buf *vcruntime_lib_name = buf_sprintf("%svcruntime%s.lib", lib_str, d_str); - lj->args.append(buf_ptr(vcruntime_lib_name)); + Buf *crt_lib_name = buf_sprintf("%sucrt%s.lib", lib_str, d_str); + lj->args.append(buf_ptr(crt_lib_name)); - Buf *crt_lib_name = buf_sprintf("%sucrt%s.lib", lib_str, d_str); - lj->args.append(buf_ptr(crt_lib_name)); + //Visual C++ 2015 Conformance Changes + //https://msdn.microsoft.com/en-us/library/bb531344.aspx + lj->args.append("legacy_stdio_definitions.lib"); - //Visual C++ 2015 Conformance Changes - //https://msdn.microsoft.com/en-us/library/bb531344.aspx - lj->args.append("legacy_stdio_definitions.lib"); + // msvcrt depends on kernel32 and ntdll + lj->args.append("kernel32.lib"); + lj->args.append("ntdll.lib"); +} + +static const char *get_libc_file(ZigLibCInstallation *lib, const char *file) { + Buf *out_buf = buf_alloc(); + os_path_join(&lib->crt_dir, buf_create_from_str(file), out_buf); + return buf_ptr(out_buf); +} + +static const char *get_libc_static_file(ZigLibCInstallation *lib, const char *file) { + Buf *out_buf = buf_alloc(); + os_path_join(&lib->static_crt_dir, buf_create_from_str(file), out_buf); + return buf_ptr(out_buf); +} + +static void add_mingw_link_args(LinkJob *lj, bool is_library) { + CodeGen *g = lj->codegen; - // msvcrt depends on kernel32 and ntdll - lj->args.append("kernel32.lib"); - lj->args.append("ntdll.lib"); + bool is_dll = g->out_type == OutTypeLib && g->is_dynamic; + + if (g->zig_target->arch == ZigLLVM_x86) { + lj->args.append("-ALTERNATENAME:__image_base__=___ImageBase"); + } else { + lj->args.append("-ALTERNATENAME:__image_base__=__ImageBase"); + } + + if (is_dll) { + lj->args.append(get_libc_file(g->libc, "dllcrt2.o")); + } else { + lj->args.append(get_libc_file(g->libc, "crt2.o")); + } + + lj->args.append(get_libc_static_file(g->libc, "crtbegin.o")); + + lj->args.append(get_libc_file(g->libc, "libmingw32.a")); + + if (is_dll) { + lj->args.append(get_libc_static_file(g->libc, "libgcc_s.a")); + lj->args.append(get_libc_static_file(g->libc, "libgcc.a")); + } else { + lj->args.append(get_libc_static_file(g->libc, "libgcc.a")); + lj->args.append(get_libc_static_file(g->libc, "libgcc_eh.a")); + } + + lj->args.append(get_libc_static_file(g->libc, "libssp.a")); + lj->args.append(get_libc_file(g->libc, "libmoldname.a")); + lj->args.append(get_libc_file(g->libc, "libmingwex.a")); + lj->args.append(get_libc_file(g->libc, "libmsvcrt.a")); + + if (g->subsystem == TargetSubsystemWindows) { + lj->args.append(get_libc_file(g->libc, "libgdi32.a")); + lj->args.append(get_libc_file(g->libc, "libcomdlg32.a")); + } + + lj->args.append(get_libc_file(g->libc, "libadvapi32.a")); + lj->args.append(get_libc_file(g->libc, "libadvapi32.a")); + lj->args.append(get_libc_file(g->libc, "libshell32.a")); + lj->args.append(get_libc_file(g->libc, "libuser32.a")); + lj->args.append(get_libc_file(g->libc, "libkernel32.a")); + + lj->args.append(get_libc_static_file(g->libc, "crtend.o")); +} + +static void add_win_link_args(LinkJob *lj, bool is_library) { + if (lj->link_in_crt) { + if (target_abi_is_gnu(lj->codegen->zig_target->abi)) { + add_mingw_link_args(lj, is_library); + } else { + add_msvc_link_args(lj, is_library); + } } else { - lj->args.append("/NODEFAULTLIB"); + lj->args.append("-NODEFAULTLIB"); if (!is_library) { - if (g->have_winmain) { - lj->args.append("/ENTRY:WinMain"); + if (lj->codegen->have_winmain) { + lj->args.append("-ENTRY:WinMain"); } else { - lj->args.append("/ENTRY:WinMainCRTStartup"); + lj->args.append("-ENTRY:WinMainCRTStartup"); } } } @@ -1180,87 +1266,93 @@ static void construct_linker_job_coff(LinkJob *lj) { Error err; CodeGen *g = lj->codegen; - lj->args.append("/ERRORLIMIT:0"); + lj->args.append("-ERRORLIMIT:0"); - lj->args.append("/NOLOGO"); + lj->args.append("-NOLOGO"); if (!g->strip_debug_symbols) { - lj->args.append("/DEBUG"); + lj->args.append("-DEBUG"); } if (g->out_type == OutTypeExe) { // TODO compile time stack upper bound detection - lj->args.append("/STACK:16777216"); + lj->args.append("-STACK:16777216"); } coff_append_machine_arg(g, &lj->args); bool is_library = g->out_type == OutTypeLib; + if (is_library && g->is_dynamic) { + lj->args.append("-DLL"); + } + + lj->args.append(buf_ptr(buf_sprintf("-OUT:%s", buf_ptr(&g->output_file_path)))); + + if (g->libc_link_lib != nullptr) { + assert(g->libc != nullptr); + + lj->args.append(buf_ptr(buf_sprintf("-LIBPATH:%s", buf_ptr(&g->libc->crt_dir)))); + + if (target_abi_is_gnu(g->zig_target->abi)) { + lj->args.append(buf_ptr(buf_sprintf("-LIBPATH:%s", buf_ptr(&g->libc->sys_include_dir)))); + lj->args.append(buf_ptr(buf_sprintf("-LIBPATH:%s", buf_ptr(&g->libc->include_dir)))); + } else { + lj->args.append(buf_ptr(buf_sprintf("-LIBPATH:%s", buf_ptr(&g->libc->msvc_lib_dir)))); + lj->args.append(buf_ptr(buf_sprintf("-LIBPATH:%s", buf_ptr(&g->libc->kernel32_lib_dir)))); + } + } + + for (size_t i = 0; i < g->lib_dirs.length; i += 1) { + const char *lib_dir = g->lib_dirs.at(i); + lj->args.append(buf_ptr(buf_sprintf("-LIBPATH:%s", lib_dir))); + } + + for (size_t i = 0; i < g->link_objects.length; i += 1) { + lj->args.append((const char *)buf_ptr(g->link_objects.at(i))); + } + switch (g->subsystem) { case TargetSubsystemAuto: if (g->zig_target->os == OsUefi) { add_uefi_link_args(lj); } else { - add_nt_link_args(lj, is_library); + add_win_link_args(lj, is_library); } break; case TargetSubsystemConsole: - lj->args.append("/SUBSYSTEM:console"); - add_nt_link_args(lj, is_library); + lj->args.append("-SUBSYSTEM:console"); + add_win_link_args(lj, is_library); break; case TargetSubsystemEfiApplication: - lj->args.append("/SUBSYSTEM:efi_application"); + lj->args.append("-SUBSYSTEM:efi_application"); add_uefi_link_args(lj); break; case TargetSubsystemEfiBootServiceDriver: - lj->args.append("/SUBSYSTEM:efi_boot_service_driver"); + lj->args.append("-SUBSYSTEM:efi_boot_service_driver"); add_uefi_link_args(lj); break; case TargetSubsystemEfiRom: - lj->args.append("/SUBSYSTEM:efi_rom"); + lj->args.append("-SUBSYSTEM:efi_rom"); add_uefi_link_args(lj); break; case TargetSubsystemEfiRuntimeDriver: - lj->args.append("/SUBSYSTEM:efi_runtime_driver"); + lj->args.append("-SUBSYSTEM:efi_runtime_driver"); add_uefi_link_args(lj); break; case TargetSubsystemNative: - lj->args.append("/SUBSYSTEM:native"); - add_nt_link_args(lj, is_library); + lj->args.append("-SUBSYSTEM:native"); + add_win_link_args(lj, is_library); break; case TargetSubsystemPosix: - lj->args.append("/SUBSYSTEM:posix"); - add_nt_link_args(lj, is_library); + lj->args.append("-SUBSYSTEM:posix"); + add_win_link_args(lj, is_library); break; case TargetSubsystemWindows: - lj->args.append("/SUBSYSTEM:windows"); - add_nt_link_args(lj, is_library); + lj->args.append("-SUBSYSTEM:windows"); + add_win_link_args(lj, is_library); break; } - lj->args.append(buf_ptr(buf_sprintf("-OUT:%s", buf_ptr(&g->output_file_path)))); - - if (g->libc_link_lib != nullptr) { - assert(g->libc != nullptr); - - lj->args.append(buf_ptr(buf_sprintf("-LIBPATH:%s", buf_ptr(&g->libc->msvc_lib_dir)))); - lj->args.append(buf_ptr(buf_sprintf("-LIBPATH:%s", buf_ptr(&g->libc->kernel32_lib_dir)))); - lj->args.append(buf_ptr(buf_sprintf("-LIBPATH:%s", buf_ptr(&g->libc->crt_dir)))); - } - - if (is_library && g->is_dynamic) { - lj->args.append("-DLL"); - } - - for (size_t i = 0; i < g->lib_dirs.length; i += 1) { - const char *lib_dir = g->lib_dirs.at(i); - lj->args.append(buf_ptr(buf_sprintf("-LIBPATH:%s", lib_dir))); - } - - for (size_t i = 0; i < g->link_objects.length; i += 1) { - lj->args.append((const char *)buf_ptr(g->link_objects.at(i))); - } - if (g->out_type == OutTypeExe || (g->out_type == OutTypeLib && g->is_dynamic)) { if (g->libc_link_lib == nullptr && !g->is_dummy_so) { Buf *builtin_a_path = build_a(g, "builtin"); @@ -1268,7 +1360,7 @@ static void construct_linker_job_coff(LinkJob *lj) { } // msvc compiler_rt is missing some stuff, so we still build it and rely on weak linkage - Buf *compiler_rt_o_path = build_compiler_rt(g); + Buf *compiler_rt_o_path = build_compiler_rt(g, OutTypeLib); lj->args.append(buf_ptr(compiler_rt_o_path)); } @@ -1280,11 +1372,10 @@ static void construct_linker_job_coff(LinkJob *lj) { continue; } if (link_lib->provided_explicitly) { - if (lj->codegen->zig_target->abi == ZigLLVM_GNU) { - Buf *arg = buf_sprintf("-l%s", buf_ptr(link_lib->name)); - lj->args.append(buf_ptr(arg)); - } - else { + if (target_abi_is_gnu(lj->codegen->zig_target->abi)) { + Buf *lib_name = buf_sprintf("lib%s.a", buf_ptr(link_lib->name)); + lj->args.append(buf_ptr(lib_name)); + } else { lj->args.append(buf_ptr(link_lib->name)); } } else { @@ -1416,18 +1507,6 @@ static void get_darwin_platform(LinkJob *lj, DarwinPlatform *platform) { } } -static bool darwin_version_lt(DarwinPlatform *platform, int major, int minor) { - if (platform->major < major) { - return true; - } else if (platform->major > major) { - return false; - } - if (platform->minor < minor) { - return true; - } - return false; -} - static void construct_linker_job_macho(LinkJob *lj) { CodeGen *g = lj->codegen; @@ -1524,7 +1603,7 @@ static void construct_linker_job_macho(LinkJob *lj) { // compiler_rt on darwin is missing some stuff, so we still build it and rely on LinkOnce if (g->out_type == OutTypeExe || is_dyn_lib) { - Buf *compiler_rt_o_path = build_compiler_rt(g); + Buf *compiler_rt_o_path = build_compiler_rt(g, OutTypeLib); lj->args.append(buf_ptr(compiler_rt_o_path)); } @@ -1552,16 +1631,6 @@ static void construct_linker_job_macho(LinkJob *lj) { lj->args.append("dynamic_lookup"); } - if (platform.kind == MacOS) { - if (darwin_version_lt(&platform, 10, 5)) { - lj->args.append("-lgcc_s.10.4"); - } else if (darwin_version_lt(&platform, 10, 6)) { - lj->args.append("-lgcc_s.10.5"); - } - } else { - zig_panic("TODO"); - } - for (size_t i = 0; i < g->darwin_frameworks.length; i += 1) { lj->args.append("-framework"); lj->args.append(buf_ptr(g->darwin_frameworks.at(i))); @@ -1585,6 +1654,11 @@ static void construct_linker_job(LinkJob *lj) { } } +void zig_link_add_compiler_rt(CodeGen *g) { + Buf *compiler_rt_o_path = build_compiler_rt(g, OutTypeObj); + g->link_objects.append(compiler_rt_o_path); +} + void codegen_link(CodeGen *g) { codegen_add_time_event(g, "Build Dependencies"); @@ -1611,14 +1685,14 @@ void codegen_link(CodeGen *g) { if (g->out_type == OutTypeLib && !g->is_dynamic) { ZigList<const char *> file_names = {}; for (size_t i = 0; i < g->link_objects.length; i += 1) { - file_names.append((const char *)buf_ptr(g->link_objects.at(i))); + file_names.append(buf_ptr(g->link_objects.at(i))); } ZigLLVM_OSType os_type = get_llvm_os_type(g->zig_target->os); codegen_add_time_event(g, "LLVM Link"); if (g->verbose_link) { fprintf(stderr, "ar rcs %s", buf_ptr(&g->output_file_path)); - for (size_t i = 0; i < g->link_objects.length; i += 1) { - fprintf(stderr, " %s", (const char *)buf_ptr(g->link_objects.at(i))); + for (size_t i = 0; i < file_names.length; i += 1) { + fprintf(stderr, " %s", file_names.at(i)); } fprintf(stderr, "\n"); } |
