[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 - name: Files are UTF-8
run: ./lint/encoding.sh . run: ./lint/encoding.sh .
- name: Lint Markdown - 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 - name: Lint frontmatter
run: ./lint/frontmatter.py . run: ./lint/frontmatter.py .

105
linker.md
View File

@ -1,34 +1,31 @@
--- ---
category: tool category: tool
name: GNU linker (ld) name: Linker script
contributors: contributors:
- ["Alexander Kovalchuk", "https://github.com/Zamuhrishka"] - ["Alexander Kovalchuk", "https://github.com/Zamuhrishka"]
translators: translators:
- ["Anuj Shah", "https://github.com/ShahAnuj2610"] - ["Anuj Shah", "https://github.com/ShahAnuj2610"]
filename: learn.ld
--- ---
## Basic concepts and definitions
**Position counter** - the linker has a special variable **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. 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. 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 other unspecified regions within the section are filled with the value indicated
in function argument. 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. into the program.
```bash ```bash
@ -45,7 +42,7 @@ _Min_Stack_Size = 0x400;
# Description of the memory card available for this processor # Description of the memory card available for this processor
# MEMORY # 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: # In our example, the controller contains three memory areas:
# RAM - starts with the address 0x20000000 and takes 128 KB; # 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. # FLASH memory is available for reading and execution.
MEMORY MEMORY
{ {
RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 128K RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 128K
CCMRAM (rw) : ORIGIN = 0x10000000, LENGTH = 64K CCMRAM (rw) : ORIGIN = 0x10000000, LENGTH = 64K
FLASH (rx) : ORIGIN = 0x8000000, LENGTH = 1024K FLASH (rx) : ORIGIN = 0x8000000, LENGTH = 1024K
} }
# We describe output sections # We describe output sections
SECTIONS SECTIONS
{ {
# The first section contains a table of interrupt vectors # The first section contains a table of interrupt vectors
.isr_vector : .isr_vector :
{ {
# Align the current position to the border of 4 bytes. # Align the current position to the border of 4 bytes.
. = ALIGN(4); . = ALIGN(4);
# There is an option --gc-sections, which allows you to collect garbage from unused # 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, # 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 # you need to specify them as an argument to the KEEP () function (analogue of the keyword
# volatile). # volatile).
# The entry (* (. Isr_vector)) means the .isr_vector sections in all object files. Because # 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)) # appeal to the section in general terms looks like this: (FILE_NAME (SECTION_NAME))
KEEP(*(.isr_vector)) 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); . = ALIGN(4);
# The expression "> MEMORY AREA" indicates which area of memory will be placed # 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. # this section. In our section, the .isr_vector section will be located in FLASH memory.
} >FLASH } >FLASH
# TOTAL: The .isr_vector section that contains the table of interrupt vectors is aligned # 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. # The second section contains the program code.
.text : .text :
{ {
# Align the current position to the border of 4 bytes. # Align the current position to the border of 4 bytes.
. = ALIGN(4); . = ALIGN(4);
# We indicate that in this section the .text areas of all # We indicate that in this section the .text areas of all
# object files # object files
*(.text) *(.text)
*(.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 (*(.init))
KEEP (*(.fini)) KEEP (*(.fini))
# Align the current position to the border of 4 bytes. # Align the current position to the border of 4 bytes.
. = ALIGN(4); . = ALIGN(4);
# The variable _etext is defined, which stores the address of the end of the .text section and which # 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 # may be available in the source code of the program through the announcement
# volaile unsigned int extern _etext; # volaile unsigned int extern _etext;
_etext = .; _etext = .;
} >FLASH } >FLASH
@ -123,15 +120,15 @@ SECTIONS
# The third section contains constant data. # The third section contains constant data.
.rodata : .rodata :
{ {
# Align the current position to the border of 4 bytes. # Align the current position to the border of 4 bytes.
. = ALIGN(4); . = ALIGN(4);
# We indicate that in this section areas .rodata will be stored # We indicate that in this section areas .rodata will be stored
# object files # object files
*(.rodata) *(.rodata)
*(.rodata*) *(.rodata*)
# Align the current position to the border of 4 bytes. # Align the current position to the border of 4 bytes.
. = ALIGN(4); . = ALIGN(4);
} >FLASH } >FLASH
@ -141,47 +138,47 @@ SECTIONS
# The fourth section contains initialized variables. # The fourth section contains initialized variables.
.data : .data :
{ {
# Align the current position to the border of 4 bytes. # Align the current position to the border of 4 bytes.
. = ALIGN(4); . = 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 = .; _sdata = .;
# We indicate that in this section the .data areas of all # We indicate that in this section the .data areas of all
# object files # object files
*(.data) *(.data)
*(.data*) *(.data*)
# Align the current position to the border of 4 bytes. # Align the current position to the border of 4 bytes.
. = ALIGN(4); . = ALIGN(4);
# Save the address of the current position (end of section) in the variable _sdata # Save the address of the current position (end of section) in the variable _sdata
_edata = .; _edata = .;
# AT function indicates that this sector is stored in one memory area # 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). # (in our case, FLASH), and it will be executed from another area of memory (in our case, RAM).
# There are two types of addresses: # There are two types of addresses:
# * VMA (Virtual memory address) - this is the run-time address at which the compiler expects # * VMA (Virtual memory address) - this is the run-time address at which the compiler expects
# see data. # see data.
# * LMA (Load memory address) is the address at which the linker stores 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 } >RAM AT> FLASH
# The fifth section contains zero-initialized variables. # The fifth section contains zero-initialized variables.
.bss : .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 = .; _sbss = .;
__bss_start__ = _sbss; __bss_start__ = _sbss;
# We indicate that in this section the .bss areas of all # We indicate that in this section the .bss areas of all
# object files # object files
*(.bss) *(.bss)
*(.bss*) *(.bss*)
# Align the current position to the border of 4 bytes. # Align the current position to the border of 4 bytes.
. = ALIGN(4); . = ALIGN(4);
# Save the address of the current position (beginning of the section) in the variable _ebss and __bss_end__ # 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: contributors:
- ["Alexander Kovalchuk", "https://github.com/Zamuhrishka"] - ["Alexander Kovalchuk", "https://github.com/Zamuhrishka"]
translators:
- ["Alexander Kovalchuk", "https://github.com/Zamuhrishka"]
--- ---
# Основные понятия и определения
**Счетчик позиций** - у компоновщика есть специальная переменная **Счетчик позиций** - у компоновщика есть специальная переменная
"." (точка) всегда содержит текущую позицию вывода. "`.`" (точка) всегда содержит текущую позицию вывода.
# Функции `ADDR(section)` - возвращает абсолютный адрес указанной секции. Однако
**ADDR(section)** - возвращает абсолютный адрес указанной секции. Однако
данная секция должна быть определенна до использования функции ADDR. данная секция должна быть определенна до использования функции ADDR.
**ALIGN(exp)** - возвращает значение счетчика позиций, выравненное на границу `ALIGN(exp)` - возвращает значение счетчика позиций, выравненное на границу
следующего за exp выражения. следующего за exp выражения.
**SIZEOF(section)** - возвращает размер секции в байтах. `SIZEOF(section)` - возвращает размер секции в байтах.
**FILL(param)** - определяет образец заполнения для текущей секции. Все `FILL(param)` - определяет образец заполнения для текущей секции. Все
остальные неуказанные регионы внутри секции заполняются значением указанными остальные неуказанные регионы внутри секции заполняются значением указанными
в аргументе функции. в аргументе функции.
**KEEP(param)** - используется чтобы помечать param как неустранимый. `KEEP(param)` - используется чтобы помечать param как неустранимый.
**ENTRY(func)** - определяет функцию, которая будет являться точкой входа `ENTRY(func)` - определяет функцию, которая будет являться точкой входа
в программу. в программу.
```bash ```bash
@ -41,7 +37,7 @@ _Min_Stack_Size = 0x400;
# Описание карты памяти доступной для данного процессора # Описание карты памяти доступной для данного процессора
# MEMORY # MEMORY
# { # {
# ИМЯ_ОБЛАСТИ_ПАМЯТИ (права доступа) : ORIGIN = АДРЕС_НАЧАЛА, LENGTH = РАЗМЕР # ИМЯ_ОБЛАСТИ_ПАМЯТИ (права доступа) : ORIGIN = АДРЕС_НАЧАЛА, LENGTH = РАЗМЕР
# } # }
# В нашем примере контроллер содержит три области памяти: # В нашем примере контроллер содержит три области памяти:
# RAM - начинается с адреса 0x20000000 и занимает 128 Кбайт; # RAM - начинается с адреса 0x20000000 и занимает 128 Кбайт;
@ -52,33 +48,33 @@ _Min_Stack_Size = 0x400;
# FLASH память доступна на чтение и исполнение. # FLASH память доступна на чтение и исполнение.
MEMORY MEMORY
{ {
RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 128K RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 128K
CCMRAM (rw) : ORIGIN = 0x10000000, LENGTH = 64K CCMRAM (rw) : ORIGIN = 0x10000000, LENGTH = 64K
FLASH (rx) : ORIGIN = 0x8000000, LENGTH = 1024K FLASH (rx) : ORIGIN = 0x8000000, LENGTH = 1024K
} }
# Описываем выходные секции # Описываем выходные секции
SECTIONS SECTIONS
{ {
# Первая секция содержит таблицу векторов прерываний # Первая секция содержит таблицу векторов прерываний
.isr_vector : .isr_vector :
{ {
# Выравниваем текущую позицию на границу 4-х байт. # Выравниваем текущую позицию на границу 4-х байт.
. = ALIGN(4); . = ALIGN(4);
# Существует опция --gc-sections, которая позволяет собирать мусор из неиспользуемых # Существует опция --gc-sections, которая позволяет собирать мусор из неиспользуемых
# входных разделов. И если есть разделы, которые сборщик мусора не должен трогать, # входных разделов. И если есть разделы, которые сборщик мусора не должен трогать,
# то их необходимо указать в качестве аргумента функции KEEP() (аналог ключевого слова # то их необходимо указать в качестве аргумента функции KEEP() (аналог ключевого слова
# volatile). # volatile).
# Запись (*(.isr_vector)) означает разделы .isr_vector во всех объектных файлах. Т.к. # Запись (*(.isr_vector)) означает разделы .isr_vector во всех объектных файлах. Т.к.
# обращение к разделу в общем виде выглядит так: (ИМЯ_ФАЙЛАМЯ_РАЗДЕЛА)) # обращение к разделу в общем виде выглядит так: (ИМЯ_ФАЙЛАМЯ_РАЗДЕЛА))
KEEP(*(.isr_vector)) KEEP(*(.isr_vector))
# Выравниваем текущую позицию на границу 4-х байт. # Выравниваем текущую позицию на границу 4-х байт.
. = ALIGN(4); . = ALIGN(4);
# Выражение ">ОБЛАСТЬАМЯТИ" указывает в какую именно область памяти будет помещена # Выражение ">ОБЛАСТЬАМЯТИ" указывает в какую именно область памяти будет помещена
# данная секция. В нашем случае секция .isr_vector будет размещена во FLASH памяти. # данная секция. В нашем случае секция .isr_vector будет размещена во FLASH памяти.
} >FLASH } >FLASH
# ИТОГО: Секция .isr_vector, которая содержит таблицу векторов прерываний выравнивается # ИТОГО: Секция .isr_vector, которая содержит таблицу векторов прерываний выравнивается
@ -88,96 +84,96 @@ SECTIONS
# Вторая секция содержит код программы. # Вторая секция содержит код программы.
.text : .text :
{ {
# Выравниваем текущую позицию на границу 4-х байт. # Выравниваем текущую позицию на границу 4-х байт.
. = ALIGN(4); . = ALIGN(4);
# Указываем, что в данной секции будут хранится области .text всех # Указываем, что в данной секции будут хранится области .text всех
# объектных файлов # объектных файлов
*(.text) *(.text)
*(.text*) *(.text*)
# Защищаем от сборщика мусора секции .init и .fini # Защищаем от сборщика мусора секции .init и .fini
KEEP (*(.init)) KEEP (*(.init))
KEEP (*(.fini)) KEEP (*(.fini))
# Выравниваем текущую позицию на границу 4-х байт. # Выравниваем текущую позицию на границу 4-х байт.
. = ALIGN(4); . = ALIGN(4);
# Определяется переменная _etext, которая хранит в себе адрес конца секции .text и которая # Определяется переменная _etext, которая хранит в себе адрес конца секции .text и которая
# может быть доступна в исходном тексте программы через объявление # может быть доступна в исходном тексте программы через объявление
# volaile unsigned int extern _etext; # volaile unsigned int extern _etext;
_etext = .; _etext = .;
} >FLASH } >FLASH
# ИТОГО: Секция .text, которая содержит код программы выравнивается по границе 4-х байт, # ИТОГО: Секция .text, которая содержит код программы выравнивается по границе 4-х байт,
# включает в себя: все секции с кодом программы во всех объектных файлах и защищенные # включает в себя: все секции с кодом программы во всех объектных файлах и защищенные
от сборщика муссора секции .init и .fini во всех объектных файлах, распологается во FLASH # от сборщика муссора секции .init и .fini во всех объектных файлах, распологается во FLASH
памяти микроконтроллера сразу за таблицей векторов. # памяти микроконтроллера сразу за таблицей векторов.
Секции text, .init и .fini. располагаются в памяти в той последовательности в которой они # Секции text, .init и .fini. располагаются в памяти в той последовательности в которой они
объявлены в скрипте. # объявлены в скрипте.
# Третья секция содержит константные данные. # Третья секция содержит константные данные.
.rodata : .rodata :
{ {
# Выравниваем текущую позицию на границу 4-х байт. # Выравниваем текущую позицию на границу 4-х байт.
. = ALIGN(4); . = ALIGN(4);
# Указываем, что в данной секции будут хранится области .rodata всех # Указываем, что в данной секции будут хранится области .rodata всех
# объектных файлов # объектных файлов
*(.rodata) *(.rodata)
*(.rodata*) *(.rodata*)
# Выравниваем текущую позицию на границу 4-х байт. # Выравниваем текущую позицию на границу 4-х байт.
. = ALIGN(4); . = ALIGN(4);
} >FLASH } >FLASH
# Сохраняем в переменной _sidata абсолютный адрес секции .data # Сохраняем в переменной _sidata абсолютный адрес секции .data
_sidata = LOADADDR(.data); _sidata = LOADADDR(.data);
# Четвертая секция содержит инициализированные переменные. # Четвертая секция содержит инициализированные переменные.
.data : .data :
{ {
# Выравниваем текущую позицию на границу 4-х байт. # Выравниваем текущую позицию на границу 4-х байт.
. = ALIGN(4); . = ALIGN(4);
# Сохраняем в переменной _sdata адрес текущей позиции (начала секции) # Сохраняем в переменной _sdata адрес текущей позиции (начала секции)
_sdata = .; _sdata = .;
# Указываем, что в данной секции будут хранится области .data всех # Указываем, что в данной секции будут хранится области .data всех
# объектных файлов # объектных файлов
*(.data) *(.data)
*(.data*) *(.data*)
# Выравниваем текущую позицию на границу 4-х байт. # Выравниваем текущую позицию на границу 4-х байт.
. = ALIGN(4); . = ALIGN(4);
# Сохраняем в переменной _sdata адрес текущей позиции (конец секции) # Сохраняем в переменной _sdata адрес текущей позиции (конец секции)
_edata = .; _edata = .;
# Функция AT указывает на то, что данный сектор хранится в одной области памяти # Функция AT указывает на то, что данный сектор хранится в одной области памяти
# (в нашем случае FLASH), а исполняться будет из другой области памяти (в нашем случае RAM). # (в нашем случае FLASH), а исполняться будет из другой области памяти (в нашем случае RAM).
# Есть два типа адресов: # Есть два типа адресов:
# * VMA (Virtual memory address) - это run-time адрес по которому компилятор ожидает # * VMA (Virtual memory address) - это run-time адрес по которому компилятор ожидает
# видеть данные. # видеть данные.
# * LMA (Load memory address) - это адрес по которому линкер хранит данные. # * LMA (Load memory address) - это адрес по которому линкер хранит данные.
#Startup должен код скопировать секцию .data из адресов LMA в адреса VMA. # Startup должен код скопировать секцию .data из адресов LMA в адреса VMA.
} >RAM AT> FLASH } >RAM AT> FLASH
# Пятая секция содержит инициализированные нулем переменные. # Пятая секция содержит инициализированные нулем переменные.
.bss : .bss :
{ {
# Сохраняем в переменной _sbss и __bss_start__ адрес текущей позиции (начала секции) # Сохраняем в переменной _sbss и __bss_start__ адрес текущей позиции (начала секции)
_sbss = .; _sbss = .;
__bss_start__ = _sbss; __bss_start__ = _sbss;
# Указываем, что в данной секции будут хранится области .bss всех # Указываем, что в данной секции будут хранится области .bss всех
# объектных файлов # объектных файлов
*(.bss) *(.bss)
*(.bss*) *(.bss*)
# Выравниваем текущую позицию на границу 4-х байт. # Выравниваем текущую позицию на границу 4-х байт.
. = ALIGN(4); . = ALIGN(4);
# Сохраняем в переменной _ebss и __bss_end__ адрес текущей позиции (начала секции) # Сохраняем в переменной _ebss и __bss_end__ адрес текущей позиции (начала секции)
@ -197,4 +193,3 @@ SECTIONS
} >RAM } >RAM
} }
``` ```