Rust的入口函数

起因

在调试Rust的时候,在Clion调用堆栈信息看到的.程序最早执行的不是main函数.在Windows下mainCRTStartup(其实在执行mainCRTStartup先执行其他的,只是看不到调用的函数,只能看到调用了ntdll.dll和kernel32.dll).先看看图.

Rust程序执行的时候,调用了ntdll.dll和kernel32.dll

Rust程序执行的时候,调用mainCRTStartup
在上图看到main函数,不是Rust的main函数,在main函数调用lang_start函数,可以说这个是Rust程序中的入口函数.
看一下调用关系图:

看过调用关系图,在看代码就容易理解了.lang_start函数,在Windows下C:/Users/用户名/.rustup/toolchains/stable-x86_64-pc-windows-gnu/lib/rustlib/src/rust/src/libstd/rt.rs
Rust的入口函数关系图

代码

fn lang_start_internal(
    main: &(dyn Fn() -> i32 + Sync + crate::panic::RefUnwindSafe),
    argc: isize,
    argv: *const *const u8,
) -> isize {
    use crate::panic;
    use crate::sys;
    use crate::sys_common;
    use crate::sys_common::thread_info;
    use crate::thread::Thread;

    sys::init();

    unsafe {
        let main_guard = sys::thread::guard::init();
        sys::stack_overflow::init();

        // Next, set up the current Thread with the guard information we just
        // created. Note that this isn't necessary in general for new threads,
        // but we just do this to name the main thread and to give it correct
        // info about the stack bounds.
        let thread = Thread::new(Some("main".to_owned()));
        thread_info::set(main_guard, thread);

        // Store our args if necessary in a squirreled away location
        sys::args::init(argc, argv);

        // Let's run some code!
        let exit_code = panic::catch_unwind(|| {
            sys_common::backtrace::__rust_begin_short_backtrace(move || main())
        });

        sys_common::cleanup();
        exit_code.unwrap_or(101) as isize
    }
}

#[cfg(not(test))]
#[lang = "start"]
fn lang_start<T: crate::process::Termination + 'static>(
    main: fn() -> T,
    argc: isize,
    argv: *const *const u8,
) -> isize {
    lang_start_internal(&move || main().report(), argc, argv)
}

Rust在Windows系统上,目前还是依赖C Runime(msvcrt.dll),可以通过查看生成的exe在petool中看到依赖,所以暂时不清楚是否在lang_start_internal是否堆的初始化,不过可以根据看到代码发现是lang_start_internal实例一个线程并设置为主线程.

秋风 2020-04-07