Skrypt jest rzeczywiście prosty. Zaprezentuję go w całej okazałości, żeby był bardziej zrozumiały. Jest to generalnie kompilacja działających i niedziałających przykładów z internetu. Minimum jest bardzo proste. Na początku w pamięci flash musi znaleźć się tablica wektorów przerwań (tablica wskaźników do funkcji obsługujących przerwania). Opisuje go sekcja oznaczona jako isr_vectors. KEEP jest konieczny, gdyż inaczej linker może chcieć wyrzucić coś, co jest nieużywane. Następnie w sekcji .text (chociaż można ją nazwać dowolnie) umieszczamy kod wykonywalny, który kompilator oznacza jako .text lub .text.* (* oznacza dowolny ciąg znaków). Po kodzie wykonywalnym umieszczamy stałe, które kompilator oznacza jako .rodata*. Teraz występuje kolejna sekcja. Zmienne zainicjowane. Musimy na nie utworzyć nową sekcję, gdyż wartości inicjujące muszą być zapisane w pamięci flash ( AT (_flash_data_start) umieszczamy sekcję po stałych), a adresy będą mapowane w pamięci RAM ( >RAM) .
Tutaj dorzuciłem małą ciekawostkę pod tytułem .ramsection. Gdy jakiejś funkcji dodamy atrybut .ramsection, np tak:
__attribute__ ((long_call, section (".ramsection")))
wtedy funkcja zostanie zmapowana do pamięci ram. Oczywiście kod startowy musi zadbać o to, aby została kod takiej funkcji został przekopiowany do pamięci RAM na starcie. Dlatego .ramsection jest w sekcji data. Podczas startu kopiujemy całą sekcję data od _data_start do _data_end na początek pamięci RAM.
Ostatnia sekcja to zmienne niezainicjowane. Są one mapowane do pamięci RAM. Dobra praktyka inżynierska nakazuje w kodzie startowym przejechać się zerami po obszarze pamięci od _bss_start do _bss_end. Oczywiście dobra praktyka inżynierska sobie, a realia sobie. Nie trzeba inicjować tego obszaru, ale podczas używania tych zmiennych należy pamiętać, że ich pierwsza wartość będzie w sumie losowa.
MEMORY
{
RAM (rwx) : ORIGIN = 0x20000000, LENGTH = 20K
FLASH (rx) : ORIGIN = 0x08000000, LENGTH = 128K
}
SECTIONS
{
. = 0x0;
.isr_vectors :
{
. = ALIGN(4);
KEEP(*(.isr_vectors))
. = ALIGN(4);
} >FLASH
.text :
{
*(.text)
*(.text.*)
*(.rodata)
*(.rodata*)
. = ALIGN(4);
_flash_data_start = .;
} >FLASH
.data : AT (_flash_data_start)
{
. = ALIGN(4);
_data_start = .;
*(.data)
*(.data.*)
*(.ramsection)
_data_end = .;
} >RAM
.bss :
{
. = ALIGN(4);
_bss_start = .;
*(.bss)
_bss_end = .;
} >RAM
}
Na koniec dorzucę:
Mój skrypt linkera - GitHub
Mój kod startowy - GitHub