Є безліч інших сайтів та прикладів. Багато тисяч, якщо не десятки тисяч. Є добре відомі бібліотеки c, що мають сценарії посилання та код завантаження, зокрема newlib, glibc, але ви можете знайти інші. Завантажувати C на C не має сенсу.
На ваше запитання відповіли, що ви намагаєтеся зробити точне порівняння у речах, які можуть бути неточними, воно може не починатися на відомій межі або закінчуватися на відомій межі. Таким чином, ви можете зробити менше, ніж щось, але якщо код не працює з точним порівнянням, то це означає, що ви занурюєте минуле .bss в наступний розділ, який може або не може спричинити погані речі, тому просто замініть на менше, ніж isnt рішення.
Так що тут іде TL; DR добре. Ви не завантажуєте мову цією мовою, ви можете безперешкодно піти з неї, але ви граєте з вогнем, коли це робите. Якщо ви тільки навчитеся робити це, вам потрібно бути на стороні обережності, а не тупої удачі чи фактів, яких ви ще не розкрили.
Сценарій лінкера та код завантаження мають дуже інтимні стосунки, вони одружені, з’єднуються на стегні, ви не розвиваєте одне без іншого, що призводить до масових збоїв. І на жаль, скрипт linker визначається лінкером, а мова складання визначена асемблером, так що при зміні ланцюгів інструментів очікується, що доведеться переписати обидва. Чому мова монтажу? Він не потребує завантажувальної програми, як правило, компільовані мови. Зрозуміло, якщо ви хочете не обмежувати використання мовою, почніть з чогось дуже простого, що має мінімальні вимоги до ланцюжка інструментів, ви не припускаєте, що .bss змінні дорівнюють нулю (робить код менш читабельним, якщо змінна ніколи не ініціалізується на цій мові , намагайся цього уникнути, це не стосується локальних змінних, тому ти повинен бути на балі, коли ти його використовуєш. так чому ми говоримо про .bss та .data ??? (глобальні роботи хороші для роботи цього рівня, але це інша тема)) інше правило простого рішення - не ініціалізувати змінні в декларації, зробіть це в коді. так, спалює більше спалаху, у вас зазвичай багато, не всі змінні ініціалізуються константами так чи інакше, що закінчують споживати інструкції.
Ви можете сказати з дизайну cortex-m, що, можливо, вони думали, що код завантаження зовсім не існує, тому немає .data або .bss підтримки. Більшість людей, які використовують глобальні представники, не можуть жити без цього.
Я міг би зробити це більш мінімальним, але мінімально функціональним прикладом для всіх cortex-ms за допомогою інструментальної ланцюга gnu, я не пам'ятаю, які версії можна починати з 5.xx або більше через поточний 9.xx. Я переключив сценарії лінкерів десь близько 3. xx або 4.xx, як я дізнався більше, і як Gnu змінив щось, що зламало моє перше.
завантажувальна програма:
.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
точка вводу в код C:
void bounce ( unsigned int );
unsigned int a;
int centry ( void )
{
a = 7;
bounce(a);
return(0);
}
скрипт лінкера.
MEMORY
{
rom : ORIGIN = 0x00000000, LENGTH = 0x1000
ram : ORIGIN = 0x20000000, LENGTH = 0x1000
}
SECTIONS
{
.text : { *(.text*) } > rom
.rodata : { *(.rodata*) } > rom
.bss : { *(.bss*) } > ram
}
Все це може бути меншим і все-таки працювати, додавши сюди додаткові речі, просто щоб побачити це на роботі.
оптимізована збірка та зв'язок.
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
для деяких постачальників ви хочете використовувати 0x08000000 або 0x01000000 або інші подібні адреси, оскільки спалах відображається там і відображається до 0x00000000 в деяких режимах завантаження. деякі мають лише стільки дзеркального відображення у 0x00000000, тому ви хочете, щоб точка векторної таблиці у просторі спалаху програми не дорівнювала нулю. оскільки це векторна таблиця, все це працює.
спершу зверніть увагу, що cortex-ms - це лише великі пальці, і з будь-якої причини вони застосували адресу функції великого пальця, тобто lsbit є непарним. Знайте свої інструменти, директиви .thumb_func повідомляють асемблеру gnu, що наступна мітка - це адреса функції великого пальця. якщо робити +1 у таблиці, це призведе до невдачі, не спокушайтесь зробити це, зробіть це правильно. Є й інші способи асемблера gnu для оголошення функції. Це мінімальний підхід.
4: 00000015
8: 0000001b
c: 0000001b
10: 0000001b
він не буде завантажуватися, якщо ви не отримаєте векторну таблицю правильно.
Можливо, потрібен лише вектор вказівника стека (можна помістити що завгодно, якщо ви хочете встановити покажчик стека самостійно в коді) та вектор скидання. Я поставив тут чотири без особливих причин. Зазвичай ставлять 16, але хотіли скоротити цей приклад.
Отже, що є мінімальним завантажувальним пристроєм C? 1. встановіть покажчик стека 2. нуль .bss 3. скопіюйте .дані 4. гілку на або зателефонуйте в точку входу C
точку входу C зазвичай називають main (). але деякі ланцюжки інструментів бачать main () і додають додаткове сміття у ваш код. Я навмисно використовую іншу назву. YMMV.
копія .data не потрібна, якщо це все на базі. будучи мікроконтролером cortex-m, це технічно можливо, але малоймовірно, тому копія .data потрібна ..... якщо є .data.
Мій перший приклад і стиль кодування - не покладатися на .data та .bss, як у цьому прикладі. Arm подбав про вказівник стеку, тому єдине, що залишилося - це зателефонувати в точку входу. Мені подобається це мати, щоб точка входу могла повернутися, багато хто стверджує, що ти ніколи цього не повинен робити. ви могли просто зробити це тоді:
.thumb_func
.global _start
_start:
stacktop: .word 0x20000800
.word centry
.word done
.word done
.word done
і не повертаються з centry () і не мають скидання коду обробника.
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
линкер поставив речі, куди ми попросили. І загалом у нас є повністю функціональна програма.
Отже, спочатку попрацюйте над сценарієм зв’язку:
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__;
}
підкреслюючи, що імена rom і ram не мають значення, вони з'єднують лише точки для лінкера між розділами.
.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__
додайте деякі елементи, щоб ми могли побачити, що зробили інструменти
void bounce ( unsigned int );
unsigned int a;
unsigned int b=4;
unsigned char c=5;
int centry ( void )
{
a = 7;
bounce(a);
return(0);
}
додайте деякі елементи, щоб розмістити їх у цих розділах. і дістати
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
тут є речі, які ми шукаємо в цьому експерименті (зауважте, немає причин насправді завантажувати чи не запускати будь-який код ... знайте свої інструменти, вивчіть їх)
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
тому ми дізналися тут, що положення змінних дуже чутливі у скриптах gnu linker. зверніть увагу на позицію data_rom_start vs data_start, але чому дані_end працюють? Я дозволяю вам це зрозуміти. Вже розуміючи, чому, можливо, не хочеться возитися зі скрипками лінкерів і просто перейти до простого програмування ...
тому ще одна річ, яку ми тут дізналися, - це те, що лінкер вирівняв data_rom_start для нас, нам не потрібен був ЗНАЧЕННЯ (4). Чи слід вважати, що це завжди спрацює?
Також зауважте, що він викладений на вихід, у нас є 5 байт .data, але він додав їх до 8. Без ALIGN (s) ми вже можемо зробити копію, використовуючи слова. На основі того, що ми бачимо з цією ланцюжком інструментів на моєму комп’ютері сьогодні, чи може це бути правдою для минулого та майбутнього? Хто знає, навіть якщо ЗНАЧЕННЯМ потрібно періодично перевіряти, щоб якась нова версія не зламала речі, вони будуть робити це час від часу.
з цього експерименту давайте переходимо до цього лише для безпечного використання.
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__;
}
переміщення кінців всередину, щоб відповідати тому, що роблять інші. І це не змінило:
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
ще один швидкий тест:
.globl bounce
bounce:
nop
bx lr
давання
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
не потрібно прокладати між відмов і .align
О, так, зараз я пам’ятаю, чому я не ставлю _end__ всередину. тому що НЕ РОБОТА.
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__;
}
якийсь простий, але дуже портативний код для виходу заміж за цей скрипт-лінкер
.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__
давання
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
ми можемо зупинитися на цьому або продовжувати рух. Якщо ми ініціалізуємося в тому ж порядку, що і сценарій посилання, це добре, якщо ми перейдемо до наступного, оскільки ми ще там не дійшли. та stm / ldm потрібно / бажано використовувати адреси вирівнювання за словом, тож якщо ви перейдете на:
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:
з bss спочатку в скрипті linker, і так, ви хочете, щоб не 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
ці петлі пройдуть швидше. тепер я не знаю, чи можуть автобуси ах бути шириною 64 біти чи ні, але для руки повного розміру ви хочете вирівняти ці речі за 64-бітовими межами. чотири регістри ldm / stm на 32-бітовій межі, але не 64-бітна межа, перетворюються на три окремі шинні транзакції, де вирівнювання по 64-бітовій межі - це одна транзакція, що зберігає кілька годин на інструкцію.
оскільки ми робимо бареметал і ми несемо повну відповідальність за все, що ми можемо сказати, перш за все, bss, то дані, то якщо у нас є купіть, то стек зростає зверху вниз, так що якщо ми нульові bss і розпливаємося на деякий час, поки ми починаємо з правильне місце, яке добре, ми ще не використовуємо цю пам'ять. тоді ми копіюємо .дані, і ми можемо пролитись у кучу добре, купу чи ні, є багато місця для стека, тому ми не наступаємо ні на кого / що-небудь (до тих пір, поки ми переконаємося, що в скрипті linker ми це робимо. якщо є занепокоєння, зробіть ALIGN () s більшим, щоб ми завжди знаходилися в межах нашого простору для цих заповнень.
тому моє просте рішення, візьміть його або залиште. Ласкаво просимо виправити будь-які помилки, я не запускав це на апараті, ані на моєму симуляторі ...
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
зберіть все це і ви отримаєте:
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
зауважте, що це працює з arm-none-eabi- і arm-linux-gnueabi та іншими варіантами, оскільки не використовувався жодний вміст ghee whiz.
Ви побачите, коли озирніться, що люди зійдуть з розуму від речей з грі-вугі у своїх сценаріях з посиланнями, величезними жахливими кухонними речами. Краще просто знати, як це зробити (або краще, як оволодіти інструментами, щоб ви могли контролювати, що відбувається), а не покладатися на людину, яка інша справа, і не знати, де вона буде ламатися, тому що ви не розумієте та / або хочете дослідити це.
як правило, не завантажуйте мову однаковою мовою (bootstrap в цьому сенсі означає, що запущений код не компілює компілятор з тим же компілятором), ви хочете використовувати більш просту мову з меншою кількістю завантажувальної програми. Ось чому C робиться в збірці, він не має вимог завантажувальної програми, які ви тільки починаєте з першої інструкції після скидання. JAVA, впевнений, що ви можете написати jvm у C та завантажувати цей C із asm, а потім завантажувати JAVA, якщо ви з C, але також виконувати JAVA в C також.
Оскільки ми контролюємо припущення щодо цих циклів копіювання, вони за визначенням жорсткіші та чіткіші, ніж налаштована вручну memcpy / memset.
Зверніть увагу на вашу іншу проблему:
unsigned int * bss_start_p = &_BSS_START;
unsigned int * bss_end_p = &_BSS_END;
якщо це локальні штрафи, немає проблем, якщо вони є глобальними, тоді вам потрібно спочатку ініціалізувати .data, щоб вони працювали, і якщо ви спробуєте виконати цей трюк .data, тоді ви не зможете. Локальні змінні, добре, що буде працювати. якщо ви з якихось причин вирішили зробити статичні місцеві жителі (місцеві глобалі, які я їх люблю називати), тоді ви знову опинитесь у біді. Кожен раз, коли ви виконуєте завдання в декларації, хоча вам слід задуматися над тим, як це реалізується та чи безпечно / безпечно. Кожен раз, коли ви припускаєте, що змінна дорівнює нулю, коли недекларована, однакова угода, якщо для локальної змінної її не вважається нульовою, якщо глобальною, то вона є. якщо ви ніколи не вважаєте, що вони дорівнюють нулю, вам ніколи не доведеться турбуватися.