Открытый код запуска для инициализации Cortex M3 .bss


10

Я разработал вдохновленный отсюда код запуска из металла для Arm Cortex M3. Однако я сталкиваюсь со следующей проблемой: предположим, я объявляю неинициализированную глобальную переменную, скажем, типа unsigned 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. Однако внутри цикла while указатель увеличивается на 4 байта, поэтому после одного шага bss_start_p = 0x20000004, следовательно, он всегда будет отличаться от bss_end_p, что приведет к бесконечному циклу и т. Д.

Есть ли стандартное решение для этого? Предполагаю ли я «заставить» каким-либо образом размер области .bss быть кратным 4? Или я должен использовать указатель на unsigned char, чтобы пройти через регион .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, которые требуют Самозагрузка, возможно, написана на C-коде, который полагается на C-работающий.
old_timer

код для копирования .data очень похож на .bss, но если вы напишите его как код выше, вам нужно скопировать .data, чтобы скопировать .data поверх.
old_timer

Ответы:


15

Как вы подозреваете, это происходит потому, что тип данных unsigned int имеет размер 4 байта. Каждое *bss_start_p = 0;утверждение на самом деле очищает четыре байта области bss.

Диапазон памяти bss должен быть правильно выровнен. Вы можете просто определить _BSS_START и _BSS_END так, чтобы общий размер был кратен четырем, но это обычно выполняется, позволяя сценарию компоновщика определять начальные и конечные местоположения.

В качестве примера, вот раздел линкера в одном из моих проектов:

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

В ALIGN(4)заявлении заботиться о вещах.

Кроме того, вы можете изменить

while(bss_start_p != bss_end_p)

в

while(bss_start_p < bss_end_p),

Это не предотвратит проблему (поскольку вы можете очистить на 1-3 байта больше, чем вы хотите), но это может минимизировать влияние :)


@CMarius После размышления, я думаю, что ваша идея указателя на символ будет работать отлично, хотя это потребует больше циклов. Но я не уверен, будут ли последующие проблемы с
выравниванием

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
ни в коем случае форма или форма не являются стандартным решением для начальной загрузки использовать memset, это безумие.
old_timer

вы не используете один и тот же язык для начальной загрузки этого языка
old_timer

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

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

4

Просто измени !=на <. В любом случае это обычно лучший подход, так как он имеет дело с такими проблемами.


3

Есть множество других сайтов и примеров. Многие тысячи, если не десятки тысяч. Существуют хорошо известные c-библиотеки со скриптами компоновщика и кодом boostrap, в частности, newlib, glibc, но есть и другие, которые вы можете найти. Самозагрузка C с C не имеет смысла.

На ваш вопрос ответили, вы пытаетесь провести точное сравнение с вещами, которые могут быть неточными, они могут не начинаться на известной границе или заканчиваться на известной границе. Таким образом, вы можете делать меньше, чем нужно, но если код не работает с точным сравнением, это означает, что вы обнуляете .bss в следующем разделе, что может или не может привести к плохим вещам, поэтому просто замените на меньше, чем isnt решение.

Так что здесь идет TL; DR в порядке. Вы не загружаете язык с этим языком, вы можете с этим сойти с рук, но вы играете с огнем, когда делаете это. Если вы только учитесь тому, как это делать, вам нужно быть осторожнее, а не тупой удачей или фактами, которые вы еще не раскрыли.

Сценарий компоновщика и загрузочный код имеют очень близкие отношения, они женаты, соединены в бедре, вы не разрабатываете один без другого, что приводит к массовому провалу. И, к сожалению, скрипт компоновщика определяется компоновщиком и языком ассемблера, определенным ассемблером, поэтому при изменении цепочек инструментов придется переписать оба. Почему ассемблер? Он не нуждается в начальной загрузке, обычно это делают скомпилированные языки. C делает, если вы не хотите ограничивать использование языка, я начну с чего-то очень простого, с минимальными особыми требованиями для цепочки инструментов, вы не предполагаете, что переменные .bss равны нулю (делает код менее читабельным, если переменная никогда не инициализируется в этом языке попробуйте избежать этого, это не относится к локальным переменным, поэтому нужно быть в курсе того, когда вы его используете. так почему мы говорим о .bss и .data ??? (глобальные переменные хороши для работы на этом уровне, но это уже другая тема)) другое правило для простого решения - не инициализировать переменные в объявлении, делайте это в коде. да горит больше флэш, обычно у вас их много, но не все переменные инициализируются константами, которые в итоге потребляют инструкции.

Вы можете сказать из дизайна cortex-m, что они, возможно, думали, что нет никакого загрузочного кода вообще, поэтому нет поддержки ни .data, ни .bss. Большинство людей, которые используют глобалы, не могут жить без них, так что здесь идет:

Я мог бы сделать это более минимальным, но минимальным функциональным примером для всех cortex-ms, используя цепочку инструментов gnu, я не помню, какие версии вы можете запустить с 5.xx или выше до текущего 9.xx Я переключил сценарии компоновщика где-то около 3. хх или 4.хх, как я узнал больше и как 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, что следующая метка - это адрес функции thumb. выполнение +1 в таблице приведет к провалу, не поддавайтесь искушению сделать это, сделайте это правильно. Существуют другие способы GNU-ассемблера для объявления функции, это минимальный подход.

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

