learnxinyminutes-docs/ru/linker.md
2024-12-08 20:29:09 -07:00

204 lines
10 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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