Я разбираюсь в написании своих скриптов для линкера и составлении карты памяти для микроконтроллеров ARM. Есть несколько вещей, которые я не понимаю. Рассмотрим файлы, которые управляют структурой программы и занимаются инициализацией контроллера: boot.S - таблица векторов прерываний. Первое "прерывание" - это база стека, второе - функция, вызываемая при перезагрузке контроллера, которые выполняет его инициализацию и вызывает main. Код (ASM): .cpu cortex-m3 .thumb .word stack_base @ Stack base .word ResetHandler @ Reset vector .word hang @ Eternal loop .thumb_func hang: b . /*.global hang*/ В дополнение я написал startup-код, которые копирует переменные из секции .data во флеше в память и обнуляет секцию .bss: Код (Text): extern unsigned long stack_base; extern unsigned long lma_data_start; extern unsigned long va_data_start; extern unsigned long va_data_end; extern unsigned long va_bss_start; extern unsigned long va_bss_end; extern int main(void); void reset_handler(void) { unsigned long *src, *dst; src = &lma_data_start; dst = &va_data_start; while (dst < &va_data_end) *dst++ = *src++; dst = &va_bss_start; while (dst < &va_bss_end) *dst++ = 0; main(); } void default_handler(void) { while (1) { /* Eternal loop */ } } __attribute__ ((section(".isr_vectors"))) void (* const interrupt_vector_table[])(void) = { (void *) &stack_base, reset_handler, default_handler }; Посмотрите, как задается адрес стека в файлах boot.S и startup.c. Эти файлы заменяют друг друга, один из них можно выкинуть, и программа будет работать с другим. Почему в файле boot.S достаточно просто определить адрес стека как слово .word stack_base, а в сишном коде от символа stack_base надо взять адрес и кастовать его в void*? Разве недостаточно в эту таблицу поместить просто число? А именно: символ stack_base при линковке содержит адрес стека. Далее я написал скрипт линкера: Код (Text): stack_base = 0x20001FFF; ENTRY(reset_handler) MEMORY { FLASH (RX) : ORIGIN = 0x08000000, LENGTH = 128K RAM (WAIL) : ORIGIN = 0x20000000, LENGTH = 8K } SECTIONS { .text : { KEEP(*(.isr_vectors)) *(.text*) *(.rodata) } > FLASH lma_data_start = .; .data : AT(lma_data_start) { va_data_start = .; *(.data*) va_data_end = .; } > RAM .bss : { va_bss_start = .; *(.bss*) va_bss_end = .; } > RAM } 1. Если оперативная память начинается по адресу 0x20000000, и ее 8 кб, то вершину стека надо устанавливать на 0x20001FFF или на 0x20002000? Или не заморачиваться и написать ORIGIN(RAM) + LENGTH(RAM)? 2. Как в скрипте ликнера символам присваиваются виртуальные адреса в SRAM, а как - адреса загрузки в оперативе? Почему lma_data_start = .; перед объявление секции - это адрес во флеше, а va_data_start = .; внутри объявления секции - это адрес оперативы? Почему линкер считает именно так? 3.При инициализации памяти в цикле: Код (C): while (dst < &va_data_end) *dst++ = *src++; зачем брать адреса символов, которые определяет линкер? Разве эти символы уже не адреса?