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