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.