Счетчик позиций - у компоновщика есть специальная переменная
«.
» (точка) всегда содержит текущую позицию вывода.
ADDR(section)
- возвращает абсолютный адрес указанной секции. Однако
данная секция должна быть определенна до использования функции ADDR.
ALIGN(exp)
- возвращает значение счетчика позиций, выравненное на границу
следующего за exp выражения.
SIZEOF(section)
- возвращает размер секции в байтах.
FILL(param)
- определяет образец заполнения для текущей секции. Все
остальные неуказанные регионы внутри секции заполняются значением указанными
в аргументе функции.
KEEP(param)
- используется чтобы помечать param как неустранимый.
ENTRY(func)
- определяет функцию, которая будет являться точкой входа
в программу.
1# Определяем точку входа в программу
2ENTRY(Reset_Handler)
3
4# Определяем переменную которая содержит адрес вершины стека
5_estack = 0x20020000;
6# Определяем переменную которая содержит значение размера кучи
7_Min_Heap_Size = 0x200;
8# Определяем переменную которая содержит значение размера стека
9_Min_Stack_Size = 0x400;
10
11# Описание карты памяти доступной для данного процессора
12# MEMORY
13# {
14# ИМЯ_ОБЛАСТИ_ПАМЯТИ (права доступа) : ORIGIN = АДРЕС_НАЧАЛА, LENGTH = РАЗМЕР
15# }
16# В нашем примере контроллер содержит три области памяти:
17# RAM - начинается с адреса 0x20000000 и занимает 128 Кбайт;
18# CCMRAM - начинается с адреса 0x10000000и занимает 64 Кбайт;
19# FLASH - начинается с адреса 0x8000000 занимает 1024 Кбайт;
20# Причем RAM память доступна для чтения, записи и исполнения.
21# CCMRAM память доступна только на чтение и запись.
22# FLASH память доступна на чтение и исполнение.
23MEMORY
24{
25 RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 128K
26 CCMRAM (rw) : ORIGIN = 0x10000000, LENGTH = 64K
27 FLASH (rx) : ORIGIN = 0x8000000, LENGTH = 1024K
28}
29
30# Описываем выходные секции
31SECTIONS
32{
33 # Первая секция содержит таблицу векторов прерываний
34 .isr_vector :
35 {
36 # Выравниваем текущую позицию на границу 4-х байт.
37 . = ALIGN(4);
38
39 # Существует опция --gc-sections, которая позволяет собирать мусор из неиспользуемых
40 # входных разделов. И если есть разделы, которые сборщик мусора не должен трогать,
41 # то их необходимо указать в качестве аргумента функции KEEP() (аналог ключевого слова
42 # volatile).
43 # Запись (*(.isr_vector)) означает разделы .isr_vector во всех объектных файлах. Т.к.
44 # обращение к разделу в общем виде выглядит так: (ИМЯ_ФАЙЛА(ИМЯ_РАЗДЕЛА))
45 KEEP(*(.isr_vector))
46
47 # Выравниваем текущую позицию на границу 4-х байт.
48 . = ALIGN(4);
49
50 # Выражение ">ОБЛАСТЬ_ПАМЯТИ" указывает в какую именно область памяти будет помещена
51 # данная секция. В нашем случае секция .isr_vector будет размещена во FLASH памяти.
52 } >FLASH
53
54# ИТОГО: Секция .isr_vector, которая содержит таблицу векторов прерываний выравнивается
55# по границе 4-х байт, помечается как недоступная для сборщика мусора и размещается в начале
56# FLASH памяти микроконтроллера.
57
58 # Вторая секция содержит код программы.
59 .text :
60 {
61 # Выравниваем текущую позицию на границу 4-х байт.
62 . = ALIGN(4);
63
64 # Указываем, что в данной секции будут хранится области .text всех
65 # объектных файлов
66 *(.text)
67 *(.text*)
68
69 # Защищаем от сборщика мусора секции .init и .fini
70 KEEP (*(.init))
71 KEEP (*(.fini))
72
73 # Выравниваем текущую позицию на границу 4-х байт.
74 . = ALIGN(4);
75
76 # Определяется переменная _etext, которая хранит в себе адрес конца секции .text и которая
77 # может быть доступна в исходном тексте программы через объявление
78 # volaile unsigned int extern _etext;
79 _etext = .;
80 } >FLASH
81
82# ИТОГО: Секция .text, которая содержит код программы выравнивается по границе 4-х байт,
83# включает в себя: все секции с кодом программы во всех объектных файлах и защищенные
84# от сборщика муссора секции .init и .fini во всех объектных файлах, распологается во FLASH
85# памяти микроконтроллера сразу за таблицей векторов.
86# Секции text, .init и .fini. располагаются в памяти в той последовательности в которой они
87# объявлены в скрипте.
88
89 # Третья секция содержит константные данные.
90 .rodata :
91 {
92 # Выравниваем текущую позицию на границу 4-х байт.
93 . = ALIGN(4);
94
95 # Указываем, что в данной секции будут хранится области .rodata всех
96 # объектных файлов
97 *(.rodata)
98 *(.rodata*)
99
100 # Выравниваем текущую позицию на границу 4-х байт.
101 . = ALIGN(4);
102 } >FLASH
103
104 # Сохраняем в переменной _sidata абсолютный адрес секции .data
105 _sidata = LOADADDR(.data);
106
107 # Четвертая секция содержит инициализированные переменные.
108 .data :
109 {
110 # Выравниваем текущую позицию на границу 4-х байт.
111 . = ALIGN(4);
112
113 # Сохраняем в переменной _sdata адрес текущей позиции (начала секции)
114 _sdata = .;
115
116 # Указываем, что в данной секции будут хранится области .data всех
117 # объектных файлов
118 *(.data)
119 *(.data*)
120
121 # Выравниваем текущую позицию на границу 4-х байт.
122 . = ALIGN(4);
123
124 # Сохраняем в переменной _sdata адрес текущей позиции (конец секции)
125 _edata = .;
126
127 # Функция AT указывает на то, что данный сектор хранится в одной области памяти
128 # (в нашем случае FLASH), а исполняться будет из другой области памяти (в нашем случае RAM).
129 # Есть два типа адресов:
130 # * VMA (Virtual memory address) - это run-time адрес по которому компилятор ожидает
131 # видеть данные.
132 # * LMA (Load memory address) - это адрес по которому линкер хранит данные.
133
134 # Startup должен код скопировать секцию .data из адресов LMA в адреса VMA.
135
136 } >RAM AT> FLASH
137
138 # Пятая секция содержит инициализированные нулем переменные.
139 .bss :
140 {
141 # Сохраняем в переменной _sbss и __bss_start__ адрес текущей позиции (начала секции)
142 _sbss = .;
143 __bss_start__ = _sbss;
144
145 # Указываем, что в данной секции будут хранится области .bss всех
146 # объектных файлов
147 *(.bss)
148 *(.bss*)
149
150 # Выравниваем текущую позицию на границу 4-х байт.
151 . = ALIGN(4);
152
153 # Сохраняем в переменной _ebss и __bss_end__ адрес текущей позиции (начала секции)
154 _ebss = .;
155 __bss_end__ = _ebss;
156 } >RAM
157
158 # Шестая секция содержит кучу и стек. Размещается в самом конце RAM.
159 ._user_heap_stack :
160 {
161 . = ALIGN(4);
162 PROVIDE ( end = . );
163 PROVIDE ( _end = . );
164 . = . + _Min_Heap_Size;
165 . = . + _Min_Stack_Size;
166 . = ALIGN(4);
167 } >RAM
168}