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