Code de démarrage nu pour l'initialisation de la région Cortex M3 .bss

10

J'ai développé à partir d' ici un code de démarrage en métal nu pour le cortex du bras M3. Cependant, je rencontre le problème suivant: supposons que je déclare une variable globale non initialisée, disons de type unsigned char dans main.c

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

cela rend la région .bss dans STM32 f103 commençant à _BSS_START = 0x20000000 et se terminant à _BSS_END = 0x20000001. Maintenant, le code de démarrage

    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++;
    }

tente d'initialiser à zéro toute la région .bss. Cependant, à l'intérieur de cette boucle, le pointeur augmente de 4 octets, donc après une étape, bss_start_p = 0x20000004, il sera donc toujours différent de bss_end_p, ce qui conduit à une boucle infinie, etc.

Existe-t-il une solution standard à cela? Suis-je supposé "forcer" d'une manière ou d'une autre la dimension de la région .bss à un multiple de 4? Ou dois-je utiliser un pointeur sur un caractère non signé pour parcourir la région .bss? Peut-être quelque chose comme:

    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
la source
utiliser moins de. les bootstraps sont écrits en assembleur pour une raison. tout d'abord, vous avez créé un problème de .data. c'est une chose de poulet et d'oeuf à utiliser / supposer que C fonctionne, vous vous fiez au minimum sur .text, .bss et .data, mais vous écrivez du code C qui s'assure que le code C fonctionnera, en utilisant des choses dans le code C qui nécessite un bootstrap éventuellement écrit en code C qui repose sur le fonctionnement de C.
old_timer
le code pour copier .data sur est très similaire à .bss, mais si vous l'écrivez comme le code ci-dessus, alors vous avez besoin de .data copié pour copier .data sur.
old_timer

Réponses:

15

Comme vous le pensez, cela se produit car le type de données int non signé a une taille de 4 octets. Chaque *bss_start_p = 0;instruction efface en fait quatre octets de la zone bss.

La plage de mémoire bss doit être alignée correctement. Vous pouvez simplement définir _BSS_START et _BSS_END afin que la taille totale soit un multiple de quatre, mais cela est généralement géré en permettant au script de l'éditeur de liens de définir les emplacements de début et de fin.

À titre d'exemple, voici la section de l'éditeur de liens dans l'un de mes projets:

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

Les ALIGN(4)déclarations s'occupent des choses.

Vous pouvez également souhaiter modifier

while(bss_start_p != bss_end_p)

à

while(bss_start_p < bss_end_p).

Cela n'empêchera pas le problème (car vous pourriez effacer 1 à 3 octets de plus que vous le souhaitez), mais cela pourrait minimiser l'impact :)

bitsmack
la source
@CMarius Après réflexion, je pense que votre idée de pointeur de caractère fonctionnerait très bien, même si cela nécessiterait plus de cycles. Mais je ne sais pas s'il y aurait des problèmes ultérieurs avec la prochaine zone de mémoire non alignée, donc je ne vais pas le mentionner dans ma réponse ...
bitsmack
1
while(bss_start_p < bss_end_p - 1)suivi d'un effacement octet de la plage de mémoire restante éliminerait le dernier problème.
glglgl
4

La solution standard est memset():

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

Si vous ne pouvez pas utiliser la bibliothèque standard, alors vous devrez décider si c'est correct dans votre cas pour arrondir la taille de la zone mémoire jusqu'à 4 octets et continuer à utiliser unsigned int *; ou si vous devez être strict à ce sujet, auquel cas vous devrez utiliser unsigned char *.

Si vous arrondissez la taille, comme dans votre première boucle, cela bss_start_ppeut en effet finir par être supérieur à bss_end_pmais c'est facile à gérer avec une comparaison inférieure à <au lieu d'un test d'inégalité.

Bien sûr, vous pouvez également remplir la plupart de la zone de mémoire avec des transferts 32 bits, et seulement les derniers octets avec des transferts 8 bits, mais c'est plus de travail pour peu de gain, en particulier ici quand ce n'est qu'un morceau de code de démarrage.

ilkkachu
la source
1
D'accord avec l'utilisation de memset(). Mais l'alignement sur 4 octets est plus ou moins indispensable. alors pourquoi ne pas le faire?
Codo
3
en aucune façon la forme ou la forme n'est la solution standard pour que le bootstrap utilise le memset, c'est fou.
old_timer
vous n'utilisez pas la même langue pour amorcer cette langue
old_timer
2
le code de bootstrap et le script de l'éditeur de liens sont très bien mariés, vous constaterez qu'il est courant que le script de l'éditeur de liens aligne et dimensionne le .bss sur au moins une limite de 4 octets pour améliorer le remplissage (dans le bootstrap) de 4x sur l'octet à la fois. (en supposant (minimum) des bus 32 bits qui sont typiques pour le bras mais il y a des exceptions)
old_timer
3
@old_timer, la fonction C standard pour définir la mémoire à une valeur particulière est memset(), et C est ce qu'ils semblent programmer. La simple implémentation de memset()est aussi à peu près juste cette boucle, ce n'est pas comme si cela dépend de beaucoup d'autre. Puisqu'il s'agit d'un microcontrôleur, je suppose également qu'il n'y a pas de liaison dynamique ou autre (et en regardant le lien, il n'y en a pas, c'est juste un appel à main()après cette boucle de mise à zéro), donc le compilateur devrait être capable d' memset()y aller avec toutes les autres fonctions (ou pour l'implémenter en ligne).
ilkkachu
4

Changez simplement !=en <. C'est généralement une meilleure approche de toute façon, car elle traite de problèmes comme celui-ci.

Elliot Alderson
la source
3

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.

old_timer
la source
génial, c'est la deuxième fois que je dépasse le nombre maximal de caractères dans une réponse ....
old_timer
Cette question appartient au stackoverflow et non au génie électrique.
old_timer
Se fier à un lien externe dans votre question n'est pas non plus une bonne forme, si le lien disparaît avant la question, alors la question pourrait ne pas avoir de sens.
old_timer
Dans ce cas, votre titre et votre contenu suffisent pour savoir que vous essayez d'amorcer C sur un microcontrôleur particulier et que vous vous aventurez dans l'initialisation .bss et .data
old_timer
mais dans ce cas ont été induits en erreur par un site Web par ailleurs très informatif.
old_timer