1cmake_minimum_required(VERSION 3.20.0)
2
3set(SORT_TYPE_NAME Lexical)
4
5# This function post process the region for easier use.
6#
7# Tasks:
8# - Symbol translation using a steering file is configured.
9function(process_region)
10  cmake_parse_arguments(REGION "" "OBJECT" "" ${ARGN})
11
12  process_region_common(${ARGN})
13
14  get_property(empty GLOBAL PROPERTY ${REGION_OBJECT}_EMPTY)
15  if(NOT empty)
16    # For scatter files we move any system symbols into first non-empty load section.
17    get_parent(OBJECT ${REGION_OBJECT} PARENT parent TYPE SYSTEM)
18    get_property(symbols GLOBAL PROPERTY ${parent}_SYMBOLS)
19    set_property(GLOBAL APPEND PROPERTY ${REGION_OBJECT}_SYMBOLS ${symbols})
20    set_property(GLOBAL PROPERTY ${parent}_SYMBOLS)
21  endif()
22
23  get_property(sections GLOBAL PROPERTY ${REGION_OBJECT}_SECTION_LIST_ORDERED)
24  foreach(section ${sections})
25
26    get_property(name_clean GLOBAL PROPERTY ${section}_NAME_CLEAN)
27    get_property(noinput    GLOBAL PROPERTY ${section}_NOINPUT)
28    get_property(type       GLOBAL PROPERTY ${section}_TYPE)
29
30    get_property(indicies GLOBAL PROPERTY ${section}_SETTINGS_INDICIES)
31    list(LENGTH indicies length)
32    foreach(idx ${indicies})
33      set(steering_postfixes Base Limit)
34      get_property(symbols GLOBAL PROPERTY ${section}_SETTING_${idx}_SYMBOLS)
35      get_property(sort    GLOBAL PROPERTY ${section}_SETTING_${idx}_SORT)
36      get_property(offset  GLOBAL PROPERTY ${section}_SETTING_${idx}_OFFSET)
37      if(DEFINED offset)
38        foreach(symbol ${symbols})
39          list(POP_FRONT steering_postfixes postfix)
40          math(EXPR offset_dec "${offset}")
41          set_property(GLOBAL APPEND PROPERTY SYMBOL_STEERING_C
42            "Image$$${name_clean}_${offset_dec}$$${postfix}"
43          )
44          set_property(GLOBAL APPEND PROPERTY SYMBOL_STEERING_FILE
45            "RESOLVE ${symbol} AS Image$$${name_clean}_${offset_dec}$$${postfix}\n"
46          )
47        endforeach()
48      elseif(sort)
49        foreach(symbol ${symbols})
50          list(POP_FRONT steering_postfixes postfix)
51          set_property(GLOBAL APPEND PROPERTY SYMBOL_STEERING_C
52            "Image$$${name_clean}_${idx}$$${postfix}"
53          )
54          set_property(GLOBAL APPEND PROPERTY SYMBOL_STEERING_FILE
55            "RESOLVE ${symbol} AS Image$$${name_clean}_${idx}$$${postfix}\n"
56          )
57        endforeach()
58      elseif(DEFINED symbols AND ${length} EQUAL 1 AND noinput)
59        set(steering_postfixes Base Limit)
60        foreach(symbol ${symbols})
61          list(POP_FRONT steering_postfixes postfix)
62          set_property(GLOBAL APPEND PROPERTY SYMBOL_STEERING_C
63            "Image$$${name_clean}$$${postfix}"
64          )
65          set_property(GLOBAL APPEND PROPERTY SYMBOL_STEERING_FILE
66            "RESOLVE ${symbol} AS Image$$${name_clean}$$${postfix}\n"
67          )
68        endforeach()
69      endif()
70    endforeach()
71
72    if("${type}" STREQUAL BSS)
73      set(ZI "$$ZI")
74    endif()
75
76    # Symbols translation here.
77    set_property(GLOBAL APPEND PROPERTY SYMBOL_STEERING_C "Image$$${name_clean}${ZI}$$Base")
78    set_property(GLOBAL APPEND PROPERTY SYMBOL_STEERING_C "Image$$${name_clean}${ZI}$$Length")
79    set_property(GLOBAL APPEND PROPERTY SYMBOL_STEERING_C "Load$$${name_clean}${ZI}$$Base")
80
81    set_property(GLOBAL APPEND PROPERTY SYMBOL_STEERING_FILE
82      "RESOLVE __${name_clean}_start AS Image$$${name_clean}${ZI}$$Base\n"
83      "RESOLVE __${name_clean}_load_start AS Load$$${name_clean}${ZI}$$Base\n"
84      "EXPORT  __${name_clean}_start AS __${name_clean}_start\n"
85    )
86
87    get_property(symbol_val GLOBAL PROPERTY SYMBOL_TABLE___${name_clean}_end)
88    set_property(GLOBAL APPEND PROPERTY SYMBOL_STEERING_C "Image$$${symbol_val}${ZI}$$Limit")
89    set_property(GLOBAL APPEND PROPERTY SYMBOL_STEERING_FILE
90        "RESOLVE __${name_clean}_end AS Image$$${symbol_val}${ZI}$$Limit\n"
91      )
92
93    if("${symbol_val}" STREQUAL "${name_clean}")
94      set_property(GLOBAL APPEND PROPERTY SYMBOL_STEERING_FILE
95        "RESOLVE __${name_clean}_size AS Image$$${name_clean}${ZI}$$Length\n"
96      )
97    else()
98      create_symbol(OBJECT ${REGION_OBJECT} SYMBOL __${name_clean}_size
99        EXPR "(ImageLimit(${symbol_val}${ZI}) - ImageBase(${name_clean}${ZI}))"
100      )
101    endif()
102    set(ZI)
103
104  endforeach()
105
106  get_property(groups GLOBAL PROPERTY ${REGION_OBJECT}_GROUP_LIST_ORDERED)
107  foreach(group ${groups})
108    get_property(name GLOBAL PROPERTY ${group}_NAME)
109    string(TOLOWER ${name} name)
110
111    get_objects(LIST sections OBJECT ${group} TYPE SECTION)
112    list(GET sections 0 section)
113    get_property(first_section_name GLOBAL PROPERTY ${section}_NAME_CLEAN)
114    list(POP_BACK sections section)
115    get_property(last_section_name GLOBAL PROPERTY ${section}_NAME_CLEAN)
116
117    # Symbols translation here.
118    set_property(GLOBAL APPEND PROPERTY SYMBOL_STEERING_C "Image$$${first_section_name}$$Base")
119    set_property(GLOBAL APPEND PROPERTY SYMBOL_STEERING_C "Load$$${first_section_name}$$Base")
120    set_property(GLOBAL APPEND PROPERTY SYMBOL_STEERING_C "Image$$${last_section_name}$$Limit")
121
122    set_property(GLOBAL APPEND PROPERTY SYMBOL_STEERING_FILE
123      "RESOLVE __${name}_start AS Image$$${first_section_name}$$Base\n"
124      "EXPORT  __${name}_start AS __${name}_start\n"
125      "RESOLVE __${name}_load_start AS Load$$${first_section_name}$$Base\n"
126      "EXPORT  __${name}_load_start AS __${name}_load_start\n"
127    )
128
129    set_property(GLOBAL APPEND PROPERTY SYMBOL_STEERING_FILE
130        "RESOLVE __${name}_end AS Image$$${last_section_name}$$Limit\n"
131      )
132
133    create_symbol(OBJECT ${REGION_OBJECT} SYMBOL __${name}_size
134      EXPR "(ImageLimit(${last_section_name}) - ImageBase(${first_section_name}))"
135    )
136  endforeach()
137
138  get_property(symbols GLOBAL PROPERTY ${REGION_OBJECT}_SYMBOLS)
139  foreach(symbol ${symbols})
140    get_property(name GLOBAL PROPERTY ${symbol}_NAME)
141    set_property(GLOBAL APPEND PROPERTY SYMBOL_STEERING_C "Image$$${name}$$Base")
142
143    set_property(GLOBAL APPEND PROPERTY SYMBOL_STEERING_FILE
144      "RESOLVE ${name} AS Image$$${name}$$Base\n"
145    )
146  endforeach()
147
148endfunction()
149
150#
151# String functions - start
152#
153
154function(system_to_string)
155  cmake_parse_arguments(STRING "" "OBJECT;STRING" "" ${ARGN})
156
157  get_property(name    GLOBAL PROPERTY ${STRING_OBJECT}_NAME)
158  get_property(regions GLOBAL PROPERTY ${STRING_OBJECT}_REGIONS)
159  get_property(format  GLOBAL PROPERTY ${STRING_OBJECT}_FORMAT)
160
161  foreach(region ${regions})
162    get_property(empty GLOBAL PROPERTY ${region}_EMPTY)
163    if(NOT empty)
164      to_string(OBJECT ${region} STRING ${STRING_STRING})
165    endif()
166  endforeach()
167
168  set(${STRING_STRING} ${${STRING_STRING}} PARENT_SCOPE)
169endfunction()
170
171function(group_to_string)
172  cmake_parse_arguments(STRING "" "OBJECT;STRING" "" ${ARGN})
173
174  get_property(type GLOBAL PROPERTY ${STRING_OBJECT}_OBJ_TYPE)
175  if(${type} STREQUAL REGION)
176    get_property(name GLOBAL PROPERTY ${STRING_OBJECT}_NAME)
177    get_property(address GLOBAL PROPERTY ${STRING_OBJECT}_ADDRESS)
178    get_property(size GLOBAL PROPERTY ${STRING_OBJECT}_SIZE)
179    set(${STRING_STRING} "${${STRING_STRING}}\n${name} ${address} NOCOMPRESS ${size}\n{\n")
180  endif()
181
182  get_property(sections GLOBAL PROPERTY ${STRING_OBJECT}_SECTIONS_FIXED)
183  foreach(section ${sections})
184    to_string(OBJECT ${section} STRING ${STRING_STRING})
185  endforeach()
186
187  get_property(groups GLOBAL PROPERTY ${STRING_OBJECT}_GROUPS)
188  foreach(group ${groups})
189    to_string(OBJECT ${group} STRING ${STRING_STRING})
190  endforeach()
191
192  get_property(sections GLOBAL PROPERTY ${STRING_OBJECT}_SECTIONS)
193  foreach(section ${sections})
194    to_string(OBJECT ${section} STRING ${STRING_STRING})
195  endforeach()
196
197  get_parent(OBJECT ${STRING_OBJECT} PARENT parent TYPE SYSTEM)
198  get_property(regions GLOBAL PROPERTY ${parent}_REGIONS)
199  list(REMOVE_ITEM regions ${STRING_OBJECT})
200  foreach(region ${regions})
201    get_property(vma GLOBAL PROPERTY ${region}_NAME)
202    get_property(sections GLOBAL PROPERTY ${STRING_OBJECT}_${vma}_SECTIONS_FIXED)
203    foreach(section ${sections})
204      to_string(OBJECT ${section} STRING ${STRING_STRING})
205    endforeach()
206
207    get_property(groups GLOBAL PROPERTY ${STRING_OBJECT}_${vma}_GROUPS)
208    foreach(group ${groups})
209      to_string(OBJECT ${group} STRING ${STRING_STRING})
210    endforeach()
211
212    get_property(sections GLOBAL PROPERTY ${STRING_OBJECT}_${vma}_SECTIONS)
213    foreach(section ${sections})
214      to_string(OBJECT ${section} STRING ${STRING_STRING})
215    endforeach()
216  endforeach()
217
218  get_property(symbols GLOBAL PROPERTY ${STRING_OBJECT}_SYMBOLS)
219  foreach(symbol ${symbols})
220    to_string(OBJECT ${symbol} STRING ${STRING_STRING})
221  endforeach()
222
223  if(${type} STREQUAL REGION)
224    set(${STRING_STRING} "${${STRING_STRING}}\n}\n")
225  endif()
226  set(${STRING_STRING} ${${STRING_STRING}} PARENT_SCOPE)
227endfunction()
228
229
230function(section_to_string)
231  cmake_parse_arguments(STRING "" "SECTION;STRING" "" ${ARGN})
232
233  get_property(name     GLOBAL PROPERTY ${STRING_SECTION}_NAME)
234  get_property(address  GLOBAL PROPERTY ${STRING_SECTION}_ADDRESS)
235  get_property(type     GLOBAL PROPERTY ${STRING_SECTION}_TYPE)
236  get_property(align    GLOBAL PROPERTY ${STRING_SECTION}_ALIGN)
237  get_property(subalign GLOBAL PROPERTY ${STRING_SECTION}_SUBALIGN)
238  get_property(endalign GLOBAL PROPERTY ${STRING_SECTION}_ENDALIGN)
239  get_property(vma      GLOBAL PROPERTY ${STRING_SECTION}_VMA)
240  get_property(lma      GLOBAL PROPERTY ${STRING_SECTION}_LMA)
241  get_property(noinput  GLOBAL PROPERTY ${STRING_SECTION}_NOINPUT)
242  get_property(noinit   GLOBAL PROPERTY ${STRING_SECTION}_NOINIT)
243
244  string(REGEX REPLACE "^[\.]" "" name_clean "${name}")
245  string(REPLACE "." "_" name_clean "${name_clean}")
246
247  set(TEMP "  ${name_clean}")
248  if(DEFINED address)
249    set(TEMP "${TEMP} ${address}")
250  else()
251    set(TEMP "${TEMP} +0")
252  endif()
253
254  if(noinit)
255    # Currently we simply uses offset +0, but we must support offset defined
256    # externally.
257    set(TEMP "${TEMP} UNINIT")
258  endif()
259
260  if(subalign)
261    # Currently we simply uses offset +0, but we must support offset defined
262    # externally.
263    set(TEMP "${TEMP} ALIGN ${subalign}")
264  endif()
265
266  if(NOT noinput)
267    set(TEMP "${TEMP}\n  {")
268
269    if("${type}" STREQUAL NOLOAD)
270      set(TEMP "${TEMP}\n    *.o(${name}*)")
271      set(TEMP "${TEMP}\n    *.o(${name}*.*)")
272    elseif(VMA_FLAGS)
273      # ToDo: Proper names as provided by armclang
274#      set(TEMP "${TEMP}\n    *.o(${SEC_NAME}*, +${VMA_FLAGS})")
275#      set(TEMP "${TEMP}\n    *.o(${SEC_NAME}*.*, +${VMA_FLAGS})")
276      set(TEMP "${TEMP}\n    *.o(${name}*)")
277      set(TEMP "${TEMP}\n    *.o(${name}*.*)")
278    else()
279      set(TEMP "${TEMP}\n    *.o(${name}*)")
280      set(TEMP "${TEMP}\n    *.o(${name}*.*)")
281    endif()
282  else()
283    set(empty TRUE)
284  endif()
285
286  get_property(indicies GLOBAL PROPERTY ${STRING_SECTION}_SETTINGS_INDICIES)
287  foreach(idx ${indicies})
288    get_property(align    GLOBAL PROPERTY ${STRING_SECTION}_SETTING_${idx}_ALIGN)
289    get_property(any      GLOBAL PROPERTY ${STRING_SECTION}_SETTING_${idx}_ANY)
290    get_property(first    GLOBAL PROPERTY ${STRING_SECTION}_SETTING_${idx}_FIRST)
291    get_property(keep     GLOBAL PROPERTY ${STRING_SECTION}_SETTING_${idx}_KEEP)
292    get_property(sort     GLOBAL PROPERTY ${STRING_SECTION}_SETTING_${idx}_SORT)
293    get_property(flags    GLOBAL PROPERTY ${STRING_SECTION}_SETTING_${idx}_FLAGS)
294    get_property(input    GLOBAL PROPERTY ${STRING_SECTION}_SETTING_${idx}_INPUT)
295    get_property(offset   GLOBAL PROPERTY ${STRING_SECTION}_SETTING_${idx}_OFFSET)
296    if(DEFINED offset)
297      set(section_close TRUE)
298      math(EXPR offset_dec "${offset} + 0")
299      if(empty)
300        set(TEMP "${TEMP} EMPTY 0x0\n  {")
301        set(empty FALSE)
302      endif()
303      set(last_index ${offset_dec})
304      if(sort)
305        set(sorttype "SORTTYPE ${SORT_TYPE_${sort}}")
306      endif()
307      set(TEMP "${TEMP}\n  }")
308      set(TEMP "${TEMP}\n  ${name_clean}_${offset_dec} (ImageBase(${name_clean}) + ${offset}) ${sorttype}\n {")
309    elseif(sort)
310      set(section_close TRUE)
311      if(empty)
312        set(TEMP "${TEMP} EMPTY 0x0\n  {")
313        set(empty FALSE)
314      endif()
315      set(last_index ${idx})
316      set(TEMP "${TEMP}\n  }")
317      set(TEMP "${TEMP}\n  ${name_clean}_${idx} +0 SORTTYPE ${SORT_TYPE_${sort}}\n  {")
318    endif()
319
320    if(empty)
321      set(TEMP "${TEMP}\n  {")
322      set(empty FALSE)
323    endif()
324
325    foreach(setting ${input})
326      #set(SETTINGS ${SETTINGS_INPUT})
327
328#      # ToDo: The code below had en error in original implementation, causing
329#      #       settings not to be applied
330#      #       Verify behaviour and activate if working as intended.
331#      if(align)
332#        set(setting "${setting}, OVERALIGN ${align}")
333#      endif()
334
335      #if(SETTINGS_KEEP)
336      # armlink has --keep=<section_id>, but is there an scatter equivalent ?
337      #endif()
338
339      if(first)
340        set(setting "${setting}, +First")
341        set(first "")
342      endif()
343
344      set(TEMP "${TEMP}\n    *.o(${setting})")
345    endforeach()
346
347    if(any)
348      if(NOT flags)
349        message(FATAL_ERROR ".ANY requires flags to be set.")
350      endif()
351      string(REPLACE ";" " " flags "${flags}")
352
353      set(TEMP "${TEMP}\n    .ANY (${flags})")
354    endif()
355  endforeach()
356
357  if(section_close OR DEFINED endalign)
358    set(section_close)
359    set(TEMP "${TEMP}\n  }")
360
361    if(DEFINED endalign)
362      if(DEFINED last_index)
363        set(align_expr "AlignExpr(ImageLimit(${name_clean}_${last_index}), ${endalign}) FIXED")
364      else()
365        set(align_expr "AlignExpr(ImageLimit(${name_clean}), ${endalign}) FIXED")
366      endif()
367    else()
368      set(align_expr "+0")
369    endif()
370
371    set(TEMP "${TEMP}\n  ${name_clean}_end ${align_expr} EMPTY 0x0\n  {")
372    set(last_index)
373  endif()
374
375  set(TEMP "${TEMP}")
376  # ToDo: add patterns here.
377
378  if("${type}" STREQUAL BSS)
379    set(ZI "$$ZI")
380  endif()
381
382  set(TEMP "${TEMP}\n  }")
383
384  set(${STRING_STRING} "${${STRING_STRING}}\n${TEMP}\n" PARENT_SCOPE)
385endfunction()
386
387function(symbol_to_string)
388  cmake_parse_arguments(STRING "" "SYMBOL;STRING" "" ${ARGN})
389
390  get_property(name     GLOBAL PROPERTY ${STRING_SYMBOL}_NAME)
391  get_property(expr     GLOBAL PROPERTY ${STRING_SYMBOL}_EXPR)
392  get_property(size     GLOBAL PROPERTY ${STRING_SYMBOL}_SIZE)
393  get_property(symbol   GLOBAL PROPERTY ${STRING_SYMBOL}_SYMBOL)
394  get_property(subalign GLOBAL PROPERTY ${STRING_SYMBOL}_SUBALIGN)
395
396  string(REPLACE "\\" "" expr "${expr}")
397  string(REGEX MATCHALL "@([^@]*)@" match_res ${expr})
398
399  foreach(match ${match_res})
400    string(REPLACE "@" "" match ${match})
401    get_property(symbol_val GLOBAL PROPERTY SYMBOL_TABLE_${match})
402    string(REPLACE "@${match}@" "ImageBase(${symbol_val})" expr ${expr})
403  endforeach()
404
405  if(DEFINED subalign)
406    set(subalign "ALIGN ${subalign}")
407  endif()
408
409  if(NOT DEFINED size)
410    set(size "0x0")
411  endif()
412
413  set(${STRING_STRING}
414    "${${STRING_STRING}}\n  ${symbol} ${expr} ${subalign} ${size} { }\n"
415    PARENT_SCOPE
416  )
417endfunction()
418
419include(${CMAKE_CURRENT_LIST_DIR}/../linker_script_common.cmake)
420
421if(DEFINED STEERING_C)
422  get_property(symbols_c GLOBAL PROPERTY SYMBOL_STEERING_C)
423  file(WRITE ${STEERING_C}  "/* AUTO-GENERATED - Do not modify\n")
424  file(APPEND ${STEERING_C} " * AUTO-GENERATED - All changes will be lost\n")
425  file(APPEND ${STEERING_C} " */\n")
426  foreach(symbol ${symbols_c})
427    file(APPEND ${STEERING_C} "extern char ${symbol}[];\n")
428  endforeach()
429
430  file(APPEND ${STEERING_C} "\nint __armlink_symbol_steering(void) {\n")
431  file(APPEND ${STEERING_C} "\treturn\n")
432  foreach(symbol ${symbols_c})
433    file(APPEND ${STEERING_C} "\t\t${OPERAND} (int)${symbol}\n")
434    set(OPERAND "&")
435  endforeach()
436  file(APPEND ${STEERING_C} "\t;\n}\n")
437endif()
438
439if(DEFINED STEERING_FILE)
440  get_property(steering_content GLOBAL PROPERTY SYMBOL_STEERING_FILE)
441  file(WRITE ${STEERING_FILE}  "; AUTO-GENERATED - Do not modify\n")
442  file(APPEND ${STEERING_FILE} "; AUTO-GENERATED - All changes will be lost\n")
443  file(APPEND ${STEERING_FILE} ${steering_content})
444endif()
445