zephyr/cmake/linker/armlink/scatter_script.cmake

445 lines
16 KiB
CMake

cmake_minimum_required(VERSION 3.20.0)
set(SORT_TYPE_NAME Lexical)
# This function post process the region for easier use.
#
# Tasks:
# - Symbol translation using a steering file is configured.
function(process_region)
cmake_parse_arguments(REGION "" "OBJECT" "" ${ARGN})
process_region_common(${ARGN})
get_property(empty GLOBAL PROPERTY ${REGION_OBJECT}_EMPTY)
if(NOT empty)
# For scatter files we move any system symbols into first non-empty load section.
get_parent(OBJECT ${REGION_OBJECT} PARENT parent TYPE SYSTEM)
get_property(symbols GLOBAL PROPERTY ${parent}_SYMBOLS)
set_property(GLOBAL APPEND PROPERTY ${REGION_OBJECT}_SYMBOLS ${symbols})
set_property(GLOBAL PROPERTY ${parent}_SYMBOLS)
endif()
get_property(sections GLOBAL PROPERTY ${REGION_OBJECT}_SECTION_LIST_ORDERED)
foreach(section ${sections})
get_property(name_clean GLOBAL PROPERTY ${section}_NAME_CLEAN)
get_property(noinput GLOBAL PROPERTY ${section}_NOINPUT)
get_property(type GLOBAL PROPERTY ${section}_TYPE)
get_property(indicies GLOBAL PROPERTY ${section}_SETTINGS_INDICIES)
list(LENGTH indicies length)
foreach(idx ${indicies})
set(steering_postfixes Base Limit)
get_property(symbols GLOBAL PROPERTY ${section}_SETTING_${idx}_SYMBOLS)
get_property(sort GLOBAL PROPERTY ${section}_SETTING_${idx}_SORT)
get_property(offset GLOBAL PROPERTY ${section}_SETTING_${idx}_OFFSET)
if(DEFINED offset)
foreach(symbol ${symbols})
list(POP_FRONT steering_postfixes postfix)
math(EXPR offset_dec "${offset}")
set_property(GLOBAL APPEND PROPERTY SYMBOL_STEERING_C
"Image$$${name_clean}_${offset_dec}$$${postfix}"
)
set_property(GLOBAL APPEND PROPERTY SYMBOL_STEERING_FILE
"RESOLVE ${symbol} AS Image$$${name_clean}_${offset_dec}$$${postfix}\n"
)
endforeach()
elseif(sort)
foreach(symbol ${symbols})
list(POP_FRONT steering_postfixes postfix)
set_property(GLOBAL APPEND PROPERTY SYMBOL_STEERING_C
"Image$$${name_clean}_${idx}$$${postfix}"
)
set_property(GLOBAL APPEND PROPERTY SYMBOL_STEERING_FILE
"RESOLVE ${symbol} AS Image$$${name_clean}_${idx}$$${postfix}\n"
)
endforeach()
elseif(DEFINED symbols AND ${length} EQUAL 1 AND noinput)
set(steering_postfixes Base Limit)
foreach(symbol ${symbols})
list(POP_FRONT steering_postfixes postfix)
set_property(GLOBAL APPEND PROPERTY SYMBOL_STEERING_C
"Image$$${name_clean}$$${postfix}"
)
set_property(GLOBAL APPEND PROPERTY SYMBOL_STEERING_FILE
"RESOLVE ${symbol} AS Image$$${name_clean}$$${postfix}\n"
)
endforeach()
endif()
endforeach()
if("${type}" STREQUAL BSS)
set(ZI "$$ZI")
endif()
# Symbols translation here.
set_property(GLOBAL APPEND PROPERTY SYMBOL_STEERING_C "Image$$${name_clean}${ZI}$$Base")
set_property(GLOBAL APPEND PROPERTY SYMBOL_STEERING_C "Image$$${name_clean}${ZI}$$Length")
set_property(GLOBAL APPEND PROPERTY SYMBOL_STEERING_C "Load$$${name_clean}${ZI}$$Base")
set_property(GLOBAL APPEND PROPERTY SYMBOL_STEERING_FILE
"RESOLVE __${name_clean}_start AS Image$$${name_clean}${ZI}$$Base\n"
"RESOLVE __${name_clean}_load_start AS Load$$${name_clean}${ZI}$$Base\n"
"EXPORT __${name_clean}_start AS __${name_clean}_start\n"
)
get_property(symbol_val GLOBAL PROPERTY SYMBOL_TABLE___${name_clean}_end)
set_property(GLOBAL APPEND PROPERTY SYMBOL_STEERING_C "Image$$${symbol_val}${ZI}$$Limit")
set_property(GLOBAL APPEND PROPERTY SYMBOL_STEERING_FILE
"RESOLVE __${name_clean}_end AS Image$$${symbol_val}${ZI}$$Limit\n"
)
if("${symbol_val}" STREQUAL "${name_clean}")
set_property(GLOBAL APPEND PROPERTY SYMBOL_STEERING_FILE
"RESOLVE __${name_clean}_size AS Image$$${name_clean}${ZI}$$Length\n"
)
else()
create_symbol(OBJECT ${REGION_OBJECT} SYMBOL __${name_clean}_size
EXPR "(ImageLimit(${symbol_val}${ZI}) - ImageBase(${name_clean}${ZI}))"
)
endif()
set(ZI)
endforeach()
get_property(groups GLOBAL PROPERTY ${REGION_OBJECT}_GROUP_LIST_ORDERED)
foreach(group ${groups})
get_property(name GLOBAL PROPERTY ${group}_NAME)
string(TOLOWER ${name} name)
get_objects(LIST sections OBJECT ${group} TYPE SECTION)
list(GET sections 0 section)
get_property(first_section_name GLOBAL PROPERTY ${section}_NAME_CLEAN)
list(POP_BACK sections section)
get_property(last_section_name GLOBAL PROPERTY ${section}_NAME_CLEAN)
# Symbols translation here.
set_property(GLOBAL APPEND PROPERTY SYMBOL_STEERING_C "Image$$${first_section_name}$$Base")
set_property(GLOBAL APPEND PROPERTY SYMBOL_STEERING_C "Load$$${first_section_name}$$Base")
set_property(GLOBAL APPEND PROPERTY SYMBOL_STEERING_C "Image$$${last_section_name}$$Limit")
set_property(GLOBAL APPEND PROPERTY SYMBOL_STEERING_FILE
"RESOLVE __${name}_start AS Image$$${first_section_name}$$Base\n"
"EXPORT __${name}_start AS __${name}_start\n"
"RESOLVE __${name}_load_start AS Load$$${first_section_name}$$Base\n"
"EXPORT __${name}_load_start AS __${name}_load_start\n"
)
set_property(GLOBAL APPEND PROPERTY SYMBOL_STEERING_FILE
"RESOLVE __${name}_end AS Image$$${last_section_name}$$Limit\n"
)
create_symbol(OBJECT ${REGION_OBJECT} SYMBOL __${name}_size
EXPR "(ImageLimit(${last_section_name}) - ImageBase(${first_section_name}))"
)
endforeach()
get_property(symbols GLOBAL PROPERTY ${REGION_OBJECT}_SYMBOLS)
foreach(symbol ${symbols})
get_property(name GLOBAL PROPERTY ${symbol}_NAME)
set_property(GLOBAL APPEND PROPERTY SYMBOL_STEERING_C "Image$$${name}$$Base")
set_property(GLOBAL APPEND PROPERTY SYMBOL_STEERING_FILE
"RESOLVE ${name} AS Image$$${name}$$Base\n"
)
endforeach()
endfunction()
#
# String functions - start
#
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)
foreach(region ${regions})
get_property(empty GLOBAL PROPERTY ${region}_EMPTY)
if(NOT empty)
to_string(OBJECT ${region} STRING ${STRING_STRING})
endif()
endforeach()
set(${STRING_STRING} ${${STRING_STRING}} 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(name GLOBAL PROPERTY ${STRING_OBJECT}_NAME)
get_property(address GLOBAL PROPERTY ${STRING_OBJECT}_ADDRESS)
get_property(size GLOBAL PROPERTY ${STRING_OBJECT}_SIZE)
set(${STRING_STRING} "${${STRING_STRING}}\n${name} ${address} NOCOMPRESS ${size}\n{\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})
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()
get_property(symbols GLOBAL PROPERTY ${STRING_OBJECT}_SYMBOLS)
foreach(symbol ${symbols})
to_string(OBJECT ${symbol} STRING ${STRING_STRING})
endforeach()
if(${type} STREQUAL REGION)
set(${STRING_STRING} "${${STRING_STRING}}\n}\n")
endif()
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(address GLOBAL PROPERTY ${STRING_SECTION}_ADDRESS)
get_property(type GLOBAL PROPERTY ${STRING_SECTION}_TYPE)
get_property(align GLOBAL PROPERTY ${STRING_SECTION}_ALIGN)
get_property(subalign GLOBAL PROPERTY ${STRING_SECTION}_SUBALIGN)
get_property(endalign GLOBAL PROPERTY ${STRING_SECTION}_ENDALIGN)
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)
string(REGEX REPLACE "^[\.]" "" name_clean "${name}")
string(REPLACE "." "_" name_clean "${name_clean}")
set(TEMP " ${name_clean}")
if(DEFINED address)
set(TEMP "${TEMP} ${address}")
else()
set(TEMP "${TEMP} +0")
endif()
if(noinit)
# Currently we simply uses offset +0, but we must support offset defined
# externally.
set(TEMP "${TEMP} UNINIT")
endif()
if(subalign)
# Currently we simply uses offset +0, but we must support offset defined
# externally.
set(TEMP "${TEMP} ALIGN ${subalign}")
endif()
if(NOT noinput)
set(TEMP "${TEMP}\n {")
if("${type}" STREQUAL NOLOAD)
set(TEMP "${TEMP}\n *.o(${name}*)")
set(TEMP "${TEMP}\n *.o(${name}*.*)")
elseif(VMA_FLAGS)
# ToDo: Proper names as provided by armclang
# set(TEMP "${TEMP}\n *.o(${SEC_NAME}*, +${VMA_FLAGS})")
# set(TEMP "${TEMP}\n *.o(${SEC_NAME}*.*, +${VMA_FLAGS})")
set(TEMP "${TEMP}\n *.o(${name}*)")
set(TEMP "${TEMP}\n *.o(${name}*.*)")
else()
set(TEMP "${TEMP}\n *.o(${name}*)")
set(TEMP "${TEMP}\n *.o(${name}*.*)")
endif()
else()
set(empty TRUE)
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(offset GLOBAL PROPERTY ${STRING_SECTION}_SETTING_${idx}_OFFSET)
if(DEFINED offset)
set(section_close TRUE)
math(EXPR offset_dec "${offset} + 0")
if(empty)
set(TEMP "${TEMP} EMPTY 0x0\n {")
set(empty FALSE)
endif()
set(last_index ${offset_dec})
if(sort)
set(sorttype "SORTTYPE ${SORT_TYPE_${sort}}")
endif()
set(TEMP "${TEMP}\n }")
set(TEMP "${TEMP}\n ${name_clean}_${offset_dec} (ImageBase(${name_clean}) + ${offset}) ${sorttype}\n {")
elseif(sort)
set(section_close TRUE)
if(empty)
set(TEMP "${TEMP} EMPTY 0x0\n {")
set(empty FALSE)
endif()
set(last_index ${idx})
set(TEMP "${TEMP}\n }")
set(TEMP "${TEMP}\n ${name_clean}_${idx} +0 SORTTYPE ${SORT_TYPE_${sort}}\n {")
endif()
if(empty)
set(TEMP "${TEMP}\n {")
set(empty FALSE)
endif()
foreach(setting ${input})
#set(SETTINGS ${SETTINGS_INPUT})
# # ToDo: The code below had en error in original implementation, causing
# # settings not to be applied
# # Verify behaviour and activate if working as intended.
# if(align)
# set(setting "${setting}, OVERALIGN ${align}")
# endif()
#if(SETTINGS_KEEP)
# armlink has --keep=<section_id>, but is there an scatter equivalent ?
#endif()
if(first)
set(setting "${setting}, +First")
set(first "")
endif()
set(TEMP "${TEMP}\n *.o(${setting})")
endforeach()
if(any)
if(NOT flags)
message(FATAL_ERROR ".ANY requires flags to be set.")
endif()
string(REPLACE ";" " " flags "${flags}")
set(TEMP "${TEMP}\n .ANY (${flags})")
endif()
endforeach()
if(section_close OR DEFINED endalign)
set(section_close)
set(TEMP "${TEMP}\n }")
if(DEFINED endalign)
if(DEFINED last_index)
set(align_expr "AlignExpr(ImageLimit(${name_clean}_${last_index}), ${endalign}) FIXED")
else()
set(align_expr "AlignExpr(ImageLimit(${name_clean}), ${endalign}) FIXED")
endif()
else()
set(align_expr "+0")
endif()
set(TEMP "${TEMP}\n ${name_clean}_end ${align_expr} EMPTY 0x0\n {")
set(last_index)
endif()
set(TEMP "${TEMP}")
# ToDo: add patterns here.
if("${type}" STREQUAL BSS)
set(ZI "$$ZI")
endif()
set(TEMP "${TEMP}\n }")
set(${STRING_STRING} "${${STRING_STRING}}\n${TEMP}\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})
get_property(symbol_val GLOBAL PROPERTY SYMBOL_TABLE_${match})
string(REPLACE "@${match}@" "ImageBase(${symbol_val})" expr ${expr})
endforeach()
if(DEFINED subalign)
set(subalign "ALIGN ${subalign}")
endif()
if(NOT DEFINED size)
set(size "0x0")
endif()
set(${STRING_STRING}
"${${STRING_STRING}}\n ${symbol} ${expr} ${subalign} ${size} { }\n"
PARENT_SCOPE
)
endfunction()
include(${CMAKE_CURRENT_LIST_DIR}/../linker_script_common.cmake)
if(DEFINED STEERING_C)
get_property(symbols_c GLOBAL PROPERTY SYMBOL_STEERING_C)
file(WRITE ${STEERING_C} "/* AUTO-GENERATED - Do not modify\n")
file(APPEND ${STEERING_C} " * AUTO-GENERATED - All changes will be lost\n")
file(APPEND ${STEERING_C} " */\n")
foreach(symbol ${symbols_c})
file(APPEND ${STEERING_C} "extern char ${symbol}[];\n")
endforeach()
file(APPEND ${STEERING_C} "\nint __armlink_symbol_steering(void) {\n")
file(APPEND ${STEERING_C} "\treturn\n")
foreach(symbol ${symbols_c})
file(APPEND ${STEERING_C} "\t\t${OPERAND} (int)${symbol}\n")
set(OPERAND "&")
endforeach()
file(APPEND ${STEERING_C} "\t;\n}\n")
endif()
if(DEFINED STEERING_FILE)
get_property(steering_content GLOBAL PROPERTY SYMBOL_STEERING_FILE)
file(WRITE ${STEERING_FILE} "; AUTO-GENERATED - Do not modify\n")
file(APPEND ${STEERING_FILE} "; AUTO-GENERATED - All changes will be lost\n")
file(APPEND ${STEERING_FILE} ${steering_content})
endif()