Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

is compiled with syscall feature working? #1024

Closed
lishaowen0426 opened this issue Jan 7, 2024 · 2 comments
Closed

is compiled with syscall feature working? #1024

lishaowen0426 opened this issue Jan 7, 2024 · 2 comments

Comments

@lishaowen0426
Copy link

lishaowen0426 commented Jan 7, 2024

In initd

extern "C" {
		#[cfg(all(not(test), not(feature = "syscall")))]
		fn runtime_entry(argc: i32, argv: *const *const u8, env: *const *const u8) -> !;
		#[cfg(all(not(test), feature = "syscall"))]
		fn main() -> !;
		#[cfg(feature = "newlib")]
		fn init_lwip();
		#[cfg(feature = "newlib")]
		fn init_rtl8139_netif(freq: u32) -> i32;
	}
unsafe {
		// And finally start the application.
		#[cfg(all(not(test), not(feature = "syscall")))]
		runtime_entry(argc, argv, environ);
		#[cfg(all(not(test), feature = "syscall"))]
		main();
}

When compiled with syscall feature, initd makes a call to main.

Here, main is assumed to be a non-return function. In my case, this main seems to be the one auto-generated by rustc in create_entry_fn in compiler/rustc_codegen_ssa/src/base.rs as the following(I'm not very familiar with rustc, correct me if i'm wrong). This is produced by radare2

       str x30, [var_10h]!         ; main.rs:3 }
       mov x2, x1                  ; int64_t arg3
       nop
       adr x8, obj.__rustc_debug_gdb_scripts_section__ ; 0xecc0
       ldrb w8, [x8]               ; 0xe2
       mov w8, w0                  ; argc
       sxtw x1, w8                 ; int64_t arg2
       nop
       adr x0, dbg.main            ; 0x2e6dc ; int64_t arg1
       mov w3, wzr
       bl sym std::rt::lang_start::hf6b748d5161ca382 ; dbg.lang_start<()>
       ldr x30, [sp], 0x10         ; 0x178000
       ret

I understand by this

#[cfg(target_os = "none")]
#[naked]
extern "C" fn task_start(_f: extern "C" fn(usize), _arg: usize) -> ! {
	// `f` is in the `x0` register
	// `arg` is in the `x1` register

	unsafe {
		asm!(
			"msr spsel, {l0}",
			"mov x25, x0",
			"mov x0, x1",
			"blr x25",
			"mov x0, xzr",
			"adrp x4, {exit}",
			"add  x4, x4, #:lo12:{exit}",
			"br x4",
			l0 = const 0,
			exit = sym crate::sys_thread_exit,
			options(noreturn)
		)
	}
}

exit is supposed to be called after blr to main(blr suggests you assume it to return?), however,

initd is actually (near the end where main is called)

      ...
      bl main                     ; lib.rs:311   main(); ; int main(int argc, char **argv)

      mov w8, wzr                 ; lib.rs:0
      strb w8, [var_166h]         ; lib.rs:1277    
      ldrb w1, [var_166h]         ; pstate
      nop
 
      bl sym hermit::core::sync::atomic::AtomicUsize::load::h2dbf1550f513adc4 ; 
      str x0, [var_90h]           ; lib.rs:280   info!("Hermit is running on common system!");
      add x0, var_88h             ; int64_t arg1
      add x1, var_90h             ; int64_t arg2
      bl sym hermit::core::cmp::PartialOrd::le::hfa5754a8d1dfd3c6 ; dbg.le<log::Level, log::LevelFilter>
      cbz w0, 0x53a84
      b 0x53ae8

     ...

What I've observed on my machine is: main returns and some code compiler has put after it is called.
However, it is not the assembly in task_start

Above, the flow goes back somewhere to the start of initd(for example, str x0, [var_90h] ; lib.rs:280 info!("Hermit is running on common system!");), then some sub-systems would be initialized again and panic.

This does not happen to runtime_entry if compiled without syscall since runtime_entry just calls abi::exit at the end.

Is this a toolchain issue or has anyone also came across this?

I guess this is probably because the compiler thinks main is non-return, so it's free to put anything it likes in the binary after it?

@lishaowen0426
Copy link
Author

lishaowen0426 commented Jan 7, 2024

extern "C" {	
		#[cfg(all(not(test), feature = "syscall"))]
		fn main() -> i32;
	}
    bl main                     ; lib.rs:311   main(); ; int main(int argc, char **argv)
    ldp x29, x30, [var_190h]    ; lib.rs:315 }
    add sp, arg_1a0h
    ret

this is not quite correct, but
by simply changing the extern declaration of main, initd do get a ret which allows it to go back to the assembly in task_start

@stlankes
Copy link
Contributor

stlankes commented Jan 8, 2024

Currently, it isn't working and will get in the future a useful feature. Later the feature will enable a "common monolithic kernel". However, I renamed the feature (see #1026).

@stlankes stlankes closed this as completed Jan 8, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants