Головий метал стартового коду для ініціалізації області Cortex M3 .bss


10

Я розробив натхненний звідси голий металевий стартовий код для кори кори М3. Однак я стикаюся з такою проблемою: припустимо, я оголошу неініціалізовану глобальну змінну, скажімо, тип непідписаний char в main.c

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

це робить область .bss в STM32 f103, починаючи з _BSS_START = 0x20000000 і закінчуючи _BSS_END = 0x20000001. Тепер, стартовий код

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

намагається ініціалізувати до нуля всю область .bss. Однак усередині цього циклу покажчик збільшується на 4 байти, тому після одного кроку bss_start_p = 0x20000004, отже, він завжди буде іншим, ніж bss_end_p, що призводить до нескінченного циклу тощо.

Чи є якесь стандартне рішення для цього? Я гадаю, що якимось чином "змушую" розмірність області .bss бути кратною 4? Або я повинен використовувати вказівник на неподписаний знак для прогулянки по області .bss? Можливо, щось на кшталт:

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

використовувати менше, ніж. завантажувальні програми записуються в зборі з причини. спочатку ви створили проблему .data. використовувати курку і яйця / припустити, що C працює, ви покладаєтесь як мінімум на .text, .bss і .data, але ви пишете код C, який гарантує, що код C буде працювати, використовуючи речі в коді C, які вимагають bootstrap, можливо, написаний в коді С, який покладається на C працює.
old_timer

код для копіювання .data over дуже схожий на .bss, але якщо ви пишете його як код вище, то вам потрібно скопіювати .data, щоб скопіювати .data.
old_timer

Відповіді:


15

Як ви підозрюєте, це відбувається тому, що тип даних без підпису int має розмір 4 байти. Кожен *bss_start_p = 0;оператор фактично очищає чотири байти області bss.

Діапазон пам'яті bss потрібно правильно вирівняти. Ви можете просто визначити _BSS_START та _BSS_END, щоб загальний розмір був кратним чотирьом, але це, як правило, обробляється, дозволяючи скрипту зв’язку визначати місця початку та зупинки.

Як приклад, ось розділ посилання в одному з моїх проектів:

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

The ALIGN(4) заяві піклуватися про речі.

Також ви можете змінити

while(bss_start_p != bss_end_p)

до

while(bss_start_p < bss_end_p).

Це не запобіжить проблемі (оскільки ви можете очистити на 1-3 більше байтів, ніж ви хочете), але це може мінімізувати вплив :)


@CMarius Після роздуму, я думаю, що ваша ідея покажчика чарівних робіт буде чудово працювати, хоча це вимагатиме більше циклів. Але я не впевнений, чи виникнуть подальші проблеми з неприєднанням наступної області пам’яті, тому я не збираюся згадувати про це у своїй відповіді ...
bitsmack

1
while(bss_start_p < bss_end_p - 1)з подальшим байтовим очищенням залишку пам'яті, що залишився, усуне останнє занепокоєння.
glglgl

4

Стандартне рішення memset():

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

Якщо ви не можете використовувати стандартну бібліотеку, вам доведеться вирішити, чи нормально у вашому випадку округлювати розмір області пам'яті до 4 байт і продовжувати використовувати unsigned int *; або якщо вам потрібно бути суворим щодо цього, у цьому випадку вам потрібно буде скористатися unsigned char *.

Якщо ви закруглете розмір, як у першому циклі, то, bss_start_pсправді, в кінцевому підсумку може бути більшим, bss_end_pале просто легко впоратися з порівнянням, ніж порівняно <замість тесту на нерівність.

Звичайно, ви також можете заповнити більшу частину пам'яті 32-бітовою передачею, і лише останні кілька байтів з 8-бітовими передачами, але це більше роботи для невеликого виграшу, особливо тут, коли це лише шматок стартового коду.


1
Дуже погоджуєтесь із використанням memset(). Але вирівнювання до 4 байтів є більш-менш необхідним. То чому б цього не зробити?
Кодо

3
жодним чином форма або форма не є стандартним рішенням для завантажувального пристрою використовувати мемсет, це божевільно.
old_timer

ви не використовуєте ту саму мову для завантаження цієї мови
old_timer

2
код завантажувального коду і сценарій зв’язку дуже одружені, ви знайдете звичайним, що скрипт linker вирівнює і розмірує .bss принаймні на 4-х байтній межі, щоб покращити заливку (у завантажувальній програмі) на 4 рази над байтами вказівки (припустимо (мінімум) 32-бітові шини, що характерно для руки, але є винятки)
old_timer

3
@old_timer, стандартна функція C для встановлення пам’яті на певне значення є memset(), а C - це те, на що вони, здається, програмують. Проста реалізація memset()також є майже таким циклом, це не так, як це залежить від багатьох інших. Оскільки це мікроконтролер, я також припускаю, що немає ніякого динамічного посилання або подібного не відбувається (і, дивлячись на посилання, немає, це просто виклик main()після цього нульового циклу), тому компілятор повинен бути здатний потрапити memset()туди разом з іншими функціями (або реалізовувати їх вбудовано).
ilkkachu

4

Просто змініть !=на <. Це, як правило, кращий підхід у будь-якому випадку, оскільки він вирішує подібні проблеми.


3

Є безліч інших сайтів та прикладів. Багато тисяч, якщо не десятки тисяч. Є добре відомі бібліотеки 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, тоді ви не зможете. Локальні змінні, добре, що буде працювати. якщо ви з якихось причин вирішили зробити статичні місцеві жителі (місцеві глобалі, які я їх люблю називати), тоді ви знову опинитесь у біді. Кожен раз, коли ви виконуєте завдання в декларації, хоча вам слід задуматися над тим, як це реалізується та чи безпечно / безпечно. Кожен раз, коли ви припускаєте, що змінна дорівнює нулю, коли недекларована, однакова угода, якщо для локальної змінної її не вважається нульовою, якщо глобальною, то вона є. якщо ви ніколи не вважаєте, що вони дорівнюють нулю, вам ніколи не доведеться турбуватися.


приголомшливо, це вже другий раз, коли я перевищив максимальну кількість символів у відповіді ....
old_timer

Це питання належить до стакового потоку, а не до електротехніки.
old_timer

Також покладатися на зовнішнє посилання у вашому питанні не є гарною формою, якщо посилання переходить до питання, то питання може не мати сенсу.
old_timer

У цьому випадку вашого заголовка та вмісту достатньо, щоб знати, що ви намагаєтеся завантажувати C на певний мікроконтролер і блукаєте в ініціалізацію .bss та .data
old_timer

але в цьому випадку нас ввели в оману дуже інакший веб-сайт.
old_timer
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.