diff --git a/cmake/linker/iar/config_file_script.cmake b/cmake/linker/iar/config_file_script.cmake index 1c9db88bc35..917c9a1602a 100644 --- a/cmake/linker/iar/config_file_script.cmake +++ b/cmake/linker/iar/config_file_script.cmake @@ -97,9 +97,13 @@ function(process_region) EXPR "@ADDR(${symbol_start})@" ) endif() + # Treat BSS to be noinit + if(type STREQUAL BSS) + set_property(GLOBAL PROPERTY ${section}_NOINIT TRUE) + endif() + endforeach() # all sections - endforeach() - + #Add houseeeping symbols for sektion start, end, size, load start. get_property(groups GLOBAL PROPERTY ${REGION_OBJECT}_GROUP_LIST_ORDERED) foreach(group ${groups}) get_property(name GLOBAL PROPERTY ${group}_NAME) @@ -146,6 +150,7 @@ function(process_region) endforeach() + # create_symbol() for region-symbols that dont have an expression ? get_property(symbols GLOBAL PROPERTY ${REGION_OBJECT}_SYMBOLS) foreach(symbol ${symbols}) get_property(name GLOBAL PROPERTY ${symbol}_NAME) @@ -173,6 +178,7 @@ function(process_region) endif() endif() + #Short circuit our vma and lma to the parent's vma and lma if(${parent_type} STREQUAL GROUP) get_property(vma GLOBAL PROPERTY ${parent}_VMA) get_property(lma GLOBAL PROPERTY ${parent}_LMA) @@ -244,7 +250,7 @@ function(system_to_string) set(${STRING_STRING} "${${STRING_STRING}}\n\n") set_property(GLOBAL PROPERTY ILINK_SYMBOL_ICF) - set(${STRING_STRING} "${${STRING_STRING}}\n") + #Generate all regions foreach(region ${regions}) get_property(empty GLOBAL PROPERTY ${region}_EMPTY) if(NOT empty) @@ -254,8 +260,27 @@ function(system_to_string) set(ILINK_CURRENT_NAME) endif() endforeach() - set(${STRING_STRING} "${${STRING_STRING}}\n") + set(${STRING_STRING} "${${STRING_STRING}}\n/*SYSTEM_SECTIONS*/\n") + # Sections that sit directly under the system are fishy characters. + # Currently there are two classes of them: + # 1 - .rel.iplt & friends - these are not used by iar tools currently. + # These do not have any parents, so get no placement. Ignore them for + # now, since the get Error[Lc041]: "foo" defined but not referenced + # 2 - TYPE LINKER_SCRIPT_FOOTER - these have vma and lma settings, and so + # are easy to handle + get_property(sections GLOBAL PROPERTY ${STRING_OBJECT}_SECTIONS) + foreach(section ${sections}) + get_property(vma GLOBAL PROPERTY ${section}_VMA) + get_property(lma GLOBAL PROPERTY ${section}_LMA) + if(DEFINED lma OR DEFINED vma) + to_string(OBJECT ${section} STRING ${STRING_STRING}) + place_in_region(STRING place OBJECT ${section}) + string(APPEND ${STRING_STRING} "${place}") + endif() + endforeach() + + #Generate all image symbols we have collected get_property(symbols_icf GLOBAL PROPERTY ILINK_SYMBOL_ICF) foreach(image_symbol ${symbols_icf}) set(${STRING_STRING} "${${STRING_STRING}}define image symbol ${image_symbol};\n") @@ -281,6 +306,38 @@ function(system_to_string) set(${STRING_STRING} ${${STRING_STRING}} PARENT_SCOPE) endfunction() +#A helper to output "place in " +function(place_in_region) + cmake_parse_arguments(PLACE "" "OBJECT;STRING" "" ${ARGN}) + set(section ${PLACE_OBJECT}) + get_property(name GLOBAL PROPERTY ${section}_NAME) + + get_property(name_clean GLOBAL PROPERTY ${section}_NAME_CLEAN) + + get_property(parent GLOBAL PROPERTY ${section}_PARENT) + get_property(noinit GLOBAL PROPERTY ${section}_NOINIT) + # This is only a trick to get the memories + get_property(parent_type GLOBAL PROPERTY ${parent}_OBJ_TYPE) + if(${parent_type} STREQUAL GROUP) + get_property(vma GLOBAL PROPERTY ${parent}_VMA) + get_property(lma GLOBAL PROPERTY ${parent}_LMA) + endif() + + if(DEFINED vma) + set(ILINK_CURRENT_NAME ${vma}) + elseif(DEFINED lma) + set(ILINK_CURRENT_NAME ${lma}) + else() + # message(FATAL_ERROR "Need either vma or lma") + endif() + + set(result "\"${name}\": place in ${ILINK_CURRENT_NAME} { block ${name_clean} };\n") + if(CONFIG_IAR_ZEPHYR_INIT AND DEFINED vma AND DEFINED lma AND (NOT ${noinit}) AND NOT ("${vma}" STREQUAL "${lma}") ) + string(APPEND result "\"${name}_init\": place in ${lma} { block ${name_clean}_init };\n") + endif() + set(${PLACE_STRING} "${result}" PARENT_SCOPE) +endfunction() + function(group_to_string) cmake_parse_arguments(STRING "" "OBJECT;STRING" "" ${ARGN}) @@ -302,55 +359,36 @@ function(group_to_string) set(${STRING_STRING} "${${STRING_STRING}}\"${name}\": place at address mem:${section_address} { block ${name_clean} };\n") endforeach() + #Generate sub-groups get_property(groups GLOBAL PROPERTY ${STRING_OBJECT}_GROUPS) foreach(group ${groups}) to_string(OBJECT ${group} STRING ${STRING_STRING}) endforeach() + #Generate sections get_property(sections GLOBAL PROPERTY ${STRING_OBJECT}_SECTIONS) foreach(section ${sections}) to_string(OBJECT ${section} STRING ${STRING_STRING}) - get_property(name GLOBAL PROPERTY ${section}_NAME) - - get_property(name_clean GLOBAL PROPERTY ${section}_NAME_CLEAN) - - get_property(parent GLOBAL PROPERTY ${section}_PARENT) - get_property(noinit GLOBAL PROPERTY ${section}_NOINIT) - # This is only a trick to get the memories - get_property(parent_type GLOBAL PROPERTY ${parent}_OBJ_TYPE) - if(${parent_type} STREQUAL GROUP) - get_property(vma GLOBAL PROPERTY ${parent}_VMA) - get_property(lma GLOBAL PROPERTY ${parent}_LMA) - endif() - - if(DEFINED vma) - set(ILINK_CURRENT_NAME ${vma}) - elseif(DEFINED lma) - set(ILINK_CURRENT_NAME ${lma}) - else() - # message(FATAL_ERROR "Need either vma or lma") - endif() - - set(${STRING_STRING} "${${STRING_STRING}}\"${name}\": place in ${ILINK_CURRENT_NAME} { block ${name_clean} };\n") - if(CONFIG_IAR_ZEPHYR_INIT AND DEFINED vma AND DEFINED lma AND NOT ${noinit}) - set(${STRING_STRING} "${${STRING_STRING}}\"${name}_init\": place in ${lma} { block ${name_clean}_init };\n") - endif() - + place_in_region(STRING place OBJECT ${section}) + string(APPEND ${STRING_STRING} "${place}") endforeach() get_parent(OBJECT ${STRING_OBJECT} PARENT parent TYPE SYSTEM) get_property(regions GLOBAL PROPERTY ${parent}_REGIONS) list(REMOVE_ITEM regions ${STRING_OBJECT}) + #Go over REGIONS foreach(region ${regions}) get_property(vma GLOBAL PROPERTY ${region}_NAME) get_property(sections GLOBAL PROPERTY ${STRING_OBJECT}_${vma}_SECTIONS_FIXED) + #Generate our fixed-sections that has vma in this region foreach(section ${sections}) to_string(OBJECT ${section} STRING ${STRING_STRING}) endforeach() + #generate our groups with vma in region get_property(groups GLOBAL PROPERTY ${STRING_OBJECT}_${vma}_GROUPS) foreach(group ${groups}) to_string(OBJECT ${group} STRING ${STRING_STRING}) @@ -378,22 +416,6 @@ function(group_to_string) set_property(GLOBAL PROPERTY ILINK_CURRENT_SECTIONS) endif() endif() - - if(${name_clean} STREQUAL last_ram_section) - get_property(group_name_lma GLOBAL PROPERTY ILINK_ROM_REGION_NAME) - set(${STRING_STRING} "${${STRING_STRING}}\n") - if(${CONFIG_LINKER_LAST_SECTION_ID}) - set(${STRING_STRING} "${${STRING_STRING}}define section last_section_id { udata32 ${CONFIG_LINKER_LAST_SECTION_ID_PATTERN}; };\n") - set(${STRING_STRING} "${${STRING_STRING}}define block last_section with fixed order { section last_section_id };\n") - else() - set(${STRING_STRING} "${${STRING_STRING}}define block last_section with fixed order { };\n") - endif() - # Not really the right place, we want the last used flash bytes not end of the world! - # set(${STRING_STRING} "${${STRING_STRING}}\".last_section\": place at end of ${group_name_lma} { block last_section };\n") - set(${STRING_STRING} "${${STRING_STRING}}\".last_section\": place in ${group_name_lma} { block last_section };\n") - set(${STRING_STRING} "${${STRING_STRING}}keep { block last_section };\n") - endif() - endforeach() endforeach() @@ -677,11 +699,6 @@ function(section_to_string) set(block_attr) set(block_attr_str) - if(empty) - set(TEMP "${TEMP}\n {") - set(empty FALSE) - endif() - list(GET input -1 last_input) set(TEMP "${TEMP} {") @@ -697,21 +714,6 @@ function(section_to_string) set(section_type "") - # build for ram, no section_type - # if("${lma}" STREQUAL "${vma}") - # # if("${vma}" STREQUAL "") - # set(section_type "") - # # else() - # # set(section_type " readwrite") - # # endif() - # elseif(NOT "${vma}" STREQUAL "") - # set(section_type " readwrite") - # elseif(NOT "${lma}" STREQUAL "") - # set(section_type " readonly") - # else() - # message(FATAL_ERROR "How to handle this? lma=${lma} vma=${vma}") - # endif() - set(TEMP "${TEMP}${section_type} ${part}section ${setting}") set_property(GLOBAL APPEND PROPERTY ILINK_CURRENT_SECTIONS "section ${setting}") set(section_type "") @@ -777,66 +779,51 @@ function(section_to_string) set(TEMP "${TEMP}\n};") - get_property(type GLOBAL PROPERTY ${parent}_OBJ_TYPE) - if(${type} STREQUAL REGION) - get_property(name GLOBAL PROPERTY ${parent}_NAME) - get_property(address GLOBAL PROPERTY ${parent}_ADDRESS) - get_property(size GLOBAL PROPERTY ${parent}_SIZE) - - endif() - get_property(current_sections GLOBAL PROPERTY ILINK_CURRENT_SECTIONS) + if(${noinit}) + list(JOIN current_sections ", " SELECTORS) + set(TEMP "${TEMP}\ndo not initialize {\n${SELECTORS}\n};") + elseif(DEFINED group_parent_vma AND DEFINED group_parent_lma) + if(DEFINED current_sections) + if(CONFIG_IAR_DATA_INIT) + set(TEMP "${TEMP}\ninitialize by copy\n") + set(TEMP "${TEMP}{\n") + foreach(section ${current_sections}) + set(TEMP "${TEMP} ${section},\n") + endforeach() + set(TEMP "${TEMP}};") - if(DEFINED group_parent_vma AND DEFINED group_parent_lma) - if(${noinit}) - list(JOIN current_sections ", " SELECTORS) - set(TEMP "${TEMP}\ndo not initialize {\n${SELECTORS}\n};") - else() + set(TEMP "${TEMP}\n\"${name}_init\": place in ${group_parent_lma} {\n") + foreach(section ${current_sections}) + set(TEMP "${TEMP} ${section}_init,\n") + endforeach() + set(TEMP "${TEMP}};") + elseif(CONFIG_IAR_ZEPHYR_INIT) + # Generate the _init block and the initialize manually statement. + # Note that we need to have the X_init block defined even if we have + # no sections, since there will come a "place in XXX" statement later. - if(DEFINED current_sections) - if(CONFIG_IAR_DATA_INIT) - set(TEMP "${TEMP}\ninitialize by copy\n") - set(TEMP "${TEMP}{\n") - foreach(section ${current_sections}) - set(TEMP "${TEMP} ${section},\n") - endforeach() - set(TEMP "${TEMP}};") + # "${TEMP}" is there too keep the ';' else it will be a list + string(REGEX REPLACE "(block[ \t\r\n]+)([^ \t\r\n]+)" "\\1\\2_init" INIT_TEMP "${TEMP}") + string(REGEX REPLACE "(rw)([ \t\r\n]+)(section[ \t\r\n]+)([^ \t\r\n,]+)" "\\1\\2\\3\\4_init" INIT_TEMP "${INIT_TEMP}") + string(REGEX REPLACE "(rw)([ \t\r\n]+)(section[ \t\r\n]+)" "ro\\2\\3" INIT_TEMP "${INIT_TEMP}") + string(REGEX REPLACE "alphabetical order, " "" INIT_TEMP "${INIT_TEMP}") + string(REGEX REPLACE "{ readwrite }" "{ }" INIT_TEMP "${INIT_TEMP}") - set(TEMP "${TEMP}\n\"${name}_init\": place in ${group_parent_lma} {\n") - foreach(section ${current_sections}) - set(TEMP "${TEMP} ${section}_init,\n") - endforeach() - set(TEMP "${TEMP}};") - elseif(CONFIG_IAR_ZEPHYR_INIT) - # Generate the _init block and the initialize manually statement. - # Note that we need to have the X_init block defined even if we have - # no sections, since there will come a "place in XXX" statement later. - - # "${TEMP}" is there too keep the ';' else it will be a list - string(REGEX REPLACE "(block[ \t\r\n]+)([^ \t\r\n]+)" "\\1\\2_init" INIT_TEMP "${TEMP}") - string(REGEX REPLACE "(rw)([ \t\r\n]+)(section[ \t\r\n]+)([^ \t\r\n,]+)" "\\1\\2\\3\\4_init" INIT_TEMP "${INIT_TEMP}") - string(REGEX REPLACE "(rw)([ \t\r\n]+)(section[ \t\r\n]+)" "ro\\2\\3" INIT_TEMP "${INIT_TEMP}") - string(REGEX REPLACE "alphabetical order, " "" INIT_TEMP "${INIT_TEMP}") - string(REGEX REPLACE "{ readwrite }" "{ }" INIT_TEMP "${INIT_TEMP}") - - # If any content is marked as keep, is has to be applied to the init block - # too, esp. for blocks that are not referenced (e.g. empty blocks wiht min_size) - if(to_be_kept) - list(APPEND to_be_kept "block ${name_clean}_init") - endif() - set(TEMP "${TEMP}\n${INIT_TEMP}\n") - set(TEMP "${TEMP}\ninitialize manually with copy friendly\n") - set(TEMP "${TEMP}{\n") - foreach(section ${current_sections}) - set(TEMP "${TEMP} ${section},\n") - endforeach() - set(TEMP "${TEMP}};") - set(current_sections) + # If any content is marked as keep, is has to be applied to the init block + # too, esp. for blocks that are not referenced (e.g. empty blocks wiht min_size) + if(to_be_kept) + list(APPEND to_be_kept "block ${name_clean}_init") endif() + set(TEMP "${TEMP}\n${INIT_TEMP}\n") + set(TEMP "${TEMP}\ninitialize manually with copy friendly\n") + set(TEMP "${TEMP}{\n") + foreach(section ${current_sections}) + set(TEMP "${TEMP} ${section},\n") + endforeach() + set(TEMP "${TEMP}};") endif() - set(current_sections) - endif() endif() diff --git a/cmake/linker/linker_script_common.cmake b/cmake/linker/linker_script_common.cmake index 272fe797777..93a179569cc 100644 --- a/cmake/linker/linker_script_common.cmake +++ b/cmake/linker/linker_script_common.cmake @@ -221,6 +221,11 @@ function(create_section) else() set(parent ${SECTION_SYSTEM}) endif() + if(SECTION_TYPE STREQUAL "LINKER_SCRIPT_FOOTER") + set(SECTION_VMA) # pretend that we have no VMA, so the section ends up in + # the general heap of sections directly below the system + set(parent ${SECTION_SYSTEM}) + endif() set_property(GLOBAL PROPERTY SECTION_${SECTION_NAME}_PARENT ${parent}) add_section(OBJECT ${parent} SECTION ${SECTION_NAME} ADDRESS ${SECTION_ADDRESS} VMA ${SECTION_VMA}) diff --git a/cmake/linker_script/arm/linker.cmake b/cmake/linker_script/arm/linker.cmake index 94c2af6e4c5..2a4f61f6e15 100644 --- a/cmake/linker_script/arm/linker.cmake +++ b/cmake/linker_script/arm/linker.cmake @@ -155,7 +155,7 @@ if(CONFIG_USERSPACE) zephyr_linker_symbol(SYMBOL "_app_smem_rom_start" EXPR "@__app_smem_group_load_start@") - zephyr_linker_section(NAME .bss VMA RAM LMA FLASH TYPE BSS) + zephyr_linker_section(NAME .bss GROUP RAM_REGION TYPE BSS) zephyr_linker_section_configure(SECTION .bss INPUT COMMON) zephyr_linker_section_configure(SECTION .bss INPUT ".kernel_bss.*") @@ -175,7 +175,7 @@ include(${COMMON_ZEPHYR_LINKER_DIR}/common-ram.cmake) include(${COMMON_ZEPHYR_LINKER_DIR}/kobject-data.cmake) if(NOT CONFIG_USERSPACE) - zephyr_linker_section(NAME .bss VMA RAM LMA FLASH TYPE BSS) + zephyr_linker_section(NAME .bss GROUP RAM_REGION TYPE BSS) zephyr_linker_section_configure(SECTION .bss INPUT COMMON) zephyr_linker_section_configure(SECTION .bss INPUT ".kernel_bss.*") # As memory is cleared in words only, it is simpler to ensure the BSS @@ -256,3 +256,12 @@ dt_comp_path(paths COMPATIBLE "zephyr,memory-region") foreach(path IN LISTS paths) zephyr_linker_dts_section(PATH ${path}) endforeach() + + +# .last_section must be last in romable region +# .last_section contains a fixed word to ensure location counter and actual +# rom region data usage match when CONFIG_LINKER_LAST_SECTION_ID=y. +zephyr_linker_section(NAME .last_section VMA FLASH LMA FLASH + NOINPUT TYPE LINKER_SCRIPT_FOOTER) +# KEEP can not be passed to zephyr_linker_section, so: +zephyr_linker_section_configure(SECTION .last_section INPUT ".last_section" KEEP) diff --git a/cmake/modules/extensions.cmake b/cmake/modules/extensions.cmake index c3841283334..d87f02f191f 100644 --- a/cmake/modules/extensions.cmake +++ b/cmake/modules/extensions.cmake @@ -5167,6 +5167,10 @@ endfunction() # the given passes. Empty list means no passes. # PASS NOT [] [...] makes the section present in # all but the given passes. Empty list means all passes. +# TYPE : Tag section for special treatment. +# NOLOAD, BSS - Ensure that the section is NOLOAD +# LINKER_SCRIPT_FOOTER - One single section to be +# generated last # Note: VMA and LMA are mutual exclusive with GROUP # function(zephyr_linker_section)