我正在尝试为Rust中的STM32编写一个bootloader,我无法弄清楚如何正确填充堆栈指针.我可以告诉代码应该是:
asm!("MOV SP, $0" :: "0"(stack_pointer)); // set the stack pointer
Run Code Online (Sandbox Code Playgroud)
但是编译器不同意:
error: invalid operand in inline asm: 'MOV SP, $0'
--> src/main.rs:38:5
|
38 | asm!("MOV SP, $0" :: "0"(stack_pointer)); // set the stack pointer
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: <inline asm>:1:11: error: unexpected token in operand
MOV SP,
^
--> src/main.rs:38:5
|
38 | asm!("MOV SP, $0" :: "0"(stack_pointer)); // set the stack pointer
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Run Code Online (Sandbox Code Playgroud)
我究竟做错了什么?它似乎在抱怨美元符号,但我直接从文档中得到了它.
根据评论中的对话,我尝试了两件事,两者都编译(!),但两者似乎都没有用(但这可能是十亿个原因中的任何一个,仍在继续):
版本A:
asm!("MOV R0, #0x0800");
asm!("LSL R0, R0, #16");
asm!("MOV R1, #0x8000");
asm!("ORR R2, R1, R0");
asm!("LDRT R0, [R2]");
asm!("MOV SP, R0");
entry_point()
Run Code Online (Sandbox Code Playgroud)
版本B:
#[inline(never)]
unsafe fn go(_addr: u32, entry_point: fn()->()) {
asm!("MOV SP, R0");
entry_point()
}
Run Code Online (Sandbox Code Playgroud)
在我看来你有两个问题:
第二部分看起来很简单global_asm!:
#![feature(global_asm)]
global_asm!(r#"
.global go
go:
mov sp, r0
bx r1
"#);
extern "C" {
pub fn go(addr: u32, entry_point: extern fn());
}
Run Code Online (Sandbox Code Playgroud)
或正常asm!:
#![feature(asm)]
#[no_mangle]
pub unsafe fn go(addr: u32, entry_point: fn()) {
asm!("mov sp, r0" :: "{r0}"(addr) : "sp");
entry_point()
}
Run Code Online (Sandbox Code Playgroud)
我认为这"0"(stack_pointer)部分不起作用,因为stack_pointer它不是一个常数。
您的版本 B 会产生相同的 ASM 代码;但它确实应该将“sp”标记为已损坏,并"{r0}"(addr)确保第一个参数确实位于r0.
Clifford似乎更喜欢传递指向“向量表”的指针,它可能如下所示:
#[repr(C)]
pub struct VectorTable {
stack_pointer: u32,
entry_point: extern fn() -> !,
}
global_asm!(r#"
.global go
go:
ldr sp, [r0]
ldr pc, [r0, #4]
"#);
extern "C" {
pub fn go(vt: &VectorTable) -> !;
}
Run Code Online (Sandbox Code Playgroud)