cmake: CMake linker script generator pass handling

To prepare for linker script creation with flexible number of linker
passes depending on system configuration then the Zephyr CMake linker
script generator has been updated to use pass names instead of pass
numbers.

This allows greater flexibility as a section can now be active based on
the settings on the pass and not the linking pass index number.

As part of this, the `PASS` processing in `linker_script_common.cmake`
has been adjusted so that it properly handles when a linking pass is
handling multiple settings, such as both `LINKER_APP_SMEM_UNALIGNED`
and `DEVICE_HANDLES_PASS1` in same linking pass.

As the number of linking passes are more flexible, then the PASS
argument in `zephyr_linker_section()` and
`zephyr_linker_section_configure()` has been updated to also support
a `NOT <name>` argument, for example: `PASS NOT LINKER_ZEPHYR_FINAL`.

Signed-off-by: Torsten Rasmussen <Torsten.Rasmussen@nordicsemi.no>
This commit is contained in:
Torsten Rasmussen 2021-11-01 13:22:55 +01:00 committed by Carles Cufí
commit 9c74027a7b
6 changed files with 59 additions and 37 deletions

View file

@ -25,12 +25,12 @@ zephyr_linker_sources_ifdef(CONFIG_GEN_ISR_TABLES
)
if(CONFIG_GEN_ISR_TABLES)
zephyr_linker_section(NAME .intList VMA IDT_LIST LMA IDT_LIST NOINPUT PASS 1)
zephyr_linker_section(NAME .intList VMA IDT_LIST LMA IDT_LIST NOINPUT PASS NOT LINKER_ZEPHYR_FINAL)
zephyr_linker_section_configure(SECTION .intList KEEP INPUT ".irq_info" FIRST)
zephyr_linker_section_configure(SECTION .intList KEEP INPUT ".intList")
zephyr_linker_section_configure(SECTION /DISCARD/ KEEP INPUT ".irq_info" PASS 2)
zephyr_linker_section_configure(SECTION /DISCARD/ KEEP INPUT ".intList" PASS 2)
zephyr_linker_section_configure(SECTION /DISCARD/ KEEP INPUT ".irq_info" PASS LINKER_ZEPHYR_FINAL)
zephyr_linker_section_configure(SECTION /DISCARD/ KEEP INPUT ".intList" PASS LINKER_ZEPHYR_FINAL)
endif()
zephyr_linker_sources_ifdef(CONFIG_ARCH_HAS_RAMFUNC_SUPPORT

View file

@ -3256,7 +3256,7 @@ endfunction()
# [ADDRESS <address>] [ALIGN <alignment>]
# [SUBALIGN <alignment>] [FLAGS <flags>]
# [HIDDEN] [NOINPUT] [NOINIT]
# [PASS <no> [<no>...]
# [PASS [NOT] <name>]
# )
#
# Zephyr linker output section.
@ -3311,11 +3311,14 @@ endfunction()
# NOINPUT : No default input sections will be defined, to setup input
# sections for section <name>, the corresponding
# `zephyr_linker_section_configure()` must be used.
# PASS <no> [<no> ..] : Linker pass iteration where this section should be active.
# PASS [NOT] <name> : Linker pass iteration where this section should be active.
# Default a section will be present during all linker passes
# But in cases a section shall only be present at a specific
# but in cases a section shall only be present at a specific
# pass, this argument can be used. For example to only have
# this section present on the first linker pass, use `PASS 1`.
# this section present on the `TEST` linker pass, use `PASS TEST`.
# It is possible to negate <name>, such as `PASS NOT <name>`.
# For example, `PASS NOT TEST` means the call is effective
# on all but the `TEST` linker pass iteration.
#
# Note: VMA and LMA are mutual exclusive with GROUP
#
@ -3353,6 +3356,17 @@ function(zephyr_linker_section)
endif()
endif()
if(DEFINED SECTION_PASS)
list(LENGTH SECTION_PASS pass_length)
if(${pass_length} GREATER 1)
list(GET SECTION_PASS 0 pass_elem_0)
if((NOT (${pass_elem_0} STREQUAL "NOT")) OR (${pass_length} GREATER 2))
message(FATAL_ERROR "zephyr_linker_section(PASS takes maximum "
"a single argument of the form: '<pass name>' or 'NOT <pass_name>'.")
endif()
endif()
endif()
set(SECTION)
zephyr_linker_arg_val_list(SECTION "${single_args}")
zephyr_linker_arg_val_list(SECTION "${options}")
@ -3513,7 +3527,7 @@ endfunction()
# Usage:
# zephyr_linker_section_configure(SECTION <section> [ALIGN <alignment>]
# [PASS <no>] [PRIO <no>] [SORT <sort>]
# [PASS [NOT] <name>] [PRIO <no>] [SORT <sort>]
# [ANY] [FIRST] [KEEP]
# )
#
@ -3542,18 +3556,20 @@ endfunction()
# you may use `PRIO 50`, `PRIO 20` and so on.
# To ensure an input section is at the end, it is advised
# to use `PRIO 200` and above.
# PASS <no> : The call should only be considered for linker pass number <no>.
# For example, `PASS 1` means the call is only effective
# on first linker pass iteration. `PASS 2` on second iteration,
# and so on.
# PASS [NOT] <name> : The call should only be considered for linker pass where
# <name> is defined. It is possible to negate <name>, such
# as `PASS NOT <name>.
# For example, `PASS TEST` means the call is only effective
# on the `TEST` linker pass iteration. `PASS NOT TEST` on
# all iterations the are not `TEST`.
# FLAGS <flags> : Special section flags such as "+RO", +XO, "+ZI".
# ANY : ANY section flag in scatter file.
# The FLAGS and ANY arguments only has effect for scatter files.
#
function(zephyr_linker_section_configure)
set(options "ANY;FIRST;KEEP")
set(single_args "ALIGN;OFFSET;PASS;PRIO;SECTION;SORT")
set(multi_args "FLAGS;INPUT;SYMBOLS")
set(single_args "ALIGN;OFFSET;PRIO;SECTION;SORT")
set(multi_args "FLAGS;INPUT;PASS;SYMBOLS")
cmake_parse_arguments(SECTION "${options}" "${single_args}" "${multi_args}" ${ARGN})
if(SECTION_UNPARSED_ARGUMENTS)
@ -3568,6 +3584,17 @@ function(zephyr_linker_section_configure)
endif()
endif()
if(DEFINED SECTION_PASS)
list(LENGTH SECTION_PASS pass_length)
if(${pass_length} GREATER 1)
list(GET SECTION_PASS 0 pass_elem_0)
if((NOT (${pass_elem_0} STREQUAL "NOT")) OR (${pass_length} GREATER 2))
message(FATAL_ERROR "zephyr_linker_section_configure(PASS takes maximum "
"a single argument of the form: '<pass name>' or 'NOT <pass_name>'.")
endif()
endif()
endif()
set(SECTION)
zephyr_linker_arg_val_list(SECTION "${single_args}")
zephyr_linker_arg_val_list(SECTION "${options}")

View file

@ -31,10 +31,7 @@ macro(configure_linker_script linker_script_gen linker_pass_define)
set(STEERING_FILE_ARG)
set(STEERING_C_ARG)
if("${linker_pass_define}" STREQUAL "LINKER_ZEPHYR_PREBUILT")
set(PASS 1)
elseif("${linker_pass_define}" STREQUAL "LINKER_ZEPHYR_FINAL")
set(PASS 2)
if("LINKER_ZEPHYR_FINAL" IN_LIST "${linker_pass_define}")
set(STEERING_FILE ${CMAKE_CURRENT_BINARY_DIR}/armlink_symbol_steering.steer)
set(STEERING_C ${CMAKE_CURRENT_BINARY_DIR}/armlink_symbol_steering.c)
set(STEERING_FILE_ARG "-DSTEERING_FILE=${STEERING_FILE}")
@ -46,7 +43,7 @@ macro(configure_linker_script linker_script_gen linker_pass_define)
${STEERING_FILE}
${STEERING_C}
COMMAND ${CMAKE_COMMAND}
-DPASS=${PASS}
-DPASS="${linker_pass_define}"
-DMEMORY_REGIONS="$<TARGET_PROPERTY:linker,MEMORY_REGIONS>"
-DGROUPS="$<TARGET_PROPERTY:linker,GROUPS>"
-DSECTIONS="$<TARGET_PROPERTY:linker,SECTIONS>"
@ -58,7 +55,7 @@ macro(configure_linker_script linker_script_gen linker_pass_define)
-P ${ZEPHYR_BASE}/cmake/linker/armlink/scatter_script.cmake
)
if("${PASS}" EQUAL 2)
if("LINKER_ZEPHYR_FINAL" IN_LIST "${linker_pass_define}")
add_library(armlink_steering OBJECT ${STEERING_C})
target_link_libraries(armlink_steering PRIVATE zephyr_interface)
endif()

