diff --git a/CMakeLists.txt b/CMakeLists.txt index 7d34a253a53616031e8321221536ad3906def692..a2b5bfc469eeb4bf4b9f20d50bb47d562d1546ea 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -651,9 +651,9 @@ set(ZIG_STD_FILES "rb.zig" "segmented_list.zig" "sort.zig" - "special/bootstrap.zig" - "special/bootstrap_lib.zig" - "special/bootstrap_windows_tls.zig" + "special/start.zig" + "special/start_lib.zig" + "special/start_windows_tls.zig" "special/build_runner.zig" "special/c.zig" "special/compiler_rt.zig" diff --git a/src/all_types.hpp b/src/all_types.hpp index bb5bef04bbbe3702e61527c04c0e4040734f0bab..0dc86c4f55f2fab9e5dfdec919f21dc7f83b8866 100644 --- a/src/all_types.hpp +++ b/src/all_types.hpp @@ -1759,7 +1759,7 @@ struct CodeGen { ZigPackage *compile_var_package; ZigType *compile_var_import; ZigType *root_import; - ZigType *bootstrap_import; + ZigType *start_import; ZigType *test_runner_import; struct { diff --git a/src/codegen.cpp b/src/codegen.cpp index 6ad779fd243345cc4d51100d863b3467d7e551e9..72ba3c6c999e96ea3fc7519104d2068277182491 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -8524,8 +8524,8 @@ static ZigType *add_special_code(CodeGen *g, ZigPackage *package, const char *ba return add_source_file(g, package, resolved_path, import_code, SourceKindPkgMain); } -static ZigPackage *create_bootstrap_pkg(CodeGen *g, ZigPackage *pkg_with_main) { - ZigPackage *package = codegen_create_package(g, buf_ptr(g->zig_std_special_dir), "bootstrap.zig", "std.special"); +static ZigPackage *create_start_pkg(CodeGen *g, ZigPackage *pkg_with_main) { + ZigPackage *package = codegen_create_package(g, buf_ptr(g->zig_std_special_dir), "start.zig", "std.special"); package->package_table.put(buf_create_from_str("root"), pkg_with_main); return package; } @@ -8651,12 +8651,12 @@ static void gen_root_source(CodeGen *g) { !g->have_c_main && !g->have_winmain && !g->have_winmain_crt_startup && ((g->have_pub_main && g->out_type == OutTypeObj) || g->out_type == OutTypeExe)) { - g->bootstrap_import = add_special_code(g, create_bootstrap_pkg(g, g->root_package), "bootstrap.zig"); + g->start_import = add_special_code(g, create_start_pkg(g, g->root_package), "start.zig"); } if (g->zig_target->os == OsWindows && !g->have_dllmain_crt_startup && g->out_type == OutTypeLib && g->is_dynamic) { - g->bootstrap_import = add_special_code(g, create_bootstrap_pkg(g, g->root_package), "bootstrap_lib.zig"); + g->start_import = add_special_code(g, create_start_pkg(g, g->root_package), "start_lib.zig"); } if (!g->error_during_imports) { @@ -8664,7 +8664,7 @@ static void gen_root_source(CodeGen *g) { } if (g->is_test_build) { create_test_compile_var_and_add_test_runner(g); - g->bootstrap_import = add_special_code(g, create_bootstrap_pkg(g, g->test_runner_package), "bootstrap.zig"); + g->start_import = add_special_code(g, create_start_pkg(g, g->test_runner_package), "start.zig"); if (!g->error_during_imports) { semantic_analyze(g); diff --git a/std/special/bootstrap.zig b/std/special/bootstrap.zig deleted file mode 100644 index 7177f58b8a379e6f71223aea10282d9f479d5b35..0000000000000000000000000000000000000000 --- a/std/special/bootstrap.zig +++ /dev/null @@ -1,146 +0,0 @@ -// This file is included in the compilation unit when exporting an executable. - -const root = @import("root"); -const std = @import("std"); -const builtin = @import("builtin"); -const assert = std.debug.assert; - -var argc_ptr: [*]usize = undefined; - -const is_wasm = switch (builtin.arch) { - .wasm32, .wasm64 => true, - else => false, -}; - -comptime { - if (builtin.link_libc) { - @export("main", main, .Strong); - } else if (builtin.os == .windows) { - @export("WinMainCRTStartup", WinMainCRTStartup, .Strong); - } else if (is_wasm and builtin.os == .freestanding) { - @export("_start", wasm_freestanding_start, .Strong); - } else { - @export("_start", _start, .Strong); - } -} - -extern fn wasm_freestanding_start() void { - _ = callMain(); -} - -nakedcc fn _start() noreturn { - if (builtin.os == builtin.Os.wasi) { - std.os.wasi.proc_exit(callMain()); - } - - switch (builtin.arch) { - .x86_64 => { - argc_ptr = asm ("lea (%%rsp), %[argc]" - : [argc] "=r" (-> [*]usize) - ); - }, - .i386 => { - argc_ptr = asm ("lea (%%esp), %[argc]" - : [argc] "=r" (-> [*]usize) - ); - }, - .aarch64, .aarch64_be => { - argc_ptr = asm ("mov %[argc], sp" - : [argc] "=r" (-> [*]usize) - ); - }, - else => @compileError("unsupported arch"), - } - // If LLVM inlines stack variables into _start, they will overwrite - // the command line argument data. - @noInlineCall(posixCallMainAndExit); -} - -extern fn WinMainCRTStartup() noreturn { - @setAlignStack(16); - if (!builtin.single_threaded) { - _ = @import("bootstrap_windows_tls.zig"); - } - std.os.windows.kernel32.ExitProcess(callMain()); -} - -// TODO https://github.com/ziglang/zig/issues/265 -fn posixCallMainAndExit() noreturn { - if (builtin.os == builtin.Os.freebsd) { - @setAlignStack(16); - } - const argc = argc_ptr[0]; - const argv = @ptrCast([*][*]u8, argc_ptr + 1); - - const envp_optional = @ptrCast([*]?[*]u8, argv + argc + 1); - var envp_count: usize = 0; - while (envp_optional[envp_count]) |_| : (envp_count += 1) {} - const envp = @ptrCast([*][*]u8, envp_optional)[0..envp_count]; - - if (builtin.os == .linux) { - // Find the beginning of the auxiliary vector - const auxv = @ptrCast([*]std.elf.Auxv, envp.ptr + envp_count + 1); - std.os.linux.elf_aux_maybe = auxv; - // Initialize the TLS area - std.os.linux.tls.initTLS(); - - if (std.os.linux.tls.tls_image) |tls_img| { - const tls_addr = std.os.linux.tls.allocateTLS(tls_img.alloc_size); - const tp = std.os.linux.tls.copyTLS(tls_addr); - std.os.linux.tls.setThreadPointer(tp); - } - } - - std.os.exit(callMainWithArgs(argc, argv, envp)); -} - -// This is marked inline because for some reason LLVM in release mode fails to inline it, -// and we want fewer call frames in stack traces. -inline fn callMainWithArgs(argc: usize, argv: [*][*]u8, envp: [][*]u8) u8 { - std.os.argv = argv[0..argc]; - std.os.environ = envp; - return callMain(); -} - -extern fn main(c_argc: i32, c_argv: [*][*]u8, c_envp: [*]?[*]u8) i32 { - var env_count: usize = 0; - while (c_envp[env_count] != null) : (env_count += 1) {} - const envp = @ptrCast([*][*]u8, c_envp)[0..env_count]; - return callMainWithArgs(@intCast(usize, c_argc), c_argv, envp); -} - -// This is marked inline because for some reason LLVM in release mode fails to inline it, -// and we want fewer call frames in stack traces. -inline fn callMain() u8 { - switch (@typeId(@typeOf(root.main).ReturnType)) { - .NoReturn => { - root.main(); - }, - .Void => { - root.main(); - return 0; - }, - .Int => { - if (@typeOf(root.main).ReturnType.bit_count != 8) { - @compileError("expected return type of main to be 'u8', 'noreturn', 'void', or '!void'"); - } - return root.main(); - }, - .ErrorUnion => { - root.main() catch |err| { - std.debug.warn("error: {}\n", @errorName(err)); - if (builtin.os != builtin.Os.zen) { - if (@errorReturnTrace()) |trace| { - std.debug.dumpStackTrace(trace.*); - } - } - return 1; - }; - return 0; - }, - else => @compileError("expected return type of main to be 'u8', 'noreturn', 'void', or '!void'"), - } -} - -const main_thread_tls_align = 32; -var main_thread_tls_bytes: [64]u8 align(main_thread_tls_align) = [1]u8{0} ** 64; diff --git a/std/special/bootstrap_lib.zig b/std/special/bootstrap_lib.zig deleted file mode 100644 index 701eee389d1627522ad51393c0c8caf0eef52fd5..0000000000000000000000000000000000000000 --- a/std/special/bootstrap_lib.zig +++ /dev/null @@ -1,16 +0,0 @@ -// This file is included in the compilation unit when exporting a DLL on windows. - -const std = @import("std"); -const builtin = @import("builtin"); - -comptime { - @export("_DllMainCRTStartup", _DllMainCRTStartup, builtin.GlobalLinkage.Strong); -} - -stdcallcc fn _DllMainCRTStartup( - hinstDLL: std.os.windows.HINSTANCE, - fdwReason: std.os.windows.DWORD, - lpReserved: std.os.windows.LPVOID, -) std.os.windows.BOOL { - return std.os.windows.TRUE; -} diff --git a/std/special/bootstrap_windows_tls.zig b/std/special/bootstrap_windows_tls.zig deleted file mode 100644 index 71165d355b1f10c88574313910c3a75330acea6a..0000000000000000000000000000000000000000 --- a/std/special/bootstrap_windows_tls.zig +++ /dev/null @@ -1,36 +0,0 @@ -const std = @import("std"); - -export var _tls_index: u32 = std.os.windows.TLS_OUT_OF_INDEXES; -export var _tls_start: u8 linksection(".tls") = 0; -export var _tls_end: u8 linksection(".tls$ZZZ") = 0; -export var __xl_a: std.os.windows.PIMAGE_TLS_CALLBACK linksection(".CRT$XLA") = null; -export var __xl_z: std.os.windows.PIMAGE_TLS_CALLBACK linksection(".CRT$XLZ") = null; - -// TODO this is how I would like it to be expressed -// TODO also note, ReactOS has a +1 on StartAddressOfRawData and AddressOfCallBacks. Investigate -// why they do that. -//export const _tls_used linksection(".rdata$T") = std.os.windows.IMAGE_TLS_DIRECTORY { -// .StartAddressOfRawData = @ptrToInt(&_tls_start), -// .EndAddressOfRawData = @ptrToInt(&_tls_end), -// .AddressOfIndex = @ptrToInt(&_tls_index), -// .AddressOfCallBacks = @ptrToInt(__xl_a), -// .SizeOfZeroFill = 0, -// .Characteristics = 0, -//}; -// This is the workaround because we can't do @ptrToInt at comptime like that. -pub const IMAGE_TLS_DIRECTORY = extern struct { - StartAddressOfRawData: *c_void, - EndAddressOfRawData: *c_void, - AddressOfIndex: *c_void, - AddressOfCallBacks: *c_void, - SizeOfZeroFill: u32, - Characteristics: u32, -}; -export const _tls_used linksection(".rdata$T") = IMAGE_TLS_DIRECTORY{ - .StartAddressOfRawData = &_tls_start, - .EndAddressOfRawData = &_tls_end, - .AddressOfIndex = &_tls_index, - .AddressOfCallBacks = &__xl_a, - .SizeOfZeroFill = 0, - .Characteristics = 0, -}; diff --git a/std/special/start.zig b/std/special/start.zig new file mode 100644 index 0000000000000000000000000000000000000000..45348feab01302886ed904566b0d1528f0d41958 --- /dev/null +++ b/std/special/start.zig @@ -0,0 +1,146 @@ +// This file is included in the compilation unit when exporting an executable. + +const root = @import("root"); +const std = @import("std"); +const builtin = @import("builtin"); +const assert = std.debug.assert; + +var argc_ptr: [*]usize = undefined; + +const is_wasm = switch (builtin.arch) { + .wasm32, .wasm64 => true, + else => false, +}; + +comptime { + if (builtin.link_libc) { + @export("main", main, .Strong); + } else if (builtin.os == .windows) { + @export("WinMainCRTStartup", WinMainCRTStartup, .Strong); + } else if (is_wasm and builtin.os == .freestanding) { + @export("_start", wasm_freestanding_start, .Strong); + } else { + @export("_start", _start, .Strong); + } +} + +extern fn wasm_freestanding_start() void { + _ = callMain(); +} + +nakedcc fn _start() noreturn { + if (builtin.os == builtin.Os.wasi) { + std.os.wasi.proc_exit(callMain()); + } + + switch (builtin.arch) { + .x86_64 => { + argc_ptr = asm ("lea (%%rsp), %[argc]" + : [argc] "=r" (-> [*]usize) + ); + }, + .i386 => { + argc_ptr = asm ("lea (%%esp), %[argc]" + : [argc] "=r" (-> [*]usize) + ); + }, + .aarch64, .aarch64_be => { + argc_ptr = asm ("mov %[argc], sp" + : [argc] "=r" (-> [*]usize) + ); + }, + else => @compileError("unsupported arch"), + } + // If LLVM inlines stack variables into _start, they will overwrite + // the command line argument data. + @noInlineCall(posixCallMainAndExit); +} + +extern fn WinMainCRTStartup() noreturn { + @setAlignStack(16); + if (!builtin.single_threaded) { + _ = @import("start_windows_tls.zig"); + } + std.os.windows.kernel32.ExitProcess(callMain()); +} + +// TODO https://github.com/ziglang/zig/issues/265 +fn posixCallMainAndExit() noreturn { + if (builtin.os == builtin.Os.freebsd) { + @setAlignStack(16); + } + const argc = argc_ptr[0]; + const argv = @ptrCast([*][*]u8, argc_ptr + 1); + + const envp_optional = @ptrCast([*]?[*]u8, argv + argc + 1); + var envp_count: usize = 0; + while (envp_optional[envp_count]) |_| : (envp_count += 1) {} + const envp = @ptrCast([*][*]u8, envp_optional)[0..envp_count]; + + if (builtin.os == .linux) { + // Find the beginning of the auxiliary vector + const auxv = @ptrCast([*]std.elf.Auxv, envp.ptr + envp_count + 1); + std.os.linux.elf_aux_maybe = auxv; + // Initialize the TLS area + std.os.linux.tls.initTLS(); + + if (std.os.linux.tls.tls_image) |tls_img| { + const tls_addr = std.os.linux.tls.allocateTLS(tls_img.alloc_size); + const tp = std.os.linux.tls.copyTLS(tls_addr); + std.os.linux.tls.setThreadPointer(tp); + } + } + + std.os.exit(callMainWithArgs(argc, argv, envp)); +} + +// This is marked inline because for some reason LLVM in release mode fails to inline it, +// and we want fewer call frames in stack traces. +inline fn callMainWithArgs(argc: usize, argv: [*][*]u8, envp: [][*]u8) u8 { + std.os.argv = argv[0..argc]; + std.os.environ = envp; + return callMain(); +} + +extern fn main(c_argc: i32, c_argv: [*][*]u8, c_envp: [*]?[*]u8) i32 { + var env_count: usize = 0; + while (c_envp[env_count] != null) : (env_count += 1) {} + const envp = @ptrCast([*][*]u8, c_envp)[0..env_count]; + return callMainWithArgs(@intCast(usize, c_argc), c_argv, envp); +} + +// This is marked inline because for some reason LLVM in release mode fails to inline it, +// and we want fewer call frames in stack traces. +inline fn callMain() u8 { + switch (@typeId(@typeOf(root.main).ReturnType)) { + .NoReturn => { + root.main(); + }, + .Void => { + root.main(); + return 0; + }, + .Int => { + if (@typeOf(root.main).ReturnType.bit_count != 8) { + @compileError("expected return type of main to be 'u8', 'noreturn', 'void', or '!void'"); + } + return root.main(); + }, + .ErrorUnion => { + root.main() catch |err| { + std.debug.warn("error: {}\n", @errorName(err)); + if (builtin.os != builtin.Os.zen) { + if (@errorReturnTrace()) |trace| { + std.debug.dumpStackTrace(trace.*); + } + } + return 1; + }; + return 0; + }, + else => @compileError("expected return type of main to be 'u8', 'noreturn', 'void', or '!void'"), + } +} + +const main_thread_tls_align = 32; +var main_thread_tls_bytes: [64]u8 align(main_thread_tls_align) = [1]u8{0} ** 64; diff --git a/std/special/start_lib.zig b/std/special/start_lib.zig new file mode 100644 index 0000000000000000000000000000000000000000..701eee389d1627522ad51393c0c8caf0eef52fd5 --- /dev/null +++ b/std/special/start_lib.zig @@ -0,0 +1,16 @@ +// This file is included in the compilation unit when exporting a DLL on windows. + +const std = @import("std"); +const builtin = @import("builtin"); + +comptime { + @export("_DllMainCRTStartup", _DllMainCRTStartup, builtin.GlobalLinkage.Strong); +} + +stdcallcc fn _DllMainCRTStartup( + hinstDLL: std.os.windows.HINSTANCE, + fdwReason: std.os.windows.DWORD, + lpReserved: std.os.windows.LPVOID, +) std.os.windows.BOOL { + return std.os.windows.TRUE; +} diff --git a/std/special/start_windows_tls.zig b/std/special/start_windows_tls.zig new file mode 100644 index 0000000000000000000000000000000000000000..71165d355b1f10c88574313910c3a75330acea6a --- /dev/null +++ b/std/special/start_windows_tls.zig @@ -0,0 +1,36 @@ +const std = @import("std"); + +export var _tls_index: u32 = std.os.windows.TLS_OUT_OF_INDEXES; +export var _tls_start: u8 linksection(".tls") = 0; +export var _tls_end: u8 linksection(".tls$ZZZ") = 0; +export var __xl_a: std.os.windows.PIMAGE_TLS_CALLBACK linksection(".CRT$XLA") = null; +export var __xl_z: std.os.windows.PIMAGE_TLS_CALLBACK linksection(".CRT$XLZ") = null; + +// TODO this is how I would like it to be expressed +// TODO also note, ReactOS has a +1 on StartAddressOfRawData and AddressOfCallBacks. Investigate +// why they do that. +//export const _tls_used linksection(".rdata$T") = std.os.windows.IMAGE_TLS_DIRECTORY { +// .StartAddressOfRawData = @ptrToInt(&_tls_start), +// .EndAddressOfRawData = @ptrToInt(&_tls_end), +// .AddressOfIndex = @ptrToInt(&_tls_index), +// .AddressOfCallBacks = @ptrToInt(__xl_a), +// .SizeOfZeroFill = 0, +// .Characteristics = 0, +//}; +// This is the workaround because we can't do @ptrToInt at comptime like that. +pub const IMAGE_TLS_DIRECTORY = extern struct { + StartAddressOfRawData: *c_void, + EndAddressOfRawData: *c_void, + AddressOfIndex: *c_void, + AddressOfCallBacks: *c_void, + SizeOfZeroFill: u32, + Characteristics: u32, +}; +export const _tls_used linksection(".rdata$T") = IMAGE_TLS_DIRECTORY{ + .StartAddressOfRawData = &_tls_start, + .EndAddressOfRawData = &_tls_end, + .AddressOfIndex = &_tls_index, + .AddressOfCallBacks = &__xl_a, + .SizeOfZeroFill = 0, + .Characteristics = 0, +};