LINUX.ORG.RU

вопрос по скриптам компоновщика для arm

 , ,


1

1

Вот есть скрипт компоновщика:

OUTPUT_FORMAT("elf32-littlearm", "elf32-littlearm", "elf32-littlearm")
OUTPUT_ARCH(arm)
MEMORY
{
    ROM  (rx) : ORIGIN = 0x08000000, LENGTH = 64K
    RAM (rwx) : ORIGIN = 0x20000000, LENGTH = 20K
}

SECTIONS
{
    .isr_vector ORIGIN(ROM) :
    {
        KEEP(*(.isr_vector))
    } >ROM
    
    .text ALIGN(4) :
    {
        *(.text*);
    } > ROM
    
    
    .common ORIGIN(RAM) (NOLOAD) :
    {
        *(COMMON)
    } >RAM
    
    .bss ALIGN(4) (NOLOAD): {
        PROVIDE(__bss_start__ = .);
        *(.bss*)
        PROVIDE(__bss_end__ = .);
    } > RAM
    
    .data ALIGN(4):
    {
        PROVIDE(__data_start__ = .);
        *(.data*)
        PROVIDE(__data_end__ = .);
    } > RAM AT>ROM
    
    PROVIDE(__data_lma__ = LOADADDR(.data));    
    PROVIDE(__stack_top__ = ORIGIN(RAM) + LENGTH(RAM));
}

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

А вот часть кода , который использует эти переменные ,чтобы перенести значение из флеша в оперативу:

extern uint8_t __data_start__, __data_end__, __data_lma__, 
   __bss_start__, __bss_end__;
 
uint32_t *dst;
dst = &__bss_start__;
while (dst < &__bss_end__)
    *dst++ = 0;
dst = &__data_start__;
uint32_t *src = &__data_lma__;
while (dst < &__data_end__)
    *dst++ = *src++;

Как я понимаю, значение экспортируемых переменных - это адрес соответствующих участков памяти.

В строках 4, 5 объявляется указатель dst значение которого адрес переменной __bss_start__ . Вопрос: почему в цикле применяется одна операция разыменовавыния (*dst++), ведь таким образом мы получаем адрес который храниться в переменной __bss_start__, но дальше мы не обращаемся к памяти по этому адресу, а работаем с ним как с обычным числом. Почему здесь не (**dst++) ?



Последнее исправление: Kito (всего исправлений: 3)
extern uint8_t __data_start__, __data_end__, __data_lma__, 
   __bss_start__, __bss_end__;

где-то в памяти есть переменные.

uint32_t *dst;

dst - указатель

dst = &__bss_start__;

направим этот указатель на переменную __bss_start__ (т.е. на её адрес)

*dst++ = 0;

*dst = 0 – записать 0 в то место, куда указывает указатель. dst++ – сдвинуть указатель.

AlexVR ★★★★★
()
Последнее исправление: AlexVR (всего исправлений: 1)
Ответ на: комментарий от Kito

Тут надо понять разницу между символом и переменной.

Когда в линкер-скрипте написано:

PROVIDE(__bss_start__ = .);

то можно считать как: а давай ка объявим «символ __bss_start__», который будет смотреть в эту текущую позицию. (В данном случае на первый байт секции bss).

Когда в Си написано:

extern uint8_t __bss_start__;

то можно считать как: Блин, где-то не в моей единице трансляции есть переменная __bss_start__ типа uint8_t. Пусть линкер найдёт одноименный символ, а адрес переменой __bss_start__ будет таким же, куда указывает символ __bss_start__.

AlexVR ★★★★★
()