Istnieje niezliczona ilość innych stron i przykładów. Wiele tysięcy, jeśli nie dziesiątki tysięcy. Istnieją dobrze znane biblioteki c ze skryptami linkera i kodem boostrap, szczególnie newlib, glibc, ale są też inne, które można znaleźć. Bootstraping C z C nie ma sensu.
Odpowiedzi na twoje pytanie próbujesz dokonać dokładnego porównania rzeczy, które mogą nie być dokładne, mogą nie zaczynać się na znanej granicy lub kończyć na znanej granicy. Więc możesz zrobić mniej niż coś, ale jeśli kod nie działał z dokładnym porównaniem, oznacza to, że zerujesz przeszłość .bss do następnej sekcji, co może, ale nie musi, powodować złe rzeczy, więc po prostu zamień na mniej niż isnt rozwiązanie.
Więc oto idzie TL; DR jest w porządku. Nie uruchamiasz języka z tym językiem, możesz na pewno uciec, ale bawisz się ogniem, kiedy to robisz. Jeśli dopiero się uczysz, jak to zrobić, musisz zachować ostrożność, a nie głupie szczęście lub fakty, których jeszcze nie odkryłeś.
Skrypt linkera i kod bootstrap mają bardzo intymny związek, są małżeństwem, łączą się w biodrze, nie rozwijasz jednego bez drugiego, co prowadzi do ogromnej awarii. I niestety skrypt linkera jest zdefiniowany przez linker i język asemblera zdefiniowany przez asembler, więc przy zmianie łańcuchów narzędzi należy spodziewać się ponownego napisania obu. Dlaczego język asemblera? Nie wymaga bootstrapu, zwykle są to języki kompilowane. C robi, jeśli nie chcesz ograniczać używania języka, zacznę od czegoś bardzo prostego, który ma minimalne wymagania specyficzne dla łańcucha narzędzi, nie zakładasz, że zmienne .bss są zerowe (sprawia, że kod jest mniej czytelny, jeśli zmienna nigdy nie jest inicjowana w tym języku , staraj się tego unikać, nie jest to prawdą w przypadku zmiennych lokalnych, więc musisz być na bieżąco, kiedy z niego korzystasz. ludzie i tak unikają globalizacji, więc dlaczego mówimy o .bss i .data ??? (globale są dobre do pracy na tym poziomie, ale to inny temat)) drugą zasadą dla prostego rozwiązania nie jest inicjowanie zmiennych w deklaracji, zrób to w kodzie. tak, pali więcej flasha, na ogół masz dużo, nie wszystkie zmienne są inicjalizowane stałymi i tak, które ostatecznie zużywają instrukcje.
Z projektu cortex-m można wywnioskować, że mogli myśleć, że w ogóle nie ma kodu ładującego, więc nie obsługuje .data ani .bss. Większość ludzi, którzy używają globałów, nie może żyć bez, więc oto:
Mógłbym to uczynić bardziej minimalnym, ale minimalnym funkcjonalnym przykładem dla wszystkich kory za pomocą gnu toolchain, nie pamiętam, które wersje można zacząć od wersji 5.xx lub wyższej w obecnych wersjach 9.xx Przełączałem skrypty linkera gdzieś w okolicach 3. xx lub 4.xx, gdy dowiedziałem się więcej i gdy gnu zmieniło coś, co złamało moje pierwsze.
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
punkt wejścia do kodu C:
void bounce ( unsigned int );
unsigned int a;
int centry ( void )
{
a = 7;
bounce(a);
return(0);
}
skrypt linkera.
MEMORY
{
rom : ORIGIN = 0x00000000, LENGTH = 0x1000
ram : ORIGIN = 0x20000000, LENGTH = 0x1000
}
SECTIONS
{
.text : { *(.text*) } > rom
.rodata : { *(.rodata*) } > rom
.bss : { *(.bss*) } > ram
}
Wszystkie te mogą być mniejsze i nadal działać, dodałem tutaj dodatkowe rzeczy, aby zobaczyć, jak działają.
zoptymalizowana kompilacja i link.
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
dla niektórych dostawców chcesz użyć 0x08000000 lub 0x01000000 lub innych podobnych adresów, ponieważ flash jest tam mapowany i dublowany do 0x00000000 w niektórych trybach rozruchu. niektóre mają tylko tyle pamięci flash dublowanej na 0x00000000, więc chcesz, aby tablica wektorów wskazywała na przestrzeń flash aplikacji nie na zero. ponieważ jest oparty na tabeli wektorów, wszystko działa.
po pierwsze zauważ, że cortex-ms to maszyny tylko dla kciuka iz jakiegokolwiek powodu wymusiły adres funkcji kciuka, co oznacza, że lsbit jest nieparzysty. Znając swoje narzędzia, dyrektywy .thumb_func informują asembler gnu, że następna etykieta to adres funkcji kciuka. zrobienie rzeczy +1 w tabeli doprowadzi do niepowodzenia, nie daj się skusić, aby to zrobić, zrób to dobrze. istnieją inne sposoby asemblera GNU, aby zadeklarować funkcję, że jest to podejście minimalne.
4: 00000015
8: 0000001b
c: 0000001b
10: 0000001b
nie uruchomi się, jeśli nie uzyskasz prawidłowej tabeli wektorów.
prawdopodobnie wystarczy wektor wskaźnika stosu (można w nim umieścić cokolwiek, jeśli sam chcesz ustawić wskaźnik stosu w kodzie) i wektor resetu. Umieściłem tutaj cztery bez konkretnego powodu. Zazwyczaj podaje 16, ale chciał skrócić ten przykład.
Więc co musi zrobić minimum bootstrapu C? 1. ustaw wskaźnik stosu 2. zero .bss 3. skopiuj. Data 4. rozgałęzienie lub wywołanie punktu wejścia C.
punkt wejścia C jest zwykle nazywany main (). ale niektóre łańcuchy narzędzi wyświetlają main () i dodają dodatkowe śmieci do kodu. Celowo używam innej nazwy. YMMV.
kopia .data nie jest potrzebna, jeśli wszystko oparte jest na pamięci RAM. będąc mikrokontrolerem z korą-m jest to technicznie możliwe, ale mało prawdopodobne, więc kopia .data jest potrzebna ..... jeśli istnieją .data.
Mój pierwszy przykład i styl kodowania to nie poleganie na .data ani .bss, jak w tym przykładzie. Arm zajął się wskaźnikiem stosu, więc pozostaje tylko zadzwonić do punktu wejścia. Lubię to mieć, aby punkt wejścia mógł wrócić, wielu ludzi twierdzi, że nigdy nie powinieneś tego robić. możesz po prostu to zrobić:
.thumb_func
.global _start
_start:
stacktop: .word 0x20000800
.word centry
.word done
.word done
.word done
i nie wraca z centry () i nie ma zresetowanego kodu procedury obsługi.
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
linker umieścił rzeczy tam, gdzie prosiliśmy. Ogólnie rzecz biorąc mamy w pełni funkcjonalny program.
Więc najpierw popracuj nad skryptem linkera:
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__;
}
podkreślając, że nazwy rom i ram nie mają znaczenia, że łączą tylko kropki łącznika między sekcjami.
.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__
dodaj kilka elementów, abyśmy mogli zobaczyć, co zrobiły narzędzia
void bounce ( unsigned int );
unsigned int a;
unsigned int b=4;
unsigned char c=5;
int centry ( void )
{
a = 7;
bounce(a);
return(0);
}
dodaj kilka elementów do umieszczenia w tych sekcjach. i dostać
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
oto rzeczy, których szukamy w tym eksperymencie (nie zauważaj żadnego powodu, aby w rzeczywistości ładować lub uruchamiać kod ... poznaj swoje narzędzia, naucz się ich)
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
dowiedzieliśmy się tutaj, że pozycja zmiennych jest bardzo wrażliwa w skryptach gnu linkera. zwróć uwagę na pozycję data_rom_start vs data_start, ale dlaczego data_end działa? Pozwolę ci to rozgryźć. Już rozumiem, dlaczego można nie chcieć bawić się skryptami linkera i po prostu przejść do prostego programowania ...
więc kolejną rzeczą, której się tutaj nauczyliśmy, jest to, że dla nas linker data_rom_start dla nas nie potrzebował ALIGN (4). Czy należy zakładać, że to zawsze zadziała?
Zauważ też, że padał on w drodze do, mamy 5 bajtów .data, ale wypełnił go do 8. Bez żadnych ALIGN (s) możemy już wykonać kopię za pomocą słów. Czy w oparciu o to, co widzimy dzisiaj dzięki temu zestawowi narzędzi na moim komputerze, może to dotyczyć przeszłości i przyszłości? Kto wie, nawet przy ALIGNach trzeba okresowo sprawdzać, czy niektóre nowe wersje nie psują rzeczy, robią to od czasu do czasu.
z tego eksperymentu przejdźmy do tego, żeby być bezpiecznym.
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__;
}
przesuwając końce do środka, aby były zgodne z tym, co robią inni ludzie. I to nie zmieniło:
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
jeszcze jeden szybki test:
.globl bounce
bounce:
nop
bx lr
dający
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
nie trzeba wstawiać między odbiciem a wyrównaniem
Och, racja, pamiętam teraz, dlaczego nie włożyłem _end__ do środka. ponieważ NIE DZIAŁ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*)
} > 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__;
}
jakiś prosty, ale bardzo przenośny kod do połączenia z tym skryptem linkera
.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__
dający
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
możemy się tam zatrzymać lub iść dalej. Jeśli inicjalizujemy w tej samej kolejności co skrypt linkera, to dobrze, jeśli przejdziemy do następnej rzeczy, ponieważ jeszcze tam nie dotarliśmy. i stm / ldm są wymagane / pożądane tylko do używania adresów wyrównanych do słów, więc jeśli zmienisz na:
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:
z bss najpierw w skrypcie linkera, i tak, nie chcesz ble.
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
te pętle będą szybsze. teraz nie wiem, czy magistrale ahb mogą mieć szerokość 64 bitów, czy nie, ale dla pełnego rozmiaru ramienia chciałbyś wyrównać te rzeczy na 64-bitowych granicach. cztery rejestry ldm / stm na 32-bitowej granicy, ale nie na 64-bitowej granicy, stają się trzema oddzielnymi transakcjami magistrali, przy czym wyrównanie na 64-bitowej granicy jest pojedynczą transakcją oszczędzającą kilka zegarów na instrukcję.
ponieważ robimy baremetal i jesteśmy w pełni odpowiedzialni za wszystko, co możemy umieścić, powiedzmy najpierw bss, a następnie dane, a następnie, jeśli mamy stos, to rośnie stos od góry do dołu, więc jeśli wyzerujemy bss i rozlejemy niektóre, dopóki zaczniemy od właściwe miejsce, które jest w porządku, jeszcze nie używamy tej pamięci. następnie kopiujemy .data i możemy przelać do stosu, który jest w porządku, sterty lub nie, jest dużo miejsca na stosie, więc nie nadepniemy na nikogo / nic (dopóki upewnimy się, że w skrypcie linkera to robimy. jeśli istnieje obawa, powiększ ALIGN (), abyśmy zawsze znajdowali się w naszej przestrzeni dla tych wypełnień.
więc moje proste rozwiązanie, weź to lub zostaw. witam, aby naprawić wszelkie błędy, nie uruchomiłem tego na sprzęcie ani na moim symulatorze ...
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
złóż wszystko razem, a otrzymasz:
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
zauważ, że działa to z arm-none-eabi- i arm-linux-gnueabi i innymi wariantami, ponieważ nie użyto żadnych świstów ghee.
Kiedy się rozejrzysz, przekonasz się, że ludzie oszaleją na punkcie skryptu ghee w swoich skryptach linkerów, ogromnych potwornych zlewozmywaków kuchennych. Lepiej po prostu wiedzieć, jak to zrobić (lub lepiej opanować narzędzia, aby kontrolować, co się dzieje), zamiast polegać na innych rzeczach i nie wiedzieć, gdzie to się zepsuje, ponieważ nie rozumiesz i / lub chcesz badać to.
jako ogólna zasada, nie ładuj języka z tym samym językiem (w tym sensie bootstrap oznacza, że kod nie kompiluje kompilatora z tym samym kompilatorem), chcesz używać prostszego języka z mniejszym ładowaniem. Dlatego C jest wykonywane w asemblerze, nie ma żadnych wymagań dotyczących ładowania początkowego, które zaczynasz od pierwszej instrukcji po zresetowaniu. JAVA, na pewno możesz napisać Jvm w C i załadować C z asm, a następnie załadować JAVA, jeśli chcesz z C, ale także wykonać JAVA w C.
Ponieważ kontrolujemy założenia dotyczące tych pętli kopiowania, są one z definicji ciaśniejsze i czystsze niż ręcznie dostrojone memcpy / memset.
Zwróć uwagę, że Twoim drugim problemem było:
unsigned int * bss_start_p = &_BSS_START;
unsigned int * bss_end_p = &_BSS_END;
jeśli są to lokalne kary, nie ma problemu, jeśli są globalne, najpierw trzeba zainicjować dane .data, aby działały, a jeśli spróbujesz wykonać tę sztuczkę, to nie powiedzie się. Zmienne lokalne, dobrze, które będą działać. jeśli z jakiegoś powodu zdecydowałeś się stworzyć statycznych miejscowych (lokalne globale lubię je nazywać), to znów jesteś w kłopotach. Za każdym razem, gdy wykonujesz zadanie w deklaracji, powinieneś się nad tym zastanowić, w jaki sposób jest ono realizowane i czy jest bezpieczne / rozsądne. Za każdym razem, gdy zakładasz, że zmienna ma wartość zero, gdy nie jest zadeklarowana, ta sama umowa, jeśli zmienna lokalna nie jest przyjmowana jako zero, jeśli jest globalna, to jest. jeśli nigdy nie zakładasz, że są zerowe, nigdy nie musisz się martwić.