Skip to main content

devela/sys/os/linux/process/
entry.rs

1// devela::sys::os::linux::entry
2//
3//! Configures the global assembly for target-architecture-specific program entry points.
4//!
5//! This module defines the low-level assembly routines that serve as the initial
6//! execution point for the program. These routines are architecture-specific and handle:
7//! 1. Setting up the minimal execution environment
8//! 2. Transferring control to the Rust entry point
9//! 3. Properly exiting with the program's return status
10//!
11//! The implementations match the system's calling conventions and use architecture-specific
12//! syscall instructions for process termination.
13
14#[doc = crate::_tags!(linux code)]
15/// Defines the program entry point and main fn translation layer for Linux systems.
16#[doc = crate::_doc_meta!{location("sys/os/linux")}]
17///
18/// Handles architecture-specific entry point setup and Rust-to-C ABI translation.
19#[doc(hidden)]
20#[macro_export]
21macro_rules! linux_entry {
22    (
23    // The main() function will return LinuxResult, and get converted to LINUX_EXIT
24    linux_result) => {
25        $crate::linux_entry![main_body:
26            if let Err(e) = main() { e.to_exit_code() } else { $crate::LINUX_EXIT::OK }
27        ];
28    };
29    (
30    // $main_body: the body of the entry point function that receives the result of main()
31    main_body: $main_body:expr) => {
32        #[inline(never)]
33        #[unsafe(no_mangle)]
34        pub extern "C" fn __main() -> i32 { $main_body }
35        $crate::linux_entry!(_start: __main);
36    };
37    (
38    //
39    _start: $main:ident) => {
40        #[cfg(target_arch = "x86_64")]
41        $crate::global_asm!(
42            ".global _start",
43            ".hidden _start",
44            ".type _start,@function",
45            "_start:",
46                "call {main}",
47                "mov rdi, rax",
48                "mov rax, {EXIT}",
49                "syscall",
50                main = sym $main,
51                EXIT = const $crate::LINUX_SYS::EXIT,
52        );
53        #[cfg(target_arch = "x86")]
54        $crate::global_asm!(
55            ".global _start",
56            ".hidden _start",
57            ".type _start,@function",
58            "_start:",
59                "call {main}",
60                "mov ebx, eax",
61                "mov eax, {EXIT}",
62                "int 0x80",
63                main = sym $main,
64                EXIT = const $crate::LINUX_SYS::EXIT,
65        );
66        #[cfg(target_arch = "arm")]
67        $crate::global_asm!(
68            ".global _start",
69            ".hidden _start",
70            ".type _start,%function",
71            "_start:",
72                "bl {main}",
73                "mov r7, #{EXIT}",
74                "swi #0",
75                main = sym $main,
76                EXIT = const $crate::LINUX_SYS::EXIT,
77        );
78        #[cfg(target_arch = "aarch64")]
79        $crate::global_asm!(
80            ".global _start",
81            ".hidden _start",
82            ".type _start,%function",
83            "_start:",
84                "mov x29, #0", // clear frame pointer
85                "mov x30, #0", // clear link register
86                "and sp, sp, #~15", // align stack
87                "bl {main}",
88                "mov x8, #{EXIT}",
89                "svc #0",
90                main = sym $main,
91                EXIT = const $crate::LINUX_SYS::EXIT,
92        );
93        // NOTE: can't use `any_target_arch_riscv` because this is resolved in calling code
94        #[cfg(any(target_arch = "riscv32", target_arch = "riscv64"))]
95        $crate::global_asm!(
96            ".global _start",
97            ".hidden _start",
98            ".type _start,@function",
99            "_start:",
100                "call {main}",
101                "li a7, {EXIT}",
102                "ecall",
103                main = sym $main,
104                EXIT = const $crate::LINUX_SYS::EXIT,
105        );
106    };
107}
108#[doc(inline)]
109pub use linux_entry;