From 814825ef47ffa276303c47e2fb43caf21314039d Mon Sep 17 00:00:00 2001 From: Alexander Kovalchuk Date: Sun, 23 Jun 2019 18:41:25 +0300 Subject: [PATCH] Add description of linker script --- ru-ru/linker-ru.html.markdown | 204 ++++++++++++++++++++++++++++++++++ 1 file changed, 204 insertions(+) create mode 100644 ru-ru/linker-ru.html.markdown diff --git a/ru-ru/linker-ru.html.markdown b/ru-ru/linker-ru.html.markdown new file mode 100644 index 00000000..49f2960f --- /dev/null +++ b/ru-ru/linker-ru.html.markdown @@ -0,0 +1,204 @@ +--- +category: tool +tool: linker +contributors: + - ["Alexander Kovalchuk", "https://github.com/Zamuhrishka"] +translators: + +filename: +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 +} +``` +