Código de inicialização bare-metal para inicialização da região .xs do Cortex M3

10

A partir daqui, desenvolvi um código de inicialização bare metal para o córtex do braço M3. No entanto, encontro o seguinte problema: suponha que declare uma variável global não inicializada, digamos do tipo char não assinado em main.c

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

isso torna a região .bss no STM32 f103 começando em _BSS_START = 0x20000000 e terminando em _BSS_END = 0x20000001. Agora, o código de inicialização

    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 inicializar para zerar toda a região .bss. No entanto, dentro desse loop while, o ponteiro aumenta com 4 bytes, portanto, após uma etapa bss_start_p = 0x20000004, portanto, sempre será diferente de bss_end_p, o que leva a um loop infinito etc.

Existe alguma solução padrão para isso? Devo "forçar" de alguma forma a dimensão da região .bss para ser um múltiplo de 4? Ou devo usar um ponteiro para char não assinado para percorrer a região .bss? Talvez algo como:

    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
fonte
use menos que. bootstraps são gravados em assembly por um motivo. primeiro, agora que você criou um problema de dados. é uma coisa de galinha e ovo usar / presumir que C funciona com base em .text, .bss e .data no mínimo, mas você está escrevendo um código C que garante que o código C funcione, usando coisas no código C que requerem uma bootstrap possivelmente escrito em código C que depende do funcionamento de C.
old_timer
o código para copiar .data é muito semelhante ao .bss, mas se você escrever como o código acima, precisará .data copiado para copiar .data.
old_timer

Respostas:

15

Como você suspeita, isso está acontecendo porque o tipo de dados int não assinado tem 4 bytes de tamanho. Cada *bss_start_p = 0;instrução, na verdade, limpa quatro bytes da área bss.

O intervalo de memória bss precisa estar alinhado corretamente. Você pode simplesmente definir _BSS_START e _BSS_END para que o tamanho total seja múltiplo de quatro, mas isso geralmente é tratado ao permitir que o script do vinculador defina os locais de início e parada.

Como exemplo, aqui está a seção vinculador em um dos meus projetos:

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

As ALIGN(4)declarações cuidam das coisas.

Além disso, você pode querer mudar

while(bss_start_p != bss_end_p)

para

while(bss_start_p < bss_end_p).

Isso não impedirá o problema (já que você pode limpar de 1 a 3 bytes a mais do que deseja), mas poderá minimizar o impacto :)

bitsmack
fonte
@CMarius Após refletir, acho que sua ideia de ponteiro de caracteres funcionaria muito bem, embora fosse necessário mais ciclos. Mas eu não tenho certeza se haveria problemas posteriores com a área de memória próximo de ser desalinhado, então eu não vou mencioná-lo na minha resposta ...
bitsmack
1
while(bss_start_p < bss_end_p - 1)seguido de uma limpeza em bytes do intervalo de memória restante eliminaria a última preocupação.
glglgl
4

A solução padrão é memset():

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

Se você não puder usar a biblioteca padrão, terá que decidir se está correto no seu caso arredondar o tamanho da área de memória até 4 bytes e continuar usando unsigned int *; ou se você precisar ser rigoroso, nesse caso, você precisará usar unsigned char *.

Se você arredondar o tamanho, como no seu primeiro loop, bss_start_ppode acabar sendo maior que, bss_end_pmas é fácil lidar com uma comparação menor que a em <vez de um teste de desigualdade.

Obviamente, você também pode preencher a maior parte da área de memória com transferências de 32 bits e apenas os últimos bytes com transferências de 8 bits, mas isso é mais útil para pouco ganho, principalmente aqui quando é apenas um pedaço de código de inicialização.

ilkkachu
fonte
1
Concordo muito com o uso de memset(). Mas o alinhamento com 4 bytes é mais ou menos necessário. Então, por que não fazer isso?
Codo
3
de forma alguma a forma padrão é a solução padrão para o bootstrap usar memset, isso é loucura.
old_timer
Você não usar a mesma linguagem para o bootstrap que a linguagem
old_timer
2
o código de bootstrap e o script do vinculador são muito casados, você verá que o script do vinculador alinha e dimensiona os .bss em pelo menos um limite de 4 bytes para melhorar o preenchimento (no bootstrap) em 4x sobre o byte por vez (assumindo (mínimo) 32 barramentos de bits que é típico para o braço, mas existem excepções)
old_timer
3
@old_timer, a função C padrão para definir a memória com um valor específico é memset()e C é o que eles parecem estar programando. A implementação simples de memset()também é basicamente esse loop, não é como se dependesse de muito mais. Como esse é um microcontrolador, eu também assumo que não há vínculo dinâmico ou algo assim (e olhando para o link, não existe, é apenas uma chamada para main()depois desse loop de zeragem), para que o compilador seja capaz de entrar memset()nele juntamente com outras funções (ou implementá-lo em linha).
Ilkkachu
4

