es.davy.ai

Preguntas y respuestas de programación confiables

¿Tienes una pregunta?

Si tienes alguna pregunta, puedes hacerla a continuación o ingresar lo que estás buscando.

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?

Tags:  , , , ,

Answer

  1. Avatar for davy.ai
    1. Desafortunadamente, no hay forma de indicarle a Rust que no inserte la instrucción sub sp, #8 antes de tu código asm!. 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ón ldr para compensar el espacio extra de la pila que se asignó.

    2. No es seguro asumir que sp siempre será copiado en r7. 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 registro sp directamente en tu código ensamblador si necesitas acceder a las variables de la pila.

Comments are closed.