Скрипт линкера для микроконтроллеров ARM

Тема в разделе "WASM.BEGINNERS", создана пользователем Aoizora, 27 июл 2017.

  1. Aoizora

    Aoizora Active Member

    Публикаций:
    0
    Регистрация:
    29 янв 2017
    Сообщения:
    369
    Я разбираюсь в написании своих скриптов для линкера и составлении карты памяти для микроконтроллеров ARM. Есть несколько вещей, которые я не понимаю. Рассмотрим файлы, которые управляют структурой программы и занимаются инициализацией контроллера:

    boot.S - таблица векторов прерываний. Первое "прерывание" - это база стека, второе - функция, вызываемая при перезагрузке контроллера, которые выполняет его инициализацию и вызывает main.
    Код (ASM):
    1. .cpu cortex-m3
    2. .thumb
    3.  
    4. .word stack_base    @ Stack base
    5. .word ResetHandler     @ Reset vector
    6. .word hang        @ Eternal loop
    7.  
    8.  
    9.  
    10. .thumb_func
    11. hang:    b .
    12.  
    13. /*.global hang*/
    В дополнение я написал startup-код, которые копирует переменные из секции .data во флеше в память и обнуляет секцию .bss:

    Код (Text):
    1.  
    2. extern unsigned long stack_base;
    3. extern unsigned long lma_data_start;
    4. extern unsigned long va_data_start;
    5. extern unsigned long va_data_end;
    6. extern unsigned long va_bss_start;
    7. extern unsigned long va_bss_end;
    8.  
    9. extern int main(void);
    10.  
    11. void reset_handler(void)
    12. {
    13.     unsigned long *src, *dst;
    14.  
    15.     src = &lma_data_start;
    16.     dst = &va_data_start;
    17.  
    18.     while (dst < &va_data_end)
    19.         *dst++ = *src++;
    20.  
    21.     dst = &va_bss_start;
    22.     while (dst < &va_bss_end)
    23.         *dst++ = 0;
    24.  
    25.     main();
    26. }
    27.  
    28. void default_handler(void)
    29. {
    30.     while (1)
    31.     {
    32.         /* Eternal loop */
    33.     }
    34. }
    35.  
    36. __attribute__ ((section(".isr_vectors")))
    37. void (* const interrupt_vector_table[])(void) =
    38. {
    39.     (void *) &stack_base,
    40.     reset_handler,
    41.     default_handler
    42. };
    Посмотрите, как задается адрес стека в файлах boot.S и startup.c. Эти файлы заменяют друг друга, один из них можно выкинуть, и программа будет работать с другим. Почему в файле boot.S достаточно просто определить адрес стека как слово .word stack_base, а в сишном коде от символа stack_base надо взять адрес и кастовать его в void*? Разве недостаточно в эту таблицу поместить просто число? А именно: символ stack_base при линковке содержит адрес стека.

    Далее я написал скрипт линкера:

    Код (Text):
    1. stack_base = 0x20001FFF;
    2.  
    3. ENTRY(reset_handler)
    4.  
    5. MEMORY
    6. {
    7.     FLASH (RX)   : ORIGIN = 0x08000000, LENGTH = 128K
    8.     RAM   (WAIL) : ORIGIN = 0x20000000, LENGTH = 8K
    9. }
    10.  
    11. SECTIONS
    12. {
    13.     .text :
    14.     {
    15.         KEEP(*(.isr_vectors))
    16.         *(.text*)
    17.         *(.rodata)
    18.     } > FLASH
    19.  
    20.     lma_data_start  = .;
    21.     .data : AT(lma_data_start)
    22.     {    va_data_start = .;
    23.         *(.data*)
    24.         va_data_end   = .;
    25.     } > RAM
    26.  
    27.     .bss :
    28.     {
    29.         va_bss_start = .;
    30.         *(.bss*)
    31.         va_bss_end   = .;
    32.     } > RAM
    33. }
    1. Если оперативная память начинается по адресу 0x20000000, и ее 8 кб, то вершину стека надо устанавливать на 0x20001FFF или на 0x20002000? Или не заморачиваться и написать ORIGIN(RAM) + LENGTH(RAM)?

    2. Как в скрипте ликнера символам присваиваются виртуальные адреса в SRAM, а как - адреса загрузки в оперативе? Почему lma_data_start = .; перед объявление секции - это адрес во флеше, а va_data_start = .; внутри объявления секции - это адрес оперативы? Почему линкер считает именно так?

    3.При инициализации памяти в цикле:

    Код (C):
    1. while (dst < &va_data_end)
    2.         *dst++ = *src++;
    зачем брать адреса символов, которые определяет линкер? Разве эти символы уже не адреса?