Ensamblador Rust: ¿Cómo indico que necesito el valor de SP?
Estoy jugando con la macro asm!
en un objetivo ARM (Thumb) integrado. Tengo un rutina de servicio de interrupción que está diseñada para obtener el número con el que se llamó a la instrucción svc
:
[cortexmrt::exception]
unsafe fn SVCall() {
let mut svc_num: u8;
asm!(
"ldr {0}, [sp, #40]", // lee el PC que se guardó antes de que ocurriera esta interrupción
"movs {1}, #2", // guarda 2 en un registro
"subs {0}, {1}", // resta 2 de ese PC que recuperamos
"ldrb {2}, [{0}]", // lee el byte en esa posición
out (reg) _,
out (reg) _,
lateout (reg) svc_num
);
defmt::info!("svcall #{}", svc_num);
}
Cuando desensamblo el código resultante compilado con opt-level = 2
(esto es importante, obtengo resultados completamente diferentes con opt-level = 0
), obtengo lo siguiente:
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}
Mis cálculos indican que solo tendría que usar un desplazamiento de 32 en mi instrucción ldr
, pero tengo que compensar la instrucción sub sp, #8
que se inserta antes de mi código.
Mis dos preguntas son:
– ¿Hay alguna manera de indicarle a Rust que no quiero que se inserte esta instrucción (o al menos, que debe venir después de mis instrucciones asm!
), porque necesito leer el valor del registro sp
?
– ¿Puedo asumir que sp
siempre se copiará en r7
y usar r7
como un puntero de base de marco de pila?
davy.ai
Desafortunadamente, no hay forma de indicarle a Rust que no inserte la instrucción
sub sp, #8
antes de tu códigoasm!
. Esto se debe a que el compilador de Rust genera automáticamente el prólogo y el epílogo de la función, y este prólogo incluye la instrucción de asignación de la pila. Sin embargo, puedes ajustar manualmente el desplazamiento en tu instrucciónldr
para compensar el espacio extra de la pila que se asignó.No es seguro asumir que
sp
siempre será copiado enr7
. Aunque es verdad para muchos procesadores ARM Cortex-M, la asignación de registros a punteros de marco de pila no está garantizada y podría incluso variar entre rutinas de servicio de interrupción. Generalmente es más seguro utilizar el registrosp
directamente en tu código ensamblador si necesitas acceder a las variables de la pila.