Apenas mude !=para <. De qualquer maneira, geralmente é uma abordagem melhor, pois lida com problemas como esse.

Elliot Alderson
fonte
3

Existem inúmeros outros sites e exemplos. Muitos milhares, senão dezenas de milhares. Existem as bibliotecas c conhecidas com scripts de vinculação e código boostrap, newlib, glibc em particular, mas existem outras que você pode encontrar. Bootstraping C com C não faz sentido.

Sua pergunta foi respondida. Você está tentando fazer uma comparação exata de coisas que podem não ser exatas, pode não começar em um limite conhecido ou terminar em um limite conhecido. Portanto, você pode fazer o que é menos, mas se o código não funcionar com uma comparação exata, isso significa que você está zerando o .bss para a próxima seção, que pode ou não fazer com que coisas ruins aconteçam, então substitua-o por um valor menor que não é a solução.

Então aqui vai TL; DR está bem. Você não inicializa um idioma com esse idioma, pode se safar com certeza, mas está brincando com fogo quando faz isso. Se você está apenas aprendendo a fazer isso, precisa estar do lado da cautela, sem ter sorte ou fatos que ainda não descobriu.

O script do vinculador e o código de bootstrap têm um relacionamento muito íntimo, são casados, unidos no quadril, você não desenvolve um sem o outro que leva ao fracasso em massa. E, infelizmente, o script do vinculador é definido pelo vinculador e a linguagem de montagem definida pelo assembler, assim como você altera as cadeias de ferramentas, espera-se que tenha que reescrever os dois. Por que linguagem assembly? Ele não precisa de bootstrap, as linguagens compiladas geralmente precisam. C faz isso se você não limitar seu uso do idioma. Começarei com algo muito simples que possui requisitos mínimos de cadeia de ferramentas, você não assume que as variáveis ​​.bss são zero (torna o código menos legível se a variável nunca for inicializada nesse idioma , tente evitar isso, não é verdade para variáveis ​​locais, portanto, tenha em mente que quando você a usa, as pessoas evitam os globais de qualquer maneira, Então, por que estamos falando sobre .bss e .data ??? (os globais são bons para este nível de trabalho, mas esse é outro tópico)) a outra regra para a solução simples é não inicializar variáveis ​​na declaração, fazê-lo no código. sim queima mais flash, você geralmente tem bastante, nem todas as variáveis ​​são inicializadas com constantes de qualquer maneira que acabam consumindo instruções.

Você pode dizer pelo design do córtex-m que eles podem estar pensando que não há código de autoinicialização, portanto, não há suporte a dados nem .bss. A maioria das pessoas que usam globals não pode viver sem, então aqui vai:

Eu poderia tornar isso mais mínimo, mas um exemplo funcional mínimo para todos os córtex-ms usando a cadeia de ferramentas gnu, não me lembro de quais versões você pode começar com 5.xx ou mais nos atuais 9.xx troquei scripts de vinculador em torno de 3. xx ou 4.xx como eu aprendi mais e como gnu mudou algo que quebrou o meu primeiro.

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

ponto de entrada no código C:

void bounce ( unsigned int );

unsigned int a;

int centry ( void )
{
    a = 7;
    bounce(a);
    return(0);
}

script vinculador.

MEMORY
{
    rom : ORIGIN = 0x00000000, LENGTH = 0x1000
    ram : ORIGIN = 0x20000000, LENGTH = 0x1000
}

SECTIONS
{
    .text : { *(.text*) } > rom
    .rodata : { *(.rodata*) } > rom
    .bss : { *(.bss*) } > ram
}

Tudo isso pode ser menor e ainda funcionar, adicionou algumas coisas extras aqui apenas para vê-lo funcionar.

construção e link otimizados.

00000000 <_start>:
   0:   20001000
   4:   00000015
   8:   0000001b
   c:   0000001b
  10:   0000001b

00000014 <reset>:
  14:   f000 f804   bl  20 <centry>
  18:   e7ff        b.n 1a <done>

0000001a <done>:
  1a:   e7fe        b.n 1a <done>

0000001c <bounce>:
  1c:   4770        bx  lr
    ...

