参考:
认识 Cargo - Rust语言圣经(Rust Course)
新建一个hello world 程序:
- fn main() {
- println!("Hello, world!");
- }
用IDA 打开exe,并加载符号:


双击该符号,然后按x,快捷键,查看所有的符号引用:
之后跳转到对应的程序位置:

PE 起始地址为140000000

读取"hello,world"字符的指令地址:140001040:


- 0:000> kp
- # Child-SP RetAddr Call Site
- 00 000000e6`c38ff9a8 00007ff7`b2571006 hello_world!__ImageBase
- 01 000000e6`c38ff9b0 00007ff7`b257101c hello_world!__ImageBase
- 02 000000e6`c38ff9e0 00007ff7`b25736a8 hello_world!__ImageBase
- 03 (Inline Function) --------`-------- hello_world!std::rt::lang_start_internal::closure$2(void)+0xb [/rustc/cc66ad468955717ab92600c770da8c1601a4ff33/library\std\src\rt.rs @ 148]
- 04 (Inline Function) --------`-------- hello_world!std::panicking::try::do_call(void)+0xb [/rustc/cc66ad468955717ab92600c770da8c1601a4ff33/library\std\src\panicking.rs @ 502]
- 05 (Inline Function) --------`-------- hello_world!std::panicking::try(void)+0xb [/rustc/cc66ad468955717ab92600c770da8c1601a4ff33/library\std\src\panicking.rs @ 466]
- 06 (Inline Function) --------`-------- hello_world!std::panic::catch_unwind(void)+0xb [/rustc/cc66ad468955717ab92600c770da8c1601a4ff33/library\std\src\panic.rs @ 142]
- 07 000000e6`c38ffa10 00007ff7`b25710ac hello_world!std::rt::lang_start_internal(void)+0xb8 [/rustc/cc66ad468955717ab92600c770da8c1601a4ff33/library\std\src\rt.rs @ 148]
- 08 000000e6`c38ffb10 00007ff7`b258a510 hello_world!main+0x2c
- 09 (Inline Function) --------`-------- hello_world!invoke_main(void)+0x22 [D:\a\_work\1\s\src\vctools\crt\vcstartup\src\startup\exe_common.inl @ 78]
- 0a 000000e6`c38ffb50 00007ffc`c2a0257d hello_world!__scrt_common_main_seh(void)+0x10c [D:\a\_work\1\s\src\vctools\crt\vcstartup\src\startup\exe_common.inl @ 288]
- 0b 000000e6`c38ffb90 00007ffc`c39caa78 KERNEL32!BaseThreadInitThunk+0x1d
- 0c 000000e6`c38ffbc0 00000000`00000000 ntdll!RtlUserThreadStart+0x28
- //! Runtime services
- //!
- //! The `rt` module provides a narrow set of runtime services,
- //! including the global heap (exported in `heap`) and unwinding and
- //! backtrace support. The APIs in this module are highly unstable,
- //! and should be considered as private implementation details for the
- //! time being.
-
- #![unstable(
- feature = "rt",
- reason = "this public module should not exist and is highly likely \
- to disappear",
- issue = "none"
- )]
- #![doc(hidden)]
- #![deny(unsafe_op_in_unsafe_fn)]
- #![allow(unused_macros)]
-
- use crate::ffi::CString;
-
- // Re-export some of our utilities which are expected by other crates.
- pub use crate::panicking::{begin_panic, panic_count};
- pub use core::panicking::{panic_display, panic_fmt};
-
- use crate::sync::Once;
- use crate::sys;
- use crate::sys_common::thread_info;
- use crate::thread::Thread;
-
- // Prints to the "panic output", depending on the platform this may be:
- // - the standard error output
- // - some dedicated platform specific output
- // - nothing (so this macro is a no-op)
- macro_rules! rtprintpanic {
- ($($t:tt)*) => {
- if let Some(mut out) = crate::sys::stdio::panic_output() {
- let _ = crate::io::Write::write_fmt(&mut out, format_args!($($t)*));
- }
- }
- }
-
- macro_rules! rtabort {
- ($($t:tt)*) => {
- {
- rtprintpanic!("fatal runtime error: {}\n", format_args!($($t)*));
- crate::sys::abort_internal();
- }
- }
- }
-
- macro_rules! rtassert {
- ($e:expr) => {
- if !$e {
- rtabort!(concat!("assertion failed: ", stringify!($e)));
- }
- };
- }
-
- macro_rules! rtunwrap {
- ($ok:ident, $e:expr) => {
- match $e {
- $ok(v) => v,
- ref err => {
- let err = err.as_ref().map(drop); // map Ok/Some which might not be Debug
- rtabort!(concat!("unwrap failed: ", stringify!($e), " = {:?}"), err)
- }
- }
- };
- }
-
- // One-time runtime initialization.
- // Runs before `main`.
- // SAFETY: must be called only once during runtime initialization.
- // NOTE: this is not guaranteed to run, for example when Rust code is called externally.
- //
- // # The `sigpipe` parameter
- //
- // Since 2014, the Rust runtime on Unix has set the `SIGPIPE` handler to
- // `SIG_IGN`. Applications have good reasons to want a different behavior
- // though, so there is a `#[unix_sigpipe = "..."]` attribute on `fn main()` that
- // can be used to select how `SIGPIPE` shall be setup (if changed at all) before
- // `fn main()` is called. See
- // for more info.
- //
- // The `sigpipe` parameter to this function gets its value via the code that
- // rustc generates to invoke `fn lang_start()`. The reason we have `sigpipe` for
- // all platforms and not only Unix, is because std is not allowed to have `cfg`
- // directives as this high level. See the module docs in
- // `src/tools/tidy/src/pal.rs` for more info. On all other platforms, `sigpipe`
- // has a value, but its value is ignored.
- //
- // Even though it is an `u8`, it only ever has 4 values. These are documented in
- // `compiler/rustc_session/src/config/sigpipe.rs`.
- #[cfg_attr(test, allow(dead_code))]
- unsafe fn init(argc: isize, argv: *const *const u8, sigpipe: u8) {
- unsafe {
- sys::init(argc, argv, sigpipe);
-
- let main_guard = sys::thread::guard::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(rtunwrap!(Ok, CString::new("main"))));
- thread_info::set(main_guard, thread);
- }
- }
-
- // One-time runtime cleanup.
- // Runs after `main` or at program exit.
- // NOTE: this is not guaranteed to run, for example when the program aborts.
- pub(crate) fn cleanup() {
- static CLEANUP: Once = Once::new();
- CLEANUP.call_once(|| unsafe {
- // Flush stdout and disable buffering.
- crate::io::cleanup();
- // SAFETY: Only called once during runtime cleanup.
- sys::cleanup();
- });
- }
-
- // To reduce the generated code of the new `lang_start`, this function is doing
- // the real work.
- #[cfg(not(test))]
- fn lang_start_internal(
- main: &(dyn Fn() -> i32 + Sync + crate::panic::RefUnwindSafe),
- argc: isize,
- argv: *const *const u8,
- sigpipe: u8,
- ) -> Result<isize, !> {
- use crate::{mem, panic};
- let rt_abort = move |e| {
- mem::forget(e);
- rtabort!("initialization or cleanup bug");
- };
- // Guard against the code called by this function from unwinding outside of the Rust-controlled
- // code, which is UB. This is a requirement imposed by a combination of how the
- // `#[lang="start"]` attribute is implemented as well as by the implementation of the panicking
- // mechanism itself.
- //
- // There are a couple of instances where unwinding can begin. First is inside of the
- // `rt::init`, `rt::cleanup` and similar functions controlled by bstd. In those instances a
- // panic is a std implementation bug. A quite likely one too, as there isn't any way to
- // prevent std from accidentally introducing a panic to these functions. Another is from
- // user code from `main` or, more nefariously, as described in e.g. issue #86030.
- // SAFETY: Only called once during runtime initialization.
- panic::catch_unwind(move || unsafe { init(argc, argv, sigpipe) }).map_err(rt_abort)?;
- let ret_code = panic::catch_unwind(move || panic::catch_unwind(main).unwrap_or(101) as isize)
- .map_err(move |e| {
- mem::forget(e);
- rtabort!("drop of the panic payload panicked");
- });
- panic::catch_unwind(cleanup).map_err(rt_abort)?;
- ret_code
- }
-
- #[cfg(not(test))]
- #[lang = "start"]
- fn lang_start
'static>( - main: fn() -> T,
- argc: isize,
- argv: *const *const u8,
- sigpipe: u8,
- ) -> isize {
- let Ok(v) = lang_start_internal(
- &move || crate::sys_common::backtrace::__rust_begin_short_backtrace(main).report().to_i32(),
- argc,
- argv,
- sigpipe,
- );
- v
- }
其核心运行时如上
看起来是利用panic 库进行一些基本的异常捕获与异常处理。
panic! 深入剖析 - Rust语言圣经(Rust Course)
- fn main() {
- panic!("crash and burn");
- }
- PS E:\learn\rust\panic_test> $env:RUST_BACKTRACE="full" ; cargo run release
- Compiling panic_test v0.1.0 (E:\learn\rust\panic_test)
- Finished dev [unoptimized + debuginfo] target(s) in 0.18s
- Running `target\debug\panic_test.exe release`
- thread 'main' panicked at src\main.rs:2:5:
- crash and burn
- stack backtrace:
- 0: 0x7ff7a439709a - std::sys_common::backtrace::_print::impl$0::fmt
- at /rustc/cc66ad468955717ab92600c770da8c1601a4ff33/library\std\src\sys_common\backtrace.rs:44
- 1: 0x7ff7a43a52db - core::fmt::rt::Argument::fmt
- at /rustc/cc66ad468955717ab92600c770da8c1601a4ff33/library\core\src\fmt\rt.rs:138
- 2: 0x7ff7a43a52db - core::fmt::write
- at /rustc/cc66ad468955717ab92600c770da8c1601a4ff33/library\core\src\fmt\mod.rs:1094
- 3: 0x7ff7a43953d1 - std::io::Write::write_fmt
- at /rustc/cc66ad468955717ab92600c770da8c1601a4ff33/library\std\src\io\mod.rs:1714
- 4: 0x7ff7a4396e1a - std::sys_common::backtrace::_print
- at /rustc/cc66ad468955717ab92600c770da8c1601a4ff33/library\std\src\sys_common\backtrace.rs:47
- 5: 0x7ff7a4396e1a - std::sys_common::backtrace::print
- at /rustc/cc66ad468955717ab92600c770da8c1601a4ff33/library\std\src\sys_common\backtrace.rs:34
- 6: 0x7ff7a4398e4a - std::panicking::default_hook::closure$1
- at /rustc/cc66ad468955717ab92600c770da8c1601a4ff33/library\std\src\panicking.rs:270
- 7: 0x7ff7a4398ab8 - std::panicking::default_hook
- at /rustc/cc66ad468955717ab92600c770da8c1601a4ff33/library\std\src\panicking.rs:290
- 8: 0x7ff7a43994fe - std::panicking::rust_panic_with_hook
- at /rustc/cc66ad468955717ab92600c770da8c1601a4ff33/library\std\src\panicking.rs:707
- 9: 0x7ff7a43993aa - std::panicking::begin_panic_handler::closure$0
- at /rustc/cc66ad468955717ab92600c770da8c1601a4ff33/library\std\src\panicking.rs:597
- 10: 0x7ff7a4397a89 - std::sys_common::backtrace::__rust_end_short_backtrace
$0,never$> - at /rustc/cc66ad468955717ab92600c770da8c1601a4ff33/library\std\src\sys_common\backtrace.rs:170
- 11: 0x7ff7a43990f0 - std::panicking::begin_panic_handler
- at /rustc/cc66ad468955717ab92600c770da8c1601a4ff33/library\std\src\panicking.rs:595
- 12: 0x7ff7a43aa235 - core::panicking::panic_fmt
- at /rustc/cc66ad468955717ab92600c770da8c1601a4ff33/library\core\src\panicking.rs:67
- 13: 0x7ff7a43910a1 - panic_test::main
- at E:\learn\rust\panic_test\src\main.rs:2
- 14: 0x7ff7a439123b - core::ops::function::FnOnce::call_once
> - at /rustc/cc66ad468955717ab92600c770da8c1601a4ff33\library\core\src\ops\function.rs:250
- 15: 0x7ff7a439119e - std::sys_common::backtrace::__rust_begin_short_backtrace
> - at /rustc/cc66ad468955717ab92600c770da8c1601a4ff33\library\std\src\sys_common\backtrace.rs:154
- 16: 0x7ff7a439119e - std::sys_common::backtrace::__rust_begin_short_backtrace
> - at /rustc/cc66ad468955717ab92600c770da8c1601a4ff33\library\std\src\sys_common\backtrace.rs:154
- 17: 0x7ff7a4391061 - std::rt::lang_start::closure$0
> - at /rustc/cc66ad468955717ab92600c770da8c1601a4ff33\library\std\src\rt.rs:166
- 18: 0x7ff7a4393558 - std::rt::lang_start_internal::closure$2
- at /rustc/cc66ad468955717ab92600c770da8c1601a4ff33/library\std\src\rt.rs:148
- 19: 0x7ff7a4393558 - std::panicking::try::do_call
- at /rustc/cc66ad468955717ab92600c770da8c1601a4ff33/library\std\src\panicking.rs:502
- 20: 0x7ff7a4393558 - std::panicking::try
- at /rustc/cc66ad468955717ab92600c770da8c1601a4ff33/library\std\src\panicking.rs:466
- 21: 0x7ff7a4393558 - std::panic::catch_unwind
- at /rustc/cc66ad468955717ab92600c770da8c1601a4ff33/library\std\src\panic.rs:142
- 22: 0x7ff7a4393558 - std::rt::lang_start_internal
- at /rustc/cc66ad468955717ab92600c770da8c1601a4ff33/library\std\src\rt.rs:148
- 23: 0x7ff7a439103a - std::rt::lang_start
> - at /rustc/cc66ad468955717ab92600c770da8c1601a4ff33\library\std\src\rt.rs:165
- 24: 0x7ff7a43910c9 - main
- 25: 0x7ff7a43a8c80 - invoke_main
- at D:\a\_work\1\s\src\vctools\crt\vcstartup\src\startup\exe_common.inl:78
- 26: 0x7ff7a43a8c80 - __scrt_common_main_seh
- at D:\a\_work\1\s\src\vctools\crt\vcstartup\src\startup\exe_common.inl:288
- 27: 0x7ffcc2a0257d - BaseThreadInitThunk
- 28: 0x7ffcc39caa78 - RtlUserThreadStart
- error: process didn't exit successfully: `target\debug\panic_test.exe release` (exit code: 101)
- fn main() {
- let v = vec![1, 2, 3];
-
- v[99];
- }
- PS E:\learn\rust\panic_test> $env:RUST_BACKTRACE="full" ; cargo run release
- Finished dev [unoptimized + debuginfo] target(s) in 0.00s
- Running `target\debug\panic_test.exe release`
- thread 'main' panicked at src\main.rs:4:6:
- index out of bounds: the len is 3 but the index is 99
- stack backtrace:
- 0: 0x7ff75aca794a - std::sys_common::backtrace::_print::impl$0::fmt
- at /rustc/cc66ad468955717ab92600c770da8c1601a4ff33/library\std\src\sys_common\backtrace.rs:44
- 1: 0x7ff75acb5c1b - core::fmt::rt::Argument::fmt
- at /rustc/cc66ad468955717ab92600c770da8c1601a4ff33/library\core\src\fmt\rt.rs:138
- 2: 0x7ff75acb5c1b - core::fmt::write
- at /rustc/cc66ad468955717ab92600c770da8c1601a4ff33/library\core\src\fmt\mod.rs:1094
- 3: 0x7ff75aca5c81 - std::io::Write::write_fmt
- at /rustc/cc66ad468955717ab92600c770da8c1601a4ff33/library\std\src\io\mod.rs:1714
- 4: 0x7ff75aca76ca - std::sys_common::backtrace::_print
- at /rustc/cc66ad468955717ab92600c770da8c1601a4ff33/library\std\src\sys_common\backtrace.rs:47
- 5: 0x7ff75aca76ca - std::sys_common::backtrace::print
- at /rustc/cc66ad468955717ab92600c770da8c1601a4ff33/library\std\src\sys_common\backtrace.rs:34
- 6: 0x7ff75aca978a - std::panicking::default_hook::closure$1
- at /rustc/cc66ad468955717ab92600c770da8c1601a4ff33/library\std\src\panicking.rs:270
- 7: 0x7ff75aca93f8 - std::panicking::default_hook
- at /rustc/cc66ad468955717ab92600c770da8c1601a4ff33/library\std\src\panicking.rs:290
- 8: 0x7ff75aca9e3e - std::panicking::rust_panic_with_hook
- at /rustc/cc66ad468955717ab92600c770da8c1601a4ff33/library\std\src\panicking.rs:707
- 9: 0x7ff75aca9d2d - std::panicking::begin_panic_handler::closure$0
- at /rustc/cc66ad468955717ab92600c770da8c1601a4ff33/library\std\src\panicking.rs:599
- 10: 0x7ff75aca8339 - std::sys_common::backtrace::__rust_end_short_backtrace
$0,never$> - at /rustc/cc66ad468955717ab92600c770da8c1601a4ff33/library\std\src\sys_common\backtrace.rs:170
- 11: 0x7ff75aca9a30 - std::panicking::begin_panic_handler
- at /rustc/cc66ad468955717ab92600c770da8c1601a4ff33/library\std\src\panicking.rs:595
- 12: 0x7ff75acbab75 - core::panicking::panic_fmt
- at /rustc/cc66ad468955717ab92600c770da8c1601a4ff33/library\core\src\panicking.rs:67
- 13: 0x7ff75acbacee - core::panicking::panic_bounds_check
- at /rustc/cc66ad468955717ab92600c770da8c1601a4ff33/library\core\src\panicking.rs:162
- 14: 0x7ff75aca1afd - core::slice::index::impl$2::index
- at /rustc/cc66ad468955717ab92600c770da8c1601a4ff33\library\core\src\slice\index.rs:261
- 15: 0x7ff75aca1076 - alloc::vec::impl$12::index
- at /rustc/cc66ad468955717ab92600c770da8c1601a4ff33\library\alloc\src\vec\mod.rs:2675
- 16: 0x7ff75aca1366 - panic_test::main
- at E:\learn\rust\panic_test\src\main.rs:4
- 17: 0x7ff75aca14ab - core::ops::function::FnOnce::call_once
> - at /rustc/cc66ad468955717ab92600c770da8c1601a4ff33\library\core\src\ops\function.rs:250
- 18: 0x7ff75aca13de - std::sys_common::backtrace::__rust_begin_short_backtrace
> - at /rustc/cc66ad468955717ab92600c770da8c1601a4ff33\library\std\src\sys_common\backtrace.rs:154
- 19: 0x7ff75aca13de - std::sys_common::backtrace::__rust_begin_short_backtrace
> - at /rustc/cc66ad468955717ab92600c770da8c1601a4ff33\library\std\src\sys_common\backtrace.rs:154
- 20: 0x7ff75aca12e1 - std::rt::lang_start::closure$0
> - at /rustc/cc66ad468955717ab92600c770da8c1601a4ff33\library\std\src\rt.rs:166
- 21: 0x7ff75aca3e08 - std::rt::lang_start_internal::closure$2
- at /rustc/cc66ad468955717ab92600c770da8c1601a4ff33/library\std\src\rt.rs:148
- 22: 0x7ff75aca3e08 - std::panicking::try::do_call
- at /rustc/cc66ad468955717ab92600c770da8c1601a4ff33/library\std\src\panicking.rs:502
- 23: 0x7ff75aca3e08 - std::panicking::try
- at /rustc/cc66ad468955717ab92600c770da8c1601a4ff33/library\std\src\panicking.rs:466
- 24: 0x7ff75aca3e08 - std::panic::catch_unwind
- at /rustc/cc66ad468955717ab92600c770da8c1601a4ff33/library\std\src\panic.rs:142
- 25: 0x7ff75aca3e08 - std::rt::lang_start_internal
- at /rustc/cc66ad468955717ab92600c770da8c1601a4ff33/library\std\src\rt.rs:148
- 26: 0x7ff75aca12ba - std::rt::lang_start
> - at /rustc/cc66ad468955717ab92600c770da8c1601a4ff33\library\std\src\rt.rs:165
- 27: 0x7ff75aca13c9 - main
- 28: 0x7ff75acb95c0 - invoke_main
- at D:\a\_work\1\s\src\vctools\crt\vcstartup\src\startup\exe_common.inl:78
- 29: 0x7ff75acb95c0 - __scrt_common_main_seh
- at D:\a\_work\1\s\src\vctools\crt\vcstartup\src\startup\exe_common.inl:288
- 30: 0x7ffcc2a0257d - BaseThreadInitThunk
- 31: 0x7ffcc39caa78 - RtlUserThreadStart
- error: process didn't exit successfully: `target\debug\panic_test.exe release` (exit code: 101)
可以看到,包括我们用windbg 看到的,比较完整的js 运行时的入口都看到了
rust 程序main 入口前,就已经安装了一个默认的panic handler ,用来打印一些全局的错误信息,和堆栈列表。
- int __cdecl main(int argc, const char **argv, const char **envp)
- {
- char v4; // [rsp+20h] [rbp-18h]
- __int64 (__fastcall *v5)(); // [rsp+30h] [rbp-8h] BYREF
-
- v5 = sub_140001040;
- v4 = 0;
- return std::rt::lang_start_internal::h8a2184178aa988dc(&v5, &off_14001D360, argc, argv, v4);
- }
其中,sub_140001040 即为main 函数:
- __int64 sub_140001040()
- {
- __int64 v1[3]; // [rsp+28h] [rbp-30h] BYREF
- __int128 v2; // [rsp+40h] [rbp-18h]
-
- v1[0] = (__int64)&off_14001D3A0;
- v1[1] = 1i64;
- v1[2] = (__int64)"called `Option::unwrap()` on a `None` value";
- v2 = 0i64;
- return std::io::stdio::_print::h445fdab5382e0576(v1);
- }