Ci sono innumerevoli altri siti ed esempi. Molte migliaia se non decine di migliaia. Ci sono le librerie c ben note con script di linker e codice boostrap, in particolare newlib, glibc ma ce ne sono altre che puoi trovare. Il bootstraping C con C non ha senso.
Alla tua domanda è stato risposto che stai cercando di fare un confronto esatto su cose che potrebbero non essere esatte, potrebbe non iniziare su un confine noto o terminare su un confine noto. Quindi puoi fare il meno che cosa, ma se il codice non ha funzionato con un confronto esatto, ciò significa che stai azzerando i .bss passati nella sezione successiva che può o meno causare cose brutte, quindi semplicemente sostituendo con un meno di isnt la soluzione.
Quindi ecco TL: DR va bene. Non bootstrap una lingua con quella lingua, puoi cavartela di sicuro, ma stai giocando con il fuoco quando lo fai. Se stai solo imparando come farlo, devi stare dalla parte della cautela, non della scema fortuna o dei fatti che non hai ancora scoperto.
Lo script del linker e il codice bootstrap hanno una relazione molto intima, sono sposati, uniti al fianco, non si sviluppa uno senza l'altro che porta a un grave fallimento. E sfortunatamente lo script del linker è definito dal linker e il linguaggio assembly definito dall'assemblatore, così come cambiate le toolchain prevedete di dover riscrivere entrambi. Perché il linguaggio assembly? Non ha bisogno di bootstrap, generalmente le lingue compilate lo fanno. C fa se non vuoi limitare l'uso del linguaggio, Ill inizio con qualcosa di molto semplice che ha requisiti specifici minimi per la toolchain, non supponi che le variabili .bss siano zero (rende il codice meno leggibile se la variabile non è mai inizializzata in quella lingua , cerca di evitarlo, non è vero per le variabili locali, quindi devi essere consapevole di quando lo usi. La gente evita comunque i globi, allora perché stiamo parlando di .bss e .data ??? (i globuli vanno bene per questo livello di lavoro ma questo è un altro argomento)) l'altra regola per la soluzione semplice non è inizializzare le variabili nella dichiarazione, ma farlo nel codice. sì, brucia più flash, generalmente ne hai molte, non tutte le variabili sono inizializzate con costanti che finiscono per consumare istruzioni.
Si può dire dal disegno cortex-m che potrebbero aver pensato che non ci sia affatto un codice bootstrap, quindi nessun supporto .data né .bss. La maggior parte delle persone che usano i globali non possono vivere senza così ecco qui:
Potrei renderlo più minimale ma un esempio funzionale minimo per tutti i cortx-ms usando la toolchain gnu, non ricordo quali versioni puoi iniziare con 5.xx o giù di lì attraverso gli attuali 9.xx Ho cambiato gli script di linker da qualche parte intorno a 3. xx o 4.xx come ho imparato di più e come gnu ha cambiato qualcosa che ha rotto il mio primo.
bootstrap:
.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 di ingresso nel codice C:
void bounce ( unsigned int );
unsigned int a;
int centry ( void )
{
a = 7;
bounce(a);
return(0);
}
script del linker.
MEMORY
{
rom : ORIGIN = 0x00000000, LENGTH = 0x1000
ram : ORIGIN = 0x20000000, LENGTH = 0x1000
}
SECTIONS
{
.text : { *(.text*) } > rom
.rodata : { *(.rodata*) } > rom
.bss : { *(.bss*) } > ram
}
Tutti questi potrebbero essere più piccoli e funzionare ancora, qui sono state aggiunte altre cose solo per vederle al lavoro.
build e link ottimizzati.
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
per alcuni fornitori si desidera utilizzare 0x08000000 o 0x01000000 o altri indirizzi simili poiché il flash è mappato lì e rispecchiato su 0x00000000 in alcune modalità di avvio. alcuni hanno solo gran parte del flash specchiato a 0x00000000, quindi si desidera avere il punto della tabella vettoriale nello spazio flash dell'applicazione non zero. poiché è basato su una tabella vettoriale, funziona tutto.
per prima cosa le cortx-ms sono solo macchine a pollice e per qualsiasi motivo hanno imposto un indirizzo di funzione pollice, il che significa che l'sbit è dispari. Conosci i tuoi strumenti, le direttive .thumb_func dicono all'assemblatore gnu che la prossima etichetta è un indirizzo di funzione pollice. fare la cosa +1 nella tabella porterà al fallimento, non essere tentato di farlo, fallo bene. ci sono altri modi dell'assemblatore gnu per dichiarare una funzione, questo è l'approccio minimo.
4: 00000015
8: 0000001b
c: 0000001b
10: 0000001b
non si avvia se non si ottiene correttamente la tabella vettoriale.
probabilmente è necessario solo il vettore del puntatore dello stack (può inserire qualsiasi cosa lì se si desidera impostare il puntatore dello stack nel codice) e il vettore di ripristino. Ne ho messi quattro qui senza un motivo particolare. Di solito metto 16 ma volevo accorciare questo esempio.
Quindi qual è il minimo che un bootstrap C deve fare? 1. impostare il puntatore dello stack 2. zero .bss 3. copiare .data 4. diramare o chiamare il punto di ingresso C.
il punto di ingresso C è generalmente chiamato main (). ma alcune toolchain vedono main () e aggiungono spazzatura extra al tuo codice. Uso intenzionalmente un nome diverso. YMMV.
la copia di .data non è necessaria se tutto questo è basato su RAM. essendo un microcontrollore cortex-m è tecnicamente possibile ma improbabile, quindi è necessaria la copia .data ..... se c'è .data.
Il mio primo esempio e uno stile di codifica è di non fare affidamento su .data né .bss, come in questo esempio. Il braccio si è preso cura del puntatore dello stack, quindi l'unica cosa rimasta è chiamare il punto di ingresso. Mi piace averlo in modo che il punto di ingresso possa tornare, molte persone sostengono che non dovresti mai farlo. potresti semplicemente fare questo allora:
.thumb_func
.global _start
_start:
stacktop: .word 0x20000800
.word centry
.word done
.word done
.word done
e non tornare da centry () e non avere reimpostato il codice del gestore.
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
il linker ha messo le cose dove abbiamo chiesto. E nel complesso abbiamo un programma completamente funzionale.
Quindi, primo lavoro sullo script del linker:
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__;
}
sottolineando che i nomi rom e ram non hanno alcun significato, collegano solo i punti per il linker tra le sezioni.
.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__
aggiungere alcuni elementi in modo che possiamo vedere cosa hanno fatto gli strumenti
void bounce ( unsigned int );
unsigned int a;
unsigned int b=4;
unsigned char c=5;
int centry ( void )
{
a = 7;
bounce(a);
return(0);
}
aggiungi alcuni elementi da posizionare in quelle sezioni. e prendi
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
essendo queste le cose che stiamo cercando in quell'esperimento (non notare alcun motivo per caricare o eseguire effettivamente alcun codice ... conoscere i propri strumenti, apprenderli)
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
quindi quello che abbiamo imparato qui è che la posizione delle variabili è molto sensibile negli script di gnu linker. notare la posizione di data_rom_start rispetto a data_start ma perché data_end funziona? Ti lascio capire. Capendo già perché non si potrebbe desiderare di dover pasticciare con gli script del linker e arrivare alla semplice programmazione ...
quindi un'altra cosa che abbiamo imparato qui è che il linker ha allineato data_rom_start per noi non avevamo bisogno di un ALIGN (4) lì dentro. Dovremmo supporre che funzionerà sempre?
Si noti inoltre che alla fine è stato completato, abbiamo 5 byte di .data ma è stato completato a 8. Senza alcun ALLINEAMENTO (s) possiamo già fare la copia usando le parole. Sulla base di ciò che vediamo oggi con questa toolchain sul mio computer, potrebbe essere vero per il passato e il futuro? Chissà, anche con gli ALIGN devono controllare periodicamente per confermare che alcune nuove versioni non hanno rotto le cose, lo faranno di volta in volta.
da quell'esperimento lasciamo passare a questo solo per essere al sicuro.
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__;
}
spostare le estremità all'interno per essere coerenti con quello che fanno gli altri. E questo non l'ha cambiato:
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
un altro test rapido:
.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
non è necessario spostarsi tra il rimbalzo e il .align
Oh, giusto, ora ricordo perché non inserisco _end__ dentro. perché NON FUNZIONA.
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__;
}
un codice semplice ma molto portatile da sposare con questo script di linker
.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
possiamo fermarci qui o andare avanti. Se inizializziamo nello stesso ordine dello script del linker, va bene se passiamo alla cosa successiva poiché non ci siamo ancora arrivati. e stm / ldm sono richiesti / desiderati solo per usare indirizzi allineati a parole, quindi se si cambia in:
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 prima nello script del linker, e sì, vuoi ble not 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
quei loop andranno più veloci. ora non so se i bus ahb possono avere una larghezza di 64 bit o meno, ma per un braccio di dimensioni normali si vorrebbe allineare queste cose su limiti di 64 bit. un registro ldm / stm a quattro registri su un limite di 32 bit ma non un limite di 64 bit diventa tre transazioni di bus separate, dove allineate su un limite di 64 bit è una singola transazione che salva diversi clock per istruzione.
dal momento che stiamo facendo baremetal e siamo totalmente responsabili di tutto ciò che possiamo dire prima bss quindi i dati quindi se abbiamo heap lo facciamo quindi lo stack cresce dall'alto verso il basso, quindi se azzeriamo bss e ne rovesciamo un po 'finché iniziamo da nel posto giusto che va bene non stiamo ancora usando quella memoria. quindi copiamo .data e possiamo riversarci nell'heap che va bene, heap o no c'è un sacco di spazio per lo stack in modo da non calpestare nessuno / niente (purché ci assicuriamo che nello script del linker lo facciamo. se c'è un problema, ingrandisci ALIGN () in modo che ci occupiamo sempre del nostro spazio per questi riempimenti.
quindi la mia soluzione semplice, prendila o lasciala. benvenuto per correggere eventuali bug, non l'ho eseguito su hardware né sul mio simulatore ...
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
metti tutto insieme e otterrai:
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
nota che questo funziona con arm-none-eabi- e arm-linux-gnueabi e le altre varianti in quanto non è stata usata alcuna roba ghee.
Quando ti guarderai intorno scoprirai che la gente impazzirà con le cose del mago ghee nei loro script linker, enormi mostruose cose da lavello della cucina. Meglio sapere semplicemente come farlo (o meglio come padroneggiare gli strumenti in modo da poter controllare cosa succede) piuttosto che fare affidamento su cose altrui e non sapere dove si romperà perché non capisci e / o vuoi fare ricerche esso.
come regola generale non eseguire il bootstrap di una lingua con la stessa lingua (bootstrap in questo senso significa eseguire codice non compilare un compilatore con lo stesso compilatore) si desidera utilizzare un linguaggio più semplice con meno di un bootstrap. Questo è il motivo per cui C viene eseguito in assembly, non ha requisiti di bootstrap a partire dalla prima istruzione dopo il ripristino. JAVA, certo che potresti scrivere il jvm in C e bootstrap quel C con asm quindi bootstrap il JAVA se vuoi con C ma esegui anche il JAVA in C.
Poiché controlliamo le ipotesi su questi loop di copia, sono per definizione più stretti e più puliti di memcpy / memset sintonizzati a mano.
Nota che l'altro tuo problema era questo:
unsigned int * bss_start_p = &_BSS_START;
unsigned int * bss_end_p = &_BSS_END;
se questi vanno bene a livello locale, nessun problema, se sono globali, allora devi prima inizializzare .data affinché funzionino e se provi quel trucco per fare .data, allora fallirai. Variabili locali, bene che funzionerà. se per qualche motivo hai deciso di creare i locali statici (globalmente locali che mi piace chiamarli), allora sei di nuovo nei guai. Ogni volta che fai un incarico in una dichiarazione, anche se dovresti pensarci, come viene implementato ed è sicuro / sano. Ogni volta che supponi che una variabile sia zero quando non dichiarata, lo stesso affare, se una variabile locale non è considerata zero, se globale allora lo è. se non supponi mai che siano zero, non dovrai mai preoccuparti.