Código de inicio de metal desnudo para la inicialización de la región .bss de Cortex M3

10

He desarrollado inspirado desde aquí un código de inicio de metal desnudo para arm cortex M3. Sin embargo, me encuentro con el siguiente problema: supongamos que declaro una variable global no inicializada, digamos de tipo unsigned char en main.c

#include ...
unsigned char var; 
...
int main()
{
 ...
}

esto hace que la región .bss en STM32 f103 comience en _BSS_START = 0x20000000 y termine en _BSS_END = 0x20000001. Ahora, el código de inicio

    unsigned int * bss_start_p = &_BSS_START; 
    unsigned int * bss_end_p = &_BSS_END;

    while(bss_start_p != bss_end_p)
    {
        *bss_start_p = 0;
        bss_start_p++;
    }

intenta inicializar a cero toda la región .bss. Sin embargo, dentro de ese ciclo while, el puntero aumenta con 4 bytes, por lo tanto, después de un paso bss_start_p = 0x20000004, por lo tanto, siempre será diferente de bss_end_p, lo que conduce a un ciclo infinito, etc.

¿Hay alguna solución estándar para esto? ¿Se supone que debo "forzar" de alguna manera la dimensión de la región .bss para que sea un múltiplo de 4? ¿O debería usar un puntero a un personaje sin signo para recorrer la región .bss? Quizás algo como:

    unsigned char * bss_start_p = (unsigned char *)(&_BSS_START); 
    unsigned char * bss_end_p = (unsigned char *)(&_BSS_END);

    while(bss_start_p != bss_end_p)
    {
        *bss_start_p = 0;
        bss_start_p++;
    }
