Zig 0.17.0-dev (Split by item)

This is an example of documentation generated by ZigDoc, an alternative to Zig's built-in Auto Doc feature. See also examples in other modes/formats. The project being documented here (as the example) is the Zig library itself.

posixCallMainAndExit

start.posixCallMainAndExit
fn posixCallMainAndExit(argc_argv_ptr: [*]usize) callconv(.c) noreturn

File

lib/std/start.zig:563

Code

fn posixCallMainAndExit(argc_argv_ptr: [*]usize) callconv(.c) noreturn {
    // We're not ready to panic until thread local storage is initialized.
    @setRuntimeSafety(false);
    // Code coverage instrumentation might try to use thread local variables.
    @disableInstrumentation();
    const argc = argc_argv_ptr[0];
    const argv: [*][*:0]u8 = @ptrCast(argc_argv_ptr + 1);

    const envp_optional: [*:null]?[*:0]u8 = @ptrCast(@alignCast(argv + argc + 1));
    var envp_count: usize = 0;
    while (envp_optional[envp_count]) |_| : (envp_count += 1) {}
    const envp = envp_optional[0..envp_count :null];

    // Find the beginning of the auxiliary vector
    const auxv: [*]elf.Auxv = @ptrCast(@alignCast(envp.ptr + envp_count + 1));

    var at_hwcap: usize = 0;
    const phdrs = init: {
        var i: usize = 0;
        var at_phdr: usize = 0;
        var at_phnum: usize = 0;
        while (auxv[i].a_type != elf.AT_NULL) : (i += 1) {
            switch (auxv[i].a_type) {
                elf.AT_PHNUM => at_phnum = auxv[i].a_un.a_val,
                elf.AT_PHDR => at_phdr = auxv[i].a_un.a_val,
                elf.AT_HWCAP => at_hwcap = auxv[i].a_un.a_val,
                else => continue,
            }
        }
        break :init @as([*]elf.Phdr, @ptrFromInt(at_phdr))[0..at_phnum];
    };

    // Apply the initial relocations as early as possible in the startup process. We cannot
    // make calls yet on some architectures (e.g. MIPS) *because* they haven't been applied yet,
    // so this must be fully inlined.
    if (builtin.link_mode == .static and builtin.position_independent_executable) {
        @call(.always_inline, std.pie.relocate, .{phdrs});
    }

    if (native_os == .linux) {
        // This must be done after PIE relocations have been applied or we may crash
        // while trying to access the global variable (happens on MIPS at least).
        std.os.linux.elf_aux_maybe = auxv;

        if (!builtin.single_threaded) {
            // ARMv6 targets (and earlier) have no support for TLS in hardware.
            // FIXME: Elide the check for targets >= ARMv7 when the target feature API
            // becomes less verbose (and more usable).
            if (comptime native_arch.isArm()) {
                if (at_hwcap & std.os.linux.HWCAP.TLS == 0) {
                    // FIXME: Make __aeabi_read_tp call the kernel helper kuser_get_tls
                    // For the time being use a simple trap instead of a @panic call to
                    // keep the binary bloat under control.
                    @trap();
                }
            }

            // Initialize the TLS area.
            std.os.linux.tls.initStatic(phdrs);
        }

        // The way Linux executables represent stack size is via the PT_GNU_STACK
        // program header. However the kernel does not recognize it; it always gives 8 MiB.
        // Here we look for the stack size in our program headers and use setrlimit
        // to ask for more stack space.
        expandStackSize(phdrs);
    }

    const opt_init_array_start = @extern([*]const *const fn () callconv(.c) void, .{
        .name = "__init_array_start",
        .linkage = .weak,
    });
    const opt_init_array_end = @extern([*]const *const fn () callconv(.c) void, .{
        .name = "__init_array_end",
        .linkage = .weak,
    });
    if (opt_init_array_start) |init_array_start| {
        const init_array_end = opt_init_array_end.?;
        const slice = init_array_start[0 .. init_array_end - init_array_start];
        for (slice) |func| func();
    }

    std.process.exit(callMainWithArgs(argc, argv, envp));
}