diff --git a/cmake/linker/linker_script_common.cmake b/cmake/linker/linker_script_common.cmake new file mode 100644 index 00000000000..67be753ca60 --- /dev/null +++ b/cmake/linker/linker_script_common.cmake @@ -0,0 +1,672 @@ +# +# Create functions - start +# + +function(create_system) + cmake_parse_arguments(OBJECT "" "ENTRY;FORMAT;NAME;OBJECT" "" ${ARGN}) + + set_property(GLOBAL PROPERTY SYSTEM_${OBJECT_NAME} TRUE) + set_property(GLOBAL PROPERTY SYSTEM_${OBJECT_NAME}_OBJ_TYPE SYSTEM) + set_property(GLOBAL PROPERTY SYSTEM_${OBJECT_NAME}_NAME ${OBJECT_NAME}) + set_property(GLOBAL PROPERTY SYSTEM_${OBJECT_NAME}_FORMAT ${OBJECT_FORMAT}) + set_property(GLOBAL PROPERTY SYSTEM_${OBJECT_NAME}_ENTRY ${OBJECT_ENTRY}) + + set(${OBJECT_OBJECT} SYSTEM_${OBJECT_NAME} PARENT_SCOPE) +endfunction() + +function(create_region) + cmake_parse_arguments(OBJECT "" "NAME;OBJECT;SIZE;START;FLAGS" "" ${ARGN}) + + if(DEFINED OBJECT_SIZE) + if(${OBJECT_SIZE} MATCHES "^([0-9]*)[kK]$") + math(EXPR OBJECT_SIZE "1024 * ${CMAKE_MATCH_1}" OUTPUT_FORMAT HEXADECIMAL) + elseif(${OBJECT_SIZE} MATCHES "^([0-9]*)[mM]$") + math(EXPR OBJECT_SIZE "1024 * 1024 * ${CMAKE_MATCH_1}" OUTPUT_FORMAT HEXADECIMAL) + elseif(NOT (${OBJECT_SIZE} MATCHES "^([0-9]*)$" OR ${OBJECT_SIZE} MATCHES "^0x([0-9a-fA-F]*)$")) + message(FATAL_ERROR "SIZE format is unknown.") + endif() + endif() + + set_property(GLOBAL PROPERTY REGION_${OBJECT_NAME} TRUE) + set_property(GLOBAL PROPERTY REGION_${OBJECT_NAME}_OBJ_TYPE REGION) + set_property(GLOBAL PROPERTY REGION_${OBJECT_NAME}_NAME ${OBJECT_NAME}) + set_property(GLOBAL PROPERTY REGION_${OBJECT_NAME}_ADDRESS ${OBJECT_START}) + set_property(GLOBAL PROPERTY REGION_${OBJECT_NAME}_FLAGS ${OBJECT_FLAGS}) + set_property(GLOBAL PROPERTY REGION_${OBJECT_NAME}_SIZE ${OBJECT_SIZE}) + + set(${OBJECT_OBJECT} REGION_${OBJECT_NAME} PARENT_SCOPE) +endfunction() + +function(get_parent) + cmake_parse_arguments(GET_PARENT "" "OBJECT;PARENT;TYPE" "" ${ARGN}) + + get_property(type GLOBAL PROPERTY ${GET_PARENT_OBJECT}_OBJ_TYPE) + if(${type} STREQUAL ${GET_PARENT_TYPE}) + # Already the right type, so just set and return. + set(${GET_PARENT_PARENT} ${GET_PARENT_OBJECT} PARENT_SCOPE) + return() + endif() + + get_property(parent GLOBAL PROPERTY ${GET_PARENT_OBJECT}_PARENT) + get_property(type GLOBAL PROPERTY ${parent}_OBJ_TYPE) + while(NOT ${type} STREQUAL ${GET_PARENT_TYPE}) + get_property(parent GLOBAL PROPERTY ${parent}_PARENT) + get_property(type GLOBAL PROPERTY ${parent}_OBJ_TYPE) + endwhile() + + set(${GET_PARENT_PARENT} ${parent} PARENT_SCOPE) +endfunction() + +function(create_group) + cmake_parse_arguments(OBJECT "" "GROUP;LMA;NAME;OBJECT;VMA" "" ${ARGN}) + + set_property(GLOBAL PROPERTY GROUP_${OBJECT_NAME} TRUE) + set_property(GLOBAL PROPERTY GROUP_${OBJECT_NAME}_OBJ_TYPE GROUP) + set_property(GLOBAL PROPERTY GROUP_${OBJECT_NAME}_NAME ${OBJECT_NAME}) + + if(DEFINED OBJECT_GROUP) + find_object(OBJECT parent NAME ${OBJECT_GROUP}) + else() + if(DEFINED OBJECT_VMA) + find_object(OBJECT obj NAME ${OBJECT_VMA}) + get_parent(OBJECT ${obj} PARENT parent TYPE REGION) + + get_property(vma GLOBAL PROPERTY ${parent}_NAME) + set_property(GLOBAL PROPERTY GROUP_${OBJECT_NAME}_VMA ${vma}) + endif() + + if(DEFINED OBJECT_LMA) + find_object(OBJECT obj NAME ${OBJECT_LMA}) + get_parent(OBJECT ${obj} PARENT parent TYPE REGION) + + get_property(lma GLOBAL PROPERTY ${parent}_NAME) + set_property(GLOBAL PROPERTY GROUP_${OBJECT_NAME}_LMA ${lma}) + endif() + endif() + + get_property(GROUP_FLAGS_INHERITED GLOBAL PROPERTY ${parent}_FLAGS) + set_property(GLOBAL PROPERTY GROUP_${OBJECT_NAME}_FLAGS ${GROUP_FLAGS_INHERITED}) + set_property(GLOBAL PROPERTY GROUP_${OBJECT_NAME}_PARENT ${parent}) + + add_group(OBJECT ${parent} GROUP GROUP_${OBJECT_NAME}) + + set(${OBJECT_OBJECT} GROUP_${OBJECT_NAME} PARENT_SCOPE) +endfunction() + +function(create_section) + set(single_args "NAME;ADDRESS;ALIGN_WITH_INPUT;TYPE;ALIGN;ENDALIGN;SUBALIGN;VMA;LMA;NOINPUT;NOINIT;NOSYMBOLS;GROUP;SYSTEM") + set(multi_args "PASS") + + cmake_parse_arguments(SECTION "" "${single_args}" "${multi_args}" ${ARGN}) + + if(DEFINED SECTION_PASS AND NOT "${PASS}" IN_LIST SECTION_PASS) + # This section is not active in this pass, ignore. + return() + endif() + + set_property(GLOBAL PROPERTY SECTION_${SECTION_NAME} TRUE) + set_property(GLOBAL PROPERTY SECTION_${SECTION_NAME}_OBJ_TYPE SECTION) + set_property(GLOBAL PROPERTY SECTION_${SECTION_NAME}_NAME ${SECTION_NAME}) + set_property(GLOBAL PROPERTY SECTION_${SECTION_NAME}_ADDRESS ${SECTION_ADDRESS}) + set_property(GLOBAL PROPERTY SECTION_${SECTION_NAME}_TYPE ${SECTION_TYPE}) + set_property(GLOBAL PROPERTY SECTION_${SECTION_NAME}_ALIGN ${SECTION_ALIGN}) + set_property(GLOBAL PROPERTY SECTION_${SECTION_NAME}_ALIGN_WITH_INPUT ${SECTION_ALIGN_WITH_INPUT}) + set_property(GLOBAL PROPERTY SECTION_${SECTION_NAME}_SUBALIGN ${SECTION_SUBALIGN}) + set_property(GLOBAL PROPERTY SECTION_${SECTION_NAME}_ENDALIGN ${SECTION_ENDALIGN}) + set_property(GLOBAL PROPERTY SECTION_${SECTION_NAME}_NOINPUT ${SECTION_NOINPUT}) + set_property(GLOBAL PROPERTY SECTION_${SECTION_NAME}_NOINIT ${SECTION_NOINIT}) + set_property(GLOBAL PROPERTY SECTION_${SECTION_NAME}_NOSYMBOLS ${SECTION_NOSYMBOLS}) + + string(REGEX REPLACE "^[\.]" "" name_clean "${SECTION_NAME}") + string(REPLACE "." "_" name_clean "${name_clean}") + set_property(GLOBAL PROPERTY SECTION_${SECTION_NAME}_NAME_CLEAN ${name_clean}) + + set_property(GLOBAL PROPERTY SYMBOL_TABLE___${name_clean}_start ${name_clean}) + set_property(GLOBAL PROPERTY SYMBOL_TABLE___${name_clean}_size ${name_clean}) + set_property(GLOBAL PROPERTY SYMBOL_TABLE___${name_clean}_load_start ${name_clean}) + set_property(GLOBAL PROPERTY SYMBOL_TABLE___${name_clean}_end ${name_clean}) + + set(INDEX 100) + set(settings_single "ALIGN;ANY;FIRST;KEEP;OFFSET;PASS;PRIO;SECTION;SORT") + set(settings_multi "FLAGS;INPUT;SYMBOLS") + foreach(settings ${SECTION_SETTINGS}) + if("${settings}" MATCHES "^{(.*)}$") + cmake_parse_arguments(SETTINGS "" "${settings_single}" "${settings_multi}" ${CMAKE_MATCH_1}) + + if(NOT ("${SETTINGS_SECTION}" STREQUAL "${SECTION_NAME}")) + continue() + endif() + + if(DEFINED SETTINGS_PASS AND NOT "${PASS}" IN_LIST SETTINGS_PASS) + # This section setting is not active in this pass, ignore. + continue() + endif() + + if(DEFINED SETTINGS_PRIO) + set(idx ${SETTINGS_PRIO}) + else() + set(idx ${INDEX}) + math(EXPR INDEX "${INDEX} + 1") + endif() + + foreach(setting ${settings_single} ${settings_multi}) + set_property(GLOBAL PROPERTY + SECTION_${SECTION_NAME}_SETTING_${idx}_${setting} + ${SETTINGS_${setting}} + ) + if(DEFINED SETTINGS_SORT) + set_property(GLOBAL PROPERTY SYMBOL_TABLE___${name_clean}_end ${name_clean}_end) + endif() + endforeach() + + set_property(GLOBAL APPEND PROPERTY SECTION_${SECTION_NAME}_SETTINGS_INDICIES ${idx}) + + endif() + endforeach() + + get_property(indicies GLOBAL PROPERTY SECTION_${SECTION_NAME}_SETTINGS_INDICIES) + if(DEFINED indicies) + list(SORT indicies COMPARE NATURAL) + set_property(GLOBAL PROPERTY SECTION_${SECTION_NAME}_SETTINGS_INDICIES ${indicies}) + endif() + + if(DEFINED SECTION_GROUP) + find_object(OBJECT parent NAME ${SECTION_GROUP}) + elseif(DEFINED SECTION_VMA OR DEFINED SECTION_LMA) + if(DEFINED SECTION_VMA) + find_object(OBJECT object NAME ${SECTION_VMA}) + get_parent(OBJECT ${object} PARENT parent TYPE REGION) + + get_property(vma GLOBAL PROPERTY ${parent}_NAME) + set_property(GLOBAL PROPERTY SECTION_${SECTION_NAME}_VMA ${vma}) + set(SECTION_VMA ${vma}) + endif() + + if(DEFINED SECTION_LMA) + find_object(OBJECT object NAME ${SECTION_LMA}) + get_parent(OBJECT ${object} PARENT parent TYPE REGION) + + get_property(lma GLOBAL PROPERTY ${parent}_NAME) + set_property(GLOBAL PROPERTY SECTION_${SECTION_NAME}_LMA ${lma}) + set(SECTION_LMA ${lma}) + endif() + else() + 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}) +endfunction() + +function(create_symbol) + cmake_parse_arguments(SYM "" "OBJECT;EXPR;SIZE;SUBALIGN;SYMBOL" "" ${ARGN}) + + set_property(GLOBAL PROPERTY SYMBOL_${SYM_SYMBOL} TRUE) + set_property(GLOBAL PROPERTY SYMBOL_${SYM_SYMBOL}_OBJ_TYPE SYMBOL) + set_property(GLOBAL PROPERTY SYMBOL_${SYM_SYMBOL}_NAME ${SYM_SYMBOL}) + set_property(GLOBAL PROPERTY SYMBOL_${SYM_SYMBOL}_EXPR ${SYM_EXPR}) + set_property(GLOBAL PROPERTY SYMBOL_${SYM_SYMBOL}_SIZE ${SYM_SIZE}) + set_property(GLOBAL PROPERTY SYMBOL_${SYM_SYMBOL}_SYMBOL ${SYM_SYMBOL}) + + set_property(GLOBAL PROPERTY SYMBOL_TABLE_${SYM_SYMBOL} ${SYM_SYMBOL}) + + add_symbol(OBJECT ${SYM_OBJECT} SYMBOL SYMBOL_${SYM_SYMBOL}) +endfunction() + +# +# Create functions - end +# + +# +# Add functions - start +# +function(add_region) + cmake_parse_arguments(ADD_REGION "" "OBJECT;REGION" "" ${ARGN}) + + get_property(exists GLOBAL PROPERTY ${ADD_REGION_OBJECT}) + if(NOT exists) + message(FATAL_ERROR + "Adding region ${ADD_REGION_REGION} to none-existing object: " + "${ADD_REGION_OBJECT}" + ) + endif() + + set_property(GLOBAL PROPERTY ${ADD_REGION_REGION}_PARENT ${ADD_REGION_OBJECT}) + set_property(GLOBAL APPEND PROPERTY ${ADD_REGION_OBJECT}_REGIONS ${ADD_REGION_REGION}) +endfunction() + +function(add_group) + cmake_parse_arguments(ADD_GROUP "" "OBJECT;GROUP" "" ${ARGN}) + + get_property(exists GLOBAL PROPERTY ${ADD_GROUP_OBJECT}) + if(NOT exists) + message(FATAL_ERROR + "Adding group ${ADD_GROUP_GROUP} to none-existing object: " + "${ADD_GROUP_OBJECT}" + ) + endif() + + get_property(vma GLOBAL PROPERTY ${ADD_GROUP_GROUP}_VMA) + get_property(object_name GLOBAL PROPERTY ${ADD_GROUP_OBJECT}_NAME) + + if((NOT DEFINED vma) OR ("${vma}" STREQUAL ${object_name})) + set_property(GLOBAL APPEND PROPERTY ${ADD_GROUP_OBJECT}_GROUPS ${ADD_GROUP_GROUP}) + else() + set_property(GLOBAL APPEND PROPERTY ${ADD_GROUP_OBJECT}_${vma}_GROUPS ${ADD_GROUP_GROUP}) + endif() +endfunction() + +function(add_section) + cmake_parse_arguments(ADD_SECTION "" "OBJECT;SECTION;ADDRESS;VMA" "" ${ARGN}) + + if(DEFINED ADD_SECTION_OBJECT) + get_property(type GLOBAL PROPERTY ${ADD_SECTION_OBJECT}_OBJ_TYPE) + get_property(object_name GLOBAL PROPERTY ${ADD_SECTION_OBJECT}_NAME) + + if(NOT DEFINED type) + message(FATAL_ERROR + "Adding section ${ADD_SECTION_SECTION} to " + "none-existing object: ${ADD_SECTION_OBJECT}" + ) + endif() + else() + set(ADD_SECTION_OBJECT RELOCATEABLE) + endif() + + if("${ADD_SECTION_VMA}" STREQUAL "${object_name}" AND DEFINED ADD_SECTION_ADDRESS) + set_property(GLOBAL APPEND PROPERTY + ${ADD_SECTION_OBJECT}_SECTIONS_FIXED + SECTION_${ADD_SECTION_SECTION} + ) + elseif(NOT DEFINED ADD_SECTION_VMA AND DEFINED SECTION_ADDRESS) + set_property(GLOBAL APPEND PROPERTY + ${ADD_SECTION_OBJECT}_SECTIONS_FIXED + SECTION_${ADD_SECTION_SECTION} + ) + elseif("${ADD_SECTION_VMA}" STREQUAL "${object_name}") + set_property(GLOBAL APPEND PROPERTY + ${ADD_SECTION_OBJECT}_SECTIONS + SECTION_${ADD_SECTION_SECTION} + ) + elseif(NOT DEFINED ADD_SECTION_VMA) + set_property(GLOBAL APPEND PROPERTY + ${ADD_SECTION_OBJECT}_SECTIONS + SECTION_${ADD_SECTION_SECTION} + ) + elseif(DEFINED SECTION_ADDRESS) + set_property(GLOBAL APPEND PROPERTY + ${ADD_SECTION_OBJECT}_${ADD_SECTION_VMA}_SECTIONS_FIXED + SECTION_${ADD_SECTION_SECTION} + ) + else() + set_property(GLOBAL APPEND PROPERTY + ${ADD_SECTION_OBJECT}_${ADD_SECTION_VMA}_SECTIONS + SECTION_${ADD_SECTION_SECTION} + ) + endif() +endfunction() + +function(add_symbol) + cmake_parse_arguments(ADD_SYMBOL "" "OBJECT;SYMBOL" "" ${ARGN}) + + # Section can be fixed address or not, VMA == LMA, . + # + get_property(exists GLOBAL PROPERTY ${ADD_SYMBOL_OBJECT}) + if(NOT exists) + message(FATAL_ERROR + "Adding symbol ${ADD_SYMBOL_SYMBOL} to none-existing object: " + "${ADD_SYMBOL_OBJECT}" + ) + endif() + + set_property(GLOBAL APPEND PROPERTY ${ADD_SYMBOL_OBJECT}_SYMBOLS ${ADD_SYMBOL_SYMBOL}) +endfunction() + +# +# Add functions - end +# + +# +# Retrieval functions - start +# +function(find_object) + cmake_parse_arguments(FIND "" "OBJECT;NAME" "" ${ARGN}) + + get_property(REGION GLOBAL PROPERTY REGION_${FIND_NAME}) + get_property(GROUP GLOBAL PROPERTY GROUP_${FIND_NAME}) + get_property(SECTION GLOBAL PROPERTY SECTION_${FIND_NAME}) + + if(REGION) + set(${FIND_OBJECT} REGION_${FIND_NAME} PARENT_SCOPE) + elseif(GROUP) + set(${FIND_OBJECT} GROUP_${FIND_NAME} PARENT_SCOPE) + elseif(SECTION) + set(${FIND_OBJECT} SECTION_${FIND_NAME} PARENT_SCOPE) + else() + message(WARNING "No object with name ${FIND_NAME} could be found.") + endif() +endfunction() + +function(get_objects) + cmake_parse_arguments(GET "" "LIST;OBJECT;TYPE" "" ${ARGN}) + + get_property(type GLOBAL PROPERTY ${GET_OBJECT}_OBJ_TYPE) + + if(${type} STREQUAL SECTION) + # A section doesn't have sub-items. + return() + endif() + + if(NOT (${GET_TYPE} STREQUAL SECTION + OR ${GET_TYPE} STREQUAL GROUP) + ) + message(WARNING "Only retrieval of SECTION GROUP objects are supported.") + return() + endif() + + set(out) + + get_parent(OBJECT ${GET_OBJECT} PARENT parent TYPE SYSTEM) + get_property(regions GLOBAL PROPERTY ${parent}_REGIONS) + list(REMOVE_ITEM regions ${GET_OBJECT}) + + if(${GET_TYPE} STREQUAL SECTION) + get_property(sections GLOBAL PROPERTY ${GET_OBJECT}_SECTIONS_FIXED) + list(APPEND out ${sections}) + + get_property(groups GLOBAL PROPERTY ${GET_OBJECT}_GROUPS) + foreach(group ${groups}) + get_objects(LIST sections OBJECT ${group} TYPE ${GET_TYPE}) + list(APPEND out ${sections}) + endforeach() + + get_property(sections GLOBAL PROPERTY ${GET_OBJECT}_SECTIONS) + list(APPEND out ${sections}) + + foreach(region ${regions}) + get_property(vma GLOBAL PROPERTY ${region}_NAME) + + get_property(sections GLOBAL PROPERTY ${GET_OBJECT}_${vma}_SECTIONS_FIXED) + list(APPEND out ${sections}) + + get_property(groups GLOBAL PROPERTY ${GET_OBJECT}_${vma}_GROUPS) + foreach(group ${groups}) + get_objects(LIST sections OBJECT ${group} TYPE ${GET_TYPE}) + list(APPEND out ${sections}) + endforeach() + + get_property(sections GLOBAL PROPERTY ${GET_OBJECT}_${vma}_SECTIONS) + list(APPEND out ${sections}) + endforeach() + endif() + + if(${GET_TYPE} STREQUAL GROUP) + get_property(groups GLOBAL PROPERTY ${GET_OBJECT}_GROUPS) + list(APPEND out ${groups}) + + foreach(group ${groups}) + get_objects(LIST subgroups OBJECT ${group} TYPE ${GET_TYPE}) + list(APPEND out ${subgroups}) + endforeach() + + foreach(region ${regions}) + get_property(vma GLOBAL PROPERTY ${region}_NAME) + + get_property(groups GLOBAL PROPERTY ${GET_OBJECT}_${vma}_GROUPS) + list(APPEND out ${groups}) + + foreach(group ${groups}) + get_objects(LIST subgroups OBJECT ${group} TYPE ${GET_TYPE}) + list(APPEND out ${subgroups}) + endforeach() + endforeach() + endif() + + set(${GET_LIST} ${out} PARENT_SCOPE) +endfunction() + +# +# Retrieval functions - end +# + +function(is_empty) + cmake_parse_arguments(IS_EMPTY "" "OBJECT" "" ${ARGN}) + + get_property(sections GLOBAL PROPERTY ${IS_EMPTY_OBJECT}_SECTIONS_FIXED) + if(DEFINED sections) + set_property(GLOBAL PROPERTY ${IS_EMPTY_OBJECT}_EMPTY FALSE) + return() + endif() + + get_property(groups GLOBAL PROPERTY ${IS_EMPTY_OBJECT}_GROUPS) + if(DEFINED groups) + set_property(GLOBAL PROPERTY ${IS_EMPTY_OBJECT}_EMPTY FALSE) + return() + endif() + + + get_property(sections GLOBAL PROPERTY ${IS_EMPTY_OBJECT}_SECTIONS) + if(DEFINED sections) + set_property(GLOBAL PROPERTY ${IS_EMPTY_OBJECT}_EMPTY FALSE) + return() + endif() + + get_parent(OBJECT ${IS_EMPTY_OBJECT} PARENT parent TYPE SYSTEM) + get_property(regions GLOBAL PROPERTY ${parent}_REGIONS) + list(REMOVE_ITEM regions ${IS_EMPTY_OBJECT}) + foreach(region ${regions}) + get_property(vma GLOBAL PROPERTY ${region}_NAME) + get_property(sections GLOBAL PROPERTY ${IS_EMPTY_OBJECT}_${vma}_SECTIONS_FIXED) + if(DEFINED sections) + set_property(GLOBAL PROPERTY ${IS_EMPTY_OBJECT}_EMPTY FALSE) + return() + endif() + + get_property(groups GLOBAL PROPERTY ${IS_EMPTY_OBJECT}_${vma}_GROUPS) + if(DEFINED groups) + set_property(GLOBAL PROPERTY ${IS_EMPTY_OBJECT}_EMPTY FALSE) + return() + endif() + + get_property(sections GLOBAL PROPERTY ${IS_EMPTY_OBJECT}_${vma}_SECTIONS) + if(DEFINED sections) + set_property(GLOBAL PROPERTY ${IS_EMPTY_OBJECT}_EMPTY FALSE) + return() + endif() + endforeach() + set_property(GLOBAL PROPERTY ${IS_EMPTY_OBJECT}_EMPTY TRUE) +endfunction() + +# This function post process the region for easier use. +# +# This is common post processing. +# If the calling _script.cmake generator implements its own +# process_region(), then the process_region_common() must be called explicitly +# from the process_region() from the _script.cmake generator. +# +# This allows a custom _script.cmake generator to completely disable +# the common post processing of regions. +# +# Tasks: +# - Apply missing settings, such as initial address for first section in a region. +# - Symbol names on sections +# - Ordered list of all sections for easier retrival on printing and configuration. +function(process_region_common) + cmake_parse_arguments(REGION_COMMON "" "OBJECT" "" ${ARGN}) + + is_empty(OBJECT ${REGION_COMMON_OBJECT}) + + set(sections) + get_objects(LIST sections OBJECT ${REGION_COMMON_OBJECT} TYPE SECTION) + set_property(GLOBAL PROPERTY ${REGION_COMMON_OBJECT}_SECTION_LIST_ORDERED ${sections}) + + set(groups) + get_objects(LIST groups OBJECT ${REGION_COMMON_OBJECT} TYPE GROUP) + set_property(GLOBAL PROPERTY ${REGION_COMMON_OBJECT}_GROUP_LIST_ORDERED ${groups}) + + list(LENGTH sections section_count) + if(section_count GREATER 0) + list(GET sections 0 section) + get_property(address GLOBAL PROPERTY ${section}_ADDRESS) + if(NOT DEFINED address) + get_parent(OBJECT ${REGION_COMMON_OBJECT} PARENT parent TYPE REGION) + get_property(address GLOBAL PROPERTY ${parent}_ADDRESS) + set_property(GLOBAL PROPERTY ${section}_ADDRESS ${address}) + endif() + endif() + + get_parent(OBJECT ${REGION_COMMON_OBJECT} PARENT parent TYPE SYSTEM) + get_property(regions GLOBAL PROPERTY ${parent}_REGIONS) + list(REMOVE_ITEM regions ${REGION_COMMON_OBJECT}) + foreach(region ${regions}) + get_property(vma GLOBAL PROPERTY ${region}_NAME) + set(sections_${vma}) + get_property(sections GLOBAL PROPERTY ${REGION_COMMON_OBJECT}_${vma}_SECTIONS_FIXED) + list(APPEND sections_${vma} ${sections}) + + get_property(groups GLOBAL PROPERTY ${REGION_COMMON_OBJECT}_${vma}_GROUPS) + foreach(group ${groups}) + get_objects(LIST sections OBJECT ${group} TYPE SECTION) + list(APPEND sections_${vma} ${sections}) + endforeach() + + get_property(sections GLOBAL PROPERTY ${REGION_COMMON_OBJECT}_${vma}_SECTIONS) + list(APPEND sections_${vma} ${sections}) + + list(LENGTH sections_${vma} section_count) + if(section_count GREATER 0) + list(GET sections_${vma} 0 section) + get_property(address GLOBAL PROPERTY ${section}_ADDRESS) + if(NOT DEFINED address) + get_property(address GLOBAL PROPERTY ${region}_ADDRESS) + set_property(GLOBAL PROPERTY ${section}_ADDRESS ${address}) + endif() + endif() + endforeach() +endfunction() + +if(NOT COMMAND process_region) + function(process_region) + process_region_common(${ARGN}) + endfunction() +endif() + + +# +# String functions - start +# +# Each linker must implement their own _to_string() functions to +# generate a correct linker script. +# +if(NOT COMMAND system_to_string) + function(system_to_string) + message(WARNING "No linker defined function found. Please implement a " + "system_to_string() function for this linker." + ) + endfunction() +endif() + +if(NOT COMMAND group_to_string) + function(group_to_string) + message(WARNING "No linker defined function found. Please implement a " + "group_to_string() function for this linker." + ) + endfunction() +endif() + +if(NOT COMMAND section_to_string) + function(section_to_string) + message(WARNING "No linker defined function found. Please implement a " + "section_to_string() function for this linker." + ) + endfunction() +endif() + +if(NOT COMMAND symbol_to_string) + function(symbol_to_string) + message(WARNING "No linker defined function found. Please implement a " + "symbol_to_string() function for this linker." + ) + endfunction() +endif() + +function(to_string) + cmake_parse_arguments(STRING "" "OBJECT;STRING" "" ${ARGN}) + + get_property(type GLOBAL PROPERTY ${STRING_OBJECT}_OBJ_TYPE) + + if("${type}" STREQUAL SYSTEM) + system_to_string(OBJECT ${STRING_OBJECT} STRING ${STRING_STRING}) + elseif(("${type}" STREQUAL REGION) OR ("${type}" STREQUAL GROUP)) + group_to_string(OBJECT ${STRING_OBJECT} STRING ${STRING_STRING}) + elseif("${type}" STREQUAL SECTION) + section_to_string(SECTION ${STRING_OBJECT} STRING ${STRING_STRING}) + elseif("${type}" STREQUAL SYMBOL) + symbol_to_string(SYMBOL ${STRING_OBJECT} STRING ${STRING_STRING}) + endif() + + set(${STRING_STRING} ${${STRING_STRING}} PARENT_SCOPE) +endfunction() + +# +# String functions - end +# + +create_system(OBJECT new_system NAME ZEPHYR_LINKER_v1 FORMAT ${FORMAT} ENTRY ${ENTRY}) + +# Sorting the memory sections in ascending order. +foreach(region ${MEMORY_REGIONS}) + if("${region}" MATCHES "^{(.*)}$") + cmake_parse_arguments(REGION "" "NAME;START" "" ${CMAKE_MATCH_1}) + math(EXPR start_dec "${REGION_START}" OUTPUT_FORMAT DECIMAL) + set(region_id ${start_dec}_${REGION_NAME}) + set(region_${region_id} ${region}) + string(REPLACE ";" "\;" region_${region_id} "${region_${region_id}}") + list(APPEND region_sort ${region_id}) + endif() +endforeach() + +list(SORT region_sort COMPARE NATURAL) +set(MEMORY_REGIONS_SORTED) +foreach(region_start ${region_sort}) + list(APPEND MEMORY_REGIONS_SORTED "${region_${region_start}}") +endforeach() +# sorting complete. + +foreach(region ${MEMORY_REGIONS_SORTED}) + if("${region}" MATCHES "^{(.*)}$") + create_region(OBJECT new_region ${CMAKE_MATCH_1}) + + add_region(OBJECT ${new_system} REGION ${new_region}) + endif() +endforeach() + +foreach(group ${GROUPS}) + if("${group}" MATCHES "^{(.*)}$") + create_group(OBJECT new_group ${CMAKE_MATCH_1}) + endif() +endforeach() + +foreach(section ${SECTIONS}) + if("${section}" MATCHES "^{(.*)}$") + create_section(${CMAKE_MATCH_1} SYSTEM ${new_system}) + endif() +endforeach() + +foreach(symbol ${SYMBOLS}) + if("${symbol}" MATCHES "^{(.*)}$") + create_symbol(OBJECT ${new_system} ${CMAKE_MATCH_1}) + endif() +endforeach() + +get_property(regions GLOBAL PROPERTY ${new_system}_REGIONS) +foreach(region ${regions}) + process_region(OBJECT ${region}) +endforeach() + +set(OUT) +to_string(OBJECT ${new_system} STRING OUT) + +if(OUT_FILE) + file(WRITE ${OUT_FILE} "${OUT}") +endif()