@@ -55,212 +55,47 @@ pub unsafe extern "C" fn memset(s: *mut u8, c: i32, n: usize) -> *mut u8 {
5555 s
5656}
5757
58- /// Calculates the length of a null-terminated string .
58+ /// Compares two byte sequences .
5959///
6060/// # Safety
6161///
62- /// `s` must be a valid pointer to a null-terminated string .
62+ /// `s1` and `s2` must be valid pointers to memory of at least `n` bytes .
6363#[ unsafe( no_mangle) ]
64- pub const unsafe extern "C" fn strlen ( s : * const u8 ) -> usize {
65- let mut len = 0 ;
66- while unsafe { * s. add ( len) } != 0 {
67- len += 1 ;
68- }
69- len
70- }
71-
72- /// Function pointer type for the main application entry point.
73- /// The function receives argc and argv and should return an exit code.
74- pub type MainFn = unsafe extern "C" fn ( i32 , * const * const u8 ) -> i32 ;
75-
76- static mut MAIN_FN : Option < MainFn > = None ;
77-
78- /// Register the main function to be called from the entry point.
79- /// This must be called before the program starts (e.g., in a constructor).
80- pub fn register_main ( main_fn : MainFn ) {
81- unsafe {
82- MAIN_FN = Some ( main_fn) ;
64+ pub unsafe extern "C" fn bcmp ( s1 : * const u8 , s2 : * const u8 , n : usize ) -> i32 {
65+ for i in 0 ..n {
66+ let a = unsafe { * s1. add ( i) } ;
67+ let b = unsafe { * s2. add ( i) } ;
68+ if a != b {
69+ return i32:: from ( a) - i32:: from ( b) ;
70+ }
8371 }
72+ 0
8473}
8574
86- /// Rust entry point called from `_start` assembly.
87- ///
88- /// The `stack` pointer points to:
89- /// `[rsp]` = argc
90- /// `[rsp+8]` = argv[0]
91- /// etc.
75+ /// Compares two byte sequences.
9276///
9377/// # Safety
9478///
95- /// The `stack` pointer must point to valid stack memory set up by the kernel
96- /// AND the binary must define a `main` function with the following signature:
97- ///
98- /// ```rust,ignore
99- /// unsafe extern "C" fn main(argc: i32, argv: *const *const u8) -> i32`
100- /// ```
79+ /// `s1` and `s2` must be valid pointers to memory of at least `n` bytes.
10180#[ unsafe( no_mangle) ]
102- pub unsafe extern "C" fn entry_rust ( stack : * const usize ) -> i32 {
103- // Read argc and argv from stack
104- let argc = unsafe { * stack } ;
105- let argv = unsafe { stack. add ( 1 ) . cast :: < * const u8 > ( ) } ;
106-
107- // SAFETY: argc is unlikely to exceed i32::MAX on real systems
108- let argc_i32 = i32:: try_from ( argc) . unwrap_or ( i32:: MAX ) ;
109-
110- // Call the main function (defined by the binary crate)
111- unsafe { main ( argc_i32, argv) }
112- }
113-
114- // External main function that must be defined by the binary using this crate.
115- // Signature: `unsafe extern "C" fn main(argc: i32, argv: *const *const u8) ->
116- // i32`
117- unsafe extern "C" {
118- fn main ( argc : i32 , argv : * const * const u8 ) -> i32 ;
81+ pub unsafe extern "C" fn memcmp ( s1 : * const u8 , s2 : * const u8 , n : usize ) -> i32 {
82+ unsafe { bcmp ( s1, s2, n) }
11983}
12084
121- #[ cfg( target_arch = "x86_64" ) ]
122- mod entry {
123- use core:: arch:: naked_asm;
124-
125- /// Entry point that receives stack pointer directly from kernel.
126- /// On `x86_64` Linux at program start:
127- ///
128- /// - `[rsp]` = argc
129- /// - `[rsp+8]` = argv[0]
130- /// - `[rsp+16]` = argv[1]
131- /// - ...
132- /// - `[rsp+8n]` = NULL
133- /// - `[rsp+8n+8]` = envp[0]
134- ///
135- /// # Safety
136- ///
137- /// This is a naked function with no prologue or epilogue. It directly
138- /// manipulates the stack pointer (`rsp`) and assumes it was called by the
139- /// kernel with a valid stack containing argc and argv. The function:
140- ///
141- /// - Reads from `[rsp]` without validating the pointer
142- /// - Modifies `rsp` directly (16-byte alignment)
143- /// - Does not preserve any registers
144- /// - Does not return normally (exits via syscall)
145- ///
146- /// This function MUST only be used as the program entry point (`_start`).
147- /// Calling it from any other context is undefined behavior. This has been
148- /// your safety notice. I WILL put UB in your Rust program.
149- #[ unsafe( no_mangle) ]
150- #[ unsafe( naked) ]
151- pub unsafe extern "C" fn _start ( ) {
152- naked_asm ! (
153- // Move stack pointer to first argument register
154- "mov rdi, rsp" ,
155- // Align stack to 16-byte boundary (System V AMD64 ABI requirement)
156- "and rsp, -16" ,
157- // Call into Rust code
158- "call {entry_rust}" ,
159- // Move return code to syscall argument
160- "mov rdi, rax" ,
161- // Exit syscall
162- "mov rax, 60" , // SYS_exit
163- "syscall" ,
164- entry_rust = sym super :: entry_rust,
165- ) ;
166- }
167- }
168-
169- #[ cfg( target_arch = "aarch64" ) ]
170- mod entry {
171- use core:: arch:: naked_asm;
172-
173- /// Entry point that receives stack pointer directly from kernel.
174- /// On `aarch64` Linux at program start, the stack layout is identical
175- /// to x86_64:
176- ///
177- /// - `[sp]` = argc
178- /// - `[sp+8]` = argv[0]
179- /// - ...
180- ///
181- /// # Safety
182- ///
183- /// This is a naked function with no prologue or epilogue. It directly
184- /// manipulates the stack pointer (`sp`) and assumes it was called by the
185- /// kernel with a valid stack containing argc and argv. The function:
186- ///
187- /// - Reads from `[sp]` without validating the pointer
188- /// - Modifies `sp` directly (16-byte alignment)
189- /// - Does not preserve any registers
190- /// - Does not return normally (exits via SVC instruction)
191- ///
192- /// This function MUST only be used as the program entry point (`_start`).
193- /// Calling it from any other context is undefined behavior.
194- #[ unsafe( no_mangle) ]
195- #[ unsafe( naked) ]
196- pub unsafe extern "C" fn _start ( ) {
197- naked_asm ! (
198- // Move stack pointer to first argument register
199- "mov x0, sp" ,
200- // Align stack to 16-byte boundary (AArch64 ABI requirement)
201- "and sp, sp, -16" ,
202- // Call into Rust code
203- "bl {entry_rust}" ,
204- // Move return code to syscall argument
205- "mov x0, x0" ,
206- // Exit syscall
207- "mov x8, 93" , // SYS_exit
208- "svc #0" ,
209- entry_rust = sym super :: entry_rust,
210- ) ;
211- }
212- }
213-
214- #[ cfg( target_arch = "riscv64" ) ]
215- mod entry {
216- use core:: arch:: naked_asm;
217-
218- /// Entry point that receives stack pointer directly from kernel.
219- /// On `riscv64` Linux at program start, the stack layout is identical
220- /// to x86_64:
221- ///
222- /// - `[sp]` = argc
223- /// - `[sp+8]` = argv[0]
224- /// - ...
225- ///
226- /// # Safety
227- ///
228- /// This is a naked function with no prologue or epilogue. It directly
229- /// manipulates the stack pointer (`sp`) and assumes it was called by the
230- /// kernel with a valid stack containing argc and argv. The function:
231- ///
232- /// - Reads from `[sp]` without validating the pointer
233- /// - Modifies `sp` directly (16-byte alignment)
234- /// - Does not preserve any registers
235- /// - Does not return normally (exits via ECALL instruction)
236- ///
237- /// This function MUST only be used as the program entry point (`_start`).
238- /// Calling it from any other context is undefined behavior.
239- #[ unsafe( no_mangle) ]
240- #[ unsafe( naked) ]
241- pub unsafe extern "C" fn _start ( ) {
242- naked_asm ! (
243- // Move stack pointer to first argument register
244- "mv a0, sp" ,
245- // Align stack to 16-byte boundary (RISC-V ABI requirement)
246- "andi sp, sp, -16" ,
247- // Call into Rust code
248- "call {entry_rust}" ,
249- // Move return code to syscall argument
250- "mv a0, a0" ,
251- // Exit syscall
252- "li a7, 93" , // SYS_exit
253- "ecall" ,
254- entry_rust = sym super :: entry_rust,
255- ) ;
85+ /// Calculates the length of a null-terminated string.
86+ ///
87+ /// # Safety
88+ ///
89+ /// `s` must be a valid pointer to a null-terminated string.
90+ #[ unsafe( no_mangle) ]
91+ pub const unsafe extern "C" fn strlen ( s : * const u8 ) -> usize {
92+ let mut len = 0 ;
93+ while unsafe { * s. add ( len) } != 0 {
94+ len += 1 ;
25695 }
96+ len
25797}
25898
259- // Re-export the entry point
260- #[ cfg( target_arch = "x86_64" ) ] pub use entry:: _start;
261- #[ cfg( target_arch = "aarch64" ) ] pub use entry:: _start;
262- #[ cfg( target_arch = "riscv64" ) ] pub use entry:: _start;
263-
26499/// Direct syscall to open a file
265100///
266101/// # Returns
0 commit comments