346 lines
12 KiB
CMake
346 lines
12 KiB
CMake
# 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)
|