//! The user-space process entry shim. Every user binary roots `_start` here (via //! `entry = _start` in build.zig) and forces this file to be analysed with //! `comptime { _ = &runtime.start._start; }`, so the whole runtime is linked in. const std = @import("std"); const system = @import("system.zig"); /// The kernel enters at `_start` with rsp 16-aligned, pointing at the System V /// process-entry block it built: argc, argv pointers, NULL, envp terminator, the /// auxiliary vector, then the strings (see system/kernel/process.zig, /// `buildEntryStack`). Capture that address in rdi — the first SysV argument — /// before `call` disturbs the stack; the call's pushed return address also puts /// rsp ≡ 8 (mod 16), satisfying the ABI before any Zig frame runs. The `ud2` is a /// safety net if `rt_start` ever returns. pub export fn _start() callconv(.naked) noreturn { asm volatile ( \\mov %%rsp, %%rdi \\call rt_start \\ud2 ); } // The process-entry block, recorded by `rt_start` for the accessors below. var argument_count: usize = 0; var argument_vector: [*]const u64 = undefined; /// The first Zig frame, entered with `stack` pointing at the kernel-built entry /// block. Record argc/argv for the accessors, then hand control to the program's /// `main`. The heap is lazy (first alloc grows it), so there is no other runtime /// init to order here. export fn rt_start(stack: [*]const u64) callconv(.c) noreturn { argument_count = stack[0]; argument_vector = stack + 1; const root = @import("root"); // the user binary's root source file root.main(); system.exit(0); } /// Number of process arguments (argc). At least 1: argument 0 is the path or /// name this binary was spawned as. pub fn argumentCount() usize { return argument_count; } /// Process argument `index` (0 = the program's own path/name), or an empty slice /// if out of range. The bytes live in the entry block at the top of the stack /// page, NUL-terminated, valid for the process's lifetime. pub fn argument(index: usize) []const u8 { if (index >= argument_count) return ""; const string: [*:0]const u8 = @ptrFromInt(argument_vector[index]); return std.mem.span(string); } /// No runtime to unwind into — report a panic as a nonzero exit code. pub const panic = std.debug.FullPanic(struct { fn panic(_: []const u8, _: ?usize) noreturn { system.exit(127); } }.panic);