#[doc(hidden)]
#[naked]
#[no_mangle]
pub unsafe extern "C" fn _start() -> ! {
llvm_asm!(
"
/* set stack pointer to bootinfo structure */
movl %ebx, %esp
/* setup a one-word stack will overwrite the beginning of the bootinfo structure */
addl $$4, %esp
/* save a backup of the affected bootinfo word */
movl (%ebx), %esi
/* now do the important stuff */
jmp _real_start
"
:
:
: "esp", "ebx", "esi", "memory"
: "volatile"
);
core::intrinsics::unreachable();
}
#[naked]
#[no_mangle]
#[doc(hidden)]
pub unsafe extern "C" fn _real_start() -> ! {
llvm_asm!(
"
/* esp is currently bottom of stack, make it top of stack */
addl $1, %esp
/* put a nonsensical value in ebp so we fail fast if we touch it */
movl $$0xdeadbeef, %ebp
/* fix the corrupted value in the bootinfo structure */
movl %esi, (%ebx)
"
:
: "{esp}" (&(STACK.stack))
"i" (STACK_SIZE)
: "esp", "ebp", "ebx", "memory"
: "volatile"
);
llvm_asm!(
"
pushl %eax
movw $$((7 << 3) | 3), %ax
movw %ax, %fs
popl %eax
"
:
:
:
: "volatile"
);
llvm_asm!(
"
pushl %ebx
call __sel4_start_init_boot_info
/* We drop another word off the stack pointer so that rustc's generated
* main can scrape the 'argc' and 'argv' off the stack.
* TODO: why is this necessary? Caller cleanup of above %ebx? */
addl $$4, %esp
"
:
:
:
: "volatile"
);
llvm_asm!(
"
/* Null terminate auxv */
pushl $$0
pushl $$0
/* Null terminate envp */
pushl $$0
/* add at least one environment string (why?) */
pushl $0
/* Null terminate argv */
pushl $$0
/* Give an argv[0] */
pushl $1
/* Give argc */
pushl $$1
/* No atexit */
movl $$0, %edx
/* Now go to the 'main' stub that rustc generates */
call main
"
:
: "{eax}" (ENVIRONMENT_STRING as *const [u8] as *const u8),
"{ebx}" (PROG_NAME as *const [u8] as *const u8)
:
: "volatile"
);
core::intrinsics::unreachable();
}