Codice di avvio in metallo nudo per l'inizializzazione della regione .bss di Cortex M3


10

Ho sviluppato ispirato da qui un codice di avvio in metallo nudo per la corteccia del braccio M3. Tuttavia, riscontro il seguente problema: supponiamo di dichiarare una variabile globale non inizializzata, diciamo di tipo unsigned char in main.c

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

questo rende la regione .bss in STM32 f103 che inizia a _BSS_START = 0x20000000 e termina a _BSS_END = 0x20000001. Ora, il codice di avvio

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

tenta di inizializzare per azzerare l'intera regione .bss. Tuttavia, all'interno di quel ciclo while il puntatore aumenta di 4 byte, quindi dopo un passo bss_start_p = 0x20000004 quindi sarà sempre diverso da bss_end_p che porta a un ciclo infinito ecc.

Esiste una soluzione standard a questo? Suppongo di "forzare" in qualche modo la dimensione della regione .bss ad essere un multiplo di 4? O dovrei usare un puntatore al carattere senza segno per attraversare la regione .bss? Forse qualcosa del tipo:

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

usare meno di. i bootstrap sono scritti in assembly per un motivo. prima di tutto ora hai creato un problema con i dati. è una cosa da gallina e uovo da usare / supporre che C funzioni su cui si basano almeno .text, .bss e .data, ma si sta scrivendo un codice C che si assicura che il codice C funzioni, usando cose nel codice C che richiedono un bootstrap probabilmente scritto nel codice C che si basa sul funzionamento di C.
old_timer

il codice per copiare .data over è molto simile a .bss, ma se lo scrivi come il codice sopra, allora devi copiare .data per copiare .data over.
old_timer

Risposte:


15

Come sospetti, ciò accade perché il tipo di dati int senza segno ha una dimensione di 4 byte. Ogni*bss_start_p = 0; istruzione cancella effettivamente quattro byte dell'area bss.

L'intervallo di memoria bss deve essere allineato correttamente. È possibile semplicemente definire _BSS_START e _BSS_END in modo che la dimensione totale sia un multiplo di quattro, ma ciò viene generalmente gestito consentendo allo script del linker di definire le posizioni di inizio e di fine.

Ad esempio, ecco la sezione linker in uno dei miei progetti:

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

Il ALIGN(4) dichiarazioni si prendono cura delle cose.

Inoltre, potresti voler cambiare

while(bss_start_p != bss_end_p)

per

while(bss_start_p < bss_end_p).

Questo non eviterà il problema (poiché potresti cancellare 1-3 byte in più di quanto desideri), ma potrebbe minimizzare l'impatto :)


@CMarius Riflettendoci, penso che la tua idea di puntatore di caratteri funzionerebbe alla grande, sebbene richiederebbe più cicli. Ma non sono sicuro che ci sarebbero problemi successivi con la prossima area di memoria non allineata, quindi non ne
parlerò

1
while(bss_start_p < bss_end_p - 1)seguito da una cancellazione byte-byte dell'intervallo di memoria rimanente eliminerebbe l'ultima preoccupazione.
glglgl

4

La soluzione standard è memset():

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

Se non riesci a utilizzare la libreria standard, dovrai decidere se nel tuo caso è corretto arrotondare la dimensione dell'area di memoria fino a 4 byte e continuare a utilizzare unsigned int *; o se devi essere severo al riguardo, nel qual caso dovrai usarlo unsigned char *.

Se arrotondi le dimensioni, come nel tuo primo ciclo, bss_start_ppotresti effettivamente finire più grande di, bss_end_pma è facile affrontare un confronto minore <di un test di disuguaglianza.

Ovviamente, potresti anche riempire la maggior parte dell'area di memoria con trasferimenti a 32 bit e solo gli ultimi pochi byte con trasferimenti a 8 bit, ma questo è più lavoro per un piccolo guadagno, in particolare qui quando è solo un pezzo di codice di avvio.


1
Sono molto d'accordo con l'uso di memset(). Ma l'allineamento a 4 byte è più o meno un must. Quindi perché non farlo?
Codo

3
in nessun modo forma o forma è la soluzione standard per il bootstrap di utilizzare memset, che è pazzo.
old_timer

non usi la stessa lingua per bootstrap quella lingua
old_timer

2
il codice bootstrap e lo script del linker sono molto sposati, troverete che lo script del linker allinea e dimensiona gli .bss su almeno un limite di 4 byte per migliorare il riempimento (nel bootstrap) di 4x su byte alla volta istruzioni (supponendo (minimo) bus a 32 bit che è tipico per arm ma ci sono eccezioni)
old_timer

3
@old_timer, è la funzione C standard per impostare la memoria su un valore particolare memset() , e C è ciò in cui sembrano programmare. La semplice implementazione di questo memset()è praticamente solo quel loop, non è come se dipendesse da molto altro. Dato che si tratta di un microcontrollore, suppongo anche che non ci siano collegamenti dinamici o simili (e guardando il collegamento, non c'è, è solo una chiamata a main()dopo quel ciclo di azzeramento), quindi il compilatore dovrebbe essere in grado di cadere memset()lì insieme ad altre funzioni (o per implementarlo in linea).
ilkkachu,

4

Passa !=a <. Di solito è comunque un approccio migliore, poiché affronta problemi come questo.


3

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.


fantastico, questa è la seconda volta che ho superato il numero massimo di caratteri in una risposta ....
old_timer

Questa domanda appartiene allo stackoverflow non all'ingegneria elettrica.
old_timer

Anche fare affidamento su un collegamento esterno nella tua domanda non è una buona forma, se il collegamento scompare prima della domanda, la domanda potrebbe non avere senso.
old_timer

In questo caso, il titolo e il contenuto sono sufficienti per sapere che si sta tentando di avviare C su un determinato microcontrollore e si sta vagando nell'inizializzazione .bss e .data
old_timer

ma in questo caso sono stati fuorviati da un sito Web altrimenti molto informativo.
old_timer
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.