aboutsummaryrefslogtreecommitdiff
path: root/src/link.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/link.cpp')
-rw-r--r--src/link.cpp308
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");
}