# ToDo: # - Ensure LMA / VMA sections are correctly grouped similar to scatter file creation. cmake_minimum_required(VERSION 3.20.0) set(SORT_TYPE_NAME SORT_BY_NAME) function(system_to_string) cmake_parse_arguments(STRING "" "OBJECT;STRING" "" ${ARGN}) get_property(name GLOBAL PROPERTY ${STRING_OBJECT}_NAME) get_property(regions GLOBAL PROPERTY ${STRING_OBJECT}_REGIONS) get_property(format GLOBAL PROPERTY ${STRING_OBJECT}_FORMAT) get_property(entry GLOBAL PROPERTY ${STRING_OBJECT}_ENTRY) get_property(symbols GLOBAL PROPERTY ${STRING_OBJECT}_SYMBOLS) set(${STRING_STRING} "OUTPUT_FORMAT(\"${format}\")\n\n") set(${STRING_STRING} "${${STRING_STRING}}MEMORY\n{\n") foreach(region ${regions}) get_property(name GLOBAL PROPERTY ${region}_NAME) get_property(address GLOBAL PROPERTY ${region}_ADDRESS) get_property(flags GLOBAL PROPERTY ${region}_FLAGS) get_property(size GLOBAL PROPERTY ${region}_SIZE) if(DEFINED flags) set(flags "(${flags})") endif() if(DEFINED address) set(start ": ORIGIN = (${address})") endif() if(DEFINED size) set(size ", LENGTH = (${size})") endif() set(memory_region " ${name} ${flags} ${start}${size}") set(${STRING_STRING} "${${STRING_STRING}}${memory_region}\n") endforeach() set(${STRING_STRING} "${${STRING_STRING}}}\n\n") set(${STRING_STRING} "${${STRING_STRING}}ENTRY(\"${entry}\")\n\n") set(${STRING_STRING} "${${STRING_STRING}}SECTIONS\n{") foreach(region ${regions}) to_string(OBJECT ${region} STRING ${STRING_STRING}) endforeach() get_property(sections GLOBAL PROPERTY ${STRING_OBJECT}_SECTIONS_FIXED) foreach(section ${sections}) to_string(OBJECT ${section} STRING ${STRING_STRING}) endforeach() get_property(sections GLOBAL PROPERTY ${STRING_OBJECT}_SECTIONS) foreach(section ${sections}) to_string(OBJECT ${section} STRING ${STRING_STRING}) endforeach() foreach(symbol ${symbols}) to_string(OBJECT ${symbol} STRING ${STRING_STRING}) endforeach() set(${STRING_STRING} "${${STRING_STRING}}\n}\n" PARENT_SCOPE) endfunction() function(symbol_to_string) cmake_parse_arguments(STRING "" "SYMBOL;STRING" "" ${ARGN}) get_property(name GLOBAL PROPERTY ${STRING_SYMBOL}_NAME) get_property(expr GLOBAL PROPERTY ${STRING_SYMBOL}_EXPR) get_property(size GLOBAL PROPERTY ${STRING_SYMBOL}_SIZE) get_property(symbol GLOBAL PROPERTY ${STRING_SYMBOL}_SYMBOL) get_property(subalign GLOBAL PROPERTY ${STRING_SYMBOL}_SUBALIGN) string(REPLACE "\\" "" expr "${expr}") string(REGEX MATCHALL "@([^@]*)@" match_res ${expr}) foreach(match ${match_res}) string(REPLACE "@" "" match ${match}) string(REPLACE "@${match}@" "${match}" expr ${expr}) endforeach() set(${STRING_STRING} "${${STRING_STRING}}\n${symbol} = ${expr};\n" PARENT_SCOPE) endfunction() function(group_to_string) cmake_parse_arguments(STRING "" "OBJECT;STRING" "" ${ARGN}) get_property(type GLOBAL PROPERTY ${STRING_OBJECT}_OBJ_TYPE) if(${type} STREQUAL REGION) get_property(empty GLOBAL PROPERTY ${STRING_OBJECT}_EMPTY) if(empty) return() endif() get_property(address GLOBAL PROPERTY ${STRING_OBJECT}_ADDRESS) set(${STRING_STRING} "${${STRING_STRING}}\n . = ${address};\n\n") else() get_property(name GLOBAL PROPERTY ${STRING_OBJECT}_NAME) get_property(symbol GLOBAL PROPERTY ${STRING_OBJECT}_SYMBOL) string(TOLOWER ${name} name) get_objects(LIST sections OBJECT ${STRING_OBJECT} TYPE SECTION) list(GET sections 0 section) get_property(first_section_name GLOBAL PROPERTY ${section}_NAME) if(DEFINED first_section_name AND "${symbol}" STREQUAL "SECTION") set_property(GLOBAL APPEND PROPERTY ${section}_START_SYMBOLS __${name}_start) else() set(${STRING_STRING} "${${STRING_STRING}}\n __${name}_start = .;\n") endif() set(${STRING_STRING} "${${STRING_STRING}}\n __${name}_size = __${name}_end - __${name}_start;\n") set(${STRING_STRING} "${${STRING_STRING}}\n __${name}_load_start = LOADADDR(${first_section_name});\n") endif() get_property(sections GLOBAL PROPERTY ${STRING_OBJECT}_SECTIONS_FIXED) foreach(section ${sections}) to_string(OBJECT ${section} STRING ${STRING_STRING}) endforeach() get_property(groups GLOBAL PROPERTY ${STRING_OBJECT}_GROUPS) foreach(group ${groups}) to_string(OBJECT ${group} STRING ${STRING_STRING}) endforeach() get_property(sections GLOBAL PROPERTY ${STRING_OBJECT}_SECTIONS) foreach(section ${sections}) to_string(OBJECT ${section} STRING ${STRING_STRING}) endforeach() get_parent(OBJECT ${STRING_OBJECT} PARENT parent TYPE SYSTEM) get_property(regions GLOBAL PROPERTY ${parent}_REGIONS) list(REMOVE_ITEM regions ${STRING_OBJECT}) foreach(region ${regions}) if(${type} STREQUAL REGION) get_property(address GLOBAL PROPERTY ${region}_ADDRESS) set(${STRING_STRING} "${${STRING_STRING}}\n . = ${address};\n\n") endif() get_property(vma GLOBAL PROPERTY ${region}_NAME) get_property(sections GLOBAL PROPERTY ${STRING_OBJECT}_${vma}_SECTIONS_FIXED) foreach(section ${sections}) to_string(OBJECT ${section} STRING ${STRING_STRING}) endforeach() get_property(groups GLOBAL PROPERTY ${STRING_OBJECT}_${vma}_GROUPS) foreach(group ${groups}) to_string(OBJECT ${group} STRING ${STRING_STRING}) endforeach() get_property(sections GLOBAL PROPERTY ${STRING_OBJECT}_${vma}_SECTIONS) foreach(section ${sections}) to_string(OBJECT ${section} STRING ${STRING_STRING}) endforeach() endforeach() if(NOT ${type} STREQUAL REGION) set(${STRING_STRING} "${${STRING_STRING}}\n __${name}_end = .;\n") endif() get_property(symbols GLOBAL PROPERTY ${STRING_OBJECT}_SYMBOLS) foreach(symbol ${symbols}) to_string(OBJECT ${symbol} STRING ${STRING_STRING}) endforeach() set(${STRING_STRING} ${${STRING_STRING}} PARENT_SCOPE) endfunction() function(section_to_string) cmake_parse_arguments(STRING "" "SECTION;STRING" "" ${ARGN}) get_property(name GLOBAL PROPERTY ${STRING_SECTION}_NAME) get_property(name_clean GLOBAL PROPERTY ${STRING_SECTION}_NAME_CLEAN) get_property(address GLOBAL PROPERTY ${STRING_SECTION}_ADDRESS) get_property(type GLOBAL PROPERTY ${STRING_SECTION}_TYPE) get_property(align_in GLOBAL PROPERTY ${STRING_SECTION}_ALIGN_WITH_INPUT) get_property(align GLOBAL PROPERTY ${STRING_SECTION}_ALIGN) get_property(subalign GLOBAL PROPERTY ${STRING_SECTION}_SUBALIGN) get_property(vma GLOBAL PROPERTY ${STRING_SECTION}_VMA) get_property(lma GLOBAL PROPERTY ${STRING_SECTION}_LMA) get_property(noinput GLOBAL PROPERTY ${STRING_SECTION}_NOINPUT) get_property(noinit GLOBAL PROPERTY ${STRING_SECTION}_NOINIT) get_property(nosymbols GLOBAL PROPERTY ${STRING_SECTION}_NOSYMBOLS) get_property(parent GLOBAL PROPERTY ${STRING_SECTION}_PARENT) get_property(start_syms GLOBAL PROPERTY ${STRING_SECTION}_START_SYMBOLS) string(REGEX REPLACE "^[\.]" "" name_clean "${name}") string(REPLACE "." "_" name_clean "${name_clean}") set(SECTION_TYPE_NOLOAD NOLOAD) set(SECTION_TYPE_BSS NOLOAD) if(DEFINED type) set(type " (${SECTION_TYPE_${type}})") endif() set(TEMP "${TEMP} :") set(secalign "") if(align_in) set(secalign " ALIGN_WITH_INPUT") endif() if(DEFINED align) set(secalign "${secalign} ALIGN(${align})") endif() if(DEFINED subalign) set(secalign "${secalign} SUBALIGN(${subalign})") endif() set(TEMP "${name} ${address}${type} :${secalign}\n{") foreach(start_symbol ${start_syms}) set(TEMP "${TEMP}\n ${start_symbol} = .;") endforeach() if(NOT nosymbols) set(TEMP "${TEMP}\n __${name_clean}_start = .;") endif() if(NOT noinput) set(TEMP "${TEMP}\n *(${name})") set(TEMP "${TEMP}\n *(\"${name}.*\")") endif() get_property(indicies GLOBAL PROPERTY ${STRING_SECTION}_SETTINGS_INDICIES) foreach(idx ${indicies}) get_property(align GLOBAL PROPERTY ${STRING_SECTION}_SETTING_${idx}_ALIGN) get_property(any GLOBAL PROPERTY ${STRING_SECTION}_SETTING_${idx}_ANY) get_property(first GLOBAL PROPERTY ${STRING_SECTION}_SETTING_${idx}_FIRST) get_property(keep GLOBAL PROPERTY ${STRING_SECTION}_SETTING_${idx}_KEEP) get_property(sort GLOBAL PROPERTY ${STRING_SECTION}_SETTING_${idx}_SORT) get_property(flags GLOBAL PROPERTY ${STRING_SECTION}_SETTING_${idx}_FLAGS) get_property(input GLOBAL PROPERTY ${STRING_SECTION}_SETTING_${idx}_INPUT) get_property(symbols GLOBAL PROPERTY ${STRING_SECTION}_SETTING_${idx}_SYMBOLS) get_property(offset GLOBAL PROPERTY ${STRING_SECTION}_SETTING_${idx}_OFFSET) if(DEFINED SETTINGS_ALIGN) set(TEMP "${TEMP}\n . = ALIGN(${align});") endif() if(DEFINED symbols) list(LENGTH symbols symbols_count) if(${symbols_count} GREATER 0) list(GET symbols 0 symbol_start) endif() if(${symbols_count} GREATER 1) list(GET symbols 1 symbol_end) endif() endif() if(DEFINED symbol_start) set(TEMP "${TEMP}\n ${symbol_start} = .;") endif() foreach(setting ${input}) if(DEFINED offset AND NOT ("${offset}" STREQUAL "${current_offset}")) set(TEMP "${TEMP}\n . = ${offset};") set(current_offset ${offset}) endif() if(keep AND sort) set(TEMP "${TEMP}\n KEEP(*(${SORT_TYPE_${sort}}(${setting})));") elseif(SETTINGS_SORT) message(WARNING "Not tested") set(TEMP "${TEMP}\n *(${SORT_TYPE_${sort}}(${setting}));") elseif(keep) set(TEMP "${TEMP}\n KEEP(*(${setting}));") else() set(TEMP "${TEMP}\n *(${setting})") endif() endforeach() if(DEFINED symbol_end) set(TEMP "${TEMP}\n ${symbol_end} = .;") endif() set(symbol_start) set(symbol_end) endforeach() if(NOT nosymbols) set(TEMP "${TEMP}\n __${name_clean}_end = .;") endif() if(DEFINED extra_symbol_end) set(TEMP "${TEMP}\n ${extra_symbol_end} = .;") endif() set(TEMP "${TEMP}\n}") 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(TEMP "${TEMP} > ${vma}") endif() if(DEFINED vma AND DEFINED lma) set(TEMP "${TEMP} AT") endif() if(DEFINED lma) set(TEMP "${TEMP} > ${lma}") endif() if(NOT nosymbols) set(TEMP "${TEMP}\n__${name_clean}_size = __${name_clean}_end - __${name_clean}_start;") set(TEMP "${TEMP}\nPROVIDE(__${name_clean}_align = ALIGNOF(${name}));") set(TEMP "${TEMP}\n__${name_clean}_load_start = LOADADDR(${name});") endif() set(${STRING_STRING} "${${STRING_STRING}}\n${TEMP}\n" PARENT_SCOPE) endfunction() # /DISCARD/ is an ld specific section, so let's append it here before processing. list(APPEND SECTIONS "{NAME\;/DISCARD/\;NOINPUT\;TRUE\;NOSYMBOLS\;TRUE}") function(process_region) cmake_parse_arguments(REGION "" "OBJECT" "" ${ARGN}) process_region_common(${ARGN}) set(groups) get_objects(LIST groups OBJECT ${REGION_OBJECT} TYPE GROUP) foreach(group ${groups}) get_property(parent GLOBAL PROPERTY ${group}_PARENT) 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) set_property(GLOBAL PROPERTY ${group}_VMA ${vma}) set_property(GLOBAL PROPERTY ${group}_LMA ${lma}) endif() endforeach() endfunction() include(${CMAKE_CURRENT_LIST_DIR}/../linker_script_common.cmake)