linker.md

Личный сайт Go-разработчика из Казани

Счетчик позиций - у компоновщика есть специальная переменная «.» (точка) всегда содержит текущую позицию вывода.

ADDR(section) - возвращает абсолютный адрес указанной секции. Однако данная секция должна быть определенна до использования функции ADDR.

ALIGN(exp) - возвращает значение счетчика позиций, выравненное на границу следующего за exp выражения.

SIZEOF(section) - возвращает размер секции в байтах.

FILL(param) - определяет образец заполнения для текущей секции. Все остальные неуказанные регионы внутри секции заполняются значением указанными в аргументе функции.

KEEP(param) - используется чтобы помечать param как неустранимый.

ENTRY(func) - определяет функцию, которая будет являться точкой входа в программу.

1# Определяем точку входа в программу 2ENTRY(Reset_Handler) 3 4# Определяем переменную которая содержит адрес вершины стека 5_estack = 0x20020000; 6# Определяем переменную которая содержит значение размера кучи 7_Min_Heap_Size = 0x200; 8# Определяем переменную которая содержит значение размера стека 9_Min_Stack_Size = 0x400; 10 11# Описание карты памяти доступной для данного процессора 12# MEMORY 13# { 14# ИМЯ_ОБЛАСТИ_ПАМЯТИ (права доступа) : ORIGIN = АДРЕС_НАЧАЛА, LENGTH = РАЗМЕР 15# } 16# В нашем примере контроллер содержит три области памяти: 17# RAM - начинается с адреса 0x20000000 и занимает 128 Кбайт; 18# CCMRAM - начинается с адреса 0x10000000и занимает 64 Кбайт; 19# FLASH - начинается с адреса 0x8000000 занимает 1024 Кбайт; 20# Причем RAM память доступна для чтения, записи и исполнения. 21# CCMRAM память доступна только на чтение и запись. 22# FLASH память доступна на чтение и исполнение. 23MEMORY 24{ 25 RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 128K 26 CCMRAM (rw) : ORIGIN = 0x10000000, LENGTH = 64K 27 FLASH (rx) : ORIGIN = 0x8000000, LENGTH = 1024K 28} 29 30# Описываем выходные секции 31SECTIONS 32{ 33 # Первая секция содержит таблицу векторов прерываний 34 .isr_vector : 35 { 36 # Выравниваем текущую позицию на границу 4-х байт. 37 . = ALIGN(4); 38 39 # Существует опция --gc-sections, которая позволяет собирать мусор из неиспользуемых 40 # входных разделов. И если есть разделы, которые сборщик мусора не должен трогать, 41 # то их необходимо указать в качестве аргумента функции KEEP() (аналог ключевого слова 42 # volatile). 43 # Запись (*(.isr_vector)) означает разделы .isr_vector во всех объектных файлах. Т.к. 44 # обращение к разделу в общем виде выглядит так: (ИМЯ_ФАЙЛА(ИМЯ_РАЗДЕЛА)) 45 KEEP(*(.isr_vector)) 46 47 # Выравниваем текущую позицию на границу 4-х байт. 48 . = ALIGN(4); 49 50 # Выражение ">ОБЛАСТЬ_ПАМЯТИ" указывает в какую именно область памяти будет помещена 51 # данная секция. В нашем случае секция .isr_vector будет размещена во FLASH памяти. 52 } >FLASH 53 54# ИТОГО: Секция .isr_vector, которая содержит таблицу векторов прерываний выравнивается 55# по границе 4-х байт, помечается как недоступная для сборщика мусора и размещается в начале 56# FLASH памяти микроконтроллера. 57 58 # Вторая секция содержит код программы. 59 .text : 60 { 61 # Выравниваем текущую позицию на границу 4-х байт. 62 . = ALIGN(4); 63 64 # Указываем, что в данной секции будут хранится области .text всех 65 # объектных файлов 66 *(.text) 67 *(.text*) 68 69 # Защищаем от сборщика мусора секции .init и .fini 70 KEEP (*(.init)) 71 KEEP (*(.fini)) 72 73 # Выравниваем текущую позицию на границу 4-х байт. 74 . = ALIGN(4); 75 76 # Определяется переменная _etext, которая хранит в себе адрес конца секции .text и которая 77 # может быть доступна в исходном тексте программы через объявление 78 # volaile unsigned int extern _etext; 79 _etext = .; 80 } >FLASH 81 82# ИТОГО: Секция .text, которая содержит код программы выравнивается по границе 4-х байт, 83# включает в себя: все секции с кодом программы во всех объектных файлах и защищенные 84# от сборщика муссора секции .init и .fini во всех объектных файлах, распологается во FLASH 85# памяти микроконтроллера сразу за таблицей векторов. 86# Секции text, .init и .fini. располагаются в памяти в той последовательности в которой они 87# объявлены в скрипте. 88 89 # Третья секция содержит константные данные. 90 .rodata : 91 { 92 # Выравниваем текущую позицию на границу 4-х байт. 93 . = ALIGN(4); 94 95 # Указываем, что в данной секции будут хранится области .rodata всех 96 # объектных файлов 97 *(.rodata) 98 *(.rodata*) 99 100 # Выравниваем текущую позицию на границу 4-х байт. 101 . = ALIGN(4); 102 } >FLASH 103 104 # Сохраняем в переменной _sidata абсолютный адрес секции .data 105 _sidata = LOADADDR(.data); 106 107 # Четвертая секция содержит инициализированные переменные. 108 .data : 109 { 110 # Выравниваем текущую позицию на границу 4-х байт. 111 . = ALIGN(4); 112 113 # Сохраняем в переменной _sdata адрес текущей позиции (начала секции) 114 _sdata = .; 115 116 # Указываем, что в данной секции будут хранится области .data всех 117 # объектных файлов 118 *(.data) 119 *(.data*) 120 121 # Выравниваем текущую позицию на границу 4-х байт. 122 . = ALIGN(4); 123 124 # Сохраняем в переменной _sdata адрес текущей позиции (конец секции) 125 _edata = .; 126 127 # Функция AT указывает на то, что данный сектор хранится в одной области памяти 128 # (в нашем случае FLASH), а исполняться будет из другой области памяти (в нашем случае RAM). 129 # Есть два типа адресов: 130 # * VMA (Virtual memory address) - это run-time адрес по которому компилятор ожидает 131 # видеть данные. 132 # * LMA (Load memory address) - это адрес по которому линкер хранит данные. 133 134 # Startup должен код скопировать секцию .data из адресов LMA в адреса VMA. 135 136 } >RAM AT> FLASH 137 138 # Пятая секция содержит инициализированные нулем переменные. 139 .bss : 140 { 141 # Сохраняем в переменной _sbss и __bss_start__ адрес текущей позиции (начала секции) 142 _sbss = .; 143 __bss_start__ = _sbss; 144 145 # Указываем, что в данной секции будут хранится области .bss всех 146 # объектных файлов 147 *(.bss) 148 *(.bss*) 149 150 # Выравниваем текущую позицию на границу 4-х байт. 151 . = ALIGN(4); 152 153 # Сохраняем в переменной _ebss и __bss_end__ адрес текущей позиции (начала секции) 154 _ebss = .; 155 __bss_end__ = _ebss; 156 } >RAM 157 158 # Шестая секция содержит кучу и стек. Размещается в самом конце RAM. 159 ._user_heap_stack : 160 { 161 . = ALIGN(4); 162 PROVIDE ( end = . ); 163 PROVIDE ( _end = . ); 164 . = . + _Min_Heap_Size; 165 . = . + _Min_Stack_Size; 166 . = ALIGN(4); 167 } >RAM 168}