1 # Copyright (c) 2025 IAR Systems AB
2 #
3 # SPDX-License-Identifier: Apache-2.0
4 
5 cmake_minimum_required(VERSION 3.17)
6 
7 set(SORT_TYPE_NAME Lexical)
8 
9 set_property(GLOBAL PROPERTY ILINK_REGION_SYMBOL_ICF)
10 
11 # This function post process the region for easier use.
12 #
13 # Tasks:
14 # - Symbol translation using a steering file is configured.
15 function(process_region)
16   cmake_parse_arguments(REGION "" "OBJECT" "" ${ARGN})
17 
18   process_region_common(${ARGN})
19 
20   get_property(empty GLOBAL PROPERTY ${REGION_OBJECT}_EMPTY)
21   if(NOT empty)
22     # For scatter files we move any system symbols into first non-empty load section.
23     get_parent(OBJECT ${REGION_OBJECT} PARENT parent TYPE SYSTEM)
24     get_property(symbols GLOBAL PROPERTY ${parent}_SYMBOLS)
25     set_property(GLOBAL APPEND PROPERTY ${REGION_OBJECT}_SYMBOLS ${symbols})
26     set_property(GLOBAL PROPERTY ${parent}_SYMBOLS)
27   endif()
28 
29   get_property(sections GLOBAL PROPERTY ${REGION_OBJECT}_SECTION_LIST_ORDERED)
30   foreach(section ${sections})
31 
32     get_property(name       GLOBAL PROPERTY ${section}_NAME)
33     get_property(name_clean GLOBAL PROPERTY ${section}_NAME_CLEAN)
34     get_property(noinput    GLOBAL PROPERTY ${section}_NOINPUT)
35     get_property(type       GLOBAL PROPERTY ${section}_TYPE)
36     get_property(nosymbols  GLOBAL PROPERTY ${section}_NOSYMBOLS)
37 
38     if(NOT nosymbols)
39       if(${name} STREQUAL .ramfunc)
40         create_symbol(OBJECT ${REGION_OBJECT} SYMBOL __${name_clean}_load_start
41           EXPR "@ADDR(.ramfunc_init)@"
42           )
43       else()
44         create_symbol(OBJECT ${REGION_OBJECT} SYMBOL __${name_clean}_load_start
45           EXPR "@LOADADDR(${name_clean})@"
46           )
47       endif()
48     endif()
49 
50     get_property(indicies GLOBAL PROPERTY ${section}_SETTINGS_INDICIES)
51     list(LENGTH indicies length)
52     foreach(idx ${indicies})
53       set(steering_postfixes Base Limit)
54       get_property(symbols GLOBAL PROPERTY ${section}_SETTING_${idx}_SYMBOLS)
55       get_property(sort    GLOBAL PROPERTY ${section}_SETTING_${idx}_SORT)
56       get_property(offset  GLOBAL PROPERTY ${section}_SETTING_${idx}_OFFSET)
57       if(DEFINED offset AND NOT offset EQUAL 0 )
58         # Same behavior as in section_to_string
59       elseif(DEFINED offset AND offset STREQUAL 0 )
60         # Same behavior as in section_to_string
61       elseif(sort)
62         # Treated by labels in the icf or image symbols.
63       elseif(DEFINED symbols AND ${length} EQUAL 1 AND noinput)
64       endif()
65     endforeach()
66 
67     # Symbols translation here.
68 
69     get_property(symbol_val GLOBAL PROPERTY SYMBOL_TABLE___${name_clean}_end)
70 
71     if("${symbol_val}" STREQUAL "${name_clean}")
72       create_symbol(OBJECT ${REGION_OBJECT} SYMBOL __${name_clean}_size
73         EXPR "@SIZE(${name_clean})@"
74         )
75     else()
76       # These seem to be thing that can't be transformed to $$Length
77       set_property(GLOBAL APPEND PROPERTY ILINK_REGION_SYMBOL_ICF
78         "define image symbol __${name_clean}_size = (__${symbol_val} - ADDR(${name_clean}))")
79     endif()
80     set(ZI)
81 
82     if(${name_clean} STREQUAL last_ram_section)
83       # A trick to add the symbol for the nxp devices
84       # _flash_used = LOADADDR(.last_section) + SIZEOF(.last_section) - __rom_region_start;
85       create_symbol(OBJECT ${REGION_OBJECT} SYMBOL _flash_used
86         EXPR "(@LOADADDR(last_section)@ + @SIZE(last_section)@ - @__rom_region_start@)"
87         )
88     endif()
89 
90     if(${name_clean} STREQUAL rom_start)
91       # The below two symbols is meant to make aliases to the _vector_table symbol.
92       list(GET symbols 0 symbol_start)
93       create_symbol(OBJECT ${REGION_OBJECT} SYMBOL __Vectors
94         EXPR "@ADDR(${symbol_start})@"
95         )
96       create_symbol(OBJECT ${REGION_OBJECT} SYMBOL __vector_table
97         EXPR "@ADDR(${symbol_start})@"
98         )
99     endif()
100 
101   endforeach()
102 
103   get_property(groups GLOBAL PROPERTY ${REGION_OBJECT}_GROUP_LIST_ORDERED)
104   foreach(group ${groups})
105     get_property(name GLOBAL PROPERTY ${group}_NAME)
106     string(TOLOWER ${name} name)
107 
108     get_property(group_type  GLOBAL PROPERTY ${group}_OBJ_TYPE)
109     get_property(parent      GLOBAL PROPERTY ${group}_PARENT)
110     get_property(parent_type GLOBAL PROPERTY ${parent}_OBJ_TYPE)
111     # Need to find the init manually group or parent
112     if(${parent_type} STREQUAL GROUP)
113       get_property(vma GLOBAL PROPERTY ${parent}_VMA)
114       get_property(lma GLOBAL PROPERTY ${parent}_LMA)
115     else()
116       get_property(vma GLOBAL PROPERTY ${group}_VMA)
117       get_property(lma GLOBAL PROPERTY ${group}_LMA)
118     endif()
119 
120     get_objects(LIST sections OBJECT ${group} TYPE SECTION)
121     list(GET sections 0 section)
122     get_property(first_section_name GLOBAL PROPERTY ${section}_NAME_CLEAN)
123     list(POP_BACK sections section)
124     get_property(last_section_name GLOBAL PROPERTY ${section}_NAME_CLEAN)
125 
126     if(DEFINED vma AND DEFINED lma)
127       # Something to init
128       create_symbol(OBJECT ${REGION_OBJECT} SYMBOL __${name}_load_start
129         EXPR "@ADDR(${first_section_name}_init)@"
130         )
131     else()
132       create_symbol(OBJECT ${REGION_OBJECT} SYMBOL __${name}_load_start
133         EXPR "@LOADADDR(${first_section_name})@"
134         )
135     endif()
136 
137     create_symbol(OBJECT ${REGION_OBJECT} SYMBOL __${name}_start
138       EXPR "@ADDR(${first_section_name})@"
139       )
140     create_symbol(OBJECT ${REGION_OBJECT} SYMBOL __${name}_end
141       EXPR "@END(${last_section_name})@"
142       )
143     create_symbol(OBJECT ${REGION_OBJECT} SYMBOL __${name}_size
144       EXPR "(@(__${name}_end)@ - @(__${name}_start)@)"
145       )
146 
147   endforeach()
148 
149   get_property(symbols GLOBAL PROPERTY ${REGION_OBJECT}_SYMBOLS)
150   foreach(symbol ${symbols})
151     get_property(name GLOBAL PROPERTY ${symbol}_NAME)
152     get_property(expr GLOBAL PROPERTY ${symbol}_EXPR)
153     if(NOT DEFINED expr)
154       create_symbol(OBJECT ${REGION_OBJECT} SYMBOL __${name}_size
155         EXPR "@(ADDR(${name})@"
156         )
157     endif()
158   endforeach()
159 
160   # This is only a trick to get the memories
161   set(groups)
162   get_objects(LIST groups OBJECT ${REGION_OBJECT} TYPE GROUP)
163   foreach(group ${groups})
164     get_property(group_type  GLOBAL PROPERTY ${group}_OBJ_TYPE)
165     get_property(parent      GLOBAL PROPERTY ${group}_PARENT)
166     get_property(parent_type GLOBAL PROPERTY ${parent}_OBJ_TYPE)
167 
168     if(${group_type} STREQUAL GROUP)
169       get_property(group_name GLOBAL PROPERTY ${group}_NAME)
170       get_property(group_lma  GLOBAL PROPERTY ${group}_LMA)
171       if(${group_name} STREQUAL ROM_REGION)
172         set_property(GLOBAL PROPERTY ILINK_ROM_REGION_NAME ${group_lma})
173       endif()
174     endif()
175 
176     if(${parent_type} STREQUAL GROUP)
177       get_property(vma GLOBAL PROPERTY ${parent}_VMA)
178       get_property(lma GLOBAL PROPERTY ${parent}_LMA)
179 
180       set_property(GLOBAL PROPERTY ${group}_VMA ${vma})
181       set_property(GLOBAL PROPERTY ${group}_LMA ${lma})
182     endif()
183   endforeach()
184 
185 endfunction()
186 
187 #
188 # String functions - start
189 #
190 
191 function(system_to_string)
192   cmake_parse_arguments(STRING "" "OBJECT;STRING" "" ${ARGN})
193 
194   get_property(name    GLOBAL PROPERTY ${STRING_OBJECT}_NAME)
195   get_property(regions GLOBAL PROPERTY ${STRING_OBJECT}_REGIONS)
196   get_property(format  GLOBAL PROPERTY ${STRING_OBJECT}_FORMAT)
197 
198   # Ilink specials
199   # set(${STRING_STRING} "build for rom;\n")
200   set(${STRING_STRING} "build for ram;\n")
201   if("${format}" MATCHES "aarch64")
202     set(${STRING_STRING} "${${STRING_STRING}}define memory mem with size = 16E;\n")
203   else()
204     set(${STRING_STRING} "${${STRING_STRING}}define memory mem with size = 4G;\n")
205   endif()
206 
207   foreach(region ${regions})
208     get_property(name    GLOBAL PROPERTY ${region}_NAME)
209     get_property(address GLOBAL PROPERTY ${region}_ADDRESS)
210     get_property(flags   GLOBAL PROPERTY ${region}_FLAGS)
211     get_property(size    GLOBAL PROPERTY ${region}_SIZE)
212 
213     if(DEFINED flags)
214       if(${flags} STREQUAL rx)
215         set(flags " rom")
216       elseif(${flags} STREQUAL ro)
217         set(flags " rom")
218       elseif(${flags} STREQUAL wx)
219         set(flags " ram")
220       elseif(${flags} STREQUAL rw)
221         set(flags " ram")
222       endif()
223     endif()
224 
225     if(${name} STREQUAL IDT_LIST)
226       # Need to use a untyped region for IDT_LIST
227       set(flags "")
228     endif()
229 
230     if(DEFINED address)
231       set(start "${address}")
232     endif()
233 
234     if(DEFINED size)
235       set(size "${size}")
236     endif()
237     # define rom region FLASH    = mem:[from 0x0 size 0x40000];
238     set(memory_region "define${flags} region ${name} = mem:[from ${start} size ${size}];")
239 
240     set(${STRING_STRING} "${${STRING_STRING}}${memory_region}\n")
241     set(flags)
242   endforeach()
243 
244   set(${STRING_STRING} "${${STRING_STRING}}\n\n")
245   set_property(GLOBAL PROPERTY ILINK_SYMBOL_ICF)
246 
247   set(${STRING_STRING} "${${STRING_STRING}}\n")
248   foreach(region ${regions})
249     get_property(empty GLOBAL PROPERTY ${region}_EMPTY)
250     if(NOT empty)
251       get_property(name    GLOBAL PROPERTY ${region}_NAME)
252       set(ILINK_CURRENT_NAME ${name})
253       to_string(OBJECT ${region} STRING ${STRING_STRING})
254       set(ILINK_CURRENT_NAME)
255     endif()
256   endforeach()
257   set(${STRING_STRING} "${${STRING_STRING}}\n")
258 
259   get_property(symbols_icf GLOBAL PROPERTY ILINK_SYMBOL_ICF)
260   foreach(image_symbol ${symbols_icf})
261     set(${STRING_STRING} "${${STRING_STRING}}define image symbol ${image_symbol};\n")
262   endforeach()
263 
264   get_property(symbols_icf GLOBAL PROPERTY ILINK_REGION_SYMBOL_ICF)
265   set(${STRING_STRING} "${${STRING_STRING}}\n")
266   foreach(image_symbol ${symbols_icf})
267     set(${STRING_STRING} "${${STRING_STRING}}${image_symbol};\n")
268   endforeach()
269 
270   if(IAR_LIBC)
271     set(${STRING_STRING} "${${STRING_STRING}}if (K_HEAP_MEM_POOL_SIZE>0)\n{\n")
272     set(${STRING_STRING} "${${STRING_STRING}}  define block HEAP with alignment=8 { symbol kheap__system_heap };\n")
273     set(${STRING_STRING} "${${STRING_STRING}}}\nelse\n{\n")
274     set(${STRING_STRING} "${${STRING_STRING}}  define block HEAP with alignment=8, expanding size { };\n")
275     set(${STRING_STRING} "${${STRING_STRING}}}\n")
276     set(${STRING_STRING} "${${STRING_STRING}}\"DLib heap\": place in RAM { block HEAP };\n")
277 #    set(${STRING_STRING} "${${STRING_STRING}}define exported symbol HEAP$$Base=kheap__system_heap;\n")
278 #    set(${STRING_STRING} "${${STRING_STRING}}define exported symbol HEAP$$Limit=END(kheap__system_heap);\n")
279   endif()
280 
281   set(${STRING_STRING} ${${STRING_STRING}} PARENT_SCOPE)
282 endfunction()
283 
284 function(group_to_string)
285   cmake_parse_arguments(STRING "" "OBJECT;STRING" "" ${ARGN})
286 
287   get_property(type GLOBAL PROPERTY ${STRING_OBJECT}_OBJ_TYPE)
288   if(${type} STREQUAL REGION)
289     get_property(name GLOBAL PROPERTY ${STRING_OBJECT}_NAME)
290     get_property(address GLOBAL PROPERTY ${STRING_OBJECT}_ADDRESS)
291     get_property(size GLOBAL PROPERTY ${STRING_OBJECT}_SIZE)
292 
293     get_property(empty GLOBAL PROPERTY ${STRING_OBJECT}_EMPTY)
294     if(empty)
295       return()
296     endif()
297 
298   else()
299     get_property(else_name GLOBAL PROPERTY ${STRING_OBJECT}_NAME)
300     get_property(else_symbol GLOBAL PROPERTY ${STRING_OBJECT}_SYMBOL)
301     string(TOLOWER ${else_name} else_name)
302 
303     get_objects(LIST sections OBJECT ${STRING_OBJECT} TYPE SECTION)
304     list(GET sections 0 section)
305     get_property(first_section_name GLOBAL PROPERTY ${section}_NAME)
306 
307   endif()
308 
309   if(${type} STREQUAL GROUP)
310     get_property(group_name GLOBAL PROPERTY ${STRING_OBJECT}_NAME)
311     get_property(group_address GLOBAL PROPERTY ${STRING_OBJECT}_ADDRESS)
312     get_property(group_vma GLOBAL PROPERTY ${STRING_OBJECT}_VMA)
313     get_property(group_lma GLOBAL PROPERTY ${STRING_OBJECT}_LMA)
314   endif()
315 
316   get_property(sections GLOBAL PROPERTY ${STRING_OBJECT}_SECTIONS_FIXED)
317   foreach(section ${sections})
318     to_string(OBJECT ${section} STRING ${STRING_STRING})
319     get_property(name       GLOBAL PROPERTY ${section}_NAME)
320     get_property(name_clean GLOBAL PROPERTY ${section}_NAME_CLEAN)
321     set(${STRING_STRING} "${${STRING_STRING}}\"${name}\": place at address mem:${address} { block ${name_clean} };\n")
322   endforeach()
323 
324   get_property(groups GLOBAL PROPERTY ${STRING_OBJECT}_GROUPS)
325   foreach(group ${groups})
326     to_string(OBJECT ${group} STRING ${STRING_STRING})
327   endforeach()
328 
329   get_property(sections GLOBAL PROPERTY ${STRING_OBJECT}_SECTIONS)
330   foreach(section ${sections})
331     to_string(OBJECT ${section} STRING ${STRING_STRING})
332 
333     get_property(name     GLOBAL PROPERTY ${section}_NAME)
334 
335     get_property(name_clean GLOBAL PROPERTY ${section}_NAME_CLEAN)
336 
337     get_property(parent   GLOBAL PROPERTY ${section}_PARENT)
338     get_property(noinit   GLOBAL PROPERTY ${section}_NOINIT)
339     # This is only a trick to get the memories
340     get_property(parent_type GLOBAL PROPERTY ${parent}_OBJ_TYPE)
341     if(${parent_type} STREQUAL GROUP)
342       get_property(vma GLOBAL PROPERTY ${parent}_VMA)
343       get_property(lma GLOBAL PROPERTY ${parent}_LMA)
344     endif()
345 
346     if(DEFINED vma)
347       set(ILINK_CURRENT_NAME ${vma})
348     elseif(DEFINED lma)
349       set(ILINK_CURRENT_NAME ${lma})
350     else()
351       # message(FATAL_ERROR "Need either vma or lma")
352     endif()
353 
354     set(${STRING_STRING} "${${STRING_STRING}}\"${name}\": place in ${ILINK_CURRENT_NAME} { block ${name_clean} };\n")
355     if(DEFINED vma AND DEFINED lma AND NOT ${noinit})
356       set(${STRING_STRING} "${${STRING_STRING}}\"${name}_init\": place in ${lma} { block ${name_clean}_init };\n")
357     endif()
358 
359   endforeach()
360 
361   get_parent(OBJECT ${STRING_OBJECT} PARENT parent TYPE SYSTEM)
362   get_property(regions GLOBAL PROPERTY ${parent}_REGIONS)
363   list(REMOVE_ITEM regions ${STRING_OBJECT})
364 
365   foreach(region ${regions})
366     get_property(vma GLOBAL PROPERTY ${region}_NAME)
367     get_property(sections GLOBAL PROPERTY ${STRING_OBJECT}_${vma}_SECTIONS_FIXED)
368 
369     foreach(section ${sections})
370       to_string(OBJECT ${section} STRING ${STRING_STRING})
371     endforeach()
372 
373     get_property(groups GLOBAL PROPERTY ${STRING_OBJECT}_${vma}_GROUPS)
374     foreach(group ${groups})
375       to_string(OBJECT ${group} STRING ${STRING_STRING})
376     endforeach()
377 
378     get_property(sections GLOBAL PROPERTY ${STRING_OBJECT}_${vma}_SECTIONS)
379     foreach(section ${sections})
380       to_string(OBJECT ${section} STRING ${STRING_STRING})
381       get_property(name     GLOBAL PROPERTY ${section}_NAME)
382       string(REGEX REPLACE "^[\.]" "" name_clean "${name}")
383       string(REPLACE "." "_" name_clean "${name_clean}")
384       set(${STRING_STRING} "${${STRING_STRING}}\"${name}\": place in ${vma} { block ${name_clean} };\n")
385 
386       # Insert 'do not initialize' here
387       get_property(current_sections GLOBAL PROPERTY ILINK_CURRENT_SECTIONS)
388       if(${name} STREQUAL .bss)
389         if(DEFINED current_sections)
390           set(${STRING_STRING} "${${STRING_STRING}}do not initialize\n")
391           set(${STRING_STRING} "${${STRING_STRING}}{\n")
392           foreach(section ${current_sections})
393             set(${STRING_STRING} "${${STRING_STRING}}  ${section},\n")
394           endforeach()
395           set(${STRING_STRING} "${${STRING_STRING}}};\n")
396           set(current_sections)
397           set_property(GLOBAL PROPERTY ILINK_CURRENT_SECTIONS)
398         endif()
399       endif()
400 
401       if(${name_clean} STREQUAL last_ram_section)
402         get_property(group_name_lma GLOBAL PROPERTY ILINK_ROM_REGION_NAME)
403         set(${STRING_STRING} "${${STRING_STRING}}\n")
404         if(${CONFIG_LINKER_LAST_SECTION_ID})
405           set(${STRING_STRING} "${${STRING_STRING}}define section last_section_id { udata32 ${CONFIG_LINKER_LAST_SECTION_ID_PATTERN}; };\n")
406           set(${STRING_STRING} "${${STRING_STRING}}define block last_section with fixed order { section last_section_id };\n")
407         else()
408           set(${STRING_STRING} "${${STRING_STRING}}define block last_section with fixed order { };\n")
409         endif()
410         # Not really the right place, we want the last used flash bytes not end of the world!
411         # set(${STRING_STRING} "${${STRING_STRING}}\".last_section\": place at end of ${group_name_lma} { block last_section };\n")
412         set(${STRING_STRING} "${${STRING_STRING}}\".last_section\": place in ${group_name_lma} { block last_section };\n")
413         set(${STRING_STRING} "${${STRING_STRING}}keep { block last_section };\n")
414       endif()
415 
416     endforeach()
417   endforeach()
418 
419   get_property(symbols GLOBAL PROPERTY ${STRING_OBJECT}_SYMBOLS)
420   set(${STRING_STRING} "${${STRING_STRING}}\n")
421   foreach(symbol ${symbols})
422     to_string(OBJECT ${symbol} STRING ${STRING_STRING})
423   endforeach()
424 
425   set(${STRING_STRING} ${${STRING_STRING}} PARENT_SCOPE)
426 endfunction()
427 
428 
429 function(section_to_string)
430   cmake_parse_arguments(STRING "" "SECTION;STRING" "" ${ARGN})
431 
432   get_property(name     GLOBAL PROPERTY ${STRING_SECTION}_NAME)
433   get_property(address  GLOBAL PROPERTY ${STRING_SECTION}_ADDRESS)
434   get_property(type     GLOBAL PROPERTY ${STRING_SECTION}_TYPE)
435   get_property(align    GLOBAL PROPERTY ${STRING_SECTION}_ALIGN)
436   get_property(subalign GLOBAL PROPERTY ${STRING_SECTION}_SUBALIGN)
437   get_property(endalign GLOBAL PROPERTY ${STRING_SECTION}_ENDALIGN)
438   get_property(vma      GLOBAL PROPERTY ${STRING_SECTION}_VMA)
439   get_property(lma      GLOBAL PROPERTY ${STRING_SECTION}_LMA)
440   get_property(noinput  GLOBAL PROPERTY ${STRING_SECTION}_NOINPUT)
441   get_property(noinit   GLOBAL PROPERTY ${STRING_SECTION}_NOINIT)
442 
443   get_property(nosymbols  GLOBAL PROPERTY ${STRING_SECTION}_NOSYMBOLS)
444   get_property(start_syms GLOBAL PROPERTY ${STRING_SECTION}_START_SYMBOLS)
445   get_property(end_syms   GLOBAL PROPERTY ${STRING_SECTION}_END_SYMBOLS)
446 
447   get_property(parent   GLOBAL PROPERTY ${STRING_SECTION}_PARENT)
448 
449   get_property(parent_type GLOBAL PROPERTY ${parent}_OBJ_TYPE)
450   if(${parent_type} STREQUAL GROUP)
451     get_property(group_parent_vma GLOBAL PROPERTY ${parent}_VMA)
452     get_property(group_parent_lma GLOBAL PROPERTY ${parent}_LMA)
453     if(NOT DEFINED vma)
454       get_property(vma GLOBAL PROPERTY ${parent}_VMA)
455     endif()
456     if(NOT DEFINED lma)
457       get_property(lma GLOBAL PROPERTY ${parent}_LMA)
458     endif()
459   endif()
460 
461   if(DEFINED group_parent_vma AND DEFINED group_parent_lma)
462     # Something to init
463     set(part "rw ")
464   else()
465     set(part)
466   endif()
467 
468 
469   set_property(GLOBAL PROPERTY ILINK_CURRENT_SECTIONS)
470 
471   string(REGEX REPLACE "^[\.]" "" name_clean "${name}")
472   string(REPLACE "." "_" name_clean "${name_clean}")
473 
474   # WA for 'Error[Lc036]: no block or place matches the pattern "ro data section .tdata_init"'
475   if("${name_clean}" STREQUAL "tdata")
476     set(TEMP "${TEMP}define block ${name_clean}_init { ro section .tdata_init };\n")
477     set(TEMP "${TEMP}\"${name_clean}_init\": place in ${ILINK_CURRENT_NAME} { block ${name_clean}_init };\n\n")
478   endif()
479 
480   get_property(indicies GLOBAL PROPERTY ${STRING_SECTION}_SETTINGS_INDICIES)
481   # ZIP_LISTS partner
482   get_property(next_indicies GLOBAL PROPERTY ${STRING_SECTION}_SETTINGS_INDICIES)
483   list(POP_FRONT next_indicies first_index)
484 
485   set(first_index_section)
486   set(first_index_section_name)
487   if(DEFINED first_index)
488     # Handle case where the first section has an offset
489     get_property(first_index_offset
490       GLOBAL PROPERTY ${STRING_SECTION}_SETTING_${first_index}_OFFSET)
491     get_property(keep   GLOBAL PROPERTY ${STRING_SECTION}_SETTING_${first_index}_KEEP)
492     if(DEFINED keep)
493       set(root "root ")
494     else()
495       set(root)
496     endif()
497     if(DEFINED first_index_offset AND NOT first_index_offset EQUAL 0 )
498       set(first_index_section_name "${name_clean}_${first_index}_offset")
499       set(first_index_section
500         "define ${root}section ${first_index_section_name} {};")
501     else()
502       set(first_index)
503     endif()
504   endif()
505 
506   foreach(start_symbol ${start_syms})
507     set_property(GLOBAL APPEND PROPERTY ILINK_SYMBOL_ICF "${start_symbol} = ADDR(${name_clean})")
508   endforeach()
509   foreach(end_symbol ${end_syms})
510     set_property(GLOBAL APPEND PROPERTY ILINK_SYMBOL_ICF "${end_symbol} = END(${name_clean})")
511   endforeach()
512 
513   if(NOT nosymbols)
514     if("${name_clean}" STREQUAL "tdata")
515       set_property(GLOBAL APPEND PROPERTY ILINK_SYMBOL_ICF "__${name_clean}_start = (__iar_tls$$INIT_DATA$$Base)")
516       set_property(GLOBAL APPEND PROPERTY ILINK_SYMBOL_ICF "__${name_clean}_end = (__iar_tls$$INIT_DATA$$Limit)")
517     else()
518       set_property(GLOBAL APPEND PROPERTY ILINK_SYMBOL_ICF "__${name_clean}_start = ADDR(${name_clean})")
519       set_property(GLOBAL APPEND PROPERTY ILINK_SYMBOL_ICF "__${name_clean}_end = END(${name_clean})")
520     endif()
521   endif()
522   # section patterns and blocks to keep { }
523   set(to_be_kept "")
524 
525   if(DEFINED first_index_section)
526     set(TEMP "${TEMP}${first_index_section}\n")
527   endif()
528 
529   set(TEMP "${TEMP}define block ${name_clean} with fixed order")
530 
531   if(align)
532     set(TEMP "${TEMP}, alignment=${align}")
533   elseif(subalign)
534     set(TEMP "${TEMP}, alignment = ${subalign}")
535   elseif(part)
536     set(TEMP "${TEMP}, alignment = input")
537   else()
538     set(TEMP "${TEMP}, alignment=4")
539   endif()
540   if(endalign)
541     set(TEMP "${TEMP}, end alignment=${endalign}")
542   endif()
543 
544   set(TEMP "${TEMP}\n{")
545 
546   # foreach(start_symbol ${start_syms})
547   #   set(TEMP "${TEMP}\n  section ${start_symbol},")
548   #   set_property(GLOBAL APPEND PROPERTY ILINK_CURRENT_SECTIONS "section ${start_symbol}")
549   # endforeach()
550 
551   # if(NOT nosymbols)
552   #   set(TEMP "${TEMP}\n  section __${name_clean}_start,")
553   #   set_property(GLOBAL APPEND PROPERTY ILINK_CURRENT_SECTIONS "section __${name_clean}_start")
554   # endif()
555 
556   list(GET indicies -1 last_index)
557   list(LENGTH indicies length)
558 
559   if(NOT noinput)
560 
561     set(TEMP "${TEMP}\n  block ${name_clean}_winput")
562     if(align)
563       list(APPEND block_attr "alignment = ${align}")
564     elseif(subalign)
565       list(APPEND block_attr "alignment = ${subalign}")
566     elseif(part)
567       # list(APPEND block_attr "alignment = input")
568     else()
569       list(APPEND block_attr "alignment=4")
570     endif()
571     list(APPEND block_attr "fixed order")
572 
573     list(JOIN block_attr ", " block_attr_str)
574     if(block_attr_str)
575       set(TEMP "${TEMP} with ${block_attr_str}")
576     endif()
577     set(block_attr)
578     set(block_attr_str)
579 
580     set(TEMP "${TEMP} { ${part}section ${name}, ${part}section ${name}.* }")
581     if(${length} GREATER 0)
582       set(TEMP "${TEMP},")
583     endif()
584     set_property(GLOBAL APPEND PROPERTY ILINK_CURRENT_SECTIONS "section ${name}")
585     set_property(GLOBAL APPEND PROPERTY ILINK_CURRENT_SECTIONS "section ${name}.*")
586   endif()
587 
588   foreach(idx idx_next IN ZIP_LISTS indicies next_indicies)
589     get_property(align    GLOBAL PROPERTY ${STRING_SECTION}_SETTING_${idx}_ALIGN)
590     get_property(any      GLOBAL PROPERTY ${STRING_SECTION}_SETTING_${idx}_ANY)
591     get_property(first    GLOBAL PROPERTY ${STRING_SECTION}_SETTING_${idx}_FIRST)
592     get_property(keep     GLOBAL PROPERTY ${STRING_SECTION}_SETTING_${idx}_KEEP)
593     get_property(sort     GLOBAL PROPERTY ${STRING_SECTION}_SETTING_${idx}_SORT)
594     get_property(flags    GLOBAL PROPERTY ${STRING_SECTION}_SETTING_${idx}_FLAGS)
595     get_property(input    GLOBAL PROPERTY ${STRING_SECTION}_SETTING_${idx}_INPUT)
596     get_property(symbols  GLOBAL PROPERTY ${STRING_SECTION}_SETTING_${idx}_SYMBOLS)
597     # Get the next offset and use that as this ones size!
598     get_property(offset   GLOBAL PROPERTY ${STRING_SECTION}_SETTING_${idx_next}_OFFSET)
599 
600     if(keep)
601       list(APPEND to_be_kept "block ${name_clean}_${idx}")
602       foreach(setting ${input})
603         list(APPEND to_be_kept "section ${setting}")
604       endforeach()
605     endif()
606     if(DEFINED symbols)
607       list(LENGTH symbols symbols_count)
608       if(${symbols_count} GREATER 0)
609         list(GET symbols 0 symbol_start)
610       endif()
611       if(${symbols_count} GREATER 1)
612         list(GET symbols 1 symbol_end)
613       endif()
614     endif()
615 
616     if(DEFINED symbol_start)
617       # set(TEMP "${TEMP}\n  section ${symbol_start},")
618       # set_property(GLOBAL APPEND PROPERTY ILINK_CURRENT_SECTIONS "section ${symbol_start}")
619       set_property(GLOBAL APPEND PROPERTY ILINK_SYMBOL_ICF "${symbol_start} = ADDR(${name_clean}_${idx})")
620     endif()
621 
622     if(DEFINED first_index AND first_index EQUAL ${idx})
623       # Create the offset
624       set(TEMP "${TEMP}\n  block ${first_index_section_name}")
625       list(APPEND block_attr "size = ${first_index_offset}")
626       if(sort)
627         if(${sort} STREQUAL NAME)
628           list(APPEND block_attr "alphabetical order")
629         endif()
630       endif()
631       if(align)
632         list(APPEND block_attr "alignment = ${align}")
633       elseif(subalign)
634         list(APPEND block_attr "alignment = ${subalign}")
635       elseif(part)
636         # list(APPEND block_attr "alignment = input")
637       else()
638         list(APPEND block_attr "alignment=4")
639       endif()
640       list(APPEND block_attr "fixed order")
641 
642       list(JOIN block_attr ", " block_attr_str)
643       if(block_attr_str)
644         set(TEMP "${TEMP} with ${block_attr_str}")
645       endif()
646       set(block_attr)
647       set(block_attr_str)
648 
649       set(TEMP "${TEMP} { section ${first_index_section_name} },\n")
650     endif()
651 
652     # block init_100 with alphabetical order { section .z_init_EARLY?_}
653     set(TEMP "${TEMP}\n  block ${name_clean}_${idx}")
654     if(DEFINED offset AND NOT offset EQUAL 0 )
655       list(APPEND block_attr "size = ${offset}")
656     elseif(DEFINED offset AND offset STREQUAL 0 )
657       # Do nothing
658     endif()
659     if(sort)
660       if(${sort} STREQUAL NAME)
661         list(APPEND block_attr "alphabetical order")
662       endif()
663     endif()
664     if(align)
665       list(APPEND block_attr "alignment = ${align}")
666     elseif(subalign)
667       list(APPEND block_attr "alignment = ${subalign}")
668     elseif(part)
669       # list(APPEND block_attr "alignment = input")
670     else()
671       list(APPEND block_attr "alignment=4")
672     endif()
673 
674     # LD
675     # There are two ways to include more than one section:
676     #
677     # *(.text .rdata)
678     # *(.text) *(.rdata)
679     #
680     # The difference between these is the order in which
681     # the `.text' and `.rdata' input sections will appear in the output section.
682     # In the first example, they will be intermingled,
683     # appearing in the same order as they are found in the linker input.
684     # In the second example, all `.text' input sections will appear first,
685     # followed by all `.rdata' input sections.
686     #
687     # ILINK solved by adding 'fixed order'
688     if(NOT sort AND NOT first)
689       list(APPEND block_attr "fixed order")
690     endif()
691 
692     list(JOIN block_attr ", " block_attr_str)
693     if(block_attr_str)
694       set(TEMP "${TEMP} with ${block_attr_str}")
695     endif()
696     set(block_attr)
697     set(block_attr_str)
698 
699     if(empty)
700       set(TEMP "${TEMP}\n  {")
701       set(empty FALSE)
702     endif()
703 
704     list(GET input -1 last_input)
705 
706     set(TEMP "${TEMP} {")
707     if(NOT DEFINED input AND NOT any)
708       set(TEMP "${TEMP} }")
709     endif()
710 
711     foreach(setting ${input})
712       if(first)
713         set(TEMP "${TEMP} first")
714         set(first "")
715       endif()
716 
717       set(section_type "")
718 
719       # build for ram, no section_type
720       # if("${lma}" STREQUAL "${vma}")
721       #		# if("${vma}" STREQUAL "")
722       #           set(section_type "")
723       #		# else()
724       #		#   set(section_type " readwrite")
725       #		# endif()
726       # elseif(NOT "${vma}" STREQUAL "")
727       #		set(section_type " readwrite")
728       # elseif(NOT "${lma}" STREQUAL "")
729       #		set(section_type " readonly")
730       # else()
731       #		message(FATAL_ERROR "How to handle this? lma=${lma} vma=${vma}")
732       # endif()
733 
734       set(TEMP "${TEMP}${section_type} ${part}section ${setting}")
735       set_property(GLOBAL APPEND PROPERTY ILINK_CURRENT_SECTIONS "section ${setting}")
736       set(section_type "")
737 
738       if("${setting}" STREQUAL "${last_input}")
739         set(TEMP "${TEMP} }")
740       else()
741         set(TEMP "${TEMP}, ")
742       endif()
743 
744       # set(TEMP "${TEMP}\n    *.o(${setting})")
745     endforeach()
746 
747     if(any)
748       if(NOT flags)
749         message(FATAL_ERROR ".ANY requires flags to be set.")
750       endif()
751       set(ANY_FLAG "")
752       foreach(flag ${flags})
753         # if("${flag}" STREQUAL +RO OR "${flag}" STREQUAL +XO)
754         #   set(ANY_FLAG "readonly")
755         # # elseif("${flag}" STREQUAL +RW)
756         # #   set(ANY_FLAG "readwrite")
757         # else
758         if("${flag}" STREQUAL +ZI)
759           set(ANY_FLAG "zeroinit")
760           set_property(GLOBAL APPEND PROPERTY ILINK_CURRENT_SECTIONS "${ANY_FLAG}")
761         endif()
762       endforeach()
763       set(TEMP "${TEMP} ${ANY_FLAG} }")
764     endif()
765 
766     if(DEFINED symbol_end)
767       # set(TEMP "${TEMP},\n  section ${symbol_end}")
768       # set_property(GLOBAL APPEND PROPERTY ILINK_CURRENT_SECTIONS "section ${symbol_end}")
769       set_property(GLOBAL APPEND PROPERTY ILINK_SYMBOL_ICF "${symbol_end} = END(${name_clean}_${idx})")
770     endif()
771     if(${length} GREATER 0)
772       if(NOT "${idx}" STREQUAL "${last_index}")
773         set(TEMP "${TEMP},")
774       elseif()
775       endif()
776     endif()
777 
778     set(symbol_start)
779     set(symbol_end)
780   endforeach()
781   set(next_indicies)
782 
783   set(last_index)
784   set(last_input)
785   set(TEMP "${TEMP}")
786 
787   # if(NOT nosymbols)
788   #   set(TEMP "${TEMP},\n  section __${name_clean}_end")
789   #   set_property(GLOBAL APPEND PROPERTY ILINK_CURRENT_SECTIONS "section __${name_clean}_end")
790   # endif()
791 
792   # foreach(end_symbol ${end_syms})
793   #   set(TEMP "${TEMP},\n  section ${end_symbol}")
794   #   set_property(GLOBAL APPEND PROPERTY ILINK_CURRENT_SECTIONS "section ${end_symbol}")
795   # endforeach()
796 
797   set(TEMP "${TEMP}\n};")
798 
799   get_property(type GLOBAL PROPERTY ${parent}_OBJ_TYPE)
800   if(${type} STREQUAL REGION)
801     get_property(name GLOBAL PROPERTY ${parent}_NAME)
802     get_property(address GLOBAL PROPERTY ${parent}_ADDRESS)
803     get_property(size GLOBAL PROPERTY ${parent}_SIZE)
804 
805   endif()
806 
807   get_property(current_sections GLOBAL PROPERTY ILINK_CURRENT_SECTIONS)
808 
809   if(DEFINED group_parent_vma AND DEFINED group_parent_lma)
810     if(${noinit})
811       list(JOIN current_sections ", " SELECTORS)
812       set(TEMP "${TEMP}\ndo not initialize {\n${SELECTORS}\n};")
813     else()
814       # Generate the _init block and the initialize manually statement.
815       # Note that we need to have the X_init block defined even if we have
816       # no sections, since there will come a "place in XXX" statement later.
817 
818       # "${TEMP}" is there too keep the ';' else it will be a list
819       string(REGEX REPLACE "(block[ \t\r\n]+)([^ \t\r\n]+)" "\\1\\2_init" INIT_TEMP "${TEMP}")
820       string(REGEX REPLACE "(rw)([ \t\r\n]+)(section[ \t\r\n]+)([^ \t\r\n,]+)" "\\1\\2\\3\\4_init" INIT_TEMP "${INIT_TEMP}")
821       string(REGEX REPLACE "(rw)([ \t\r\n]+)(section[ \t\r\n]+)" "ro\\2\\3" INIT_TEMP "${INIT_TEMP}")
822       string(REGEX REPLACE "alphabetical order, " "" INIT_TEMP "${INIT_TEMP}")
823       string(REGEX REPLACE "{ readwrite }" "{ }" INIT_TEMP "${INIT_TEMP}")
824 
825       # If any content is marked as keep, is has to be applied to the init block
826       # too, esp. for blocks that are not referenced (e.g. empty blocks wiht min_size)
827       if(to_be_kept)
828         list(APPEND to_be_kept "block ${name_clean}_init")
829       endif()
830       set(TEMP "${TEMP}\n${INIT_TEMP}\n")
831       if(DEFINED current_sections)
832         set(TEMP "${TEMP}\ninitialize manually with copy friendly\n")
833         set(TEMP "${TEMP}{\n")
834         foreach(section ${current_sections})
835           set(TEMP "${TEMP}  ${section},\n")
836         endforeach()
837         set(TEMP "${TEMP}};")
838         set(current_sections)
839       endif()
840     endif()
841   endif()
842 
843   # Finally, add the keeps.
844   if(to_be_kept)
845     list(JOIN to_be_kept ", " K)
846     set(TEMP "${TEMP}\nkeep { ${K} };\n")
847   endif()
848 
849   set(${STRING_STRING} "${${STRING_STRING}}\n${TEMP}\n" PARENT_SCOPE)
850 endfunction()
851 
852 function(symbol_to_string)
853   cmake_parse_arguments(STRING "" "SYMBOL;STRING" "" ${ARGN})
854 
855   get_property(name     GLOBAL PROPERTY ${STRING_SYMBOL}_NAME)
856   get_property(expr     GLOBAL PROPERTY ${STRING_SYMBOL}_EXPR)
857   get_property(size     GLOBAL PROPERTY ${STRING_SYMBOL}_SIZE)
858   get_property(symbol   GLOBAL PROPERTY ${STRING_SYMBOL}_SYMBOL)
859   get_property(subalign GLOBAL PROPERTY ${STRING_SYMBOL}_SUBALIGN)
860 
861   string(REPLACE "\\" "" expr "${expr}")
862   string(REGEX MATCHALL "@([^@]*)@" match_res ${expr})
863 
864   foreach(match ${match_res})
865     string(REPLACE "@" "" match ${match})
866     get_property(symbol_val GLOBAL PROPERTY SYMBOL_TABLE_${match})
867     string(REPLACE "@${match}@" "${match}" expr ${expr})
868   endforeach()
869 
870   list(LENGTH match_res match_res_count)
871 
872   if(match_res_count)
873     if(${match_res_count} GREATER 1)
874       set(${STRING_STRING}
875         "${${STRING_STRING}}define image symbol ${symbol} = ${expr};\n"
876         )
877     else()
878       if((expr MATCHES "Base|Limit|Length") OR (expr MATCHES "ADDR\\(|END\\(|SIZE\\("))
879         # Anything like $$Base/$$Limit/$$Length should be an image symbol
880         if( "${symbol}" STREQUAL "__tdata_size")
881           # This will handle the alignment of the TBSS block
882           set(${STRING_STRING}
883             "${${STRING_STRING}}define image symbol ${symbol}=(__iar_tls$$INIT_DATA$$Limit-__iar_tls$$INIT_DATA$$Base);\n"
884             )
885         elseif( "${symbol}" STREQUAL "__tbss_size")
886           # This will handle the alignment of the TBSS block by
887           # pre-padding bytes
888           set(${STRING_STRING}
889             "${${STRING_STRING}}define image symbol ${symbol}=((tbss$$Limit-__iar_tls$$DATA$$Base)-(__iar_tls$$INIT_DATA$$Limit-__iar_tls$$INIT_DATA$$Base));\n"
890             )
891         else()
892           set(${STRING_STRING}
893             "${${STRING_STRING}}define image symbol ${symbol} = ${expr};\n"
894             )
895         endif()
896       else()
897         list(GET match_res 0 match)
898         string(REPLACE "@" "" match ${match})
899         get_property(symbol_val GLOBAL PROPERTY SYMBOL_TABLE_${match})
900         if(symbol_val)
901           set(${STRING_STRING}
902             "${${STRING_STRING}}define image symbol ${symbol} = ${expr};\n"
903             )
904         else()
905           # Treatmen of "zephyr_linker_symbol(SYMBOL z_arm_platform_init EXPR "@SystemInit@")"
906           set_property(GLOBAL APPEND PROPERTY SYMBOL_STEERING_FILE
907             "--redirect ${symbol}=${expr}\n"
908             )
909         endif()
910       endif()
911     endif()
912   else()
913     # Handle things like ADDR(.ramfunc)
914     if(${expr} MATCHES "^[A-Za-z]?ADDR\\(.+\\)")
915       # string(REGEX REPLACE "^[A-Za-z]?ADDR\\((.+)\\)" "(\\1$$Base)" expr ${expr})
916       set(${STRING_STRING}
917         "${${STRING_STRING}}define image symbol ${symbol} = ${expr};\n"
918         )
919     else()
920       set(${STRING_STRING}
921         "${${STRING_STRING}}define exported symbol ${symbol} = ${expr};\n"
922         )
923     endif()
924   endif()
925 
926   set(${STRING_STRING} ${${STRING_STRING}} PARENT_SCOPE)
927 endfunction()
928 
929 include(${CMAKE_CURRENT_LIST_DIR}/../linker_script_common.cmake)
930 
931 if(DEFINED STEERING_FILE)
932   get_property(steering_content GLOBAL PROPERTY SYMBOL_STEERING_FILE)
933   file(WRITE ${STEERING_FILE}  "/* AUTO-GENERATED - Do not modify\n")
934   file(APPEND ${STEERING_FILE} " * AUTO-GENERATED - All changes will be lost\n")
935   file(APPEND ${STEERING_FILE} " */\n")
936 
937   file(APPEND ${STEERING_FILE} ${steering_content})
938 endif()
939