1# ToDo: 2# - Ensure LMA / VMA sections are correctly grouped similar to scatter file creation. 3cmake_minimum_required(VERSION 3.20.0) 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 92 # Output a comment for the section start 93 set(${STRING_STRING} "${${STRING_STRING}}\n /* ${type} : ${STRING_OBJECT} */") 94 95 if(${type} STREQUAL REGION) 96 get_property(empty GLOBAL PROPERTY ${STRING_OBJECT}_EMPTY) 97 if(empty) 98 return() 99 endif() 100 101 get_property(address GLOBAL PROPERTY ${STRING_OBJECT}_ADDRESS) 102 set(${STRING_STRING} "${${STRING_STRING}}\n . = ${address};\n\n") 103 else() 104 get_property(name GLOBAL PROPERTY ${STRING_OBJECT}_NAME) 105 get_property(symbol GLOBAL PROPERTY ${STRING_OBJECT}_SYMBOL) 106 string(TOLOWER ${name} name) 107 108 get_objects(LIST sections OBJECT ${STRING_OBJECT} TYPE SECTION) 109 list(GET sections 0 section) 110 get_property(first_section_name GLOBAL PROPERTY ${section}_NAME) 111 112 if(DEFINED first_section_name AND "${symbol}" STREQUAL "SECTION") 113 set_property(GLOBAL APPEND PROPERTY ${section}_START_SYMBOLS __${name}_start) 114 else() 115 set(${STRING_STRING} "${${STRING_STRING}}\n __${name}_start = .;\n") 116 endif() 117 118 set(${STRING_STRING} "${${STRING_STRING}}\n __${name}_size = __${name}_end - __${name}_start;\n") 119 set(${STRING_STRING} "${${STRING_STRING}}\n __${name}_load_start = LOADADDR(${first_section_name});\n") 120 endif() 121 122 get_property(sections GLOBAL PROPERTY ${STRING_OBJECT}_SECTIONS_FIXED) 123 foreach(section ${sections}) 124 to_string(OBJECT ${section} STRING ${STRING_STRING}) 125 endforeach() 126 127 get_property(groups GLOBAL PROPERTY ${STRING_OBJECT}_GROUPS) 128 foreach(group ${groups}) 129 to_string(OBJECT ${group} STRING ${STRING_STRING}) 130 endforeach() 131 132 get_property(sections GLOBAL PROPERTY ${STRING_OBJECT}_SECTIONS) 133 foreach(section ${sections}) 134 to_string(OBJECT ${section} STRING ${STRING_STRING}) 135 endforeach() 136 137 get_parent(OBJECT ${STRING_OBJECT} PARENT parent TYPE SYSTEM) 138 get_property(regions GLOBAL PROPERTY ${parent}_REGIONS) 139 list(REMOVE_ITEM regions ${STRING_OBJECT}) 140 foreach(region ${regions}) 141 if(${type} STREQUAL REGION) 142 get_property(address GLOBAL PROPERTY ${region}_ADDRESS) 143 set(${STRING_STRING} "${${STRING_STRING}}\n . = ${address};\n\n") 144 endif() 145 146 get_property(vma GLOBAL PROPERTY ${region}_NAME) 147 get_property(sections GLOBAL PROPERTY ${STRING_OBJECT}_${vma}_SECTIONS_FIXED) 148 foreach(section ${sections}) 149 to_string(OBJECT ${section} STRING ${STRING_STRING}) 150 endforeach() 151 152 get_property(groups GLOBAL PROPERTY ${STRING_OBJECT}_${vma}_GROUPS) 153 foreach(group ${groups}) 154 to_string(OBJECT ${group} STRING ${STRING_STRING}) 155 endforeach() 156 157 get_property(sections GLOBAL PROPERTY ${STRING_OBJECT}_${vma}_SECTIONS) 158 foreach(section ${sections}) 159 to_string(OBJECT ${section} STRING ${STRING_STRING}) 160 endforeach() 161 endforeach() 162 163 if(NOT ${type} STREQUAL REGION) 164 set(${STRING_STRING} "${${STRING_STRING}}\n __${name}_end = .;\n") 165 endif() 166 167 get_property(symbols GLOBAL PROPERTY ${STRING_OBJECT}_SYMBOLS) 168 foreach(symbol ${symbols}) 169 to_string(OBJECT ${symbol} STRING ${STRING_STRING}) 170 endforeach() 171 172 set(${STRING_STRING} ${${STRING_STRING}} PARENT_SCOPE) 173endfunction() 174 175# Helper to add size-checks and padding to handle MIN_SIZE and MAX_SIZE 176macro(add_min_max_size TEMP min_size max_size symbol_start symbol_end) 177 if(DEFINED ${min_size}) 178 set(${TEMP} "${${TEMP}}\n . = MAX(${${symbol_start}} + ${${min_size}}, .); /*MIN_SIZE*/") 179 endif() 180 if(DEFINED ${max_size}) 181 set(${TEMP} "${${TEMP}}\n ASSERT( ${${symbol_end}} <= ( ${${symbol_start}} + ${${max_size}}), \"MAX_SIZE\");\n . = MIN( ., ${${symbol_start}} + ${${max_size}}); /*MAX_SIZE*/") 182 endif() 183endmacro() 184 185function(section_to_string) 186 cmake_parse_arguments(STRING "" "SECTION;STRING" "" ${ARGN}) 187 188 get_property(name GLOBAL PROPERTY ${STRING_SECTION}_NAME) 189 get_property(name_clean GLOBAL PROPERTY ${STRING_SECTION}_NAME_CLEAN) 190 get_property(address GLOBAL PROPERTY ${STRING_SECTION}_ADDRESS) 191 get_property(type GLOBAL PROPERTY ${STRING_SECTION}_TYPE) 192 get_property(align_in GLOBAL PROPERTY ${STRING_SECTION}_ALIGN_WITH_INPUT) 193 get_property(align GLOBAL PROPERTY ${STRING_SECTION}_ALIGN) 194 get_property(subalign GLOBAL PROPERTY ${STRING_SECTION}_SUBALIGN) 195 get_property(vma GLOBAL PROPERTY ${STRING_SECTION}_VMA) 196 get_property(lma GLOBAL PROPERTY ${STRING_SECTION}_LMA) 197 get_property(noinput GLOBAL PROPERTY ${STRING_SECTION}_NOINPUT) 198 get_property(noinit GLOBAL PROPERTY ${STRING_SECTION}_NOINIT) 199 get_property(nosymbols GLOBAL PROPERTY ${STRING_SECTION}_NOSYMBOLS) 200 get_property(parent GLOBAL PROPERTY ${STRING_SECTION}_PARENT) 201 get_property(start_syms GLOBAL PROPERTY ${STRING_SECTION}_START_SYMBOLS) 202 get_property(sect_min_size GLOBAL PROPERTY ${STRING_SECTION}_MIN_SIZE) 203 get_property(sect_max_size GLOBAL PROPERTY ${STRING_SECTION}_MAX_SIZE) 204 205 string(REGEX REPLACE "^[\.]" "" name_clean "${name}") 206 string(REPLACE "." "_" name_clean "${name_clean}") 207 208 set(SECTION_TYPE_NOLOAD NOLOAD) 209 set(SECTION_TYPE_BSS NOLOAD) 210 if(DEFINED type) 211 set(type " (${SECTION_TYPE_${type}})") 212 endif() 213 214 set(TEMP "${TEMP} :") 215 set(secalign "") 216 217 if(align_in) 218 set(secalign " ALIGN_WITH_INPUT") 219 endif() 220 221 if(DEFINED align) 222 set(secalign "${secalign} ALIGN(${align})") 223 endif() 224 225 if(DEFINED subalign) 226 set(secalign "${secalign} SUBALIGN(${subalign})") 227 endif() 228 229 set(TEMP "${name} ${address}${type} :${secalign}\n{") 230 231 # Symbol names for size_check 232 set(sect_symbol_start) 233 set(sect_symbol_end) 234 235 foreach(start_symbol ${start_syms}) 236 set(TEMP "${TEMP}\n ${start_symbol} = .;") 237 set(sect_symbol_start "${start_symbol}") 238 endforeach() 239 240 if(NOT nosymbols) 241 set(TEMP "${TEMP}\n __${name_clean}_start = .;") 242 set(sect_symbol_start "__${name_clean}_start") 243 endif() 244 245 # Min and Max size may need symbols too, even if the user did not want them 246 if((DEFINED sect_min_size OR DEFINED sect_max_size) 247 AND NOT DEFINED sect_symbol_start) 248 set(sect_symbol_start "__${name_clean}_size_check_start") 249 endif() 250 251 if(NOT noinput) 252 set(TEMP "${TEMP}\n *(${name})") 253 set(TEMP "${TEMP}\n *(\"${name}.*\")") 254 endif() 255 256 get_property(indicies GLOBAL PROPERTY ${STRING_SECTION}_SETTINGS_INDICIES) 257 foreach(idx ${indicies}) 258 get_property(align GLOBAL PROPERTY ${STRING_SECTION}_SETTING_${idx}_ALIGN) 259 get_property(any GLOBAL PROPERTY ${STRING_SECTION}_SETTING_${idx}_ANY) 260 get_property(first GLOBAL PROPERTY ${STRING_SECTION}_SETTING_${idx}_FIRST) 261 get_property(keep GLOBAL PROPERTY ${STRING_SECTION}_SETTING_${idx}_KEEP) 262 get_property(sort GLOBAL PROPERTY ${STRING_SECTION}_SETTING_${idx}_SORT) 263 get_property(flags GLOBAL PROPERTY ${STRING_SECTION}_SETTING_${idx}_FLAGS) 264 get_property(input GLOBAL PROPERTY ${STRING_SECTION}_SETTING_${idx}_INPUT) 265 get_property(symbols GLOBAL PROPERTY ${STRING_SECTION}_SETTING_${idx}_SYMBOLS) 266 get_property(offset GLOBAL PROPERTY ${STRING_SECTION}_SETTING_${idx}_OFFSET) 267 get_property(min_size GLOBAL PROPERTY ${STRING_SECTION}_SETTING_${idx}_MIN_SIZE) 268 get_property(max_size GLOBAL PROPERTY ${STRING_SECTION}_SETTING_${idx}_MAX_SIZE) 269 270 if(DEFINED align) 271 set(TEMP "${TEMP}\n . = ALIGN(${align});") 272 endif() 273 274 if(DEFINED symbols) 275 list(LENGTH symbols symbols_count) 276 if(${symbols_count} GREATER 0) 277 list(GET symbols 0 symbol_start) 278 endif() 279 if(${symbols_count} GREATER 1) 280 list(GET symbols 1 symbol_end) 281 endif() 282 endif() 283 # Min and Max size may need symbols too, even if the user did not want them 284 if(DEFINED min_size OR DEFINED max_size) 285 foreach(se "start" "end") 286 if(NOT DEFINED symbol_${se}) 287 set(symbol_${se} "__${name_clean}_${idx}_size_check_${se}") 288 endif() 289 endforeach() 290 endif() 291 292 if(DEFINED offset AND NOT ("${offset}" STREQUAL "${current_offset}")) 293 set(TEMP "${TEMP}\n . = ${offset}; /* OFFSET */") 294 set(current_offset ${offset}) 295 endif() 296 297 if(DEFINED symbol_start) 298 set(TEMP "${TEMP}\n ${symbol_start} = .;") 299 endif() 300 301 foreach(setting ${input}) 302 if(DEFINED offset AND NOT ("${offset}" STREQUAL "${current_offset}")) 303 set(TEMP "${TEMP}\n . = ${offset};") 304 set(current_offset ${offset}) 305 endif() 306 307 #setting may have file-pattern or not. 308 if(setting MATCHES "(.+)\\((.+)\\)") 309 set(file_pattern "${CMAKE_MATCH_1}") 310 set(section_pattern "${CMAKE_MATCH_2}") 311 else() 312 set(file_pattern "*") 313 set(section_pattern "${setting}") 314 endif() 315 316 if(sort) 317 set(section_pattern "${SORT_TYPE_${sort}}(${section_pattern})") 318 endif() 319 set(pattern "${file_pattern}(${section_pattern})") 320 if(keep) 321 set(pattern "KEEP(${pattern})") 322 endif() 323 set(TEMP "${TEMP}\n ${pattern};") 324 endforeach() 325 326 if(DEFINED symbol_end) 327 set(TEMP "${TEMP}\n ${symbol_end} = .;") 328 endif() 329 330 add_min_max_size(TEMP min_size max_size symbol_start symbol_end) 331 332 set(symbol_start) 333 set(symbol_end) 334 endforeach() 335 336 if(NOT nosymbols) 337 set(TEMP "${TEMP}\n __${name_clean}_end = .;") 338 set(sect_symbol_end "__${name_clean}_end") 339 endif() 340 341 if(DEFINED extra_symbol_end) 342 set(TEMP "${TEMP}\n ${extra_symbol_end} = .;") 343 set(sect_symbol_end "${extra_symbol_end}") 344 endif() 345 346 # Min and Max size may need symbols too, even if the user did not want them 347 if((DEFINED sect_min_size OR DEFINED sect_max_size) 348 AND NOT DEFINED sect_symbol_end) 349 set(sect_symbol_end "__${name_clean}_size_check_end") 350 endif() 351 352 add_min_max_size(TEMP sect_min_size sect_max_size sect_symbol_start sect_symbol_end) 353 354 set(TEMP "${TEMP}\n}") 355 356 get_property(parent_type GLOBAL PROPERTY ${parent}_OBJ_TYPE) 357 if(${parent_type} STREQUAL GROUP) 358 get_property(vma GLOBAL PROPERTY ${parent}_VMA) 359 get_property(lma GLOBAL PROPERTY ${parent}_LMA) 360 endif() 361 362 if(DEFINED vma) 363 set(TEMP "${TEMP} > ${vma}") 364 endif() 365 366 if(DEFINED vma AND DEFINED lma) 367 set(TEMP "${TEMP} AT") 368 endif() 369 370 if(DEFINED lma) 371 set(TEMP "${TEMP} > ${lma}") 372 endif() 373 374 if(NOT nosymbols) 375 set(TEMP "${TEMP}\n__${name_clean}_size = __${name_clean}_end - __${name_clean}_start;") 376 set(TEMP "${TEMP}\nPROVIDE(__${name_clean}_align = ALIGNOF(${name}));") 377 set(TEMP "${TEMP}\n__${name_clean}_load_start = LOADADDR(${name});") 378 endif() 379 380 set(${STRING_STRING} "${${STRING_STRING}}\n${TEMP}\n" PARENT_SCOPE) 381endfunction() 382 383# /DISCARD/ is an ld specific section, so let's append it here before processing. 384list(APPEND SECTIONS "{NAME\;/DISCARD/\;NOINPUT\;TRUE\;NOSYMBOLS\;TRUE}") 385 386function(process_region) 387 cmake_parse_arguments(REGION "" "OBJECT" "" ${ARGN}) 388 389 process_region_common(${ARGN}) 390 391 set(groups) 392 get_objects(LIST groups OBJECT ${REGION_OBJECT} TYPE GROUP) 393 foreach(group ${groups}) 394 get_property(parent GLOBAL PROPERTY ${group}_PARENT) 395 get_property(parent_type GLOBAL PROPERTY ${parent}_OBJ_TYPE) 396 397 if(${parent_type} STREQUAL GROUP) 398 get_property(vma GLOBAL PROPERTY ${parent}_VMA) 399 get_property(lma GLOBAL PROPERTY ${parent}_LMA) 400 401 set_property(GLOBAL PROPERTY ${group}_VMA ${vma}) 402 set_property(GLOBAL PROPERTY ${group}_LMA ${lma}) 403 endif() 404 endforeach() 405endfunction() 406 407include(${CMAKE_CURRENT_LIST_DIR}/../linker_script_common.cmake) 408