View file

@ -32,16 +32,10 @@ macro(configure_linker_script linker_script_gen linker_pass_define)
set(extra_dependencies ${ARGN})
if(CONFIG_CMAKE_LINKER_GENERATOR)
if("${linker_pass_define}" STREQUAL "LINKER_ZEPHYR_PREBUILT")
set(PASS 1)
elseif("${linker_pass_define}" STREQUAL "LINKER_ZEPHYR_FINAL")
set(PASS 2)
endif()
add_custom_command(
OUTPUT ${linker_script_gen}
COMMAND ${CMAKE_COMMAND}
-DPASS=${PASS}
-DPASS="${linker_pass_define}"
-DFORMAT="$<TARGET_PROPERTY:linker,FORMAT>"
-DENTRY="$<TARGET_PROPERTY:linker,ENTRY>"
-DMEMORY_REGIONS="$<TARGET_PROPERTY:linker,MEMORY_REGIONS>"

View file

@ -100,9 +100,11 @@ function(create_section)
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()
if(DEFINED SECTION_PASS)
if(NOT (${SECTION_PASS} IN_LIST PASS))
# This section is not active in this pass, ignore.
return()
endif()
endif()
set_property(GLOBAL PROPERTY SECTION_${SECTION_NAME} TRUE)
@ -128,8 +130,8 @@ function(create_section)
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")
set(settings_single "ALIGN;ANY;FIRST;KEEP;OFFSET;PRIO;SECTION;SORT")
set(settings_multi "FLAGS;INPUT;PASS;SYMBOLS")
foreach(settings ${SECTION_SETTINGS})
if("${settings}" MATCHES "^{(.*)}$")
cmake_parse_arguments(SETTINGS "" "${settings_single}" "${settings_multi}" ${CMAKE_MATCH_1})
@ -138,9 +140,11 @@ function(create_section)
continue()
endif()
if(DEFINED SETTINGS_PASS AND NOT "${PASS}" IN_LIST SETTINGS_PASS)
# This section setting is not active in this pass, ignore.
continue()
if(DEFINED SETTINGS_PASS)
if(NOT (${SETTINGS_PASS} IN_LIST PASS))
# This section setting is not active in this pass, ignore.
continue()
endif()
endif()
if(DEFINED SETTINGS_PRIO)

View file

@ -179,5 +179,5 @@ zephyr_linker_section(NAME zephyr_dbg_info KVMA RAM_REGION GROUP RODATA_REGION N
zephyr_linker_section_configure(SECTION zephyr_dbg_info INPUT ".zephyr_dbg_info" KEEP)
zephyr_linker_section(NAME device_handles KVMA RAM_REGION GROUP RODATA_REGION NOINPUT ${XIP_ALIGN_WITH_INPUT} ENDALIGN 16)
zephyr_linker_section_configure(SECTION device_handles INPUT .__device_handles_pass1* KEEP SORT NAME PASS 1)
zephyr_linker_section_configure(SECTION device_handles INPUT .__device_handles_pass2* KEEP SORT NAME PASS 2)
zephyr_linker_section_configure(SECTION device_handles INPUT .__device_handles_pass1* KEEP SORT NAME PASS LINKER_ZEPHYR_PREBUILT)
zephyr_linker_section_configure(SECTION device_handles INPUT .__device_handles_pass2* KEEP SORT NAME PASS NOT LINKER_ZEPHYR_PREBUILT)