learnxinyminutes-docs/ru/linker.md

196 lines
9.7 KiB
Markdown
Raw Permalink Normal View History

2019-06-23 15:41:25 +00:00
---
contributors:
- ["Alexander Kovalchuk", "https://github.com/Zamuhrishka"]
---
2024-12-19 00:02:09 +00:00
**Счетчик позиций** - у компоновщика есть специальная переменная
"`.`" (точка) всегда содержит текущую позицию вывода.
2019-06-23 15:41:25 +00:00
2024-12-19 00:02:09 +00:00
`ADDR(section)` - возвращает абсолютный адрес указанной секции. Однако
2019-06-23 15:41:25 +00:00
данная секция должна быть определенна до использования функции ADDR.
2024-12-19 00:02:09 +00:00
`ALIGN(exp)` - возвращает значение счетчика позиций, выравненное на границу
2019-06-23 15:41:25 +00:00
следующего за exp выражения.
2024-12-19 00:02:09 +00:00
`SIZEOF(section)` - возвращает размер секции в байтах.
2019-06-23 15:41:25 +00:00
2024-12-19 00:02:09 +00:00
`FILL(param)` - определяет образец заполнения для текущей секции. Все
остальные неуказанные регионы внутри секции заполняются значением указанными
2019-06-23 15:41:25 +00:00
в аргументе функции.
2024-12-19 00:02:09 +00:00
`KEEP(param)` - используется чтобы помечать param как неустранимый.
2019-06-23 15:41:25 +00:00
2024-12-19 00:02:09 +00:00
`ENTRY(func)` - определяет функцию, которая будет являться точкой входа
2019-06-23 15:41:25 +00:00
в программу.
```bash
# Определяем точку входа в программу
ENTRY(Reset_Handler)
2022-06-15 09:17:20 +00:00
# Определяем переменную которая содержит адрес вершины стека
2024-12-19 00:02:09 +00:00
_estack = 0x20020000;
# Определяем переменную которая содержит значение размера кучи
2019-06-23 15:41:25 +00:00
_Min_Heap_Size = 0x200;
2022-06-15 09:17:20 +00:00
# Определяем переменную которая содержит значение размера стека
2024-12-19 00:02:09 +00:00
_Min_Stack_Size = 0x400;
2019-06-23 15:41:25 +00:00
# Описание карты памяти доступной для данного процессора
# MEMORY
# {
2024-12-19 00:02:09 +00:00
# ИМЯ_ОБЛАСТИ_ПАМЯТИ (права доступа) : ORIGIN = АДРЕС_НАЧАЛА, LENGTH = РАЗМЕР
2019-06-23 15:41:25 +00:00
# }
# В нашем примере контроллер содержит три области памяти:
# RAM - начинается с адреса 0x20000000 и занимает 128 Кбайт;
# CCMRAM - начинается с адреса 0x10000000и занимает 64 Кбайт;
# FLASH - начинается с адреса 0x8000000 занимает 1024 Кбайт;
2022-06-15 09:17:20 +00:00
# Причем RAM память доступна для чтения, записи и исполнения.
2019-06-23 15:41:25 +00:00
# CCMRAM память доступна только на чтение и запись.
# FLASH память доступна на чтение и исполнение.
MEMORY
{
2024-12-19 00:02:09 +00:00
RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 128K
CCMRAM (rw) : ORIGIN = 0x10000000, LENGTH = 64K
FLASH (rx) : ORIGIN = 0x8000000, LENGTH = 1024K
2019-06-23 15:41:25 +00:00
}
# Описываем выходные секции
SECTIONS
{
2024-12-19 00:02:09 +00:00
# Первая секция содержит таблицу векторов прерываний
2019-06-23 15:41:25 +00:00
.isr_vector :
{
2024-12-19 00:02:09 +00:00
# Выравниваем текущую позицию на границу 4-х байт.
2019-06-23 15:41:25 +00:00
. = ALIGN(4);
2024-12-19 00:02:09 +00:00
# Существует опция --gc-sections, которая позволяет собирать мусор из неиспользуемых
# входных разделов. И если есть разделы, которые сборщик мусора не должен трогать,
# то их необходимо указать в качестве аргумента функции KEEP() (аналог ключевого слова
# volatile).
# Запись (*(.isr_vector)) означает разделы .isr_vector во всех объектных файлах. Т.к.
# обращение к разделу в общем виде выглядит так: (ИМЯ_ФАЙЛАМЯ_РАЗДЕЛА))
KEEP(*(.isr_vector))
2019-06-23 15:41:25 +00:00
2024-12-19 00:02:09 +00:00
# Выравниваем текущую позицию на границу 4-х байт.
2019-06-23 15:41:25 +00:00
. = ALIGN(4);
2024-12-19 00:02:09 +00:00
# Выражение ">ОБЛАСТЬАМЯТИ" указывает в какую именно область памяти будет помещена
# данная секция. В нашем случае секция .isr_vector будет размещена во FLASH памяти.
2019-06-23 15:41:25 +00:00
} >FLASH
2024-12-19 00:02:09 +00:00
# ИТОГО: Секция .isr_vector, которая содержит таблицу векторов прерываний выравнивается
# по границе 4-х байт, помечается как недоступная для сборщика мусора и размещается в начале
2019-06-23 15:41:25 +00:00
# FLASH памяти микроконтроллера.
# Вторая секция содержит код программы.
.text :
{
2024-12-19 00:02:09 +00:00
# Выравниваем текущую позицию на границу 4-х байт.
2019-06-23 15:41:25 +00:00
. = ALIGN(4);
2024-12-19 00:02:09 +00:00
2019-06-23 15:41:25 +00:00
# Указываем, что в данной секции будут хранится области .text всех
2024-12-19 00:02:09 +00:00
# объектных файлов
*(.text)
*(.text*)
2019-06-23 15:41:25 +00:00
2024-12-19 00:02:09 +00:00
# Защищаем от сборщика мусора секции .init и .fini
2019-06-23 15:41:25 +00:00
KEEP (*(.init))
KEEP (*(.fini))
2024-12-19 00:02:09 +00:00
# Выравниваем текущую позицию на границу 4-х байт.
2019-06-23 15:41:25 +00:00
. = ALIGN(4);
2024-12-19 00:02:09 +00:00
# Определяется переменная _etext, которая хранит в себе адрес конца секции .text и которая
# может быть доступна в исходном тексте программы через объявление
# volaile unsigned int extern _etext;
_etext = .;
2019-06-23 15:41:25 +00:00
} >FLASH
2024-12-19 00:02:09 +00:00
# ИТОГО: Секция .text, которая содержит код программы выравнивается по границе 4-х байт,
# включает в себя: все секции с кодом программы во всех объектных файлах и защищенные
# от сборщика муссора секции .init и .fini во всех объектных файлах, распологается во FLASH
# памяти микроконтроллера сразу за таблицей векторов.
# Секции text, .init и .fini. располагаются в памяти в той последовательности в которой они
# объявлены в скрипте.
2019-06-23 15:41:25 +00:00
# Третья секция содержит константные данные.
.rodata :
{
2024-12-19 00:02:09 +00:00
# Выравниваем текущую позицию на границу 4-х байт.
2019-06-23 15:41:25 +00:00
. = ALIGN(4);
2024-12-19 00:02:09 +00:00
# Указываем, что в данной секции будут хранится области .rodata всех
# объектных файлов
*(.rodata)
*(.rodata*)
# Выравниваем текущую позицию на границу 4-х байт.
2019-06-23 15:41:25 +00:00
. = ALIGN(4);
} >FLASH
2024-12-19 00:02:09 +00:00
# Сохраняем в переменной _sidata абсолютный адрес секции .data
2019-06-23 15:41:25 +00:00
_sidata = LOADADDR(.data);
# Четвертая секция содержит инициализированные переменные.
2024-12-19 00:02:09 +00:00
.data :
2019-06-23 15:41:25 +00:00
{
2024-12-19 00:02:09 +00:00
# Выравниваем текущую позицию на границу 4-х байт.
2019-06-23 15:41:25 +00:00
. = ALIGN(4);
2024-12-19 00:02:09 +00:00
# Сохраняем в переменной _sdata адрес текущей позиции (начала секции)
_sdata = .;
# Указываем, что в данной секции будут хранится области .data всех
# объектных файлов
*(.data)
*(.data*)
2019-06-23 15:41:25 +00:00
2024-12-19 00:02:09 +00:00
# Выравниваем текущую позицию на границу 4-х байт.
2019-06-23 15:41:25 +00:00
. = ALIGN(4);
2024-12-19 00:02:09 +00:00
2019-06-23 15:41:25 +00:00
# Сохраняем в переменной _sdata адрес текущей позиции (конец секции)
2024-12-19 00:02:09 +00:00
_edata = .;
# Функция AT указывает на то, что данный сектор хранится в одной области памяти
# (в нашем случае FLASH), а исполняться будет из другой области памяти (в нашем случае RAM).
# Есть два типа адресов:
# * VMA (Virtual memory address) - это run-time адрес по которому компилятор ожидает
# видеть данные.
# * LMA (Load memory address) - это адрес по которому линкер хранит данные.
# Startup должен код скопировать секцию .data из адресов LMA в адреса VMA.
2019-06-23 15:41:25 +00:00
} >RAM AT> FLASH
2024-12-19 00:02:09 +00:00
# Пятая секция содержит инициализированные нулем переменные.
2019-06-23 15:41:25 +00:00
.bss :
{
2024-12-19 00:02:09 +00:00
# Сохраняем в переменной _sbss и __bss_start__ адрес текущей позиции (начала секции)
_sbss = .;
2019-06-23 15:41:25 +00:00
__bss_start__ = _sbss;
2024-12-19 00:02:09 +00:00
# Указываем, что в данной секции будут хранится области .bss всех
# объектных файлов
2019-06-23 15:41:25 +00:00
*(.bss)
*(.bss*)
2024-12-19 00:02:09 +00:00
# Выравниваем текущую позицию на границу 4-х байт.
2019-06-23 15:41:25 +00:00
. = ALIGN(4);
2024-12-19 00:02:09 +00:00
2019-06-23 15:41:25 +00:00
# Сохраняем в переменной _ebss и __bss_end__ адрес текущей позиции (начала секции)
2024-12-19 00:02:09 +00:00
_ebss = .;
2019-06-23 15:41:25 +00:00
__bss_end__ = _ebss;
} >RAM
# Шестая секция содержит кучу и стек. Размещается в самом конце RAM.
._user_heap_stack :
{
. = ALIGN(4);
PROVIDE ( end = . );
PROVIDE ( _end = . );
. = . + _Min_Heap_Size;
. = . + _Min_Stack_Size;
. = ALIGN(4);
} >RAM
}
```