```
C Marius
fuente
usar menos de. Los bootstraps se escriben en conjunto por una razón. En primer lugar, ahora ha creado un problema .data. es una cosa de huevo y gallina para usar / asuma que C funciona, confía en .text, .bss y .data como mínimo, pero está escribiendo un código C que se asegura de que el código C funcione, usando cosas en el código C que requieren un Bootstrap posiblemente escrito en código C que se basa en el funcionamiento de C.
old_timer
el código para copiar .data es muy similar a .bss, pero si lo escribe como el código anterior, entonces necesita copiar .data para copiar .data.
old_timer

Respuestas:

15

Como sospecha, esto está sucediendo porque el tipo de datos int sin signo tiene un tamaño de 4 bytes. Cada *bss_start_p = 0;declaración en realidad borra cuatro bytes del área bss.

El rango de memoria bss debe alinearse correctamente. Simplemente puede definir _BSS_START y _BSS_END para que el tamaño total sea un múltiplo de cuatro, pero esto generalmente se maneja permitiendo que el script del vinculador defina las ubicaciones de inicio y detención.

Como ejemplo, aquí está la sección de enlaces en uno de mis proyectos:

.bss (NOLOAD) : ALIGN(4)
{
    __bss_start__ = .;
    *(.bss)
    . = ALIGN(4);
    __bss_end__ = .;
} >RAM

Las ALIGN(4)declaraciones se encargan de las cosas.

Además, es posible que desee cambiar

while(bss_start_p != bss_end_p)

a

while(bss_start_p < bss_end_p).

Esto no evitará el problema (ya que puede estar borrando 1-3 bytes más de lo que desea), pero podría minimizar el impacto :)

bitsmack
fuente
@CMarius Después de reflexionar, creo que tu idea de puntero de caracteres funcionaría muy bien, aunque requeriría más ciclos. Pero no estoy seguro de si habría problemas posteriores con la desalineación de la siguiente área de memoria, así que no voy a mencionarlo en mi respuesta ...
bitsmack
1
while(bss_start_p < bss_end_p - 1)seguido de un borrado en bytes del rango de memoria restante eliminaría la última preocupación.
glglgl
4

La solución estándar es memset():

#include <string.h>
memset(&_BSS_START, 0, &_BSS_END - &_BSS_START)

Si no puede usar la biblioteca estándar, tendrá que decidir si está bien en su caso redondear el tamaño del área de memoria hasta 4 bytes y continuar usando unsigned int *; o si necesita ser estricto al respecto, en cuyo caso deberá usarlo unsigned char *.

Si redondeas el tamaño, como en tu primer ciclo, entonces bss_start_ppuede terminar siendo mayor que bss_end_peso, pero es fácil lidiar con una comparación menor que <en una prueba de desigualdad.

Por supuesto, también podría llenar la mayor parte del área de memoria con transferencias de 32 bits, y solo los últimos bytes con transferencias de 8 bits, pero eso es más trabajo por poca ganancia, particularmente aquí cuando es solo una pieza de código de inicio.

ilkkachu
fuente
1
Estoy muy de acuerdo con el uso de memset(). Pero la alineación a 4 bytes es más o menos imprescindible. Entonces por qué no hacerlo?
Codo
3
de ninguna manera la forma o la forma es la solución estándar para que el bootstrap use memset, eso es una locura.
old_timer
no usas el mismo idioma para arrancar ese idioma
old_timer
2
el código de arranque y la secuencia de comandos del enlazador están muy casados, encontrará que es común que la secuencia de comandos del alineador alinee y clasifique el .bss en al menos un límite de 4 bytes para mejorar el relleno (en la rutina de arranque) en 4 veces sobre el byte a la vez. (suponiendo (mínimo) buses de 32 bits que es típico para armar pero hay excepciones)
old_timer
3
@old_timer, la función estándar de C para configurar la memoria en un valor particular es memset(), y C es en lo que parecen estar programando. La implementación simple de memset()es también solo ese bucle, no es que dependa de mucho más. Como se trata de un microcontrolador, también supongo que no hay un enlace dinámico o algo así (y mirando el enlace, no lo hay, es solo una llamada main()después de ese ciclo de puesta a cero), por lo que el compilador debería ser capaz de caer memset()allí junto con otras funciones (o para implementarlo en línea).
ilkkachu
4

Solo cambia !=a <. Por lo general, ese es un mejor enfoque, ya que trata problemas como este.

Elliot Alderson
fuente
3

Hay innumerables otros sitios y ejemplos. Muchos miles, si no decenas de miles. Existen las conocidas bibliotecas c con scripts de enlace y código boostrap, newlib, glibc en particular, pero hay otros que puede encontrar. Bootstraping C con C no tiene sentido.

Su pregunta ha sido respondida, está tratando de hacer una comparación exacta de cosas que podrían no ser exactas, que podrían no comenzar en un límite conocido o terminar en un límite conocido. Por lo tanto, puede hacer menos que nada, pero si el código no funcionó con una comparación exacta, eso significa que está pasando a cero .bss en la siguiente sección, lo que puede o no causar que sucedan cosas malas, por lo que simplemente reemplace con un valor menor que no la solución.

Así que aquí va TL; DR está bien. No arranca un idioma con ese idioma, puede salirse con la suya, pero está jugando con fuego cuando lo hace. Si solo está aprendiendo cómo hacer esto, debe ser cauteloso, no tener suerte o hechos que aún no ha descubierto.

El script de enlazador y el código de arranque tienen una relación muy íntima, están casados, unidos en la cadera, no se desarrolla uno sin el otro que conduce a un fracaso masivo. Y desafortunadamente, el script del enlazador está definido por el enlazador y el lenguaje ensamblador definido por el ensamblador, por lo que a medida que cambia las cadenas de herramientas, tendrá que volver a escribir ambos. ¿Por qué lenguaje ensamblador? No necesita bootstrap, los lenguajes compilados generalmente sí. C lo hace si no desea limitar su uso del lenguaje, comenzaré con algo muy simple que tenga requisitos específicos mínimos de cadena de herramientas, no asuma que las variables .bss son cero (hace que el código sea menos legible si la variable nunca se inicializa en ese idioma) , trate de evitar esto, no es cierto para las variables locales, por lo que debe tener en cuenta cuándo usarlo. Entonces, ¿por qué estamos hablando de .bss y .data ??? (los globales son buenos para este nivel de trabajo, pero ese es otro tema)) la otra regla para la solución simple es no inicializar variables en la declaración, hágalo en el código. sí quema más flash, generalmente tiene mucho, no todas las variables se inicializan con constantes de todos modos que terminan consumiendo instrucciones.

Se puede deducir por el diseño de la cortezax-m que pueden haber estado pensando que no hay ningún código de arranque en absoluto, por lo que no hay soporte .data ni .bss. La mayoría de las personas que usan globals no pueden vivir sin ellas, así que aquí va:

Podría hacer esto más minimalista, pero un ejemplo funcional mínimo para todos los córtex-ms que usan la cadena de herramientas gnu, no recuerdo qué versiones puede comenzar con 5.xx más o menos a través del 9.xx actual Cambié los scripts del enlazador en algún lugar alrededor de 3. xx o 4.xx cuando aprendí más y cuando gnu cambió algo que rompió el primero.

oreja:

.thumb

.thumb_func
.global _start
_start:
stacktop: .word 0x20000800
.word reset
.word done
.word done
.word done

.thumb_func
reset:
    bl centry
    b done

.thumb_func
done:   b .

.thumb_func
.globl bounce
bounce:
    bx lr

punto de entrada en el código C:

void bounce ( unsigned int );

unsigned int a;

int centry ( void )
{
    a = 7;
    bounce(a);
    return(0);
}

script de enlazador.

MEMORY
{
    rom : ORIGIN = 0x00000000, LENGTH = 0x1000
    ram : ORIGIN = 0x20000000, LENGTH = 0x1000
}

SECTIONS
{
    .text : { *(.text*) } > rom
    .rodata : { *(.rodata*) } > rom
    .bss : { *(.bss*) } > ram
}

Todos estos podrían ser más pequeños y seguir funcionando, se agregaron algunas cosas adicionales aquí solo para verlo en el trabajo.

construcción y enlace optimizados.

00000000 <_start>:
   0:   20001000
   4:   00000015
   8:   0000001b
   c:   0000001b
  10:   0000001b

00000014 <reset>:
  14:   f000 f804   bl  20 <centry>
  18:   e7ff        b.n 1a <done>

0000001a <done>:
  1a:   e7fe        b.n 1a <done>

0000001c <bounce>:
  1c:   4770        bx  lr
    ...

00000020 <centry>:
  20:   2207        movs    r2, #7
  22:   b510        push    {r4, lr}
  24:   4b04        ldr r3, [pc, #16]   ; (38 <centry+0x18>)
  26:   2007        movs    r0, #7
  28:   601a        str r2, [r3, #0]
  2a:   f7ff fff7   bl  1c <bounce>
  2e:   2000        movs    r0, #0
  30:   bc10        pop {r4}
  32:   bc02        pop {r1}
  34:   4708        bx  r1
  36:   46c0        nop         ; (mov r8, r8)
  38:   20000000    andcs   r0, r0, r0

Disassembly of section .bss:

20000000 <a>:
20000000:   00000000    andeq   r0, r0, r0

para algunos proveedores, desea utilizar 0x08000000 o 0x01000000 u otras direcciones similares, ya que el flash se asigna allí y se refleja en 0x00000000 en algunos modos de arranque. algunos solo tienen una gran parte del flash reflejado en 0x00000000, por lo que desea que el punto de la tabla de vectores en el espacio del flash de la aplicación no sea cero. ya que está basado en una tabla de vectores, todo funciona.

Primero, tenga en cuenta que los córtex-ms son máquinas de solo pulgar y, por cualquier motivo, imponen una dirección de función de pulgar, lo que significa que lsbit es impar. Conozca sus herramientas, las directivas .thumb_func le dicen al ensamblador gnu que la siguiente etiqueta es una dirección de función de pulgar. hacer lo +1 en la tabla conducirá al fracaso, no caigas en la tentación de hacerlo, hazlo bien. Hay otras formas de ensamblador de GNU para declarar una función. Este es el enfoque mínimo.

   4:   00000015
   8:   0000001b
   c:   0000001b
  10:   0000001b

no arrancará si no obtienes la tabla de vectores correcta.

podría decirse que solo necesita el vector del puntero de la pila (puede poner cualquier cosa allí si desea establecer el puntero de la pila en el código) y el vector de reinicio. Puse cuatro aquí sin ninguna razón en particular. Por lo general, pon 16 pero quería acortar este ejemplo.

Entonces, ¿qué es lo mínimo que debe hacer un bootstrap C? 1. establezca el puntero de la pila 2. cero .bss 3. copie .data 4. bifurque o llame al punto de entrada C

el punto de entrada C generalmente se llama main (). pero algunas cadenas de herramientas ven main () y agregan basura adicional a su código. Intencionalmente uso un nombre diferente. YMMV.

la copia de .data no es necesaria si todo esto está basado en ram. Al ser un microcontrolador Cortex-M, es técnicamente posible pero poco probable, por lo que se necesita la copia .data ..... si hay .data.

Mi primer ejemplo y un estilo de codificación es no confiar en .data ni .bss, como en este ejemplo. Arm se encargó del puntero de la pila, por lo que lo único que queda es llamar al punto de entrada. Me gusta tenerlo para que el punto de entrada pueda regresar, mucha gente argumenta que nunca debes hacer eso. entonces podrías hacer esto:

.thumb_func
.global _start
_start:
stacktop: .word 0x20000800
.word centry
.word done
.word done
.word done

y no volver de centry () y no tener código de reinicio del controlador.

00000020 <centry>:
  20:   2207        movs    r2, #7
  22:   b510        push    {r4, lr}
  24:   4b04        ldr r3, [pc, #16]   ; (38 <centry+0x18>)
  26:   2007        movs    r0, #7
  28:   601a        str r2, [r3, #0]
  2a:   f7ff fff7   bl  1c <bounce>
  2e:   2000        movs    r0, #0
  30:   bc10        pop {r4}
  32:   bc02        pop {r1}
  34:   4708        bx  r1
  36:   46c0        nop         ; (mov r8, r8)
  38:   20000000    andcs   r0, r0, r0

Disassembly of section .bss:

20000000 <a>:
20000000:   00000000

el enlazador ha puesto las cosas donde pedimos. Y en general tenemos un programa completamente funcional.

Así que primero trabaje en el script del enlazador:

MEMORY
{
    bob : ORIGIN = 0x00000000, LENGTH = 0x1000
    ted : ORIGIN = 0x20000000, LENGTH = 0x1000
}

SECTIONS
{
    .text : { *(.text*) } > bob

    .rodata : { *(.rodata*) } > bob

   __data_rom_start__ = .;
   .data : {
    __data_start__ = .;
    *(.data*)
   } > ted AT > bob
   __data_end__ = .;
   __data_size__ = __data_end__ - __data_start__;

   .bss  : {
   __bss_start__ = .;
   *(.bss*)
   } > ted
   __bss_end__ = .;
   __bss_size__ = __bss_end__ - __bss_start__;

}

enfatizando que los nombres rom y ram no tienen significado, solo conectan los puntos para el enlazador entre secciones.

.thumb

.thumb_func
.global _start
_start:
stacktop: .word 0x20000800
.word reset
.word done
.word done
.word done

.thumb_func
reset:
    bl centry
    b done

.thumb_func
done:   b .

.thumb_func
.globl bounce
bounce:
    bx lr

.align
.word __data_rom_start__
.word __data_start__
.word __data_end__
.word __data_size__

agregue algunos elementos para que podamos ver lo que hicieron las herramientas

void bounce ( unsigned int );

unsigned int a;

unsigned int b=4;
unsigned char c=5;

int centry ( void )
{
    a = 7;
    bounce(a);
    return(0);
}

agregue algunos elementos para colocar en esas secciones. y obten

Disassembly of section .text:

00000000 <_start>:
   0:   20000800    andcs   r0, r0, r0, lsl #16
   4:   00000015    andeq   r0, r0, r5, lsl r0
   8:   0000001b    andeq   r0, r0, r11, lsl r0
   c:   0000001b    andeq   r0, r0, r11, lsl r0
  10:   0000001b    andeq   r0, r0, r11, lsl r0

00000014 <reset>:
  14:   f000 f80c   bl  30 <centry>
  18:   e7ff        b.n 1a <done>

0000001a <done>:
  1a:   e7fe        b.n 1a <done>

0000001c <bounce>:
  1c:   4770        bx  lr
  1e:   46c0        nop         ; (mov r8, r8)
  20:   0000004c    andeq   r0, r0, r12, asr #32
  24:   20000000    andcs   r0, r0, r0
  28:   20000008    andcs   r0, r0, r8
  2c:   00000008    andeq   r0, r0, r8

00000030 <centry>:
  30:   2207        movs    r2, #7
  32:   b510        push    {r4, lr}
  34:   4b04        ldr r3, [pc, #16]   ; (48 <centry+0x18>)
  36:   2007        movs    r0, #7
  38:   601a        str r2, [r3, #0]
  3a:   f7ff ffef   bl  1c <bounce>
  3e:   2000        movs    r0, #0
  40:   bc10        pop {r4}
  42:   bc02        pop {r1}
  44:   4708        bx  r1
  46:   46c0        nop         ; (mov r8, r8)
  48:   20000008    andcs   r0, r0, r8

Disassembly of section .data:

20000000 <c>:
20000000:   00000005    andeq   r0, r0, r5

20000004 <b>:
20000004:   00000004    andeq   r0, r0, r4

Disassembly of section .bss:

20000008 <a>:
20000008:   00000000    andeq   r0, r0, r0

aquí están las cosas que estamos buscando en ese experimento (no hay razón para cargar o ejecutar ningún código ... conozca sus herramientas, aprenda)

  1c:   4770        bx  lr
  1e:   46c0        nop         ; (mov r8, r8)
  20:   0000004c    andeq   r0, r0, r12, asr #32
  24:   20000000    andcs   r0, r0, r0
  28:   20000008    andcs   r0, r0, r8
  2c:   00000008    andeq   r0, r0, r8

Entonces, lo que aprendimos aquí es que la posición de las variables es muy sensible en los scripts de gnu linker. tenga en cuenta la posición de data_rom_start vs data_start, pero ¿por qué funciona data_end ? Te dejaré resolver eso. Ya entendiendo por qué uno no querría tener que meterse con los scripts del enlazador y simplemente llegar a una programación simple ...

así que otra cosa que aprendimos aquí es que el enlazador alineó data_rom_start para nosotros, no necesitábamos un ALIGN (4) allí. ¿Debemos suponer que eso siempre funcionará?

También tenga en cuenta que se completó en el camino hacia afuera, tenemos 5 bytes de .data pero se completó a 8. Sin ALIGN () s, ya podemos hacer la copia usando palabras. Según lo que vemos hoy con esta cadena de herramientas en mi computadora, ¿podría ser cierto para el pasado y el futuro? Quién sabe, incluso con ALIGNs necesita verificar periódicamente para confirmar que alguna nueva versión no rompió las cosas, lo harán de vez en cuando.

de ese experimento pasemos a esto solo para estar seguros.

MEMORY
{
    bob : ORIGIN = 0x00000000, LENGTH = 0x1000
    ted : ORIGIN = 0x20000000, LENGTH = 0x1000
}

SECTIONS
{
    .text : { *(.text*) } > bob

    .rodata : { *(.rodata*) } > bob

   . = ALIGN(4);
   __data_rom_start__ = .;
   .data : {
    __data_start__ = .;
    *(.data*)
   . = ALIGN(4);
   __data_end__ = .;
   } > ted AT > bob
   __data_size__ = __data_end__ - __data_start__;

   . = ALIGN(4);
   .bss  : {
   __bss_start__ = .;
   *(.bss*)
   . = ALIGN(4);
   __bss_end__ = .;
   } > ted
   __bss_size__ = __bss_end__ - __bss_start__;

}

moviendo los extremos hacia adentro para ser consistente con lo que hacen otras personas. Y eso no lo cambió:

0000001c <bounce>:
  1c:   4770        bx  lr
  1e:   46c0        nop         ; (mov r8, r8)
  20:   0000004c    andeq   r0, r0, r12, asr #32
  24:   20000000    andcs   r0, r0, r0
  28:   20000008    andcs   r0, r0, r8
  2c:   00000008    andeq   r0, r0, r8

Una prueba rápida más:

.globl bounce
bounce:
    nop
    bx lr

dando

0000001c <bounce>:
  1c:   46c0        nop         ; (mov r8, r8)
  1e:   4770        bx  lr
  20:   0000004c    andeq   r0, r0, r12, asr #32
  24:   20000000    andcs   r0, r0, r0
  28:   20000008    andcs   r0, r0, r8
  2c:   00000008    andeq   r0, r0, r8

no es necesario rellenar entre rebote y .align

Ohh, claro, ahora recuerdo por qué no pongo el final dentro. porque NO FUNCIONA.

MEMORY
{
    bob : ORIGIN = 0x00000000, LENGTH = 0x1000
    ted : ORIGIN = 0x20000000, LENGTH = 0x1000
}

SECTIONS
{
    .text : { *(.text*) } > bob

    .rodata : { *(.rodata*) } > bob

   . = ALIGN(4);
   __data_rom_start__ = .;
   .data : {
    __data_start__ = .;
    *(.data*)
   } > ted AT > bob
   . = ALIGN(4);
   __data_end__ = .;
   __data_size__ = __data_end__ - __data_start__;

   . = ALIGN(4);
   .bss  : {
   __bss_start__ = .;
   *(.bss*)
   } > ted
   . = ALIGN(4);
   __bss_end__ = .;
   __bss_size__ = __bss_end__ - __bss_start__;

}

algún código simple, pero muy portátil para casarse con este script enlazador

.thumb

.thumb_func
.global _start
_start:
stacktop: .word 0x20000800
.word reset
.word done
.word done
.word done

.thumb_func
reset:

    ldr r0,blen
    cmp r0,#0
    beq bss_zero_done
    ldr r1,bstart
    mov r2,#0
bss_zero:
    stmia r1!,{r2}
    sub r0,#4
    bne bss_zero
bss_zero_done:

    ldr r0,dlen
    cmp r0,#0
    beq data_copy_done
    ldr r1,rstart
    ldr r2,dstart
data_copy:
    ldmia r1!,{r3}
    stmia r2!,{r3}
    sub r0,#4
    bne data_copy
data_copy_done:

    bl centry
    b done

.thumb_func
done:   b .

.thumb_func
.globl bounce
bounce:
    nop
    bx lr

.align
bstart: .word __bss_start__
blen:   .word __bss_size__
rstart: .word __data_rom_start__
dstart: .word __data_start__
dlen:   .word __data_size__

dando

Disassembly of section .text:

00000000 <_start>:
   0:   20000800    andcs   r0, r0, r0, lsl #16
   4:   00000015    andeq   r0, r0, r5, lsl r0
   8:   0000003d    andeq   r0, r0, sp, lsr r0
   c:   0000003d    andeq   r0, r0, sp, lsr r0
  10:   0000003d    andeq   r0, r0, sp, lsr r0

00000014 <reset>:
  14:   480c        ldr r0, [pc, #48]   ; (48 <blen>)
  16:   2800        cmp r0, #0
  18:   d004        beq.n   24 <bss_zero_done>
  1a:   490a        ldr r1, [pc, #40]   ; (44 <bstart>)
  1c:   2200        movs    r2, #0

0000001e <bss_zero>:
  1e:   c104        stmia   r1!, {r2}
  20:   3804        subs    r0, #4
  22:   d1fc        bne.n   1e <bss_zero>

00000024 <bss_zero_done>:
  24:   480b        ldr r0, [pc, #44]   ; (54 <dlen>)
  26:   2800        cmp r0, #0
  28:   d005        beq.n   36 <data_copy_done>
  2a:   4908        ldr r1, [pc, #32]   ; (4c <rstart>)
  2c:   4a08        ldr r2, [pc, #32]   ; (50 <dstart>)

0000002e <data_copy>:
  2e:   c908        ldmia   r1!, {r3}
  30:   c208        stmia   r2!, {r3}
  32:   3804        subs    r0, #4
  34:   d1fb        bne.n   2e <data_copy>

00000036 <data_copy_done>:
  36:   f000 f80f   bl  58 <centry>
  3a:   e7ff        b.n 3c <done>

0000003c <done>:
  3c:   e7fe        b.n 3c <done>

0000003e <bounce>:
  3e:   46c0        nop         ; (mov r8, r8)
  40:   4770        bx  lr
  42:   46c0        nop         ; (mov r8, r8)

00000044 <bstart>:
  44:   20000008    andcs   r0, r0, r8

00000048 <blen>:
  48:   00000004    andeq   r0, r0, r4

0000004c <rstart>:
  4c:   00000074    andeq   r0, r0, r4, ror r0

00000050 <dstart>:
  50:   20000000    andcs   r0, r0, r0

00000054 <dlen>:
  54:   00000008    andeq   r0, r0, r8

00000058 <centry>:
  58:   2207        movs    r2, #7
  5a:   b510        push    {r4, lr}
  5c:   4b04        ldr r3, [pc, #16]   ; (70 <centry+0x18>)
  5e:   2007        movs    r0, #7
  60:   601a        str r2, [r3, #0]
  62:   f7ff ffec   bl  3e <bounce>
  66:   2000        movs    r0, #0
  68:   bc10        pop {r4}
  6a:   bc02        pop {r1}
  6c:   4708        bx  r1
  6e:   46c0        nop         ; (mov r8, r8)
  70:   20000008    andcs   r0, r0, r8

Disassembly of section .data:

20000000 <c>:
20000000:   00000005    andeq   r0, r0, r5

20000004 <b>:
20000004:   00000004    andeq   r0, r0, r4

Disassembly of section .bss:

20000008 <a>:
20000008:   00000000    andeq   r0, r0, r0

podemos parar allí o seguir adelante. Si inicializamos en el mismo orden que el script del enlazador, está bien si pasamos a lo siguiente, ya que aún no hemos llegado allí. y stm / ldm solo son necesarios / deseados para usar direcciones alineadas por palabras, por lo que si cambia a:

    ldr r0,blen
    cmp r0,#0
    beq bss_zero_done
    ldr r1,bstart
    mov r2,#0
    mov r3,#0
    mov r4,#0
    mov r5,#0
bss_zero:
    stmia r1!,{r2,r3,r4,r5}
    sub r0,#16
    ble bss_zero
bss_zero_done:

con bss primero en el script del enlazador, y sí, no quieres bls.

Disassembly of section .text:

00000000 <_start>:
   0:   20000800    andcs   r0, r0, r0, lsl #16
   4:   00000015    andeq   r0, r0, r5, lsl r0
   8:   00000043    andeq   r0, r0, r3, asr #32
   c:   00000043    andeq   r0, r0, r3, asr #32
  10:   00000043    andeq   r0, r0, r3, asr #32

00000014 <reset>:
  14:   480d        ldr r0, [pc, #52]   ; (4c <blen>)
  16:   2800        cmp r0, #0
  18:   d007        beq.n   2a <bss_zero_done>
  1a:   490b        ldr r1, [pc, #44]   ; (48 <bstart>)
  1c:   2200        movs    r2, #0
  1e:   2300        movs    r3, #0
  20:   2400        movs    r4, #0
  22:   2500        movs    r5, #0

00000024 <bss_zero>:
  24:   c13c        stmia   r1!, {r2, r3, r4, r5}
  26:   3804        subs    r0, #4
  28:   ddfc        ble.n   24 <bss_zero>

0000002a <bss_zero_done>:
  2a:   480b        ldr r0, [pc, #44]   ; (58 <dlen>)
  2c:   2800        cmp r0, #0
  2e:   d005        beq.n   3c <data_copy_done>
  30:   4907        ldr r1, [pc, #28]   ; (50 <rstart>)
  32:   4a08        ldr r2, [pc, #32]   ; (54 <dstart>)

00000034 <data_copy>:
  34:   c978        ldmia   r1!, {r3, r4, r5, r6}
  36:   c278        stmia   r2!, {r3, r4, r5, r6}
  38:   3810        subs    r0, #16
  3a:   ddfb        ble.n   34 <data_copy>

0000003c <data_copy_done>:
  3c:   f000 f80e   bl  5c <centry>
  40:   e7ff        b.n 42 <done>

00000042 <done>:
  42:   e7fe        b.n 42 <done>

00000044 <bounce>:
  44:   46c0        nop         ; (mov r8, r8)
  46:   4770        bx  lr

00000048 <bstart>:
  48:   20000000    andcs   r0, r0, r0

0000004c <blen>:
  4c:   00000004    andeq   r0, r0, r4

00000050 <rstart>:
  50:   20000004    andcs   r0, r0, r4

00000054 <dstart>:
  54:   20000004    andcs   r0, r0, r4

00000058 <dlen>:
  58:   00000008    andeq   r0, r0, r8

0000005c <centry>:
  5c:   2207        movs    r2, #7
  5e:   b510        push    {r4, lr}
  60:   4b04        ldr r3, [pc, #16]   ; (74 <centry+0x18>)
  62:   2007        movs    r0, #7
  64:   601a        str r2, [r3, #0]
  66:   f7ff ffed   bl  44 <bounce>
  6a:   2000        movs    r0, #0
  6c:   bc10        pop {r4}
  6e:   bc02        pop {r1}
  70:   4708        bx  r1
  72:   46c0        nop         ; (mov r8, r8)
  74:   20000000    andcs   r0, r0, r0

Disassembly of section .bss:

20000000 <a>:
20000000:   00000000    andeq   r0, r0, r0

Disassembly of section .data:

20000004 <c>:
20000004:   00000005    andeq   r0, r0, r5

20000008 <b>:
20000008:   00000004    andeq   r0, r0, r4

esos bucles irán más rápido. ahora no sé si los buses ahb pueden tener 64 bits de ancho o no, pero para un brazo de tamaño completo querrás alinear estas cosas en los límites de 64 bits. un ldm / stm de cuatro registros en un límite de 32 bits pero no un límite de 64 bits se convierte en tres transacciones de bus separadas, donde alineado en un límite de 64 bits es una transacción única que ahorra varios relojes por instrucción.

dado que estamos haciendo baremetal y somos totalmente responsables de todo lo que podemos poner, digamos bss primero, luego datos, luego, si tenemos un montón, entonces la pila crece de arriba hacia abajo, por lo que si ponemos a cero bss y derramamos algo siempre que comencemos en el lugar correcto que está bien todavía no estamos usando esa memoria. luego copiamos .data y podemos derramar en el montón que está bien, el montón o no hay mucho espacio para la pila, por lo que no estamos pisando a nadie / nada (siempre y cuando nos aseguremos de que en el script del enlazador lo hagamos). Si existe alguna preocupación, haga que ALIGN () sea más grande para que siempre estemos dentro de nuestro espacio para estos rellenos.

entonces mi solución simple, tómalo o déjalo. bienvenido a corregir cualquier error, no ejecuté esto en hardware ni en mi simulador ...

MEMORY
{
    bob : ORIGIN = 0x00000000, LENGTH = 0x1000
    ted : ORIGIN = 0x20000000, LENGTH = 0x1000
}

SECTIONS
{
    .text : { *(.text*) } > bob

    .rodata : { *(.rodata*) } > bob

   . = ALIGN(8);
   .bss  : {
   __bss_start__ = .;
   *(.bss*)
   } > ted
   . = ALIGN(4);
   __bss_end__ = .;
   __bss_size__ = __bss_end__ - __bss_start__;

   . = ALIGN(8);
   __data_rom_start__ = .;
   .data : {
    __data_start__ = .;
    *(.data*)
   } > ted AT > bob
   . = ALIGN(4);
   __data_end__ = .;
   __data_size__ = __data_end__ - __data_start__;

}



.thumb

.thumb_func
.global _start
_start:
stacktop: .word 0x20000800
.word reset
.word done
.word done
.word done

.thumb_func
reset:

    ldr r0,blen
    cmp r0,#0
    beq bss_zero_done
    ldr r1,bstart
    mov r2,#0
    mov r3,#0
    mov r4,#0
    mov r5,#0
bss_zero:
    stmia r1!,{r2,r3,r4,r5}
    sub r0,#16
    ble bss_zero
bss_zero_done:

    ldr r0,dlen
    cmp r0,#0
    beq data_copy_done
    ldr r1,rstart
    ldr r2,dstart
data_copy:
    ldmia r1!,{r3,r4,r5,r6}
    stmia r2!,{r3,r4,r5,r6}
    sub r0,#16
    ble data_copy
data_copy_done:

    bl centry
    b done

.thumb_func
done:   b .

.thumb_func
.globl bounce
bounce:
    nop
    bx lr

.align
bstart: .word __bss_start__
blen:   .word __bss_size__
rstart: .word __data_rom_start__
dstart: .word __data_start__
dlen:   .word __data_size__


void bounce ( unsigned int );

unsigned int a;

unsigned int b=4;
unsigned char c=5;

int centry ( void )
{
    a = 7;
    bounce(a);
    return(0);
}

arm-none-eabi-as --warn --fatal-warnings flash.s -o flash.o
arm-none-eabi-ld -o hello.elf -T flash.ld flash.o centry.o
arm-none-eabi-objdump -D hello.elf > hello.list
arm-none-eabi-objcopy hello.elf hello.bin -O binary

ponlo todo junto y obtienes:

Disassembly of section .text:

00000000 <_start>:
   0:   20000800    andcs   r0, r0, r0, lsl #16
   4:   00000015    andeq   r0, r0, r5, lsl r0
   8:   00000043    andeq   r0, r0, r3, asr #32
   c:   00000043    andeq   r0, r0, r3, asr #32
  10:   00000043    andeq   r0, r0, r3, asr #32

00000014 <reset>:
  14:   480d        ldr r0, [pc, #52]   ; (4c <blen>)
  16:   2800        cmp r0, #0
  18:   d007        beq.n   2a <bss_zero_done>
  1a:   490b        ldr r1, [pc, #44]   ; (48 <bstart>)
  1c:   2200        movs    r2, #0
  1e:   2300        movs    r3, #0
  20:   2400        movs    r4, #0
  22:   2500        movs    r5, #0

00000024 <bss_zero>:
  24:   c13c        stmia   r1!, {r2, r3, r4, r5}
  26:   3810        subs    r0, #16
  28:   ddfc        ble.n   24 <bss_zero>

0000002a <bss_zero_done>:
  2a:   480b        ldr r0, [pc, #44]   ; (58 <dlen>)
  2c:   2800        cmp r0, #0
  2e:   d005        beq.n   3c <data_copy_done>
  30:   4907        ldr r1, [pc, #28]   ; (50 <rstart>)
  32:   4a08        ldr r2, [pc, #32]   ; (54 <dstart>)

00000034 <data_copy>:
  34:   c978        ldmia   r1!, {r3, r4, r5, r6}
  36:   c278        stmia   r2!, {r3, r4, r5, r6}
  38:   3810        subs    r0, #16
  3a:   ddfb        ble.n   34 <data_copy>

0000003c <data_copy_done>:
  3c:   f000 f80e   bl  5c <centry>
  40:   e7ff        b.n 42 <done>

00000042 <done>:
  42:   e7fe        b.n 42 <done>

00000044 <bounce>:
  44:   46c0        nop         ; (mov r8, r8)
  46:   4770        bx  lr

00000048 <bstart>:
  48:   20000000    andcs   r0, r0, r0

0000004c <blen>:
  4c:   00000004    andeq   r0, r0, r4

00000050 <rstart>:
  50:   20000008    andcs   r0, r0, r8

00000054 <dstart>:
  54:   20000004    andcs   r0, r0, r4

00000058 <dlen>:
  58:   00000008    andeq   r0, r0, r8

0000005c <centry>:
  5c:   2207        movs    r2, #7
  5e:   b510        push    {r4, lr}
  60:   4b04        ldr r3, [pc, #16]   ; (74 <centry+0x18>)
  62:   2007        movs    r0, #7
  64:   601a        str r2, [r3, #0]
  66:   f7ff ffed   bl  44 <bounce>
  6a:   2000        movs    r0, #0
  6c:   bc10        pop {r4}
  6e:   bc02        pop {r1}
  70:   4708        bx  r1
  72:   46c0        nop         ; (mov r8, r8)
  74:   20000000    andcs   r0, r0, r0

Disassembly of section .bss:

20000000 <a>:
20000000:   00000000    andeq   r0, r0, r0

Disassembly of section .data:

20000004 <c>:
20000004:   00000005    andeq   r0, r0, r5

20000008 <b>:
20000008:   00000004    andeq   r0, r0, r4

tenga en cuenta que esto funciona con arm-none-eabi- y arm-linux-gnueabi y las otras variantes, ya que no se utilizó ningún ghee whiz.

Cuando mires a tu alrededor, encontrarás que la gente se volverá loca con cosas geniales de ghee en sus scripts de enlazadores, enormes y monstruosas cosas de fregadero de cocina. Es mejor saber cómo hacerlo (o mejor cómo dominar las herramientas para que pueda controlar lo que sucede) en lugar de confiar en las cosas de otra persona y no saber dónde se romperá porque no comprende y / o no quiere investigar eso.

como regla general, no inicie un lenguaje con el mismo idioma (bootstrap en este sentido, que significa ejecutar código que no compila un compilador con el mismo compilador), desea utilizar un lenguaje más simple con menos bootstrap. Es por eso que C se realiza en el ensamblaje, no tiene requisitos de arranque, solo debe comenzar desde la primera instrucción después del reinicio. JAVA, seguro de que puede escribir el jvm en C y arrancar ese C con asm y luego arrancar el JAVA si lo hace con C pero también ejecutar el JAVA en C también.

Debido a que controlamos los supuestos en estos bucles de copia, son por definición más estrictos y más limpios que memcpy / memset sintonizados a mano.

Tenga en cuenta que su otro problema fue este:

unsigned int * bss_start_p = &_BSS_START; 
unsigned int * bss_end_p = &_BSS_END;

si estos son locales bien, no hay problema, si estos son globales, entonces necesita .data inicializado primero para que funcionen y si intenta ese truco para hacer .data, entonces fallará. Variables locales, bien, eso funcionará. si por alguna razón decidiste hacer los locales estáticos (globales locales que me gusta llamarlos), entonces estás nuevamente en problemas. Cada vez que haces una tarea en una declaración, aunque deberías pensarlo, cómo se implementa y si es seguro / correcto. Cada vez que asume que una variable es cero cuando no se declara, mismo trato, si una variable local no se supone que es cero, si es global, entonces lo es. Si nunca asumes que son cero, entonces nunca tienes que preocuparte.

viejo contador de tiempo
fuente
increíble, esta es la segunda vez que he excedido el recuento máximo de caracteres en una respuesta ...
old_timer
Esta pregunta pertenece al stackoverflow, no a la ingeniería eléctrica.
old_timer
También confiar en un enlace externo en su pregunta no es una buena forma, si el enlace desaparece antes de la pregunta, entonces la pregunta podría no tener sentido.
old_timer
En este caso, su título y contenido son suficientes para saber que está intentando arrancar C en un microcontrolador en particular y se está desplazando hacia la inicialización .bss y .data
old_timer
pero en este caso han sido engañados por un sitio web muy informativo.
old_timer