feature. See also
. The project being documented here (as the example) is the Zig library itself.
start._start
fn _start() callconv(.naked) noreturn
File
Code
fn _start() callconv(.naked) noreturn {
if (native_os == .plan9 and native_arch == .x86_64) {
std.os.plan9.tos = asm volatile (""
: [tos] "={rax}" (-> *std.os.plan9.Tos),
);
}
// 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 => "",
.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 => "",
.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 => "",
else => @compileError("unsupported arch"),
});
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
);
// 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 =>
\\ 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 =>
\\ mov fp, 0
\\ mov blink, 0
\\ mov r0, sp
\\ and sp, sp, -16
\\ b %[posixCallMainAndExit]
,
.arm, .armeb, .thumb, .thumbeb =>
// 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 =>
// 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 =>
\\ 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 =>
\\ 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 =>
// 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 =>
\\ 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 =>
\\ 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:
\\ 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:
\\ 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 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:
\\ 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 =>
// 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 =>
// 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 =>
// 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 =>
\\ 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 =>
// i7 = LR
\\ mov %%g0, %%fp
\\ mov %%g0, %%i7
\\ add %%sp, 64, %%o0
\\ and %%sp, -8, %%sp
\\ ba,a %[posixCallMainAndExit]
,
.sparc64 =>
// (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)
\\ movi a0, 0
\\ movi a15, 0
\\ mov a2, sp
\\ movi a8, -16
\\ and sp, sp, a8
\\ call0 %[posixCallMainAndExit]
else
\\ 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),
);
}