он не загрузится, если вы не получите правильную таблицу векторов.

возможно, нужен только вектор указателя стека (можно поместить что угодно, если вы хотите установить указатель стека самостоятельно в коде) и вектор сброса. Я положил четыре здесь без особой причины. Обычно ставят 16, но хотели сократить этот пример.

Так какой же минимальный загрузчик C должен сделать? 1. установить указатель стека 2. ноль .bss 3. скопировать .data 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. обратите внимание на положение data_rom_start против data_start, но почему работает data_end ? Я позволю тебе понять это. Уже понимая, почему не нужно связываться со скриптами компоновщика и просто приступить к простому программированию ...

Итак, еще одна вещь, которую мы узнали здесь, это то, что компоновщик выровнял data_rom_start для нас, нам там не нужен ALIGN (4). Должны ли мы предполагать, что это всегда будет работать?

Также обратите внимание, что он дополняется при выходе в. У нас есть 5 байт .data, но он дополняет его до 8. Без каких-либо ALIGN () мы уже можем сделать копию, используя слова. Исходя из того, что мы видим сегодня с помощью этого набора инструментов на моем компьютере, может ли это быть правдой для прошлого и будущего? Кто знает, даже если ALIGN необходимо периодически проверять, чтобы какая-то новая версия ничего не сломала, они будут делать это время от времени.

из этого эксперимента давайте перейдем к этому, просто чтобы быть в безопасности.

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

нет необходимости вставлять между bounce и .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 в скрипте компоновщика, и да, вы хотите ble не 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

эти петли будут идти быстрее. теперь я не знаю, могут ли шины ahb иметь ширину 64 бита или нет, но для полноразмерного плеча вы бы хотели выровнять эти вещи по границам 64 бита. четыре регистра ldm / stm на 32-битной границе, но не на 64-битной границе, становятся тремя отдельными шинными транзакциями, где выравнивание на 64-битной границе представляет собой одну транзакцию, сохраняющую несколько тактов на команду.

так как мы делаем голые металлы и мы несем полную ответственность за все, что мы можем сначала сказать, скажем, bss, затем данные, затем, если у нас будет куча, стек будет расти сверху вниз, поэтому, если мы обнуляем bss и растекаемся по некоторым, пока мы начинаем правильное место, которое хорошо, мы еще не используем эту память. затем мы копируем .data поверх и можем пролить в кучу, что нормально, куча или нет, есть много места для стека, поэтому мы не наступаем ни на кого / что-либо (пока мы уверены, что в сценарии компоновщика мы это делаем. если есть проблема, сделайте ALIGN () больше, чтобы мы всегда располагали пространство для этих заливок.

так что мое простое решение, принять его или оставить. добро пожаловать, чтобы исправить любые ошибки, я не запускал это ни на оборудовании, ни на моем симуляторе ...

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 и другими вариантами, так как никакие гхи-одаренные материалы не использовались.

Когда вы оглядываетесь вокруг, вы обнаружите, что люди сойдут с ума от гхи-одаренности в своих скриптах компоновщика, огромных чудовищных кухонных вещей. Лучше просто знать, как это сделать (или лучше, как овладеть инструментами, чтобы вы могли контролировать то, что происходит), чем полагаться на чужие вещи и не знать, где это сломается, потому что вы не понимаете и / или хотите исследовать Это.

Как правило, не загружайте язык с тем же языком (загрузочный термин в этом смысле означает запуск кода без компиляции с тем же компилятором), вы хотите использовать более простой язык с меньшим количеством загрузчика. Вот почему C выполняется в сборке, у него нет требований к начальной загрузке, вы просто начинаете с первой инструкции после сброса. JAVA, конечно, вы можете написать jvm на C и загрузить C с помощью asm, а затем, если вы захотите с C, запустить JAVA, но также выполнить JAVA на C.

Поскольку мы контролируем допущения для этих циклов копирования, они по определению более плотные и чистые, чем настроенные вручную memcpy / memset.

Обратите внимание, что ваша другая проблема заключалась в следующем:

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

если это локально, нет проблем, если они глобальные, то сначала вам нужно инициализировать .data, чтобы они работали, и если вы попробуете этот трюк для выполнения .data, то у вас ничего не получится. Локальные переменные, хорошо, что будут работать. если вы по какой-то причине решили создать статические локальные объекты (локальные глобалы, которые мне нравятся называть), то вы снова попадаете в беду. Каждый раз, когда вы делаете присвоение в объявлении, вы должны подумать о том, как оно реализовано и безопасно ли оно. Каждый раз, когда вы предполагаете, что переменная равна нулю, когда она не объявлена, действует то же самое, если локальная переменная не считается равной нулю, если она глобальная, то это так. если вы никогда не предполагаете, что они равны нулю, вам никогда не придется беспокоиться.


офигенно, это второй раз, когда я превышаю максимальное количество символов в ответе ...
old_timer

Этот вопрос относится к stackoverflow, а не к электротехнике.
old_timer

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

В этом случае вашего заголовка и содержимого достаточно, чтобы знать, что вы пытаетесь загрузить C на конкретном микроконтроллере и переходите к инициализации .bss и .data
old_timer

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