cmake: CMake linker functions implemented
This commit introduces zephyr_linker CMake functions for creation of linker scripts. The linker functions supports the following features: - Configuration of memory sections - Configuration of memory groups - Creation of output sections - Configuration of input section the should go into output section and how those should be treated, such as sorting, keep, priority. - Defining linker symbols - Specifying Kernel VMA to support virtual linking on x86 Overview of functions and macros introduce with this commit: - pow2round - zephyr_linker - zephyr_linker_memory - zephyr_linker_memory_ifdef - zephyr_linker_group - zephyr_linker_section - zephyr_linker_section_ifdef - zephyr_iterable_section - zephyr_linker_section_obj_level - zephyr_linker_section_configure - zephyr_linker_symbol - zephyr_linker_property_append Signed-off-by: Torsten Rasmussen <Torsten.Rasmussen@nordicsemi.no>
This commit is contained in:
parent
da926f6855
commit
a7d2fd9fb6
1 changed files with 649 additions and 0 deletions
|
@ -21,6 +21,8 @@
|
|||
# 3.5. File system management
|
||||
# 4. Devicetree extensions
|
||||
# 4.1 dt_*
|
||||
# 5. Zephyr linker functions
|
||||
# 5.1. zephyr_linker*
|
||||
|
||||
########################################################
|
||||
# 1. Zephyr-aware extensions
|
||||
|
@ -1248,6 +1250,38 @@ function(check_dtc_flag flag ok)
|
|||
endif()
|
||||
endfunction()
|
||||
|
||||
# Function to round number to next power of two.
|
||||
#
|
||||
# Usage:
|
||||
# pow2round(<variable>)
|
||||
#
|
||||
# Example:
|
||||
# set(test 2)
|
||||
# pow2round(test)
|
||||
# # test is still 2
|
||||
#
|
||||
# set(test 5)
|
||||
# pow2round(test)
|
||||
# # test is now 8
|
||||
#
|
||||
# Arguments:
|
||||
# n = Variable containing the number to round
|
||||
function(pow2round n)
|
||||
math(EXPR x "${${n}} & (${${n}} - 1)")
|
||||
if(${x} EQUAL 0)
|
||||
return()
|
||||
endif()
|
||||
|
||||
math(EXPR ${n} "${${n}} | (${${n}} >> 1)")
|
||||
math(EXPR ${n} "${${n}} | (${${n}} >> 2)")
|
||||
math(EXPR ${n} "${${n}} | (${${n}} >> 4)")
|
||||
math(EXPR ${n} "${${n}} | (${${n}} >> 8)")
|
||||
math(EXPR ${n} "${${n}} | (${${n}} >> 16)")
|
||||
math(EXPR ${n} "${${n}} | (${${n}} >> 32)")
|
||||
math(EXPR ${n} "${${n}} + 1")
|
||||
set(${n} ${${n}} PARENT_SCOPE)
|
||||
endfunction()
|
||||
|
||||
########################################################
|
||||
# 2. Kconfig-aware extensions
|
||||
########################################################
|
||||
|
@ -2809,3 +2843,618 @@ function(dt_chosen var)
|
|||
set(${var} ${${var}} PARENT_SCOPE)
|
||||
endif()
|
||||
endfunction()
|
||||
|
||||
########################################################
|
||||
# 5. Zephyr linker function
|
||||
########################################################
|
||||
# 5.1. zephyr_linker*
|
||||
#
|
||||
# The following methods are for defining linker structure using CMake functions.
|
||||
#
|
||||
# This allows Zephyr developers to define linker sections and their content and
|
||||
# have this configuration rendered into an appropriate linker script based on
|
||||
# the toolchain in use.
|
||||
# For example:
|
||||
# ld linker scripts with GNU ld
|
||||
# ARM scatter files with ARM linker.
|
||||
#
|
||||
# Example usage:
|
||||
# zephyr_linker_section(
|
||||
# NAME my_data
|
||||
# VMA RAM
|
||||
# LMA FLASH
|
||||
# )
|
||||
#
|
||||
# and to configure special input sections for the section
|
||||
# zephyr_linker_section_configure(
|
||||
# SECTION my_data
|
||||
# INPUT "my_custom_data"
|
||||
# KEEP
|
||||
# )
|
||||
|
||||
|
||||
# Usage:
|
||||
# zephyr_linker([FORMAT <format>]
|
||||
# [ENTRY <entry symbol>]
|
||||
# )
|
||||
#
|
||||
# Zephyr linker general settings.
|
||||
# This function specifies general settings for the linker script to be generated.
|
||||
#
|
||||
# FORMAT <format>: The output format of the linked executable.
|
||||
# ENTRY <entry symbolformat>: The code entry symbol.
|
||||
#
|
||||
function(zephyr_linker)
|
||||
set(single_args "ENTRY;FORMAT")
|
||||
cmake_parse_arguments(LINKER "" "${single_args}" "" ${ARGN})
|
||||
|
||||
if(LINKER_UNPARSED_ARGUMENTS)
|
||||
message(FATAL_ERROR "zephyr_linker(${ARGV0} ...) given unknown "
|
||||
"arguments: ${LINKER_UNPARSED_ARGUMENTS}"
|
||||
)
|
||||
endif()
|
||||
|
||||
if(DEFINED LINKER_FORMAT)
|
||||
get_property(format_defined TARGET linker PROPERTY FORMAT SET)
|
||||
if(format_defined)
|
||||
message(FATAL_ERROR "zephyr_linker(FORMAT ...) already configured.")
|
||||
else()
|
||||
set_property(TARGET linker PROPERTY FORMAT ${LINKER_FORMAT})
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(DEFINED LINKER_ENTRY)
|
||||
get_property(entry_defined TARGET linker PROPERTY ENTRY SET)
|
||||
if(entry_defined)
|
||||
message(FATAL_ERROR "zephyr_linker(ENTRY ...) already configured.")
|
||||
else()
|
||||
set_property(TARGET linker PROPERTY ENTRY ${LINKER_ENTRY})
|
||||
endif()
|
||||
endif()
|
||||
endfunction()
|
||||
|
||||
# Usage:
|
||||
# zephyr_linker_memory(NAME <name> START <address> SIZE <size> FLAGS <flags>)
|
||||
#
|
||||
# Zephyr linker memory.
|
||||
# This function specifies a memory region for the platform in use.
|
||||
#
|
||||
# Note:
|
||||
# This function should generally be called with values obtained from
|
||||
# devicetree or Kconfig.
|
||||
#
|
||||
# NAME <name> : Name of the memory region, for example FLASH.
|
||||
# START <address>: Start address of the memory region.
|
||||
# Start address can be given as decimal or hex value.
|
||||
# SIZE <size> : Size of the memory region.
|
||||
# Size can be given as decimal value, hex value, or decimal with postfix k or m.
|
||||
# All the following are valid values:
|
||||
# 1048576, 0x10000, 1024k, 1024K, 1m, and 1M.
|
||||
# FLAGS <flags> : Flags describing properties of the memory region.
|
||||
# Currently supported:
|
||||
# r: Read-only region
|
||||
# w: Read-write region
|
||||
# x: Executable region
|
||||
# The flags r and x, or w and x may be combined like: rx, wx.
|
||||
function(zephyr_linker_memory)
|
||||
set(single_args "FLAGS;NAME;SIZE;START")
|
||||
cmake_parse_arguments(MEMORY "" "${single_args}" "" ${ARGN})
|
||||
|
||||
if(MEMORY_UNPARSED_ARGUMENTS)
|
||||
message(FATAL_ERROR "zephyr_linker_memory(${ARGV0} ...) given unknown "
|
||||
"arguments: ${MEMORY_UNPARSED_ARGUMENTS}"
|
||||
)
|
||||
endif()
|
||||
|
||||
foreach(arg ${single_args})
|
||||
if(NOT DEFINED MEMORY_${arg})
|
||||
message(FATAL_ERROR "zephyr_linker_memory(${ARGV0} ...) missing required "
|
||||
"argument: ${arg}"
|
||||
)
|
||||
endif()
|
||||
endforeach()
|
||||
|
||||
set(MEMORY)
|
||||
zephyr_linker_arg_val_list(MEMORY "${single_args}")
|
||||
|
||||
string(REPLACE ";" "\;" MEMORY "${MEMORY}")
|
||||
set_property(TARGET linker
|
||||
APPEND PROPERTY MEMORY_REGIONS "{${MEMORY}}"
|
||||
)
|
||||
endfunction()
|
||||
|
||||
# Usage:
|
||||
# zephyr_linker_memory_ifdef(<setting> NAME <name> START <address> SIZE <size> FLAGS <flags>)
|
||||
#
|
||||
# Will create memory region if <setting> is enabled.
|
||||
#
|
||||
# <setting>: Setting to check for True value before invoking
|
||||
# zephyr_linker_memory()
|
||||
#
|
||||
# See zephyr_linker_memory() description for other supported arguments.
|
||||
#
|
||||
macro(zephyr_linker_memory_ifdef feature_toggle)
|
||||
if(${${feature_toggle}})
|
||||
zephyr_linker_memory(${ARGN})
|
||||
endif()
|
||||
endmacro()
|
||||
|
||||
# Usage:
|
||||
# zephyr_linker_group(NAME <name> [VMA <region|group>] [LMA <region|group>])
|
||||
# zephyr_linker_group(NAME <name> GROUP <group>)
|
||||
#
|
||||
# Zephyr linker group.
|
||||
# This function specifies a group inside a memory region or another group.
|
||||
#
|
||||
# The group ensures that all section inside the group are located together inside
|
||||
# the specified group.
|
||||
#
|
||||
# This also allows for section placement inside a given group without the section
|
||||
# itself needing the precise knowledge regarding the exact memory region this
|
||||
# section will be placed in, as that will be determined by the group setup.
|
||||
#
|
||||
# Each group will define the following linker symbols:
|
||||
# __<name>_start : Start address of the group
|
||||
# __<name>_end : End address of the group
|
||||
# __<name>_size : Size of the group
|
||||
#
|
||||
# Note: <name> will be converted to lower casing for linker symbols definitions.
|
||||
#
|
||||
# NAME <name> : Name of the group.
|
||||
# VMA <region|group> : VMA Memory region or group to be used for this group.
|
||||
# If a group is used then the VMA region of that group will be used.
|
||||
# LMA <region|group> : Memory region or group to be used for this group.
|
||||
# GROUP <group> : Place the new group inside the existing group <group>
|
||||
#
|
||||
# Note: VMA and LMA are mutual exclusive with GROUP
|
||||
#
|
||||
# Example:
|
||||
# zephyr_linker_memory(NAME memA START ... SIZE ... FLAGS ...)
|
||||
# zephyr_linker_group(NAME groupA LMA memA)
|
||||
# zephyr_linker_group(NAME groupB LMA groupA)
|
||||
#
|
||||
# will create two groups in same memory region as groupB will inherit the LMA
|
||||
# from groupA:
|
||||
#
|
||||
# +-----------------+
|
||||
# | memory region A |
|
||||
# | |
|
||||
# | +-------------+ |
|
||||
# | | groupA | |
|
||||
# | +-------------+ |
|
||||
# | |
|
||||
# | +-------------+ |
|
||||
# | | groupB | |
|
||||
# | +-------------+ |
|
||||
# | |
|
||||
# +-----------------+
|
||||
#
|
||||
# whereas
|
||||
# zephyr_linker_memory(NAME memA START ... SIZE ... FLAGS ...)
|
||||
# zephyr_linker_group(NAME groupA LMA memA)
|
||||
# zephyr_linker_group(NAME groupB GROUP groupA)
|
||||
#
|
||||
# will create groupB inside groupA:
|
||||
#
|
||||
# +---------------------+
|
||||
# | memory region A |
|
||||
# | |
|
||||
# | +-----------------+ |
|
||||
# | | groupA | |
|
||||
# | | | |
|
||||
# | | +-------------+ | |
|
||||
# | | | groupB | | |
|
||||
# | | +-------------+ | |
|
||||
# | | | |
|
||||
# | +-----------------+ |
|
||||
# | |
|
||||
# +---------------------+
|
||||
function(zephyr_linker_group)
|
||||
set(single_args "NAME;GROUP;LMA;VMA")
|
||||
cmake_parse_arguments(GROUP "" "${single_args}" "" ${ARGN})
|
||||
|
||||
if(GROUP_UNPARSED_ARGUMENTS)
|
||||
message(FATAL_ERROR "zephyr_linker_group(${ARGV0} ...) given unknown "
|
||||
"arguments: ${GROUP_UNPARSED_ARGUMENTS}"
|
||||
)
|
||||
endif()
|
||||
|
||||
if(DEFINED GROUP_GROUP AND (DEFINED GROUP_VMA OR DEFINED GROUP_LMA))
|
||||
message(FATAL_ERROR "zephyr_linker_group(GROUP ...) cannot be used with "
|
||||
"VMA or LMA"
|
||||
)
|
||||
endif()
|
||||
|
||||
set(GROUP)
|
||||
zephyr_linker_arg_val_list(GROUP "${single_args}")
|
||||
|
||||
string(REPLACE ";" "\;" GROUP "${GROUP}")
|
||||
set_property(TARGET linker
|
||||
APPEND PROPERTY GROUPS "{${GROUP}}"
|
||||
)
|
||||
endfunction()
|
||||
|
||||
# Usage:
|
||||
# zephyr_linker_section(NAME <name> [GROUP <group>]
|
||||
# [VMA <region|group>] [LMA <region|group>]
|
||||
# [ADDRESS <address>] [ALIGN <alignment>]
|
||||
# [SUBALIGN <alignment>] [FLAGS <flags>]
|
||||
# [HIDDEN] [NOINPUT] [NOINIT]
|
||||
# [PASS <no> [<no>...]
|
||||
# )
|
||||
#
|
||||
# Zephyr linker output section.
|
||||
# This function specifies an output section for the linker.
|
||||
#
|
||||
# When using zephyr_linker_section(NAME <name>) an output section with <name>
|
||||
# will be configured. This section will default include input sections of the
|
||||
# same name, unless NOINPUT is specified.
|
||||
# This means the section named `foo` will default include the sections matching
|
||||
# `foo` and `foo.*`
|
||||
# Each output section will define the following linker symbols:
|
||||
# __<name>_start : Start address of the section
|
||||
# __<name>_end : End address of the section
|
||||
# __<name>_size : Size of the section
|
||||
# __<name>_load_start : Load address of the section, if VMA = LMA then this
|
||||
# value will be identical to `__<name>_start`
|
||||
#
|
||||
# The location of the output section can be controlled using LMA, VMA, and
|
||||
# address parameters
|
||||
#
|
||||
# NAME <name> : Name of the output section.
|
||||
# VMA <region|group> : VMA Memory region or group where code / data is located runtime (VMA)
|
||||
# If <group> is used here it means the section will use the
|
||||
# same VMA memory region as <group> but will not be placed
|
||||
# inside the group itself, see also GROUP argument.
|
||||
# KVMA <region|group> : Kernel VMA Memory region or group where code / data is located runtime (VMA)
|
||||
# When MMU is active and Kernel VM base and offset is different
|
||||
# from SRAM base and offset, then the region defined by KVMA will
|
||||
# be used as VMA.
|
||||
# If <group> is used here it means the section will use the
|
||||
# same VMA memory region as <group> but will not be placed
|
||||
# inside the group itself, see also GROUP argument.
|
||||
# LMA <region|group> : Memory region or group where code / data is loaded (LMA)
|
||||
# If VMA is different from LMA, the code / data will be loaded
|
||||
# from LMA into VMA at bootup, this is usually the case for
|
||||
# global or static variables that are loaded in rom and copied
|
||||
# to ram at boot time.
|
||||
# If <group> is used here it means the section will use the
|
||||
# same LMA memory region as <group> but will not be placed
|
||||
# inside the group itself, see also GROUP argument.
|
||||
# GROUP <group> : Place this section inside the group <group>
|
||||
# ADDRESS <address> : Specific address to use for this section.
|
||||
# ALIGN_WITH_INPUT : The alignment difference between VMA and LMA is kept
|
||||
# intact for this section.
|
||||
# ALIGN <alignment> : Align the execution address with alignment.
|
||||
# SUBALIGN <alignment>: Align input sections with alignment value.
|
||||
# ENDALIGN <alignment>: Align the end so that next output section will start aligned.
|
||||
# This only has effect on Scatter scripts.
|
||||
# Note: Regarding all alignment attributes. Not all linkers may handle alignment
|
||||
# in identical way. For example the Scatter file will align both load and
|
||||
# execution address (LMA and VMA) to be aligned when given the ALIGN attribute.
|
||||
# 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.
|
||||
# Default a section will be present during all linker passes
|
||||
# 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`.
|
||||
#
|
||||
# Note: VMA and LMA are mutual exclusive with GROUP
|
||||
#
|
||||
function(zephyr_linker_section)
|
||||
set(options "ALIGN_WITH_INPUT;HIDDEN;NOINIT;NOINPUT")
|
||||
set(single_args "ADDRESS;ALIGN;ENDALIGN;GROUP;KVMA;LMA;NAME;SUBALIGN;TYPE;VMA")
|
||||
set(multi_args "PASS")
|
||||
cmake_parse_arguments(SECTION "${options}" "${single_args}" "${multi_args}" ${ARGN})
|
||||
|
||||
if(SECTION_UNPARSED_ARGUMENTS)
|
||||
message(WARNING "zephyr_linker_section(${ARGV0} ...) given unknown "
|
||||
"arguments: ${SECTION_UNPARSED_ARGUMENTS}"
|
||||
)
|
||||
endif()
|
||||
|
||||
if(DEFINED SECTION_GROUP AND (DEFINED SECTION_VMA OR DEFINED SECTION_LMA))
|
||||
message(FATAL_ERROR "zephyr_linker_section(GROUP ...) cannot be used with "
|
||||
"VMA or LMA"
|
||||
)
|
||||
endif()
|
||||
|
||||
if(DEFINED SECTION_KVMA)
|
||||
# If KVMA is set and the Kernel virtual memory settings reqs are met, we
|
||||
# substitute the VMA setting with the specified KVMA value.
|
||||
if(CONFIG_MMU)
|
||||
math(EXPR KERNEL_MEM_VM_OFFSET
|
||||
"(${CONFIG_KERNEL_VM_BASE} + ${CONFIG_KERNEL_VM_OFFSET})\
|
||||
- (${CONFIG_SRAM_BASE_ADDRESS} + ${CONFIG_SRAM_OFFSET})"
|
||||
)
|
||||
|
||||
if(NOT (${KERNEL_MEM_VM_OFFSET} EQUAL 0))
|
||||
set(SECTION_VMA ${SECTION_KVMA})
|
||||
set(SECTION_KVMA)
|
||||
endif()
|
||||
endif()
|
||||
endif()
|
||||
|
||||
set(SECTION)
|
||||
zephyr_linker_arg_val_list(SECTION "${single_args}")
|
||||
zephyr_linker_arg_val_list(SECTION "${options}")
|
||||
zephyr_linker_arg_val_list(SECTION "${multi_args}")
|
||||
|
||||
string(REPLACE ";" "\;" SECTION "${SECTION}")
|
||||
set_property(TARGET linker
|
||||
APPEND PROPERTY SECTIONS "{${SECTION}}"
|
||||
)
|
||||
endfunction()
|
||||
|
||||
# Usage:
|
||||
# zephyr_linker_section_ifdef(<setting>
|
||||
# NAME <name> [VMA <region>] [LMA <region>]
|
||||
# [ADDRESS <address>] [ALIGN <alignment>]
|
||||
# [SUBALIGN <alignment>] [FLAGS <flags>]
|
||||
# [HIDDEN] [NOINPUT] [NOINIT]
|
||||
# [PASS <no> [<no>...]
|
||||
# )
|
||||
#
|
||||
# Will create an output section if <setting> is enabled.
|
||||
#
|
||||
# <setting>: Setting to check for True value before invoking
|
||||
# zephyr_linker_section()
|
||||
#
|
||||
# See zephyr_linker_section() description for other supported arguments.
|
||||
#
|
||||
macro(zephyr_linker_section_ifdef feature_toggle)
|
||||
if(${${feature_toggle}})
|
||||
zephyr_linker_section(${ARGN})
|
||||
endif()
|
||||
endmacro()
|
||||
|
||||
# Usage:
|
||||
# zephyr_iterable_section(NAME <name> [GROUP <group>]
|
||||
# [VMA <region|group>] [LMA <region|group>]
|
||||
# [ALIGN_WITH_INPUT] [SUBALIGN <alignment>]
|
||||
# )
|
||||
#
|
||||
#
|
||||
# Define an output section which will set up an iterable area
|
||||
# of equally-sized data structures. For use with Z_STRUCT_SECTION_ITERABLE.
|
||||
# Input sections will be sorted by name in lexicographical order.
|
||||
#
|
||||
# Each list for an input section will define the following linker symbols:
|
||||
# _<name>_list_start: Start of the iterable list
|
||||
# _<name>_list_end : End of the iterable list
|
||||
#
|
||||
# The output section will be named `<name>_area` and define the following linker
|
||||
# symbols:
|
||||
# __<name>_area_start : Start address of the section
|
||||
# __<name>_area_end : End address of the section
|
||||
# __<name>_area_size : Size of the section
|
||||
# __<name>_area_load_start : Load address of the section, if VMA = LMA then this
|
||||
# value will be identical to `__<name>_area_start`
|
||||
#
|
||||
# NAME <name> : Name of the struct type, the output section be named
|
||||
# accordingly as: <name>_area.
|
||||
# VMA <region|group> : VMA Memory region where code / data is located runtime (VMA)
|
||||
# LMA <region|group> : Memory region where code / data is loaded (LMA)
|
||||
# If VMA is different from LMA, the code / data will be loaded
|
||||
# from LMA into VMA at bootup, this is usually the case for
|
||||
# global or static variables that are loaded in rom and copied
|
||||
# to ram at boot time.
|
||||
# GROUP <group> : Place this section inside the group <group>
|
||||
# ADDRESS <address> : Specific address to use for this section.
|
||||
# ALIGN_WITH_INPUT : The alignment difference between VMA and LMA is kept
|
||||
# intact for this section.
|
||||
# SUBALIGN <alignment>: Force input alignment with size <alignment>
|
||||
# Note: Regarding all alignment attributes. Not all linkers may handle alignment
|
||||
# in identical way. For example the Scatter file will align both load and
|
||||
# execution address (LMA and VMA) to be aligned when given the ALIGN attribute.
|
||||
#/
|
||||
function(zephyr_iterable_section)
|
||||
# ToDo - Should we use ROM, RAM, etc as arguments ?
|
||||
set(options "ALIGN_WITH_INPUT")
|
||||
set(single_args "GROUP;LMA;NAME;SUBALIGN;VMA")
|
||||
set(multi_args "")
|
||||
set(align_input)
|
||||
cmake_parse_arguments(SECTION "${options}" "${single_args}" "${multi_args}" ${ARGN})
|
||||
|
||||
if(NOT DEFINED SECTION_NAME)
|
||||
message(FATAL_ERROR "zephyr_iterable_section(${ARGV0} ...) missing "
|
||||
"required argument: NAME"
|
||||
)
|
||||
endif()
|
||||
|
||||
if(NOT DEFINED SECTION_SUBALIGN)
|
||||
message(FATAL_ERROR "zephyr_iterable_section(${ARGV0} ...) missing "
|
||||
"required argument: SUBALIGN"
|
||||
)
|
||||
endif()
|
||||
|
||||
if(SECTION_ALIGN_WITH_INPUT)
|
||||
set(align_input ALIGN_WITH_INPUT)
|
||||
endif()
|
||||
|
||||
zephyr_linker_section(
|
||||
NAME ${SECTION_NAME}_area
|
||||
GROUP "${SECTION_GROUP}"
|
||||
VMA "${SECTION_VMA}" LMA "${SECTION_LMA}"
|
||||
NOINPUT ${align_input} SUBALIGN ${SECTION_SUBALIGN}
|
||||
)
|
||||
zephyr_linker_section_configure(
|
||||
SECTION ${SECTION_NAME}_area
|
||||
INPUT "._${SECTION_NAME}.static.*"
|
||||
SYMBOLS _${SECTION_NAME}_list_start _${SECTION_NAME}_list_end
|
||||
KEEP SORT NAME
|
||||
)
|
||||
endfunction()
|
||||
|
||||
# Usage:
|
||||
# zephyr_linker_section_obj_level(SECTION <section> LEVEL <level>)
|
||||
#
|
||||
# generate a symbol to mark the start of the objects array for
|
||||
# the specified object and level, then link all of those objects
|
||||
# (sorted by priority). Ensure the objects aren't discarded if there is
|
||||
# no direct reference to them.
|
||||
#
|
||||
# This is useful content such as struct devices.
|
||||
#
|
||||
# For example: zephyr_linker_section_obj_level(SECTION init LEVEL PRE_KERNEL_1)
|
||||
# will create an input section matching `.z_init_PRE_KERNEL_1?_` and
|
||||
# `.z_init_PRE_KERNEL_1??_`.
|
||||
#
|
||||
# SECTION <section>: Section in which the objects shall be placed
|
||||
# LEVEL <level> : Priority level, all input sections matching the level
|
||||
# will be sorted.
|
||||
#
|
||||
function(zephyr_linker_section_obj_level)
|
||||
set(single_args "SECTION;LEVEL")
|
||||
cmake_parse_arguments(OBJ "" "${single_args}" "" ${ARGN})
|
||||
|
||||
if(NOT DEFINED OBJ_SECTION)
|
||||
message(FATAL_ERROR "zephyr_linker_section_obj_level(${ARGV0} ...) "
|
||||
"missing required argument: SECTION"
|
||||
)
|
||||
endif()
|
||||
|
||||
if(NOT DEFINED OBJ_LEVEL)
|
||||
message(FATAL_ERROR "zephyr_linker_section_obj_level(${ARGV0} ...) "
|
||||
"missing required argument: LEVEL"
|
||||
)
|
||||
endif()
|
||||
|
||||
zephyr_linker_section_configure(
|
||||
SECTION ${OBJ_SECTION}
|
||||
INPUT ".z_${OBJ_SECTION}_${OBJ_LEVEL}?_"
|
||||
SYMBOLS __${OBJ_SECTION}_${OBJ_LEVEL}_start
|
||||
KEEP SORT NAME
|
||||
)
|
||||
zephyr_linker_section_configure(
|
||||
SECTION ${OBJ_SECTION}
|
||||
INPUT ".z_${OBJ_SECTION}_${OBJ_LEVEL}??_"
|
||||
KEEP SORT NAME
|
||||
)
|
||||
endfunction()
|
||||
|
||||
# Usage:
|
||||
# zephyr_linker_section_configure(SECTION <section> [ALIGN <alignment>]
|
||||
# [PASS <no>] [PRIO <no>] [SORT <sort>]
|
||||
# [ANY] [FIRST] [KEEP]
|
||||
# )
|
||||
#
|
||||
# Configure an output section with additional input sections.
|
||||
# An output section can be configured with additional input sections besides its
|
||||
# default section.
|
||||
# For example, adding the input section `foo` to the output section bar, with KEEP
|
||||
# attribute, then call:
|
||||
# zephyr_linker_section_configure(SECTION bar INPUT foo KEEP)
|
||||
#
|
||||
# ALIGN <alignment> : Will align the input section placement inside the load
|
||||
# region with <alignment>
|
||||
# FIRST : The first input section in the list should be marked as
|
||||
# first section in output.
|
||||
# SORT <NAME> : Sort the input sections according to <type>.
|
||||
# Currently only `NAME` is supported.
|
||||
# KEEP : Do no eliminate input section during linking
|
||||
# PRIO : The priority of the input section. Per default, input
|
||||
# sections order is not guaranteed by all linkers, but
|
||||
# using priority, then Zephyr CMake linker will create
|
||||
# sections so order can be guaranteed. All unprioritized
|
||||
# sections will internally be given a CMake process order
|
||||
# priority counting from 100, so first unprioritized section
|
||||
# is handles internal pri0 100, next 101, and so on.
|
||||
# To ensure a specific input section come before those,
|
||||
# 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.
|
||||
# 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")
|
||||
cmake_parse_arguments(SECTION "${options}" "${single_args}" "${multi_args}" ${ARGN})
|
||||
|
||||
if(SECTION_UNPARSED_ARGUMENTS)
|
||||
message(FATAL_ERROR "zephyr_linker_section_configure(${ARGV0} ...) given unknown arguments: ${SECTION_UNPARSED_ARGUMENTS}")
|
||||
endif()
|
||||
|
||||
if(DEFINED SECTION_SYMBOLS)
|
||||
list(LENGTH SECTION_SYMBOLS symbols_count)
|
||||
if(${symbols_count} GREATER 2)
|
||||
message(FATAL_ERROR "zephyr_linker_section_configure(SYMBOLS [start_sym [end_sym]]) takes maximum two symbol names (start and end).")
|
||||
|
||||
endif()
|
||||
endif()
|
||||
|
||||
set(SECTION)
|
||||
zephyr_linker_arg_val_list(SECTION "${single_args}")
|
||||
zephyr_linker_arg_val_list(SECTION "${options}")
|
||||
zephyr_linker_arg_val_list(SECTION "${multi_args}")
|
||||
|
||||
string(REPLACE ";" "\;" SECTION "${SECTION}")
|
||||
set_property(TARGET linker
|
||||
APPEND PROPERTY SECTION_SETTINGS "{${SECTION}}"
|
||||
)
|
||||
endfunction()
|
||||
|
||||
# Usage:
|
||||
# zephyr_linker_symbol(SYMBOL <name> EXPR <expr>)
|
||||
#
|
||||
# Add additional user defined symbol to the generated linker script.
|
||||
#
|
||||
# SYMBOL <name>: Symbol name to be available.
|
||||
# EXPR <expr> : Expression that defines the symbol. Due to linker limitations
|
||||
# all expressions should only contain simple math, such as
|
||||
# `+, -, *` and similar. The expression will go directly into the
|
||||
# linker, and all `%<symbol>%` will be replaced with the referred
|
||||
# symbol.
|
||||
#
|
||||
# Example:
|
||||
# To create a new symbol `bar` pointing to the start VMA address of section
|
||||
# `foo` + 1024, one can write:
|
||||
# zephyr_linker_symbol(SYMBOL bar EXPR "(%foo% + 1024)")
|
||||
#
|
||||
function(zephyr_linker_symbol)
|
||||
set(single_args "EXPR;SYMBOL")
|
||||
cmake_parse_arguments(SYMBOL "" "${single_args}" "" ${ARGN})
|
||||
|
||||
if(SECTION_UNPARSED_ARGUMENTS)
|
||||
message(WARNING "zephyr_linker_symbol(${ARGV0} ...) given unknown "
|
||||
"arguments: ${SECTION_UNPARSED_ARGUMENTS}"
|
||||
)
|
||||
endif()
|
||||
|
||||
set(SYMBOL)
|
||||
zephyr_linker_arg_val_list(SYMBOL "${single_args}")
|
||||
|
||||
string(REPLACE ";" "\;" SYMBOL "${SYMBOL}")
|
||||
set_property(TARGET linker
|
||||
APPEND PROPERTY SYMBOLS "{${SYMBOL}}"
|
||||
)
|
||||
endfunction()
|
||||
|
||||
# Internal helper macro for zephyr_linker*() functions.
|
||||
# The macro will create a list of argument-value pairs for defined arguments
|
||||
# that can be passed on to linker script generators and processed as a CMake
|
||||
# function call using cmake_parse_arguments.
|
||||
#
|
||||
# For example, having the following argument and value:
|
||||
# FOO: bar
|
||||
# BAZ: <undefined>
|
||||
# QUX: option set
|
||||
#
|
||||
# will create a list as: "FOO;bar;QUX:TRUE" which can then be parsed as argument
|
||||
# list later.
|
||||
macro(zephyr_linker_arg_val_list list arguments)
|
||||
foreach(arg ${arguments})
|
||||
if(DEFINED ${list}_${arg})
|
||||
list(APPEND ${list} ${arg} "${${list}_${arg}}")
|
||||
endif()
|
||||
endforeach()
|
||||
endmacro()
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue