Il existe d'innombrables autres sites et exemples. Plusieurs milliers sinon des dizaines de milliers. Il existe des bibliothèques c bien connues avec des scripts de l'éditeur de liens et du code boostrap, newlib, glibc en particulier, mais il y en a d'autres que vous pouvez trouver. Bootstraping C avec C n'a aucun sens.
Il a été répondu à votre question que vous essayez de faire une comparaison exacte sur des choses qui pourraient ne pas être exactes, cela pourrait ne pas commencer sur une frontière connue ou se terminer sur une frontière connue. Vous pouvez donc faire moins que la chose, mais si le code n'a pas fonctionné avec une comparaison exacte, cela signifie que vous remettez à zéro .bss dans la section suivante, ce qui peut ou non provoquer de mauvaises choses, il suffit donc de remplacer par un moins que isnt la solution.
Alors voilà TL; DR va bien. Vous ne démarrez pas une langue avec cette langue, vous pouvez vous en tirer, mais vous jouez avec le feu lorsque vous faites cela. Si vous apprenez simplement à le faire, vous devez être du côté de la prudence, pas d'une chance stupide ou de faits que vous n'avez pas encore découverts.
Le script de l'éditeur de liens et le code d'amorçage ont une relation très intime, ils sont mariés, unis à la hanche, vous ne développez pas l'un sans l'autre, ce qui conduit à un échec massif. Et malheureusement, le script de l'éditeur de liens est défini par l'éditeur de liens et le langage d'assemblage défini par l'assembleur, de sorte que lorsque vous modifiez les chaînes d'outils, vous devrez avoir à réécrire les deux. Pourquoi le langage d'assemblage? Il n'a pas besoin de bootstrap, les langages compilés le font généralement. C le fait si vous ne voulez pas limiter votre utilisation de la langauge, je vais commencer par quelque chose de très simple qui a des exigences spécifiques minimales pour la chaîne d'outils, vous ne supposez pas que les variables .bss sont nulles (rend le code moins lisible si la variable n'est jamais initialisée dans cette langue , essayez d'éviter cela, ce n'est pas vrai pour les variables locales, vous devez donc être au courant quand vous l'utilisez. les gens évitent les globaux de toute façon, alors pourquoi parlons-nous de .bss et .data ??? (les globaux sont bons pour ce travail de niveau mais c'est un autre sujet)) l'autre règle pour la solution simple est de ne pas initialiser les variables dans la déclaration, faites-le dans le code. oui brûle plus de flash, vous en avez généralement beaucoup, toutes les variables ne sont de toute façon pas initialisées avec des constantes qui finissent par consommer des instructions.
La conception de cortex-m peut dire qu'ils pensaient peut-être qu'il n'y avait aucun code de bootstrap, donc pas de support .data ni .bss. La plupart des gens qui utilisent des globaux ne peuvent pas vivre sans alors voici:
Je pourrais rendre cela plus minimal mais un exemple fonctionnel minimal pour tous les cortex-ms en utilisant la chaîne d'outils gnu, je ne me souviens pas quelles versions vous pouvez commencer avec 5.xx ou plus dans les 9.xx actuels, j'ai changé de script de l'éditeur de liens quelque part autour de 3. xx ou 4.xx au fur et à mesure que j'en apprenais plus et que gnu changeait quelque chose qui a cassé mon premier.
amorcer:
.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
point d'entrée en code C:
void bounce ( unsigned int );
unsigned int a;
int centry ( void )
{
a = 7;
bounce(a);
return(0);
}
script de l'éditeur de liens.
MEMORY
{
rom : ORIGIN = 0x00000000, LENGTH = 0x1000
ram : ORIGIN = 0x20000000, LENGTH = 0x1000
}
SECTIONS
{
.text : { *(.text*) } > rom
.rodata : { *(.rodata*) } > rom
.bss : { *(.bss*) } > ram
}
Tout cela pourrait être plus petit et fonctionner, a ajouté quelques trucs supplémentaires ici juste pour le voir au travail.
construction et lien optimisés.
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
pour certains fournisseurs, vous souhaitez utiliser 0x08000000 ou 0x01000000 ou d'autres adresses similaires car le flash y est mappé et mis en miroir sur 0x00000000 dans certains modes de démarrage. certains n'ont qu'une partie du flash en miroir à 0x00000000, vous voulez donc que le point de la table vectorielle sur l'espace flash de l'application ne soit pas nul. car il est basé sur une table vectorielle, tout fonctionne.
notez d'abord que les cortex-ms sont des machines uniquement pour le pouce et pour une raison quelconque, elles ont appliqué une adresse de fonction de pouce, ce qui signifie que le lsbit est impair. Connaissez vos outils, les directives .thumb_func indiquent à l'assembleur gnu que la prochaine étiquette est une adresse de fonction thumb. faire la chose +1 dans le tableau conduira à l'échec, ne soyez pas tenté de le faire, faites-le bien. il existe d'autres façons d'assembler gnu pour déclarer une fonction, c'est l'approche minimale.
4: 00000015
8: 0000001b
c: 0000001b
10: 0000001b
il ne démarre pas si vous n'obtenez pas la bonne table vectorielle.
sans doute n'a besoin que du vecteur de pointeur de pile (peut y mettre n'importe quoi si vous souhaitez définir le pointeur de pile vous-même dans le code) et du vecteur de réinitialisation. J'en mets quatre ici sans raison particulière. Habituellement, mettre 16, mais je voulais raccourcir cet exemple.
Alors, quel est le minimum qu'un bootstrap C doit faire? 1. définissez le pointeur de pile 2. zéro .bss 3. copiez .data 4. branchez ou appelez le point d'entrée C
le point d'entrée C est généralement appelé main (). mais certaines chaînes d'outils voient main () et ajoutent des ordures supplémentaires à votre code. J'utilise intentionnellement un nom différent. YMMV.
la copie de .data n'est pas nécessaire si tout est basé sur ram. étant un microcontrôleur cortex-m, il est techniquement possible mais peu probable, donc la copie .data est nécessaire ..... s'il y a .data.
Mon premier exemple et un style de codage est de ne pas compter sur .data ni .bss, comme dans cet exemple. Arm s'est occupé du pointeur de pile, il ne reste donc plus qu'à appeler le point d'entrée. J'aime l'avoir pour que le point d'entrée puisse revenir, beaucoup de gens soutiennent que vous ne devriez jamais faire ça. vous pouvez alors faire ceci:
.thumb_func
.global _start
_start:
stacktop: .word 0x20000800
.word centry
.word done
.word done
.word done
et ne pas revenir de centry () et ne pas réinitialiser le code du gestionnaire.
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
l'éditeur de liens a mis les choses où nous avons demandé. Et dans l'ensemble, nous avons un programme entièrement fonctionnel.
Alors commencez par travailler sur le script de l'éditeur de liens:
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__;
}
soulignant que les noms rom et ram n'ont aucune signification, ils ne font que connecter les points pour l'éditeur de liens entre les sections.
.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__
ajouter des éléments afin que nous puissions voir ce que les outils ont fait
void bounce ( unsigned int );
unsigned int a;
unsigned int b=4;
unsigned char c=5;
int centry ( void )
{
a = 7;
bounce(a);
return(0);
}
ajoutez des éléments à placer dans ces sections. et obtenir
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
voici ce que nous recherchons dans cette expérience (notez aucune raison de charger ou d'exécuter du code ... connaissez vos outils, apprenez-les)
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
donc ce que nous avons appris ici est que la position des variables est très sensible dans les scripts de l'éditeur de liens gnu. notez la position de data_rom_start par rapport à data_start mais pourquoi data_end fonctionne-t-il? Je vais vous laisser comprendre ça. Comprenant déjà pourquoi on ne voudrait pas avoir à jouer avec les scripts de l'éditeur de liens et à se contenter d'une programmation simple ...
donc une autre chose que nous avons apprise ici est que le linker alignait data_rom_start pour nous, nous n'avions pas besoin d'un ALIGN (4) là-dedans. Faut-il supposer que cela fonctionnera toujours?
Notez également qu'il a complété à la sortie, nous avons 5 octets de .data mais il l'a complété à 8. Sans aucun ALIGN () nous pouvons déjà faire la copie en utilisant des mots. D'après ce que nous voyons avec cette chaîne d'outils sur mon ordinateur aujourd'hui, cela pourrait-il être vrai pour le passé et le futur? Qui sait, même avec les ALIGNs doivent vérifier périodiquement pour confirmer qu'une nouvelle version n'a pas cassé les choses, ils le feront de temps en temps.
de cette expérience permet de passer à cela juste pour être sûr.
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__;
}
déplacer les extrémités à l'intérieur pour être cohérent avec ce que font les autres. Et cela ne l'a pas changé:
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 autre test rapide:
.globl bounce
bounce:
nop
bx lr
donnant
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
pas besoin de passer du rebond au .align
Ohh, c'est vrai, je me souviens maintenant pourquoi je ne mets pas le _end__ à l'intérieur. car cela NE FONCTIONNE PAS.
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__;
}
du code simple mais très portable à marier à ce script de l'éditeur de liens
.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__
donnant
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
nous pouvons nous arrêter là ou continuer. Si nous initialisons dans le même ordre que le script de l'éditeur de liens, cela ne pose aucun problème si nous passons à l'étape suivante car nous n'y sommes pas encore arrivés. et stm / ldm sont uniquement requis / souhaités pour utiliser des adresses alignées sur des mots, donc si vous passez à:
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:
avec bss d'abord dans le script de l'éditeur de liens, et oui, vous voulez ble pas 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
ces boucles iront plus vite. maintenant, je ne sais pas si les bus ahb peuvent avoir une largeur de 64 bits ou non, mais pour un bras de taille normale, vous voudriez aligner ces choses sur des limites de 64 bits. un ldm / stm à quatre registres sur une frontière de 32 bits mais pas une frontière de 64 bits devient trois transactions de bus distinctes, où aligné sur une frontière de 64 bits est une transaction unique économisant plusieurs horloges par instruction.
puisque nous faisons du baremetal et nous sommes entièrement responsables de tout ce que nous pouvons mettre, disons d'abord bss, puis les données, puis si nous avons un tas, alors la pile augmente de haut en bas, donc si nous mettons à zéro bss et en débordons aussi longtemps que nous commençons à le bon endroit qui est bien nous n'utilisons pas encore cette mémoire. Ensuite, nous copions les données. et nous pouvons déverser dans le tas, c'est bien, tas ou pas, il y a beaucoup de place pour la pile, donc nous ne marchons sur personne / rien (tant que nous nous assurons que dans le script de l'éditeur de liens nous le faisons. s'il y a un problème, agrandissez les ALIGN () pour que nous nous trouvions toujours dans notre espace pour ces remplissages.
donc ma solution simple, à prendre ou à laisser. bienvenue pour corriger les bugs, je ne l'ai pas exécuté sur le matériel ni sur mon simulateur ...
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
mettez tout cela ensemble et vous obtenez:
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
notez que cela fonctionne avec arm-none-eabi- et arm-linux-gnueabi et les autres variantes car aucun truc de ghee whiz n'a été utilisé.
Vous constaterez que lorsque vous regardez autour de vous, les gens vont devenir fous avec des trucs de ghee dans leurs scripts de liaison, d'énormes choses monstrueuses d'évier de cuisine. Mieux vaut juste savoir comment le faire (ou mieux comment maîtriser les outils afin que vous puissiez contrôler ce qui se passe) plutôt que de compter sur quelqu'un d'autre et de ne pas savoir où cela va se casser parce que vous ne comprenez pas et / ou ne voulez pas rechercher il.
en règle générale, n'amorcez pas un langage avec le même langage (bootstrap dans ce sens signifiant exécuter du code ne compilant pas un compilateur avec le même compilateur), vous voulez utiliser un langage plus simple avec moins d'amorçage. C'est pourquoi C est fait en assembleur, il n'a pas d'exigences de bootstrap que vous venez de démarrer à partir de la première instruction après la réinitialisation. JAVA, bien sûr, vous pourriez écrire le jvm en C et amorcer ce C avec asm puis amorcer le JAVA si vous voulez avec C mais aussi exécuter le JAVA en C aussi.
Parce que nous contrôlons les hypothèses sur ces boucles de copie, elles sont par définition plus strictes et plus propres que les memcpy / memset réglés à la main.
Notez que votre autre problème était le suivant:
unsigned int * bss_start_p = &_BSS_START;
unsigned int * bss_end_p = &_BSS_END;
si ce sont des amendes locales, pas de problème, si elles sont globales, vous devez d'abord initialiser .data pour qu'elles fonctionnent et si vous essayez cette astuce pour faire .data, vous échouerez. Variables locales, très bien cela fonctionnera. si pour une raison quelconque vous avez décidé de créer des sections locales statiques (des globales locales j'aime les appeler), vous êtes à nouveau en difficulté. Chaque fois que vous effectuez une affectation dans une déclaration, vous devez y penser, comment est-ce implémenté et est-il sûr / sain d'esprit. Chaque fois que vous supposez qu'une variable est nulle lorsqu'elle n'est pas déclarée, même chose, si une variable locale n'est pas supposée être nulle, si elle est globale, elle l'est. si vous ne les supposez jamais nulles, vous n'avez jamais à vous inquiéter.