diff --git a/CMakeLists.txt b/CMakeLists.txt index d11414c005..03fae22296 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -643,7 +643,7 @@ set(ZIG_STD_FILES "special/bootstrap_lib.zig" "special/bootstrap_windows_tls.zig" "special/build_runner.zig" - "special/builtin.zig" + "special/c.zig" "special/compiler_rt.zig" "special/compiler_rt/stack_probe.zig" "special/compiler_rt/arm/aeabi_fcmp.zig" diff --git a/src/link.cpp b/src/link.cpp index dc73796247..7566838a36 100644 --- a/src/link.cpp +++ b/src/link.cpp @@ -776,8 +776,8 @@ 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, 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. + // when we link compiler_rt and libc.zig as libraries rather than objects. + // Here we workaround this by having compiler_rt and libc.zig be objects. // TODO write our own linker. https://github.com/ziglang/zig/issues/1535 if (parent_gen->zig_target->os == OsMacOSX) { child_out_type = OutTypeObj; @@ -787,7 +787,7 @@ static Buf *build_a_raw(CodeGen *parent_gen, const char *aname, Buf *full_path, parent_gen->libc); codegen_set_out_name(child_gen, buf_create_from_str(aname)); - // This is so that compiler_rt and builtin libraries know whether they + // This is so that compiler_rt and libc.zig libraries know whether they // will eventually be linked with libc. They make different decisions // about what to export depending on whether libc is linked. if (parent_gen->libc_link_lib != nullptr) { @@ -1002,8 +1002,8 @@ static void construct_linker_job_elf(LinkJob *lj) { if (!g->is_dummy_so && (g->out_type == OutTypeExe || is_dyn_lib)) { if (g->libc_link_lib == nullptr) { - Buf *builtin_a_path = build_a(g, "builtin"); - lj->args.append(buf_ptr(builtin_a_path)); + Buf *libc_a_path = build_a(g, "c"); + lj->args.append(buf_ptr(libc_a_path)); } Buf *compiler_rt_o_path = build_compiler_rt(g, OutTypeLib); @@ -1092,30 +1092,33 @@ static void construct_linker_job_wasm(LinkJob *lj) { lj->args.append("-error-limit=0"); - if (g->zig_target->os != OsWASI) { - lj->args.append("--no-entry"); // So lld doesn't look for _start. + if (g->out_type != OutTypeExe) { + lj->args.append("--no-entry"); // So lld doesn't look for _start. + + // If there are any C source files we cannot rely on individual exports. + if (g->c_source_files.length != 0) { + lj->args.append("--export-all"); + } else { + 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)); + } + } } lj->args.append("--allow-undefined"); 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)); - } + if (g->out_type != OutTypeObj) { + Buf *libc_a_path = build_a(g, "c"); + lj->args.append(buf_ptr(libc_a_path)); Buf *compiler_rt_o_path = build_compiler_rt(g, OutTypeLib); lj->args.append(buf_ptr(compiler_rt_o_path)); @@ -1356,8 +1359,8 @@ static void construct_linker_job_coff(LinkJob *lj) { 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"); - lj->args.append(buf_ptr(builtin_a_path)); + Buf *libc_a_path = build_a(g, "c"); + lj->args.append(buf_ptr(libc_a_path)); } // msvc compiler_rt is missing some stuff, so we still build it and rely on weak linkage diff --git a/src/target.cpp b/src/target.cpp index 1954fd7e2e..bf4cc6aac8 100644 --- a/src/target.cpp +++ b/src/target.cpp @@ -1376,6 +1376,9 @@ bool target_is_single_threaded(const ZigTarget *target) { } ZigLLVM_EnvironmentType target_default_abi(ZigLLVM_ArchType arch, Os os) { + if (arch == ZigLLVM_wasm32 || arch == ZigLLVM_wasm64) { + return ZigLLVM_Musl; + } switch (os) { case OsFreestanding: case OsAnanas: @@ -1490,6 +1493,7 @@ static const AvailableLibC libcs_available[] = { {ZigLLVM_systemz, OsLinux, ZigLLVM_Musl}, {ZigLLVM_sparc, OsLinux, ZigLLVM_GNU}, {ZigLLVM_sparcv9, OsLinux, ZigLLVM_GNU}, + {ZigLLVM_wasm32, OsFreestanding, ZigLLVM_Musl}, {ZigLLVM_x86_64, OsLinux, ZigLLVM_GNU}, {ZigLLVM_x86_64, OsLinux, ZigLLVM_GNUX32}, {ZigLLVM_x86_64, OsLinux, ZigLLVM_Musl}, @@ -1508,7 +1512,6 @@ bool target_can_build_libc(const ZigTarget *target) { } const char *target_libc_generic_name(const ZigTarget *target) { - assert(target->os == OsLinux); switch (target->abi) { case ZigLLVM_GNU: case ZigLLVM_GNUABIN32: @@ -1520,6 +1523,7 @@ const char *target_libc_generic_name(const ZigTarget *target) { case ZigLLVM_Musl: case ZigLLVM_MuslEABI: case ZigLLVM_MuslEABIHF: + case ZigLLVM_UnknownEnvironment: return "musl"; case ZigLLVM_CODE16: case ZigLLVM_EABI: @@ -1530,7 +1534,6 @@ const char *target_libc_generic_name(const ZigTarget *target) { case ZigLLVM_Cygnus: case ZigLLVM_CoreCLR: case ZigLLVM_Simulator: - case ZigLLVM_UnknownEnvironment: zig_unreachable(); } zig_unreachable(); diff --git a/std/special/builtin.zig b/std/special/c.zig similarity index 94% rename from std/special/builtin.zig rename to std/special/c.zig index 3776cc22bf..d5de52a6a3 100644 --- a/std/special/builtin.zig +++ b/std/special/c.zig @@ -1,10 +1,26 @@ -// These functions are provided when not linking against libc because LLVM -// sometimes generates code that calls them. +// This is Zig's multi-target implementation of libc. +// When builtin.link_libc is true, we need to export all the functions and +// provide an entire C API. +// Otherwise, only the functions which LLVM generates calls to need to be generated, +// such as memcpy, memset, and some math functions. const std = @import("std"); const builtin = @import("builtin"); const maxInt = std.math.maxInt; +const is_wasm = switch (builtin.arch) { .wasm32, .wasm64 => true, else => false}; +const is_freestanding = switch (builtin.os) { .freestanding => true, else => false }; +comptime { + if (is_freestanding and is_wasm) { + @export("_start", wasm_start, .Strong); + } +} + +extern fn main(argc: c_int, argv: [*][*]u8) c_int; +extern fn wasm_start() c_int { + return main(0, undefined); +} + // Avoid dragging in the runtime safety mechanisms into this .o file, // unless we're trying to test this file. pub fn panic(msg: []const u8, error_return_trace: ?*builtin.StackTrace) noreturn {