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.