diff options
| author | Andrew Kelley <andrew@ziglang.org> | 2019-12-12 18:56:39 -0500 |
|---|---|---|
| committer | Andrew Kelley <andrew@ziglang.org> | 2019-12-12 18:56:39 -0500 |
| commit | 7699b5b997c7a024a6d9558df0ec72d71ef402fe (patch) | |
| tree | ea996d6252efe24158a802fb50c1a28c3b3d6717 /lib/std/special | |
| parent | 81f1f72197113a45e827d5c984e219a28aa28083 (diff) | |
| parent | fff3c1fff4c3ebfcb2bd4f08a43ae7815b5c446b (diff) | |
| download | zig-7699b5b997c7a024a6d9558df0ec72d71ef402fe.tar.gz zig-7699b5b997c7a024a6d9558df0ec72d71ef402fe.zip | |
Merge branch 'Xe-expose-callMain'
closes #3891
Diffstat (limited to 'lib/std/special')
| -rw-r--r-- | lib/std/special/c.zig | 2 | ||||
| -rw-r--r-- | lib/std/special/start.zig | 286 | ||||
| -rw-r--r-- | lib/std/special/start_windows_tls.zig | 48 | ||||
| -rw-r--r-- | lib/std/special/test_runner.zig | 6 |
4 files changed, 5 insertions, 337 deletions
diff --git a/lib/std/special/c.zig b/lib/std/special/c.zig index 4c2eb2a958..0895b1e6f9 100644 --- a/lib/std/special/c.zig +++ b/lib/std/special/c.zig @@ -83,7 +83,7 @@ pub fn panic(msg: []const u8, error_return_trace: ?*builtin.StackTrace) noreturn @setCold(true); std.debug.panic("{}", msg); } - if (builtin.os != .freestanding) { + if (builtin.os != .freestanding and builtin.os != .other) { std.os.abort(); } while (true) {} diff --git a/lib/std/special/start.zig b/lib/std/special/start.zig deleted file mode 100644 index 60745dab7f..0000000000 --- a/lib/std/special/start.zig +++ /dev/null @@ -1,286 +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; -const uefi = std.os.uefi; - -var starting_stack_ptr: [*]usize = undefined; - -const is_wasm = switch (builtin.arch) { - .wasm32, .wasm64 => true, - else => false, -}; - -const is_mips = switch (builtin.arch) { - .mips, .mipsel, .mips64, .mips64el => true, - else => false, -}; - -comptime { - if (builtin.output_mode == .Lib and builtin.link_mode == .Dynamic) { - if (builtin.os == .windows and !@hasDecl(root, "_DllMainCRTStartup")) { - @export("_DllMainCRTStartup", _DllMainCRTStartup, .Strong); - } - } else if (builtin.output_mode == .Exe or @hasDecl(root, "main")) { - if (builtin.link_libc and @hasDecl(root, "main")) { - if (@typeInfo(@TypeOf(root.main)).Fn.calling_convention != .C) { - @export("main", main, .Weak); - } - } else if (builtin.os == .windows) { - if (!@hasDecl(root, "WinMain") and !@hasDecl(root, "WinMainCRTStartup")) { - @export("WinMainCRTStartup", WinMainCRTStartup, .Strong); - } - } else if (builtin.os == .uefi) { - if (!@hasDecl(root, "EfiMain")) @export("EfiMain", EfiMain, .Strong); - } else if (builtin.os != .freestanding) { - if (is_mips) { - if (!@hasDecl(root, "__start")) @export("__start", _start, .Strong); - } else { - if (!@hasDecl(root, "_start")) @export("_start", _start, .Strong); - } - } else if (is_wasm) { - if (!@hasDecl(root, "_start")) @export("_start", wasm_freestanding_start, .Strong); - } - } -} - -stdcallcc fn _DllMainCRTStartup( - hinstDLL: std.os.windows.HINSTANCE, - fdwReason: std.os.windows.DWORD, - lpReserved: std.os.windows.LPVOID, -) std.os.windows.BOOL { - if (@hasDecl(root, "DllMain")) { - return root.DllMain(hinstDLL, fdwReason, lpReserved); - } - - return std.os.windows.TRUE; -} - -extern fn wasm_freestanding_start() void { - // 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. - _ = @call(.{ .modifier = .always_inline }, callMain, .{}); -} - -extern fn EfiMain(handle: uefi.Handle, system_table: *uefi.tables.SystemTable) usize { - const bad_efi_main_ret = "expected return type of main to be 'void', 'noreturn', or 'usize'"; - uefi.handle = handle; - uefi.system_table = system_table; - - switch (@typeInfo(@TypeOf(root.main).ReturnType)) { - .NoReturn => { - root.main(); - }, - .Void => { - root.main(); - return 0; - }, - .Int => |info| { - if (info.bits != @typeInfo(usize).Int.bits) { - @compileError(bad_efi_main_ret); - } - return root.main(); - }, - else => @compileError(bad_efi_main_ret), - } -} - -nakedcc fn _start() noreturn { - if (builtin.os == builtin.Os.wasi) { - // 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. - std.os.wasi.proc_exit(@call(.{ .modifier = .always_inline }, callMain, .{})); - } - - switch (builtin.arch) { - .x86_64 => { - starting_stack_ptr = asm ("" - : [argc] "={rsp}" (-> [*]usize) - ); - }, - .i386 => { - starting_stack_ptr = asm ("" - : [argc] "={esp}" (-> [*]usize) - ); - }, - .aarch64, .aarch64_be, .arm => { - starting_stack_ptr = asm ("mov %[argc], sp" - : [argc] "=r" (-> [*]usize) - ); - }, - .riscv64 => { - starting_stack_ptr = asm ("mv %[argc], sp" - : [argc] "=r" (-> [*]usize) - ); - }, - .mipsel => { - // Need noat here because LLVM is free to pick any register - starting_stack_ptr = asm ( - \\ .set noat - \\ move %[argc], $sp - : [argc] "=r" (-> [*]usize) - ); - }, - else => @compileError("unsupported arch"), - } - // If LLVM inlines stack variables into _start, they will overwrite - // the command line argument data. - @call(.{ .modifier = .never_inline }, posixCallMainAndExit, .{}); -} - -stdcallcc fn WinMainCRTStartup() noreturn { - @setAlignStack(16); - if (!builtin.single_threaded) { - _ = @import("start_windows_tls.zig"); - } - - std.debug.maybeEnableSegfaultHandler(); - - std.os.windows.kernel32.ExitProcess(initEventLoopAndCallMain()); -} - -// TODO https://github.com/ziglang/zig/issues/265 -fn posixCallMainAndExit() noreturn { - if (builtin.os == builtin.Os.freebsd) { - @setAlignStack(16); - } - const argc = starting_stack_ptr[0]; - const argv = @ptrCast([*][*:0]u8, starting_stack_ptr + 1); - - const envp_optional = @ptrCast([*:null]?[*:0]u8, argv + argc + 1); - var envp_count: usize = 0; - while (envp_optional[envp_count]) |_| : (envp_count += 1) {} - const envp = @ptrCast([*][*:0]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 - const gnu_stack_phdr = std.os.linux.tls.initTLS() orelse @panic("ELF missing stack size"); - - 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); - } - - // TODO This is disabled because what should we do when linking libc and this code - // does not execute? And also it's causing a test failure in stack traces in release modes. - - //// Linux ignores the stack size from the ELF file, and instead always does 8 MiB. A further - //// problem is that it uses PROT_GROWSDOWN which prevents stores to addresses too far down - //// the stack and requires "probing". So here we allocate our own stack. - //const wanted_stack_size = gnu_stack_phdr.p_memsz; - //assert(wanted_stack_size % std.mem.page_size == 0); - //// Allocate an extra page as the guard page. - //const total_size = wanted_stack_size + std.mem.page_size; - //const new_stack = std.os.mmap( - // null, - // total_size, - // std.os.PROT_READ | std.os.PROT_WRITE, - // std.os.MAP_PRIVATE | std.os.MAP_ANONYMOUS, - // -1, - // 0, - //) catch @panic("out of memory"); - //std.os.mprotect(new_stack[0..std.mem.page_size], std.os.PROT_NONE) catch {}; - //std.os.exit(@call(.{.stack = new_stack}, callMainWithArgs, .{argc, argv, envp})); - } - - std.os.exit(@call(.{ .modifier = .always_inline }, callMainWithArgs, .{ argc, argv, envp })); -} - -fn callMainWithArgs(argc: usize, argv: [*][*:0]u8, envp: [][*:0]u8) u8 { - std.os.argv = argv[0..argc]; - std.os.environ = envp; - - std.debug.maybeEnableSegfaultHandler(); - - return initEventLoopAndCallMain(); -} - -extern fn main(c_argc: i32, c_argv: [*][*:0]u8, c_envp: [*:null]?[*:0]u8) i32 { - var env_count: usize = 0; - while (c_envp[env_count] != null) : (env_count += 1) {} - const envp = @ptrCast([*][*:0]u8, c_envp)[0..env_count]; - return @call(.{ .modifier = .always_inline }, callMainWithArgs, .{ @intCast(usize, c_argc), c_argv, envp }); -} - -// General error message for a malformed return type -const bad_main_ret = "expected return type of main to be 'void', '!void', 'noreturn', 'u8', or '!u8'"; - -// 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 initEventLoopAndCallMain() u8 { - if (std.event.Loop.instance) |loop| { - if (!@hasDecl(root, "event_loop")) { - loop.init() catch |err| { - std.debug.warn("error: {}\n", .{@errorName(err)}); - if (@errorReturnTrace()) |trace| { - std.debug.dumpStackTrace(trace.*); - } - return 1; - }; - defer loop.deinit(); - - var result: u8 = undefined; - var frame: @Frame(callMainAsync) = undefined; - _ = @asyncCall(&frame, &result, callMainAsync, loop); - loop.run(); - return result; - } - } - - // 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. - return @call(.{ .modifier = .always_inline }, callMain, .{}); -} - -async fn callMainAsync(loop: *std.event.Loop) u8 { - // This prevents the event loop from terminating at least until main() has returned. - loop.beginOneEvent(); - defer loop.finishOneEvent(); - return callMain(); -} - -// This is not marked inline because it is called with @asyncCall when -// there is an event loop. -fn callMain() u8 { - switch (@typeInfo(@TypeOf(root.main).ReturnType)) { - .NoReturn => { - root.main(); - }, - .Void => { - root.main(); - return 0; - }, - .Int => |info| { - if (info.bits != 8) { - @compileError(bad_main_ret); - } - return root.main(); - }, - .ErrorUnion => { - const result = root.main() catch |err| { - std.debug.warn("error: {}\n", .{@errorName(err)}); - if (@errorReturnTrace()) |trace| { - std.debug.dumpStackTrace(trace.*); - } - return 1; - }; - switch (@typeInfo(@TypeOf(result))) { - .Void => return 0, - .Int => |info| { - if (info.bits != 8) { - @compileError(bad_main_ret); - } - return result; - }, - else => @compileError(bad_main_ret), - } - }, - else => @compileError(bad_main_ret), - } -} diff --git a/lib/std/special/start_windows_tls.zig b/lib/std/special/start_windows_tls.zig deleted file mode 100644 index bfd0e44122..0000000000 --- a/lib/std/special/start_windows_tls.zig +++ /dev/null @@ -1,48 +0,0 @@ -const std = @import("std"); -const builtin = @import("builtin"); - -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; - -comptime { - if (builtin.arch == .i386) { - // The __tls_array is the offset of the ThreadLocalStoragePointer field - // in the TEB block whose base address held in the %fs segment. - asm ( - \\ .global __tls_array - \\ __tls_array = 0x2C - ); - } -} - -// 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/lib/std/special/test_runner.zig b/lib/std/special/test_runner.zig index 7bb53774d3..0335c8562d 100644 --- a/lib/std/special/test_runner.zig +++ b/lib/std/special/test_runner.zig @@ -1,9 +1,9 @@ const std = @import("std"); const io = std.io; const builtin = @import("builtin"); -const test_fn_list = builtin.test_functions; pub fn main() anyerror!void { + const test_fn_list = builtin.test_functions; var ok_count: usize = 0; var skip_count: usize = 0; var progress = std.Progress{}; @@ -16,7 +16,9 @@ pub fn main() anyerror!void { var test_node = root_node.start(test_fn.name, null); test_node.activate(); progress.refresh(); - if (progress.terminal == null) std.debug.warn("{}/{} {}...", .{ i + 1, test_fn_list.len, test_fn.name }); + if (progress.terminal == null) { + std.debug.warn("{}/{} {}...", .{ i + 1, test_fn_list.len, test_fn.name }); + } if (test_fn.func()) |_| { ok_count += 1; test_node.end(); |
