1# ToDo:
2# - Ensure LMA / VMA sections are correctly grouped similar to scatter file creation.
3cmake_minimum_required(VERSION 3.18)
4
5set(SORT_TYPE_NAME SORT_BY_NAME)
6
7function(system_to_string)
8  cmake_parse_arguments(STRING "" "OBJECT;STRING" "" ${ARGN})
9
10  get_property(name    GLOBAL PROPERTY ${STRING_OBJECT}_NAME)
11  get_property(regions GLOBAL PROPERTY ${STRING_OBJECT}_REGIONS)
12  get_property(format  GLOBAL PROPERTY ${STRING_OBJECT}_FORMAT)
13  get_property(entry   GLOBAL PROPERTY ${STRING_OBJECT}_ENTRY)
14  get_property(symbols GLOBAL PROPERTY ${STRING_OBJECT}_SYMBOLS)
15
16  set(${STRING_STRING} "OUTPUT_FORMAT(\"${format}\")\n\n")
17
18  set(${STRING_STRING} "${${STRING_STRING}}MEMORY\n{\n")
19  foreach(region ${regions})
20    get_property(name    GLOBAL PROPERTY ${region}_NAME)
21    get_property(address GLOBAL PROPERTY ${region}_ADDRESS)
22    get_property(flags   GLOBAL PROPERTY ${region}_FLAGS)
23    get_property(size    GLOBAL PROPERTY ${region}_SIZE)
24
25    if(DEFINED flags)
26      set(flags "(${flags})")
27    endif()
28
29    if(DEFINED address)
30      set(start ": ORIGIN = (${address})")
31    endif()
32
33    if(DEFINED size)
34      set(size ", LENGTH = (${size})")
35    endif()
36    set(memory_region "  ${name} ${flags} ${start}${size}")
37
38    set(${STRING_STRING} "${${STRING_STRING}}${memory_region}\n")
39  endforeach()
40
41  set(${STRING_STRING} "${${STRING_STRING}}}\n\n")
42
43  set(${STRING_STRING} "${${STRING_STRING}}ENTRY(\"${entry}\")\n\n")
44
45  set(${STRING_STRING} "${${STRING_STRING}}SECTIONS\n{")
46  foreach(region ${regions})
47    to_string(OBJECT ${region} STRING ${STRING_STRING})
48  endforeach()
49
50  get_property(sections GLOBAL PROPERTY ${STRING_OBJECT}_SECTIONS_FIXED)
51  foreach(section ${sections})
52    to_string(OBJECT ${section} STRING ${STRING_STRING})
53  endforeach()
54
55  get_property(sections GLOBAL PROPERTY ${STRING_OBJECT}_SECTIONS)
56  foreach(section ${sections})
57    to_string(OBJECT ${section} STRING ${STRING_STRING})
58  endforeach()
59
60  foreach(symbol ${symbols})
61    to_string(OBJECT ${symbol} STRING ${STRING_STRING})
62  endforeach()
63
64  set(${STRING_STRING} "${${STRING_STRING}}\n}\n" PARENT_SCOPE)
65endfunction()
66
67function(symbol_to_string)
68  cmake_parse_arguments(STRING "" "SYMBOL;STRING" "" ${ARGN})
69
70  get_property(name     GLOBAL PROPERTY ${STRING_SYMBOL}_NAME)
71  get_property(expr     GLOBAL PROPERTY ${STRING_SYMBOL}_EXPR)
72  get_property(size     GLOBAL PROPERTY ${STRING_SYMBOL}_SIZE)
73  get_property(symbol   GLOBAL PROPERTY ${STRING_SYMBOL}_SYMBOL)
74  get_property(subalign GLOBAL PROPERTY ${STRING_SYMBOL}_SUBALIGN)
75
76  string(REPLACE "\\" "" expr "${expr}")
77  string(REGEX MATCHALL "%([^%]*)%" match_res ${expr})
78
79  foreach(match ${match_res})
80    string(REPLACE "%" "" match ${match})
81    string(REPLACE "%${match}%" "${match}" expr ${expr})
82  endforeach()
83
84  set(${STRING_STRING} "${${STRING_STRING}}\n${symbol} = ${expr};\n" PARENT_SCOPE)
85endfunction()
86
87function(group_to_string)
88  cmake_parse_arguments(STRING "" "OBJECT;STRING" "" ${ARGN})
89
90  get_property(type GLOBAL PROPERTY ${STRING_OBJECT}_OBJ_TYPE)
91  if(${type} STREQUAL REGION)
92    get_property(empty GLOBAL PROPERTY ${STRING_OBJECT}_EMPTY)
93    if(empty)
94      return()
95    endif()
96
97    get_property(address GLOBAL PROPERTY ${STRING_OBJECT}_ADDRESS)
98    set(${STRING_STRING} "${${STRING_STRING}}\n  . = ${address};\n\n")
99  else()
100    get_property(name GLOBAL PROPERTY ${STRING_OBJECT}_NAME)
101    get_property(symbol GLOBAL PROPERTY ${STRING_OBJECT}_SYMBOL)
102    string(TOLOWER ${name} name)
103
104    get_objects(LIST sections OBJECT ${STRING_OBJECT} TYPE SECTION)
105    list(GET sections 0 section)
106    get_property(first_section_name GLOBAL PROPERTY ${section}_NAME)
107
108    if(DEFINED first_section_name AND "${symbol}" STREQUAL "SECTION")
109      set_property(GLOBAL APPEND PROPERTY ${section}_START_SYMBOLS __${name}_start)
110    else()
111      set(${STRING_STRING} "${${STRING_STRING}}\n  __${name}_start = .;\n")
112    endif()
113
114    set(${STRING_STRING} "${${STRING_STRING}}\n  __${name}_size = __${name}_end - __${name}_start;\n")
115    set(${STRING_STRING} "${${STRING_STRING}}\n  __${name}_load_start = LOADADDR(${first_section_name});\n")
116  endif()
117
118  get_property(sections GLOBAL PROPERTY ${STRING_OBJECT}_SECTIONS_FIXED)
119  foreach(section ${sections})
120    to_string(OBJECT ${section} STRING ${STRING_STRING})
121  endforeach()
122
123  get_property(groups GLOBAL PROPERTY ${STRING_OBJECT}_GROUPS)
124  foreach(group ${groups})
125    to_string(OBJECT ${group} STRING ${STRING_STRING})
126  endforeach()
127
128  get_property(sections GLOBAL PROPERTY ${STRING_OBJECT}_SECTIONS)
129  foreach(section ${sections})
130    to_string(OBJECT ${section} STRING ${STRING_STRING})
131  endforeach()
132
133  get_parent(OBJECT ${STRING_OBJECT} PARENT parent TYPE SYSTEM)
134  get_property(regions GLOBAL PROPERTY ${parent}_REGIONS)
135  list(REMOVE_ITEM regions ${STRING_OBJECT})
136  foreach(region ${regions})
137    if(${type} STREQUAL REGION)
138      get_property(address GLOBAL PROPERTY ${region}_ADDRESS)
139      set(${STRING_STRING} "${${STRING_STRING}}\n  . = ${address};\n\n")
140    endif()
141
142    get_property(vma GLOBAL PROPERTY ${region}_NAME)
143    get_property(sections GLOBAL PROPERTY ${STRING_OBJECT}_${vma}_SECTIONS_FIXED)
144    foreach(section ${sections})
145      to_string(OBJECT ${section} STRING ${STRING_STRING})
146    endforeach()
147
148    get_property(groups GLOBAL PROPERTY ${STRING_OBJECT}_${vma}_GROUPS)
149    foreach(group ${groups})
150      to_string(OBJECT ${group} STRING ${STRING_STRING})
151    endforeach()
152
153    get_property(sections GLOBAL PROPERTY ${STRING_OBJECT}_${vma}_SECTIONS)
154    foreach(section ${sections})
155      to_string(OBJECT ${section} STRING ${STRING_STRING})
156    endforeach()
157  endforeach()
158
159  if(NOT ${type} STREQUAL REGION)
160    set(${STRING_STRING} "${${STRING_STRING}}\n  __${name}_end = .;\n")
161  endif()
162
163  get_property(symbols GLOBAL PROPERTY ${STRING_OBJECT}_SYMBOLS)
164  foreach(symbol ${symbols})
165    to_string(OBJECT ${symbol} STRING ${STRING_STRING})
166  endforeach()
167
168  set(${STRING_STRING} ${${STRING_STRING}} PARENT_SCOPE)
169endfunction()
170
171function(section_to_string)
172  cmake_parse_arguments(STRING "" "SECTION;STRING" "" ${ARGN})
173
174  get_property(name       GLOBAL PROPERTY ${STRING_SECTION}_NAME)
175  get_property(name_clean GLOBAL PROPERTY ${STRING_SECTION}_NAME_CLEAN)
176  get_property(address    GLOBAL PROPERTY ${STRING_SECTION}_ADDRESS)
177  get_property(type       GLOBAL PROPERTY ${STRING_SECTION}_TYPE)
178  get_property(align_in   GLOBAL PROPERTY ${STRING_SECTION}_ALIGN_WITH_INPUT)
179  get_property(align      GLOBAL PROPERTY ${STRING_SECTION}_ALIGN)
180  get_property(subalign   GLOBAL PROPERTY ${STRING_SECTION}_SUBALIGN)
181  get_property(vma        GLOBAL PROPERTY ${STRING_SECTION}_VMA)
182  get_property(lma        GLOBAL PROPERTY ${STRING_SECTION}_LMA)
183  get_property(noinput    GLOBAL PROPERTY ${STRING_SECTION}_NOINPUT)
184  get_property(noinit     GLOBAL PROPERTY ${STRING_SECTION}_NOINIT)
185  get_property(nosymbols  GLOBAL PROPERTY ${STRING_SECTION}_NOSYMBOLS)
186  get_property(parent     GLOBAL PROPERTY ${STRING_SECTION}_PARENT)
187  get_property(start_syms GLOBAL PROPERTY ${STRING_SECTION}_START_SYMBOLS)
188
189  string(REGEX REPLACE "^[\.]" "" name_clean "${name}")
190  string(REPLACE "." "_" name_clean "${name_clean}")
191
192  set(SECTION_TYPE_NOLOAD NOLOAD)
193  set(SECTION_TYPE_BSS    NOLOAD)
194  if(DEFINED type)
195    set(type " (${SECTION_TYPE_${type}})")
196  endif()
197
198  set(TEMP "${TEMP} :")
199  set(secalign "")
200
201  if(align_in)
202    set(secalign " ALIGN_WITH_INPUT")
203  endif()
204
205  if(DEFINED align)
206    set(secalign "${secalign} ALIGN(${align})")
207  endif()
208
209  if(DEFINED subalign)
210    set(secalign "${secalign} SUBALIGN(${subalign})")
211  endif()
212
213  set(TEMP "${name} ${address}${type} :${secalign}\n{")
214
215  foreach(start_symbol ${start_syms})
216    set(TEMP "${TEMP}\n  ${start_symbol} = .;")
217  endforeach()
218
219  if(NOT nosymbols)
220    set(TEMP "${TEMP}\n  __${name_clean}_start = .;")
221  endif()
222
223  if(NOT noinput)
224    set(TEMP "${TEMP}\n  *(${name})")
225    set(TEMP "${TEMP}\n  *(\"${name}.*\")")
226  endif()
227
228  get_property(indicies GLOBAL PROPERTY ${STRING_SECTION}_SETTINGS_INDICIES)
229  foreach(idx ${indicies})
230    get_property(align    GLOBAL PROPERTY ${STRING_SECTION}_SETTING_${idx}_ALIGN)
231    get_property(any      GLOBAL PROPERTY ${STRING_SECTION}_SETTING_${idx}_ANY)
232    get_property(first    GLOBAL PROPERTY ${STRING_SECTION}_SETTING_${idx}_FIRST)
233    get_property(keep     GLOBAL PROPERTY ${STRING_SECTION}_SETTING_${idx}_KEEP)
234    get_property(sort     GLOBAL PROPERTY ${STRING_SECTION}_SETTING_${idx}_SORT)
235    get_property(flags    GLOBAL PROPERTY ${STRING_SECTION}_SETTING_${idx}_FLAGS)
236    get_property(input    GLOBAL PROPERTY ${STRING_SECTION}_SETTING_${idx}_INPUT)
237    get_property(symbols  GLOBAL PROPERTY ${STRING_SECTION}_SETTING_${idx}_SYMBOLS)
238    get_property(offset   GLOBAL PROPERTY ${STRING_SECTION}_SETTING_${idx}_OFFSET)
239
240    if(DEFINED SETTINGS_ALIGN)
241      set(TEMP "${TEMP}\n  . = ALIGN(${align});")
242    endif()
243
244    if(DEFINED symbols)
245      list(LENGTH symbols symbols_count)
246      if(${symbols_count} GREATER 0)
247        list(GET symbols 0 symbol_start)
248      endif()
249      if(${symbols_count} GREATER 1)
250        list(GET symbols 1 symbol_end)
251      endif()
252    endif()
253
254    if(DEFINED symbol_start)
255      set(TEMP "${TEMP}\n  ${symbol_start} = .;")
256    endif()
257
258    foreach(setting ${input})
259      if(DEFINED offset AND NOT ("${offset}" STREQUAL "${current_offset}"))
260        set(TEMP "${TEMP}\n  . = ${offset};")
261        set(current_offset ${offset})
262      endif()
263
264      if(keep AND sort)
265        set(TEMP "${TEMP}\n  KEEP(*(${SORT_TYPE_${sort}}(${setting})));")
266      elseif(SETTINGS_SORT)
267        message(WARNING "Not tested")
268        set(TEMP "${TEMP}\n  *(${SORT_TYPE_${sort}}(${setting}));")
269      elseif(keep)
270        set(TEMP "${TEMP}\n  KEEP(*(${setting}));")
271      else()
272        set(TEMP "${TEMP}\n  *(${setting})")
273      endif()
274    endforeach()
275
276    if(DEFINED symbol_end)
277      set(TEMP "${TEMP}\n  ${symbol_end} = .;")
278    endif()
279
280    set(symbol_start)
281    set(symbol_end)
282  endforeach()
283
284  if(NOT nosymbols)
285    set(TEMP "${TEMP}\n  __${name_clean}_end = .;")
286  endif()
287
288  if(DEFINED extra_symbol_end)
289    set(TEMP "${TEMP}\n  ${extra_symbol_end} = .;")
290  endif()
291
292  set(TEMP "${TEMP}\n}")
293
294  get_property(parent_type GLOBAL PROPERTY ${parent}_OBJ_TYPE)
295  if(${parent_type} STREQUAL GROUP)
296    get_property(vma GLOBAL PROPERTY ${parent}_VMA)
297    get_property(lma GLOBAL PROPERTY ${parent}_LMA)
298  endif()
299
300  if(DEFINED vma)
301    set(TEMP "${TEMP} > ${vma}")
302  endif()
303
304  if(DEFINED vma AND DEFINED lma)
305    set(TEMP "${TEMP} AT")
306  endif()
307
308  if(DEFINED lma)
309    set(TEMP "${TEMP} > ${lma}")
310  endif()
311
312  if(NOT nosymbols)
313    set(TEMP "${TEMP}\n__${name_clean}_size = __${name_clean}_end - __${name_clean}_start;")
314    set(TEMP "${TEMP}\n__${name_clean}_load_start = LOADADDR(${name});")
315  endif()
316
317  set(${STRING_STRING} "${${STRING_STRING}}\n${TEMP}\n" PARENT_SCOPE)
318endfunction()
319
320# /DISCARD/ is an ld specific section, so let's append it here before processing.
321list(APPEND SECTIONS "{NAME\;/DISCARD/\;NOINPUT\;TRUE\;NOSYMBOLS\;TRUE}")
322
323function(process_region)
324  cmake_parse_arguments(REGION "" "OBJECT" "" ${ARGN})
325
326  process_region_common(${ARGN})
327
328  set(groups)
329  get_objects(LIST groups OBJECT ${REGION_OBJECT} TYPE GROUP)
330  foreach(group ${groups})
331    get_property(parent GLOBAL PROPERTY ${group}_PARENT)
332    get_property(parent_type GLOBAL PROPERTY ${parent}_OBJ_TYPE)
333
334    if(${parent_type} STREQUAL GROUP)
335      get_property(vma GLOBAL PROPERTY ${parent}_VMA)
336      get_property(lma GLOBAL PROPERTY ${parent}_LMA)
337
338      set_property(GLOBAL PROPERTY ${group}_VMA ${vma})
339      set_property(GLOBAL PROPERTY ${group}_LMA ${lma})
340    endif()
341  endforeach()
342endfunction()
343
344include(${CMAKE_CURRENT_LIST_DIR}/../linker_script_common.cmake)
345