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.

_start

start._start
fn _start() callconv(.naked) noreturn

File

lib/std/start.zig:164

Code

fn _start() callconv(.naked) noreturn {
    // TODO set Top of Stack on non x86_64-plan9
    if (native_os == .plan9 and native_arch == .x86_64) {
        // from /sys/src/libc/amd64/main9.s
        std.os.plan9.tos = asm volatile (""
            : [tos] "={rax}" (-> *std.os.plan9.Tos),
        );
    }

    // This is the first userspace frame. Prevent DWARF-based unwinders from unwinding further. We
    // prevent FP-based unwinders from unwinding further by zeroing the register below.
    if (builtin.unwind_tables != .none or !builtin.strip_debug_info) asm volatile (switch (native_arch) {
            .aarch64, .aarch64_be => ".cfi_undefined lr",
            .alpha => ".cfi_undefined $26",
            .arc, .arceb => ".cfi_undefined blink",
            .arm, .armeb, .thumb, .thumbeb => "", // https://github.com/llvm/llvm-project/issues/115891
            .csky => ".cfi_undefined lr",
            .hexagon => ".cfi_undefined r31",
            .kvx => ".cfi_undefined r14",
            .loongarch32, .loongarch64 => ".cfi_undefined 1",
            .m68k => ".cfi_undefined %%pc",
            .m88k => ".cfi_undefined %%r1",
            .microblaze, .microblazeel => "", // No CFI support.
            .mips, .mipsel, .mips64, .mips64el => ".cfi_undefined $ra",
            .or1k => ".cfi_undefined r9",
            .powerpc, .powerpcle, .powerpc64, .powerpc64le => ".cfi_undefined lr",
            .riscv32, .riscv32be, .riscv64, .riscv64be => if (builtin.zig_backend == .stage2_riscv64)
                ""
            else
                ".cfi_undefined ra",
            .s390x => ".cfi_undefined %%r14",
            .sh, .sheb => ".cfi_undefined pr",
            .sparc, .sparc64 => ".cfi_undefined %%i7",
            .x86 => ".cfi_undefined %%eip",
            .x86_64 => ".cfi_undefined %%rip",
            .xtensa, .xtensaeb => "", // No CFI support.
            else => @compileError("unsupported arch"),
        });

    // Move this to the riscv prong below when this is resolved: https://github.com/ziglang/zig/issues/20918
    if (builtin.cpu.arch.isRISCV() and builtin.zig_backend != .stage2_riscv64) asm volatile (
        \\ .weak __global_pointer$
        \\ .hidden __global_pointer$
        \\ .option push
        \\ .option norelax
        \\ lla gp, __global_pointer$
        \\ .option pop
    );

    // Note that we maintain a very low level of trust with regards to ABI guarantees at this point.
    // We will redundantly align the stack, clear the link register, etc. While e.g. the Linux
    // kernel is usually good about upholding the ABI guarantees, the same cannot be said of dynamic
    // linkers; musl's ldso, for example, opts to not align the stack when invoking the dynamic
    // linker explicitly.
    asm volatile (switch (native_arch) {
            .x86_64 =>
            \\ xorl %%ebp, %%ebp
            \\ movq %%rsp, %%rdi
            \\ andq $-16, %%rsp
            \\ callq %[posixCallMainAndExit:P]
            ,
            .x86 =>
            \\ xorl %%ebp, %%ebp
            \\ movl %%esp, %%eax
            \\ andl $-16, %%esp
            \\ subl $12, %%esp
            \\ pushl %%eax
            \\ calll %[posixCallMainAndExit:P]
            ,
            .aarch64, .aarch64_be =>
            \\ mov fp, #0
            \\ mov lr, #0
            \\ mov x0, sp
            \\ and sp, x0, #-16
            \\ b %[posixCallMainAndExit]
            ,
            .alpha =>
            // $15 = FP, $26 = LR, $29 = GP, $30 = SP
            \\ br $29, 1f
            \\1:
            \\ ldgp $29, 0($29)
            \\ mov 0, $15
            \\ mov 0, $26
            \\ mov $30, $16
            \\ ldi $1, -16
            \\ and $30, $30, $1
            \\ jsr $26, %[posixCallMainAndExit]
            ,
            .arc, .arceb =>
            // ARC v1 and v2 had a very low stack alignment requirement of 4; v3 increased it to 16.
            \\ mov fp, 0
            \\ mov blink, 0
            \\ mov r0, sp
            \\ and sp, sp, -16
            \\ b %[posixCallMainAndExit]
            ,
            .arm, .armeb, .thumb, .thumbeb =>
            // Note that this code must work for Thumb-1.
            // r7 = FP (local), r11 = FP (unwind)
            \\ movs v1, #0
            \\ mov r7, v1
            \\ mov r11, v1
            \\ mov lr, v1
            \\ mov a1, sp
            \\ subs v1, #16
            \\ ands v1, a1
            \\ mov sp, v1
            \\ b %[posixCallMainAndExit]
            ,
            .csky =>
            // The CSKY ABI assumes that `gb` is set to the address of the GOT in order for
            // position-independent code to work. We depend on this in `std.pie` to locate
            // `_DYNAMIC` as well.
            // r8 = FP
            \\ grs t0, 1f
            \\ 1:
            \\ lrw gb, 1b@GOTPC
            \\ addu gb, t0
            \\ movi r8, 0
            \\ movi lr, 0
            \\ mov a0, sp
            \\ andi sp, sp, -8
            \\ jmpi %[posixCallMainAndExit]
            ,
            .hexagon =>
            // r29 = SP, r30 = FP, r31 = LR
            \\ r30 = #0
            \\ r31 = #0
            \\ r0 = r29
            \\ r29 = and(r29, #-8)
            \\ memw(r29 + #-8) = r29
            \\ r29 = add(r29, #-8)
            \\ call %[posixCallMainAndExit]
            ,
            .kvx =>
            \\ make $fp = 0
            \\ ;;
            \\ set $ra = $fp
            \\ copyd $r0 = $sp
            \\ andd $sp = $sp, -32
            \\ ;;
            \\ goto %[posixCallMainAndExit]
            ,
            .loongarch32 =>
            \\ move $fp, $zero
            \\ move $ra, $zero
            \\ move $a0, $sp
            \\ srli.w $sp, $sp, 4
            \\ slli.w $sp, $sp, 4
            \\ b %[posixCallMainAndExit]
            ,
            .loongarch64 =>
            \\ move $fp, $zero
            \\ move $ra, $zero
            \\ move $a0, $sp
            \\ bstrins.d $sp, $zero, 3, 0
            \\ b %[posixCallMainAndExit]
            ,
            .or1k =>
            // r1 = SP, r2 = FP, r9 = LR
            \\ l.ori r2, r0, 0
            \\ l.ori r9, r0, 0
            \\ l.ori r3, r1, 0
            \\ l.andi r1, r1, -4
            \\ l.jal %[posixCallMainAndExit]
            ,
            .riscv32, .riscv32be, .riscv64, .riscv64be =>
            \\ li fp, 0
            \\ li ra, 0
            \\ mv a0, sp
            \\ andi sp, sp, -16
            \\ tail %[posixCallMainAndExit]@plt
            ,
            .m68k =>
            // Note that the - 8 is needed because pc in the jsr instruction points into the middle
            // of the jsr instruction. (The lea is 6 bytes, the jsr is 4 bytes.)
            \\ suba.l %%fp, %%fp
            \\ move.l %%sp, %%a0
            \\ move.l %%a0, %%d0
            \\ and.l #-4, %%d0
            \\ move.l %%d0, %%sp
            \\ move.l %%a0, -(%%sp)
            \\ lea %[posixCallMainAndExit] - . - 8, %%a0
            \\ jsr (%%pc, %%a0)
            ,
            .m88k =>
            // r1 = LR, r30 = FP, r31 = SP
            \\ or %%r0, %%r0, %%r0
            \\ or %%r0, %%r0, %%r0
            \\ or %%30, %%r0, %%r0
            \\ or %%r1, %%r0, %%r0
            \\ or %%r2, %%r31, %%r0
            \\ clr %%r31, %%r31, 4<0>
            \\ br.n %[posixCallMainAndExit]
            ,
            .microblaze, .microblazeel =>
            // r1 = SP, r15 = LR, r19 = FP, r20 = GP
            \\ ori r15, r0, 0
            \\ ori r19, r0, 0
            \\ mfs r20, rpc
            \\ addi r20, r20, _GLOBAL_OFFSET_TABLE_ + 8
            \\ ori r5, r1, 0
            \\ andi r1, r1, -4
            \\ brlid r15, %[posixCallMainAndExit]
            ,
            .mips, .mipsel =>
            \\ move $fp, $zero
            \\ bal 1f
            \\ .gpword .
            \\ .gpword %[posixCallMainAndExit]
            \\1:
            // The `gp` register on MIPS serves a similar purpose to `r2` (ToC pointer) on PPC64.
            \\ lw $gp, 0($ra)
            \\ nop
            \\ subu $gp, $ra, $gp
            \\ lw $t9, 4($ra)
            \\ nop
            \\ addu $t9, $t9, $gp
            \\ move $ra, $zero
            \\ move $a0, $sp
            \\ and $sp, -8
            \\ subu $sp, $sp, 16
            \\ jalr $t9
            ,
            .mips64, .mips64el => switch (builtin.abi) {
                .gnuabin32, .muslabin32, .abin32 =>
                \\ move $fp, $zero
                \\ bal 1f
                \\ .gpword .
                \\ .gpword %[posixCallMainAndExit]
                \\1:
                // The `gp` register on MIPS serves a similar purpose to `r2` (ToC pointer) on PPC64.
                \\ lw $gp, 0($ra)
                \\ subu $gp, $ra, $gp
                \\ lw $t9, 4($ra)
                \\ addu $t9, $t9, $gp
                \\ move $ra, $zero
                \\ move $a0, $sp
                \\ and $sp, -8
                \\ subu $sp, $sp, 16
                \\ jalr $t9
                ,
                else =>
                \\ move $fp, $zero
                // This is needed because early MIPS versions don't support misaligned loads. Without
                // this directive, the hidden `nop` inserted to fill the delay slot after `bal` would
                // cause the two doublewords to be aligned to 4 bytes instead of 8.
                \\ .balign 8
                \\ bal 1f
                \\ .gpdword .
                \\ .gpdword %[posixCallMainAndExit]
                \\1:
                // The `gp` register on MIPS serves a similar purpose to `r2` (ToC pointer) on PPC64.
                \\ ld $gp, 0($ra)
                \\ dsubu $gp, $ra, $gp
                \\ ld $t9, 8($ra)
                \\ daddu $t9, $t9, $gp
                \\ move $ra, $zero
                \\ move $a0, $sp
                \\ and $sp, -16
                \\ dsubu $sp, $sp, 16
                \\ jalr $t9
                ,
            },
            .powerpc, .powerpcle =>
            // Set up the initial stack frame, and clear the back chain pointer.
            // r1 = SP, r31 = FP
            \\ mr 3, 1
            \\ clrrwi 1, 1, 4
            \\ li 0, 0
            \\ stwu 1, -16(1)
            \\ stw 0, 0(1)
            \\ li 31, 0
            \\ mtlr 0
            \\ b %[posixCallMainAndExit]
            ,
            .powerpc64, .powerpc64le =>
            // Set up the ToC and initial stack frame, and clear the back chain pointer.
            // r1 = SP, r2 = ToC, r31 = FP
            \\ addis 2, 12, .TOC. - %[_start]@ha
            \\ addi 2, 2, .TOC. - %[_start]@l
            \\ mr 3, 1
            \\ clrrdi 1, 1, 4
            \\ li 0, 0
            \\ stdu 0, -32(1)
            \\ li 31, 0
            \\ mtlr 0
            \\ b %[posixCallMainAndExit]
            \\ nop
            ,
            .s390x =>
            // Set up the stack frame (register save area and cleared back-chain slot).
            // r11 = FP, r14 = LR, r15 = SP
            \\ lghi %%r11, 0
            \\ lghi %%r14, 0
            \\ lgr %%r2, %%r15
            \\ lghi %%r0, -16
            \\ ngr %%r15, %%r0
            \\ aghi %%r15, -160
            \\ lghi %%r0, 0
            \\ stg  %%r0, 0(%%r15)
            \\ jg %[posixCallMainAndExit]
            ,
            .sh, .sheb =>
            // r14 = FP, r15 = SP, pr = LR
            \\ mov #0, r0
            \\ lds r0, pr
            \\ mov r0, r14
            \\ mov r15, r4
            \\ mov #-4, r0
            \\ and r0, r15
            \\ mov.l 2f, r1
            \\1:
            \\ bsrf r1
            \\2:
            \\ .balign 4
            \\ .long %[posixCallMainAndExit]@PCREL - (1b + 4 - .)
            ,
            .sparc =>
            // argc is stored after a register window (16 registers * 4 bytes).
            // i7 = LR
            \\ mov %%g0, %%fp
            \\ mov %%g0, %%i7
            \\ add %%sp, 64, %%o0
            \\ and %%sp, -8, %%sp
            \\ ba,a %[posixCallMainAndExit]
            ,
            .sparc64 =>
            // argc is stored after a register window (16 registers * 8 bytes) plus the stack bias
            // (2047 bytes).
            // i7 = LR
            \\ mov %%g0, %%fp
            \\ mov %%g0, %%i7
            \\ add %%sp, 2175, %%o0
            \\ add %%sp, 2047, %%sp
            \\ and %%sp, -16, %%sp
            \\ sub %%sp, 2047, %%sp
            \\ ba,a %[posixCallMainAndExit]
            ,
            .xtensa, .xtensaeb => if (builtin.abi == .call0)
                // a0 = LR, a15 = FP, a1 = SP
                \\ movi a0, 0
                \\ movi a15, 0
                \\ mov a2, sp
                \\ movi a8, -16
                \\ and sp, sp, a8
                \\ call0 %[posixCallMainAndExit]
            else
                // a0 = LR, a7 = FP, a1 = SP
                \\ movi a0, 0
                \\ movi a7, 0
                \\ mov a6, sp
                \\ movi a8, -16
                \\ and sp, sp, a8
                \\ call4 %[posixCallMainAndExit]
            ,
            else => @compileError("unsupported arch"),
        }
        :
        : [_start] "X" (&_start),
          [posixCallMainAndExit] "X" (&posixCallMainAndExit),
    );
}