我正在處理asm!嵌入式 ARM (Thumb) 目標上的宏。我有一個中斷服務例程,旨在獲取svc呼叫指令的編號:
#[cortex_m_rt::exception]
unsafe fn SVCall() {
let mut svc_num: u8;
asm!(
"ldr {0}, [sp, #40]", // read the PC that was saved before this interrupt happened
"movs {1}, #2", // store 2 in a reg
"subs {0}, {1}", // subtract 2 from that PC we recovered
"ldrb {2}, [{0}]", // read the byte at that position
out (reg) _,
out (reg) _,
lateout (reg) svc_num
);
defmt::info!("svcall #{}", svc_num);
}
當我反匯編編譯的結果代碼opt-level = 2(這很重要,我得到完全不同的結果opt-level = 0)時,我得到以下資訊:
08000502 <SVCall>:
8000502: b580 push {r7, lr}
8000504: 466f mov r7, sp
8000506: b082 sub sp, #8
8000508: 980a ldr r0, [sp, #40] ; 0x28
800050a: 2102 movs r1, #2
800050c: 1a40 subs r0, r0, r1
800050e: 7802 ldrb r2, [r0, #0]
8000510: f807 2c05 strb.w r2, [r7, #-5]
8000514: f000 fb04 bl 8000b20 <_defmt_acquire>
8000518: f240 000e movw r0, #14
800051c: f2c0 0000 movt r0, #0
8000520: f000 fb70 bl 8000c04 <_ZN5defmt6export9make_istr17h6ffa41eb00995773E>
8000524: f8ad 0004 strh.w r0, [sp, #4]
8000528: a801 add r0, sp, #4
800052a: f000 fba4 bl 8000c76 <_ZN5defmt6export6header17h9dd906a13f87833fE>
800052e: f240 0002 movw r0, #2
8000532: f2c0 0000 movt r0, #0
8000536: f000 fb65 bl 8000c04 <_ZN5defmt6export9make_istr17h6ffa41eb00995773E>
800053a: f827 0c02 strh.w r0, [r7, #-2]
800053e: 1eb8 subs r0, r7, #2
8000540: f000 fb61 bl 8000c06 <_ZN5defmt6export4istr17hddd45161235dee63E>
8000544: 1f78 subs r0, r7, #5
8000546: f000 fbb3 bl 8000cb0 <_ZN5defmt6export8integers2i817h6232ecd7ea5eb90dE>
800054a: f000 faeb bl 8000b24 <_defmt_release>
800054e: b002 add sp, #8
8000550: bd80 pop {r7, pc}
我的計算表明我應該只需要在我的ldr指令中使用 32 的偏移量,但是我必須補償sub sp, #8在我的代碼之前插入的指令。
我的兩個問題是:
- 有沒有辦法向 Rust 表明我不希望插入這條指令(或者至少,它必須在我的
asm!指令之后),因為我需要讀取sp暫存器的值? - 我可以假設它
sp總是被復制r7并r7用作堆疊幀基指標嗎?
uj5u.com熱心網友回復:
您可以使用裸函式:
#![no_std]
#![feature(asm, naked_functions)]
#[naked]
#[export_name = "SVCall"]
pub unsafe extern "C" fn SVCall() {
asm!(
"ldr r0, [sp, #40]", // read the PC that was saved before this interrupt happened
"ldrb r0, [r0, #-2]", // read the byte at PC - 2
"b other_func", // call other_func with that byte as first argument
options(noreturn)
);
}
pub extern "C" fn other_func(svc_num: u8) {
// do something
}
編輯:感謝 Peter Cordes 指出我之前的答案不起作用的許多方式。本質上,裸函式應該包含一個行內匯編塊,并且您只能在匯編中呼叫具有定義 ABI 的函式。
uj5u.com熱心網友回復:
......我不想插入這條指令......
這根本不會幫助你:
下一個編譯器版本可能會使用push {r6, r7, lr}而不是,push {r7, lr}您感興趣的資訊位于sp 44而不是sp 40。
...我可以假設
sp將始終復制到r7...
即使是這種情況,push {r6, r7, lr}這個假設也無法解決問題。
// read the PC that was saved before this interrupt happened
要做到這一點,除了用匯編語言撰寫整個函式并從匯編代碼中呼叫高級語言部分(例如 Rust、C、C ...)之外別無他法。
在高級語言函式中使用行內匯編無法做到這一點。至少沒有一個可以保證使用較新的編譯器版本。
轉載請註明出處,本文鏈接:https://www.uj5u.com/shujuku/369158.html
