Я решил поучиться работать с GNU LD. Начать решил с малого: в стандартный файл скрипта для STM32L152RE, который идет в комплекте с EmBitz, добавить секции для размещения данных в EEPROM (по умолчанию их там нет).
Посмотрите, пожалуйста, я все правильно сделал?
Спойлер
Код: Выделить всё
OUTPUT_FORMAT("elf32-littlearm", "elf32-littlearm", "elf32-littlearm")
OUTPUT_ARCH(arm)
SEARCH_DIR(.)
/* Memory Spaces Definitions */
MEMORY
{
ROM (rx) : ORIGIN = 0x08000000, LENGTH = 512K
RAM (rwx) : ORIGIN = 0x20000000, LENGTH = 80K
/*
ДОБАВИЛ определения для встроенной в контроллер EEPROM. Значения адресов и размеров взяты из даташита.
*/
EEP1 (rw) : ORIGIN = 0x08080000, LENGTH = 8K
EEP2 (rw) : ORIGIN = 0x08082000, LENGTH = 8K
}
SECTIONS
{
.text :
{
KEEP(*(.isr_vector))
*(.text*)
KEEP(*(.init))
KEEP(*(.fini))
/* .ctors */
*crtbegin.o(.ctors)
*crtbegin?.o(.ctors)
*(EXCLUDE_FILE(*crtend?.o *crtend.o) .ctors)
*(SORT(.ctors.*))
*(.ctors)
/* .dtors */
*crtbegin.o(.dtors)
*crtbegin?.o(.dtors)
*(EXCLUDE_FILE(*crtend?.o *crtend.o) .dtors)
*(SORT(.dtors.*))
*(.dtors)
*(.rodata*)
KEEP(*(.eh_frame*))
} > ROM
.ARM.extab :
{
*(.ARM.extab* .gnu.linkonce.armextab.*)
} > ROM
__exidx_start = .;
.ARM.exidx :
{
*(.ARM.exidx* .gnu.linkonce.armexidx.*)
} > ROM
__exidx_end = .;
__etext = .;
.data : AT (__etext)
{
__data_start__ = .;
*(vtable)
*(.data*)
. = ALIGN(4);
/* preinit data */
PROVIDE_HIDDEN (__preinit_array_start = .);
KEEP(*(.preinit_array))
PROVIDE_HIDDEN (__preinit_array_end = .);
. = ALIGN(4);
/* init data */
PROVIDE_HIDDEN (__init_array_start = .);
KEEP(*(SORT(.init_array.*)))
KEEP(*(.init_array))
PROVIDE_HIDDEN (__init_array_end = .);
. = ALIGN(4);
/* finit data */
PROVIDE_HIDDEN (__fini_array_start = .);
KEEP(*(SORT(.fini_array.*)))
KEEP(*(.fini_array))
PROVIDE_HIDDEN (__fini_array_end = .);
. = ALIGN(4);
/* All data end */
__data_end__ = .;
} > RAM
.bss (NOLOAD):
{
__bss_start__ = .;
*(.bss*)
*(COMMON)
__bss_end__ = .;
} > RAM
.heap (NOLOAD):
{
__end__ = .;
end = __end__;
*(.heap*)
__HeapLimit = .;
} > RAM
/* .stack_dummy section doesn't contains any symbols. It is only
* used for linker to calculate size of stack sections, and assign
* values to stack symbols later */
.stack_dummy (NOLOAD):
{
*(.stack)
} > RAM
/*
ДОБАВИЛ две секции, соответствующие двум банкам EEPROM.
Использовал KEEP, чтобы компоновщик не удалял данные, которые по той или иной причине должны быть записаны в память, но не используются в программе непосредственно.
*/
.eeprom_bank_1 :
{
KEEP (*(.eep_bank_1));
} > EEP1
.eeprom_bank_2 :
{
KEEP (*(.eep_bank_2));
} > EEP2
/* Set stack top to end of RAM, and stack limit move down by
* size of stack_dummy section */
__StackTop = ORIGIN(RAM) + LENGTH(RAM);
__StackLimit = __StackTop - SIZEOF(.stack_dummy);
PROVIDE(__stack = __StackTop);
/* Check if data + heap + stack exceeds RAM limit */
ASSERT(__StackLimit >= __HeapLimit, "region RAM overflowed with stack")
}
Проверял, объявляя массив вот так:
Код: Выделить всё
volatile uint32_t a[10] __attribute__ ((section(".eep_bank_2"))) = {1,2,3,4,5,6,7,8,9,10};
Но, тем не менее, у меня есть вопросы.
Вопрос номер один. Я просто добавил новые секции в конец перечисления секций. Этого достаточно, чтобы они встали, как надо? Если да, то зачем при объявлении секции .data используется атрибут AT?
Вопрос номер два. Я правильно понимаю, что, по сути, две записи, которые я привожу ниже, эквивалентны?
Код: Выделить всё
MEMORY
{
...
EEP1 (rw) : ORIGIN = 0x08080000, LENGTH = 8K
...
}
...
.eeprom_bank_1 :
{
KEEP (*(.eep_bank_1));
} > EEP1
Код: Выделить всё
.eeprom_bank_1 0x08080000 :
{
KEEP(*(.eep_bank_1));
}