[linker] correct indentation

This commit is contained in:
Boris Verkhovskiy 2024-12-18 17:02:09 -07:00
parent 29e880808e
commit 755d45e978
3 changed files with 143 additions and 151 deletions

View File

@ -23,6 +23,6 @@ jobs:
- name: Files are UTF-8
run: ./lint/encoding.sh .
- name: Lint Markdown
run: mdl . --ignore-front-matter -r MD003,MD005,MD011,MD019,MD023,MD027,MD028,MD035,MD037,MD038,MD039,MD047
run: mdl . --ignore-front-matter -r MD003,MD005,MD011,MD019,MD023,MD025,MD027,MD028,MD035,MD037,MD038,MD039,MD047
- name: Lint frontmatter
run: ./lint/frontmatter.py .

105
linker.md
View File

@ -1,34 +1,31 @@
---
category: tool
name: GNU linker (ld)
name: Linker script
contributors:
- ["Alexander Kovalchuk", "https://github.com/Zamuhrishka"]
translators:
- ["Anuj Shah", "https://github.com/ShahAnuj2610"]
filename: learn.ld
---
## Basic concepts and definitions
**Position counter** - the linker has a special variable
"." (dot) always contains the current output position.
"`.`" (dot) always contains the current output position.
## Functions
**ADDR (section)** - returns the absolute address of the specified section. However
`ADDR (section)` - returns the absolute address of the specified section. However
this section must be defined before using the ADDR function.
**ALIGN (exp)** - returns the value of the position counter aligned to the border
`ALIGN (exp)` - returns the value of the position counter aligned to the border
following the exp expression.
**SIZEOF (section)** - returns the size of the section in bytes.
`SIZEOF (section)` - returns the size of the section in bytes.
**FILL (param)** - defines the fill pattern for the current section. All
`FILL (param)` - defines the fill pattern for the current section. All
other unspecified regions within the section are filled with the value indicated
in function argument.
**KEEP (param)** - used to mark param as fatal.
`KEEP (param)` - used to mark param as fatal.
**ENTRY (func)** - defines the function that will be the entry point
`ENTRY (func)` - defines the function that will be the entry point
into the program.
```bash
@ -45,7 +42,7 @@ _Min_Stack_Size = 0x400;
# Description of the memory card available for this processor
# MEMORY
# {
#MEMORY_DOMAIN_NAME (access rights): ORIGIN = START_ADDRESS, LENGTH = SIZE
# MEMORY_DOMAIN_NAME (access rights) : ORIGIN = START_ADDRESS, LENGTH = SIZE
# }
# In our example, the controller contains three memory areas:
# RAM - starts with the address 0x20000000 and takes 128 KB;
@ -56,33 +53,33 @@ _Min_Stack_Size = 0x400;
# FLASH memory is available for reading and execution.
MEMORY
{
RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 128K
CCMRAM (rw) : ORIGIN = 0x10000000, LENGTH = 64K
FLASH (rx) : ORIGIN = 0x8000000, LENGTH = 1024K
RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 128K
CCMRAM (rw) : ORIGIN = 0x10000000, LENGTH = 64K
FLASH (rx) : ORIGIN = 0x8000000, LENGTH = 1024K
}
# We describe output sections
SECTIONS
{
# The first section contains a table of interrupt vectors
# The first section contains a table of interrupt vectors
.isr_vector :
{
# Align the current position to the border of 4 bytes.
# Align the current position to the border of 4 bytes.
. = ALIGN(4);
# There is an option --gc-sections, which allows you to collect garbage from unused
# input sections. And if there are sections that the garbage collector should not touch,
# you need to specify them as an argument to the KEEP () function (analogue of the keyword
# volatile).
# The entry (* (. Isr_vector)) means the .isr_vector sections in all object files. Because
# appeal to the section in general terms looks like this: (FILE_NAME (SECTION_NAME))
# There is an option --gc-sections, which allows you to collect garbage from unused
# input sections. And if there are sections that the garbage collector should not touch,
# you need to specify them as an argument to the KEEP () function (analogue of the keyword
# volatile).
# The entry (* (. Isr_vector)) means the .isr_vector sections in all object files. Because
# appeal to the section in general terms looks like this: (FILE_NAME (SECTION_NAME))
KEEP(*(.isr_vector))
# Align the current position to the border of 4 bytes.
# Align the current position to the border of 4 bytes.
. = ALIGN(4);
# The expression "> MEMORY AREA" indicates which area of memory will be placed
# this section. In our section, the .isr_vector section will be located in FLASH memory.
# The expression "> MEMORY AREA" indicates which area of memory will be placed
# this section. In our section, the .isr_vector section will be located in FLASH memory.
} >FLASH
# TOTAL: The .isr_vector section that contains the table of interrupt vectors is aligned
@ -92,24 +89,24 @@ SECTIONS
# The second section contains the program code.
.text :
{
# Align the current position to the border of 4 bytes.
# Align the current position to the border of 4 bytes.
. = ALIGN(4);
# We indicate that in this section the .text areas of all
# object files
# object files
*(.text)
*(.text*)
# Protect the .init and .fini sections from the garbage collector
# Protect the .init and .fini sections from the garbage collector
KEEP (*(.init))
KEEP (*(.fini))
# Align the current position to the border of 4 bytes.
# Align the current position to the border of 4 bytes.
. = ALIGN(4);
# The variable _etext is defined, which stores the address of the end of the .text section and which
# may be available in the source code of the program through the announcement
# volaile unsigned int extern _etext;
# The variable _etext is defined, which stores the address of the end of the .text section and which
# may be available in the source code of the program through the announcement
# volaile unsigned int extern _etext;
_etext = .;
} >FLASH
@ -123,15 +120,15 @@ SECTIONS
# The third section contains constant data.
.rodata :
{
# Align the current position to the border of 4 bytes.
# Align the current position to the border of 4 bytes.
. = ALIGN(4);
# We indicate that in this section areas .rodata will be stored
# object files
# We indicate that in this section areas .rodata will be stored
# object files
*(.rodata)
*(.rodata*)
# Align the current position to the border of 4 bytes.
# Align the current position to the border of 4 bytes.
. = ALIGN(4);
} >FLASH
@ -141,47 +138,47 @@ SECTIONS
# The fourth section contains initialized variables.
.data :
{
# Align the current position to the border of 4 bytes.
# Align the current position to the border of 4 bytes.
. = ALIGN(4);
# Save the address of the current position (beginning of the section) in the variable _sdata
# Save the address of the current position (beginning of the section) in the variable _sdata
_sdata = .;
# We indicate that in this section the .data areas of all
# object files
# We indicate that in this section the .data areas of all
# object files
*(.data)
*(.data*)
# Align the current position to the border of 4 bytes.
# Align the current position to the border of 4 bytes.
. = ALIGN(4);
# Save the address of the current position (end of section) in the variable _sdata
_edata = .;
# AT function indicates that this sector is stored in one memory area
# (in our case, FLASH), and it will be executed from another area of memory (in our case, RAM).
# There are two types of addresses:
# * VMA (Virtual memory address) - this is the run-time address at which the compiler expects
# see data.
# * LMA (Load memory address) is the address at which the linker stores data.
# AT function indicates that this sector is stored in one memory area
# (in our case, FLASH), and it will be executed from another area of memory (in our case, RAM).
# There are two types of addresses:
# * VMA (Virtual memory address) - this is the run-time address at which the compiler expects
# see data.
# * LMA (Load memory address) is the address at which the linker stores data.
#Startup must code to copy the .data section from the LMA addresses to the VMA addresses.
#Startup must code to copy the .data section from the LMA addresses to the VMA addresses.
} >RAM AT> FLASH
# The fifth section contains zero-initialized variables.
.bss :
{
# Save the address of the current position (beginning of the section) in the variable _sbss and __bss_start__
# Save the address of the current position (beginning of the section) in the variable _sbss and __bss_start__
_sbss = .;
__bss_start__ = _sbss;
# We indicate that in this section the .bss areas of all
# object files
# We indicate that in this section the .bss areas of all
# object files
*(.bss)
*(.bss*)
# Align the current position to the border of 4 bytes.
# Align the current position to the border of 4 bytes.
. = ALIGN(4);
# Save the address of the current position (beginning of the section) in the variable _ebss and __bss_end__

View File

@ -1,30 +1,26 @@
---
contributors:
- ["Alexander Kovalchuk", "https://github.com/Zamuhrishka"]
translators:
- ["Alexander Kovalchuk", "https://github.com/Zamuhrishka"]
---
# Основные понятия и определения
**Счетчик позиций** - у компоновщика есть специальная переменная
"." (точка) всегда содержит текущую позицию вывода.
**Счетчик позиций** - у компоновщика есть специальная переменная
"`.`" (точка) всегда содержит текущую позицию вывода.
# Функции
**ADDR(section)** - возвращает абсолютный адрес указанной секции. Однако
`ADDR(section)` - возвращает абсолютный адрес указанной секции. Однако
данная секция должна быть определенна до использования функции ADDR.
**ALIGN(exp)** - возвращает значение счетчика позиций, выравненное на границу
`ALIGN(exp)` - возвращает значение счетчика позиций, выравненное на границу
следующего за exp выражения.
**SIZEOF(section)** - возвращает размер секции в байтах.
`SIZEOF(section)` - возвращает размер секции в байтах.
**FILL(param)** - определяет образец заполнения для текущей секции. Все
остальные неуказанные регионы внутри секции заполняются значением указанными
`FILL(param)` - определяет образец заполнения для текущей секции. Все
остальные неуказанные регионы внутри секции заполняются значением указанными
в аргументе функции.
**KEEP(param)** - используется чтобы помечать param как неустранимый.
`KEEP(param)` - используется чтобы помечать param как неустранимый.
**ENTRY(func)** - определяет функцию, которая будет являться точкой входа
`ENTRY(func)` - определяет функцию, которая будет являться точкой входа
в программу.
```bash
@ -32,16 +28,16 @@ translators:
ENTRY(Reset_Handler)
# Определяем переменную которая содержит адрес вершины стека
_estack = 0x20020000;
# Определяем переменную которая содержит значение размера кучи
_estack = 0x20020000;
# Определяем переменную которая содержит значение размера кучи
_Min_Heap_Size = 0x200;
# Определяем переменную которая содержит значение размера стека
_Min_Stack_Size = 0x400;
_Min_Stack_Size = 0x400;
# Описание карты памяти доступной для данного процессора
# MEMORY
# {
# ИМЯ_ОБЛАСТИ_ПАМЯТИ (права доступа) : ORIGIN = АДРЕС_НАЧАЛА, LENGTH = РАЗМЕР
# ИМЯ_ОБЛАСТИ_ПАМЯТИ (права доступа) : ORIGIN = АДРЕС_НАЧАЛА, LENGTH = РАЗМЕР
# }
# В нашем примере контроллер содержит три области памяти:
# RAM - начинается с адреса 0x20000000 и занимает 128 Кбайт;
@ -52,136 +48,136 @@ _Min_Stack_Size = 0x400;
# FLASH память доступна на чтение и исполнение.
MEMORY
{
RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 128K
CCMRAM (rw) : ORIGIN = 0x10000000, LENGTH = 64K
FLASH (rx) : ORIGIN = 0x8000000, LENGTH = 1024K
RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 128K
CCMRAM (rw) : ORIGIN = 0x10000000, LENGTH = 64K
FLASH (rx) : ORIGIN = 0x8000000, LENGTH = 1024K
}
# Описываем выходные секции
SECTIONS
{
# Первая секция содержит таблицу векторов прерываний
# Первая секция содержит таблицу векторов прерываний
.isr_vector :
{
# Выравниваем текущую позицию на границу 4-х байт.
# Выравниваем текущую позицию на границу 4-х байт.
. = ALIGN(4);
# Существует опция --gc-sections, которая позволяет собирать мусор из неиспользуемых
# входных разделов. И если есть разделы, которые сборщик мусора не должен трогать,
# то их необходимо указать в качестве аргумента функции KEEP() (аналог ключевого слова
# volatile).
# Запись (*(.isr_vector)) означает разделы .isr_vector во всех объектных файлах. Т.к.
# обращение к разделу в общем виде выглядит так: (ИМЯ_ФАЙЛАМЯ_РАЗДЕЛА))
KEEP(*(.isr_vector))
# Существует опция --gc-sections, которая позволяет собирать мусор из неиспользуемых
# входных разделов. И если есть разделы, которые сборщик мусора не должен трогать,
# то их необходимо указать в качестве аргумента функции KEEP() (аналог ключевого слова
# volatile).
# Запись (*(.isr_vector)) означает разделы .isr_vector во всех объектных файлах. Т.к.
# обращение к разделу в общем виде выглядит так: (ИМЯ_ФАЙЛАМЯ_РАЗДЕЛА))
KEEP(*(.isr_vector))
# Выравниваем текущую позицию на границу 4-х байт.
# Выравниваем текущую позицию на границу 4-х байт.
. = ALIGN(4);
# Выражение ">ОБЛАСТЬАМЯТИ" указывает в какую именно область памяти будет помещена
# данная секция. В нашем случае секция .isr_vector будет размещена во FLASH памяти.
# Выражение ">ОБЛАСТЬАМЯТИ" указывает в какую именно область памяти будет помещена
# данная секция. В нашем случае секция .isr_vector будет размещена во FLASH памяти.
} >FLASH
# ИТОГО: Секция .isr_vector, которая содержит таблицу векторов прерываний выравнивается
# по границе 4-х байт, помечается как недоступная для сборщика мусора и размещается в начале
# ИТОГО: Секция .isr_vector, которая содержит таблицу векторов прерываний выравнивается
# по границе 4-х байт, помечается как недоступная для сборщика мусора и размещается в начале
# FLASH памяти микроконтроллера.
# Вторая секция содержит код программы.
.text :
{
# Выравниваем текущую позицию на границу 4-х байт.
# Выравниваем текущую позицию на границу 4-х байт.
. = ALIGN(4);
# Указываем, что в данной секции будут хранится области .text всех
# объектных файлов
*(.text)
*(.text*)
# Защищаем от сборщика мусора секции .init и .fini
# Указываем, что в данной секции будут хранится области .text всех
# объектных файлов
*(.text)
*(.text*)
# Защищаем от сборщика мусора секции .init и .fini
KEEP (*(.init))
KEEP (*(.fini))
# Выравниваем текущую позицию на границу 4-х байт.
# Выравниваем текущую позицию на границу 4-х байт.
. = ALIGN(4);
# Определяется переменная _etext, которая хранит в себе адрес конца секции .text и которая
# может быть доступна в исходном тексте программы через объявление
# volaile unsigned int extern _etext;
_etext = .;
# Определяется переменная _etext, которая хранит в себе адрес конца секции .text и которая
# может быть доступна в исходном тексте программы через объявление
# volaile unsigned int extern _etext;
_etext = .;
} >FLASH
# ИТОГО: Секция .text, которая содержит код программы выравнивается по границе 4-х байт,
# включает в себя: все секции с кодом программы во всех объектных файлах и защищенные
от сборщика муссора секции .init и .fini во всех объектных файлах, распологается во FLASH
памяти микроконтроллера сразу за таблицей векторов.
Секции text, .init и .fini. располагаются в памяти в той последовательности в которой они
объявлены в скрипте.
# ИТОГО: Секция .text, которая содержит код программы выравнивается по границе 4-х байт,
# включает в себя: все секции с кодом программы во всех объектных файлах и защищенные
# от сборщика муссора секции .init и .fini во всех объектных файлах, распологается во FLASH
# памяти микроконтроллера сразу за таблицей векторов.
# Секции text, .init и .fini. располагаются в памяти в той последовательности в которой они
# объявлены в скрипте.
# Третья секция содержит константные данные.
.rodata :
{
# Выравниваем текущую позицию на границу 4-х байт.
# Выравниваем текущую позицию на границу 4-х байт.
. = ALIGN(4);
# Указываем, что в данной секции будут хранится области .rodata всех
# объектных файлов
*(.rodata)
*(.rodata*)
# Выравниваем текущую позицию на границу 4-х байт.
# Указываем, что в данной секции будут хранится области .rodata всех
# объектных файлов
*(.rodata)
*(.rodata*)
# Выравниваем текущую позицию на границу 4-х байт.
. = ALIGN(4);
} >FLASH
# Сохраняем в переменной _sidata абсолютный адрес секции .data
# Сохраняем в переменной _sidata абсолютный адрес секции .data
_sidata = LOADADDR(.data);
# Четвертая секция содержит инициализированные переменные.
.data :
.data :
{
# Выравниваем текущую позицию на границу 4-х байт.
# Выравниваем текущую позицию на границу 4-х байт.
. = ALIGN(4);
# Сохраняем в переменной _sdata адрес текущей позиции (начала секции)
_sdata = .;
# Указываем, что в данной секции будут хранится области .data всех
# объектных файлов
*(.data)
*(.data*)
# Сохраняем в переменной _sdata адрес текущей позиции (начала секции)
_sdata = .;
# Выравниваем текущую позицию на границу 4-х байт.
# Указываем, что в данной секции будут хранится области .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.
_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 = .;
# Сохраняем в переменной _sbss и __bss_start__ адрес текущей позиции (начала секции)
_sbss = .;
__bss_start__ = _sbss;
# Указываем, что в данной секции будут хранится области .bss всех
# объектных файлов
# Указываем, что в данной секции будут хранится области .bss всех
# объектных файлов
*(.bss)
*(.bss*)
# Выравниваем текущую позицию на границу 4-х байт.
# Выравниваем текущую позицию на границу 4-х байт.
. = ALIGN(4);
# Сохраняем в переменной _ebss и __bss_end__ адрес текущей позиции (начала секции)
_ebss = .;
_ebss = .;
__bss_end__ = _ebss;
} >RAM
@ -197,4 +193,3 @@ SECTIONS
} >RAM
}
```