00000020 <centry>:
  20:   2207        movs    r2, #7
  22:   b510        push    {r4, lr}
  24:   4b04        ldr r3, [pc, #16]   ; (38 <centry+0x18>)
  26:   2007        movs    r0, #7
  28:   601a        str r2, [r3, #0]
  2a:   f7ff fff7   bl  1c <bounce>
  2e:   2000        movs    r0, #0
  30:   bc10        pop {r4}
  32:   bc02        pop {r1}
  34:   4708        bx  r1
  36:   46c0        nop         ; (mov r8, r8)
  38:   20000000    andcs   r0, r0, r0

Disassembly of section .bss:

20000000 <a>:
20000000:   00000000    andeq   r0, r0, r0

para alguns fornecedores, você deseja usar 0x08000000 ou 0x01000000 ou outros endereços semelhantes, pois o flash é mapeado lá e espelhado para 0x00000000 em alguns modos de inicialização. alguns têm apenas o flash espelhado em 0x00000000, portanto, você deseja que a tabela do vetor aponte no espaço do flash do aplicativo diferente de zero. uma vez que é baseado em tabela vetorial, tudo funciona.

primeira nota: o córtex-ms são máquinas apenas de polegar e, por qualquer motivo, eles aplicaram um endereço de função de polegar, o que significa que o lsbit é ímpar. Conheça suas ferramentas, as diretivas .thumb_func informam ao assembler do gnu que o próximo rótulo é um endereço de função de polegar. fazer o +1 na tabela levará ao fracasso, não fique tentado a fazê-lo, faça o que é certo. existem outras maneiras de o gnu assembler declarar uma função, essa é a abordagem mínima.

   4:   00000015
   8:   0000001b
   c:   0000001b
  10:   0000001b

ele não inicializa se você não acertar a tabela de vetores.

indiscutivelmente, você só precisa do vetor do ponteiro da pilha (pode colocar qualquer coisa lá se desejar definir o ponteiro da pilha no código) e do vetor de redefinição. Coloquei quatro aqui sem nenhuma razão específica. Normalmente coloque 16, mas queria encurtar este exemplo.

Então, qual é o mínimo que um bootstrap C precisa fazer? 1. defina o ponteiro da pilha 2. zero .bss 3. copie. Dados 4. ramifique ou chame o ponto de entrada C

o ponto de entrada C é geralmente chamado de main (). mas algumas cadeias de ferramentas vêem main () e adicionam lixo extra ao seu código. Eu intencionalmente uso um nome diferente. YMMV.

a cópia do arquivo .data não será necessária se tudo for baseado em RAM. sendo um microcontrolador córtex-m, é tecnicamente possível, mas improvável, portanto a cópia .data é necessária ..... se houver .data.

Meu primeiro exemplo e um estilo de codificação é não confiar em .data nem em .bss, como neste exemplo. Arm cuidou do ponteiro da pilha, então a única coisa que resta é chamar o ponto de entrada. Eu gosto de tê-lo para que o ponto de entrada possa retornar, muitas pessoas argumentam que você nunca deve fazer isso. você poderia fazer isso então:

.thumb_func
.global _start
_start:
stacktop: .word 0x20000800
.word centry
.word done
.word done
.word done

e não retornar de centry () e não ter redefinido o código do manipulador.

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

o vinculador colocou as coisas onde pedimos. No geral, temos um programa totalmente funcional.

Então, primeiro trabalhe no script do vinculador:

MEMORY
{
    bob : ORIGIN = 0x00000000, LENGTH = 0x1000
    ted : ORIGIN = 0x20000000, LENGTH = 0x1000
}

SECTIONS
{
    .text : { *(.text*) } > bob

    .rodata : { *(.rodata*) } > bob

   __data_rom_start__ = .;
   .data : {
    __data_start__ = .;
    *(.data*)
   } > ted AT > bob
   __data_end__ = .;
   __data_size__ = __data_end__ - __data_start__;

   .bss  : {
   __bss_start__ = .;
   *(.bss*)
   } > ted
   __bss_end__ = .;
   __bss_size__ = __bss_end__ - __bss_start__;

}

enfatizando que os nomes rom e ram não têm significado, eles apenas conectam os pontos do vinculador entre as seções.

.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__

adicione alguns itens para que possamos ver o que as ferramentas fizeram

void bounce ( unsigned int );

unsigned int a;

unsigned int b=4;
unsigned char c=5;

int centry ( void )
{
    a = 7;
    bounce(a);
    return(0);
}

adicione alguns itens para colocar nessas seções. e pegue

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

aqui estão as coisas que procuramos nessa experiência (observe que não há razão para realmente carregar nem executar qualquer código ... conheça suas ferramentas, aprenda-as)

  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

então o que aprendemos aqui é que a posição das variáveis ​​é muito sensível nos scripts do gnu linker. observe a posição de data_rom_start vs data_start, mas por que data_end funciona? Vou deixar você descobrir isso. Já entendo por que alguém pode não querer mexer nos scripts do vinculador e apenas começar a programação simples ...

outra coisa que aprendemos aqui é que o vinculador alinhado data_rom_start para nós não precisamos de um ALIGN (4) lá. Devemos assumir que isso sempre funcionará?

Observe também que preenchido no caminho para, temos 5 bytes de .data, mas preenchido para 8. Sem ALIGN () s, já podemos fazer a cópia usando palavras. Com base no que vemos com esta cadeia de ferramentas em meu computador hoje, isso pode ser verdade para o passado e o futuro? Quem sabe, mesmo com os ALIGNs, verifique periodicamente para confirmar se alguma nova versão não quebrou as coisas, eles farão isso de tempos em tempos.

a partir desse experimento, vamos passar para isso apenas por segurança.

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__;

}

movendo as extremidades para dentro para ser consistente com o que as outras pessoas fazem. E isso não mudou:

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

mais um teste rápido:

.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

não há necessidade de alternar entre o ressalto e o alinhamento.

Ohh, certo, agora me lembro porque não coloco o _end__ dentro. porque não funciona.

MEMORY
{
    bob : ORIGIN = 0x00000000, LENGTH = 0x1000
    ted : ORIGIN = 0x20000000, LENGTH = 0x1000
}

SECTIONS
{
    .text : { *(.text*) } > bob

    .rodata : { *(.rodata*) } > bob

   . = ALIGN(4);
   __data_rom_start__ = .;
   .data : {
    __data_start__ = .;
    *(.data*)
   } > ted AT > bob
   . = ALIGN(4);
   __data_end__ = .;
   __data_size__ = __data_end__ - __data_start__;

   . = ALIGN(4);
   .bss  : {
   __bss_start__ = .;
   *(.bss*)
   } > ted
   . = ALIGN(4);
   __bss_end__ = .;
   __bss_size__ = __bss_end__ - __bss_start__;

}

algum código simples, mas muito portátil, para se casar com esse script vinculador

.thumb

.thumb_func
.global _start
_start:
stacktop: .word 0x20000800
.word reset
.word done
.word done
.word done

.thumb_func
reset:

    ldr r0,blen
    cmp r0,#0
    beq bss_zero_done
    ldr r1,bstart
    mov r2,#0
bss_zero:
    stmia r1!,{r2}
    sub r0,#4
    bne bss_zero
bss_zero_done:

    ldr r0,dlen
    cmp r0,#0
    beq data_copy_done
    ldr r1,rstart
    ldr r2,dstart
data_copy:
    ldmia r1!,{r3}
    stmia r2!,{r3}
    sub r0,#4
    bne data_copy
data_copy_done:

    bl centry
    b done

.thumb_func
done:   b .

.thumb_func
.globl bounce
bounce:
    nop
    bx lr

.align
bstart: .word __bss_start__
blen:   .word __bss_size__
rstart: .word __data_rom_start__
dstart: .word __data_start__
dlen:   .word __data_size__

dando

Disassembly of section .text:

00000000 <_start>:
   0:   20000800    andcs   r0, r0, r0, lsl #16
   4:   00000015    andeq   r0, r0, r5, lsl r0
   8:   0000003d    andeq   r0, r0, sp, lsr r0
   c:   0000003d    andeq   r0, r0, sp, lsr r0
  10:   0000003d    andeq   r0, r0, sp, lsr r0

00000014 <reset>:
  14:   480c        ldr r0, [pc, #48]   ; (48 <blen>)
  16:   2800        cmp r0, #0
  18:   d004        beq.n   24 <bss_zero_done>
  1a:   490a        ldr r1, [pc, #40]   ; (44 <bstart>)
  1c:   2200        movs    r2, #0

0000001e <bss_zero>:
  1e:   c104        stmia   r1!, {r2}
  20:   3804        subs    r0, #4
  22:   d1fc        bne.n   1e <bss_zero>

00000024 <bss_zero_done>:
  24:   480b        ldr r0, [pc, #44]   ; (54 <dlen>)
  26:   2800        cmp r0, #0
  28:   d005        beq.n   36 <data_copy_done>
  2a:   4908        ldr r1, [pc, #32]   ; (4c <rstart>)
  2c:   4a08        ldr r2, [pc, #32]   ; (50 <dstart>)

0000002e <data_copy>:
  2e:   c908        ldmia   r1!, {r3}
  30:   c208        stmia   r2!, {r3}
  32:   3804        subs    r0, #4
  34:   d1fb        bne.n   2e <data_copy>

00000036 <data_copy_done>:
  36:   f000 f80f   bl  58 <centry>
  3a:   e7ff        b.n 3c <done>

0000003c <done>:
  3c:   e7fe        b.n 3c <done>

0000003e <bounce>:
  3e:   46c0        nop         ; (mov r8, r8)
  40:   4770        bx  lr
  42:   46c0        nop         ; (mov r8, r8)

00000044 <bstart>:
  44:   20000008    andcs   r0, r0, r8

00000048 <blen>:
  48:   00000004    andeq   r0, r0, r4

0000004c <rstart>:
  4c:   00000074    andeq   r0, r0, r4, ror r0

00000050 <dstart>:
  50:   20000000    andcs   r0, r0, r0

00000054 <dlen>:
  54:   00000008    andeq   r0, r0, r8

00000058 <centry>:
  58:   2207        movs    r2, #7
  5a:   b510        push    {r4, lr}
  5c:   4b04        ldr r3, [pc, #16]   ; (70 <centry+0x18>)
  5e:   2007        movs    r0, #7
  60:   601a        str r2, [r3, #0]
  62:   f7ff ffec   bl  3e <bounce>
  66:   2000        movs    r0, #0
  68:   bc10        pop {r4}
  6a:   bc02        pop {r1}
  6c:   4708        bx  r1
  6e:   46c0        nop         ; (mov r8, r8)
  70:   20000008    andcs   r0, r0, r8

Disassembly of section .data:

20000000 <c>:
20000000:   00000005    andeq   r0, r0, r5

20000004 <b>:
20000004:   00000004    andeq   r0, r0, r4

Disassembly of section .bss:

20000008 <a>:
20000008:   00000000    andeq   r0, r0, r0

podemos parar por aí ou continuar. Se inicializarmos na mesma ordem que o script do vinculador, tudo bem se passarmos para a próxima coisa, pois ainda não chegamos lá. e stm / ldm são necessários / desejados apenas para usar endereços alinhados por palavras; portanto, se você mudar para:

    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:

com o bss primeiro no script do vinculador, e sim, você não quer 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

esses loops serão mais rápidos. agora não sei se os barramentos ahb podem ter 64 bits de largura ou não, mas para um braço de tamanho completo, você desejaria alinhar essas coisas nos limites de 64 bits. um registro ldm / stm de quatro em um limite de 32 bits, mas não um limite de 64 bits, torna-se três transações de barramento separadas, onde alinhadas em um limite de 64 bits é uma transação única que salva vários relógios por instrução.

como estamos fazendo baremetal e somos totalmente responsáveis ​​por tudo o que podemos dizer, digamos bss, em seguida, dados e, em seguida, se tivermos um monte de pilha, a pilha cresce de cima para baixo, portanto, se zerarmos bss e derramarmos algumas, desde que iniciemos em No lugar certo, tudo bem, ainda não estamos usando essa memória. copiamos .data e podemos espalhar para o heap, tudo bem, heap ou não, há muito espaço para a pilha, por isso não estamos pisando em ninguém / em nada (desde que tenhamos certeza de que no script do vinculador fazemos isso. se houver uma preocupação, faça com que ALIGN () seja maior, para que possamos sempre estar em nosso espaço para esses preenchimentos.

então minha solução simples, pegue ou largue. bem-vindo a corrigir quaisquer erros, eu não executei isso no hardware nem no meu simulador ...

MEMORY
{
    bob : ORIGIN = 0x00000000, LENGTH = 0x1000
    ted : ORIGIN = 0x20000000, LENGTH = 0x1000
}

SECTIONS
{
    .text : { *(.text*) } > bob

    .rodata : { *(.rodata*) } > bob

   . = ALIGN(8);
   .bss  : {
   __bss_start__ = .;
   *(.bss*)
   } > ted
   . = ALIGN(4);
   __bss_end__ = .;
   __bss_size__ = __bss_end__ - __bss_start__;

   . = ALIGN(8);
   __data_rom_start__ = .;
   .data : {
    __data_start__ = .;
    *(.data*)
   } > ted AT > bob
   . = ALIGN(4);
   __data_end__ = .;
   __data_size__ = __data_end__ - __data_start__;

}



.thumb

.thumb_func
.global _start
_start:
stacktop: .word 0x20000800
.word reset
.word done
.word done
.word done

.thumb_func
reset:

    ldr r0,blen
    cmp r0,#0
    beq bss_zero_done
    ldr r1,bstart
    mov r2,#0
    mov r3,#0
    mov r4,#0
    mov r5,#0
bss_zero:
    stmia r1!,{r2,r3,r4,r5}
    sub r0,#16
    ble bss_zero
bss_zero_done:

    ldr r0,dlen
    cmp r0,#0
    beq data_copy_done
    ldr r1,rstart
    ldr r2,dstart
data_copy:
    ldmia r1!,{r3,r4,r5,r6}
    stmia r2!,{r3,r4,r5,r6}
    sub r0,#16
    ble data_copy
data_copy_done:

    bl centry
    b done

.thumb_func
done:   b .

.thumb_func
.globl bounce
bounce:
    nop
    bx lr

.align
bstart: .word __bss_start__
blen:   .word __bss_size__
rstart: .word __data_rom_start__
dstart: .word __data_start__
dlen:   .word __data_size__


void bounce ( unsigned int );

unsigned int a;

unsigned int b=4;
unsigned char c=5;

int centry ( void )
{
    a = 7;
    bounce(a);
    return(0);
}

arm-none-eabi-as --warn --fatal-warnings flash.s -o flash.o
arm-none-eabi-ld -o hello.elf -T flash.ld flash.o centry.o
arm-none-eabi-objdump -D hello.elf > hello.list
arm-none-eabi-objcopy hello.elf hello.bin -O binary

junte tudo e você obtém:

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

note que isso funciona com arm-none-eabi- e arm-linux-gnueabi e as outras variantes, já que nenhum material ghee whiz foi usado.

Quando você olha ao redor, você descobre que as pessoas enlouquecem com coisas ghee whiz em seus scripts de vinculação, imensas coisas monstruosas na pia da cozinha. É melhor apenas saber como fazê-lo (ou melhor como dominar as ferramentas para que você possa controlar o que acontece), em vez de confiar nas coisas de outra pessoa e não saber onde isso vai acontecer, porque você não entende e / ou deseja pesquisar isto.

Como regra geral, não inicialize um idioma com o mesmo idioma (nesse sentido, iniciando o código sem compilar um compilador com o mesmo compilador), você deseja usar um idioma mais simples com menos bootstrap. É por isso que C é feito em montagem, não há requisitos de inicialização, basta iniciar a partir da primeira instrução após a redefinição. JAVA, certifique-se de escrever a jvm em C e inicializar esse C com asm e, em seguida, inicializar o JAVA se você desejar com C, mas também executar o JAVA em C também.

Como controlamos as suposições nesses ciclos de cópia, elas são, por definição, mais rígidas e limpas do que o memcpy / memset ajustado manualmente.

Observe que seu outro problema foi este:

unsigned int * bss_start_p = &_BSS_START; 
unsigned int * bss_end_p = &_BSS_END;

se estes são locais, não há problema, se são globais, você precisa primeiro .data inicializado para que funcionem e se você tentar esse truque para executar .data, falhará. Variáveis ​​locais, tudo bem que funcionará. se você, por algum motivo, decidiu criar os locais estáticos (globais locais que eu gosto de chamá-los), então você voltará a ter problemas novamente. Toda vez que você faz uma tarefa em uma declaração, embora deva pensar sobre isso, como isso é implementado e é seguro / são. Toda vez que você assume que uma variável é zero quando não declarada, o mesmo negócio, se uma variável local não for assumida como zero, se for global, será. se você nunca assume que eles são zero, nunca precisa se preocupar.

old_timer
fonte
incrível, esta é a segunda vez que eu ter excedido a contagem de caracteres no máximo em uma resposta ....
old_timer
Esta questão pertence ao stackoverflow, não à engenharia elétrica.
old_timer
Também não é uma boa forma confiar em um link externo na sua pergunta. Se o link desaparecer antes da pergunta, a pergunta poderá não fazer sentido.
old_timer
Neste caso, o seu título e conteúdo é suficiente para saber que você está tentando inicializar C em um microcontrolador particular e estão vagando em .bss e inicialização .data
old_timer
mas, nesse caso, foram enganados por um site muito informativo.
old_timer