Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion cmake/linker/ld/target_relocation.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ macro(toolchain_ld_relocation)
-b ${MEM_RELOCATION_SRAM_BSS_LD}
-c ${MEM_RELOCATION_CODE}
--default_ram_region ${MEM_REGION_DEFAULT_RAM}
DEPENDS app kernel ${ZEPHYR_LIBS_PROPERTY}
DEPENDS app kernel ${ZEPHYR_LIBS_PROPERTY} ${DICT_FILE}
)

add_library(code_relocation_source_lib STATIC ${MEM_RELOCATION_CODE})
Expand Down
20 changes: 13 additions & 7 deletions cmake/modules/extensions.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -1330,9 +1330,11 @@ endmacro()
# The following optional arguments are supported:
# - NOCOPY: this flag indicates that the file data does not need to be copied
# at boot time (For example, for flash XIP).
# - NOKEEP: suppress the generation of KEEP() statements in the linker script,
# to allow any unused code in the given files/library to be discarded.
# - PHDR [program_header]: add program header. Used on Xtensa platforms.
function(zephyr_code_relocate)
set(options NOCOPY)
set(options NOCOPY NOKEEP)
set(single_args LIBRARY LOCATION PHDR)
set(multi_args FILES)
cmake_parse_arguments(CODE_REL "${options}" "${single_args}"
Expand Down Expand Up @@ -1392,21 +1394,25 @@ function(zephyr_code_relocate)
endif()
endif()
if(NOT CODE_REL_NOCOPY)
set(copy_flag COPY)
set(flag_list COPY)
else()
set(copy_flag NOCOPY)
set(flag_list NOCOPY)
endif()
if(CODE_REL_NOKEEP)
list(APPEND flag_list NOKEEP)
endif()
if(CODE_REL_PHDR)
set(CODE_REL_LOCATION "${CODE_REL_LOCATION}\ :${CODE_REL_PHDR}")
endif()
# We use the "|" character to separate code relocation directives instead
# of using CMake lists. This way, the ";" character can be reserved for
# generator expression file lists.
# We use the "|" character to separate code relocation directives, instead of
# using set_property(APPEND) to produce a ";"-separated CMake list. This way,
# each directive can embed multiple CMake lists, representing flags and files,
# the latter of which can come from generator expressions.
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Only major notice is that it appears there originally was a specific reason for not using ; for anything else than the CMake list of files:

Thanks @tejlmand for pointing this out. I have updated the comment.

I believe this comment exists simply because the strings that are now separated by | used to be separated by ;.
PR #50791 added support for calling zephyr_code_relocate() with a list of FILES, or a genex producing one.
Previously, the function accepted only one file or glob at a time, so ; didn't need to be reserved for any lists.

So, that PR allowed for having one CMake list per string. With this PR, there are two lists per string, and they're separated by a colon. If anything can break from that, it would probably hinge on parse_input_string() in the Python script.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes, my initial conclusion was also that your changes should not have unintended side-effects, but I didn't examined the existing code in details, as we know, the devil is in the details 😉 .

Thanks for carrying out more in-depth analysis and updating the comment.

get_property(code_rel_str TARGET code_data_relocation_target
PROPERTY COMPILE_DEFINITIONS)
set_property(TARGET code_data_relocation_target
PROPERTY COMPILE_DEFINITIONS
"${code_rel_str}|${CODE_REL_LOCATION}:${copy_flag}:${file_list}")
"${code_rel_str}|${CODE_REL_LOCATION}:${flag_list}:${file_list}")
endfunction()

# Usage:
Expand Down
16 changes: 16 additions & 0 deletions doc/kernel/code-relocation.rst
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,22 @@ This section shows additional configuration options that can be set in
zephyr_code_relocate(FILES ${sources} LOCATION SRAM)
zephyr_code_relocate(FILES $<TARGET_PROPERTY:my_tgt,SOURCES> LOCATION SRAM)

NOKEEP flag
===========

By default, all relocated functions and variables will be marked with ``KEEP()``
when generating ``linker_relocate.ld``. Therefore, if any input file happens to
contain unused symbols, then they will not be discarded by the linker, even when
it is invoked with ``--gc-sections``. If you'd like to override this behavior,
you can pass ``NOKEEP`` to your ``zephyr_code_relocate()`` call.

.. code-block:: none

zephyr_code_relocate(FILES src/file1.c LOCATION SRAM2_TEXT NOKEEP)

The example above will help ensure that any unused code found in the .text
sections of ``file1.c`` will not stick to SRAM2.

NOCOPY flag
===========

Expand Down
55 changes: 35 additions & 20 deletions scripts/build/gen_relocate_app.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,8 @@
ignored.
- COPY/NOCOPY defines whether the script should generate the relocation code in
code_relocation.c or not
- NOKEEP will suppress the default behavior of marking every relocated symbol
with KEEP() in the generated linker script.

Multiple regions can be appended together like SRAM2_DATA_BSS
this will place data and bss inside SRAM2.
Expand Down Expand Up @@ -94,12 +96,17 @@ def for_section_named(cls, name: str):
class OutputSection(NamedTuple):
obj_file_name: str
section_name: str
keep: bool = True


PRINT_TEMPLATE = """
KEEP(*{obj_file_name}({section_name}))
"""

PRINT_TEMPLATE_NOKEEP = """
*{obj_file_name}({section_name})
"""

SECTION_LOAD_MEMORY_SEQ = """
__{0}_{1}_rom_start = LOADADDR(.{0}_{1}_reloc);
"""
Expand Down Expand Up @@ -274,10 +281,16 @@ def assign_to_correct_mem_region(
if align_size:
mpu_align[memory_region] = int(align_size)

keep_sections = '|NOKEEP' not in memory_region
memory_region = memory_region.replace('|NOKEEP', '')

output_sections = {}
for used_kind in use_section_kinds:
# Pass through section kinds that go into this memory region
output_sections[used_kind] = full_list_of_sections[used_kind]
output_sections[used_kind] = [
section._replace(keep=keep_sections)
for section in full_list_of_sections[used_kind]
]

return {MemoryRegion(memory_region): output_sections}

Expand Down Expand Up @@ -308,10 +321,12 @@ def section_kinds_from_memory_region(memory_region: str) -> 'Tuple[set[SectionKi


def print_linker_sections(list_sections: 'list[OutputSection]'):
return ''.join(PRINT_TEMPLATE.format(obj_file_name=section.obj_file_name,
section_name=section.section_name)
for section in sorted(list_sections))

out = ''
for section in sorted(list_sections):
template = PRINT_TEMPLATE if section.keep else PRINT_TEMPLATE_NOKEEP
out += template.format(obj_file_name=section.obj_file_name,
section_name=section.section_name)
return out

def add_phdr(memory_type, phdrs):
return f'{memory_type} {phdrs[memory_type] if memory_type in phdrs else ""}'
Expand Down Expand Up @@ -485,20 +500,23 @@ def get_obj_filename(searchpath, filename):
return fullname


# Extracts all possible components for the input strin:
# <mem_region>[\ :program_header]:<flag>:<file_name>
# Returns a 4-tuple with them: (mem_region, program_header, flag, file_name)
# Extracts all possible components for the input string:
# <mem_region>[\ :program_header]:<flag_1>[;<flag_2>...]:<file_1>[;<file_2>...]
# Returns a 4-tuple with them: (mem_region, program_header, flags, files)
# If no `program_header` is defined, returns an empty string
def parse_input_string(line):
line = line.replace(' :', ':')
# Be careful when splitting by : to avoid breaking absolute paths on Windows
mem_region, rest = line.split(':', 1)

flag_sep = ':NOCOPY:' if ':NOCOPY' in line else ':COPY:'
mem_region_phdr, copy_flag, file_name = line.partition(flag_sep)
copy_flag = copy_flag.replace(':', '')
phdr = ''
if mem_region.endswith(' '):
mem_region = mem_region.rstrip()
phdr, rest = rest.split(':', 1)

mem_region, _, phdr = mem_region_phdr.partition(':')
# Split lists by semicolons, in part to support generator expressions
flag_list, file_list = (lst.split(';') for lst in rest.split(':', 1))

return mem_region, phdr, copy_flag, file_name
return mem_region, phdr, flag_list, file_list


# Create a dict with key as memory type and files as a list of values.
Expand All @@ -515,17 +533,15 @@ def create_dict_wrt_mem():
if ':' not in line:
continue

mem_region, phdr, copy_flag, file_list = parse_input_string(line)
mem_region, phdr, flag_list, file_list = parse_input_string(line)

# Handle any program header
if phdr != '':
phdrs[mem_region] = f':{phdr}'

# Split file names by semicolons, to support generator expressions
file_glob_list = file_list.split(';')
file_name_list = []
# Use glob matching on each file in the list
for file_glob in file_glob_list:
for file_glob in file_list:
glob_results = glob.glob(file_glob)
if not glob_results:
warnings.warn("File: "+file_glob+" Not found")
Expand All @@ -534,14 +550,13 @@ def create_dict_wrt_mem():
warnings.warn("Regex in file lists is deprecated, please use file(GLOB) instead")
file_name_list.extend(glob_results)
if len(file_name_list) == 0:
warnings.warn("No files in string: "+file_list+" found")
continue
if mem_region == '':
continue
if args.verbose:
print("Memory region ", mem_region, " Selected for files:", file_name_list)

mem_region = "|".join((mem_region, copy_flag))
mem_region = "|".join((mem_region, *flag_list))

if mem_region in rel_dict:
rel_dict[mem_region].extend(file_name_list)
Expand Down
5 changes: 3 additions & 2 deletions tests/application_development/code_relocation/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -37,8 +37,9 @@ zephyr_code_relocate(FILES src/test_file3.c LOCATION SRAM2_TEXT)
zephyr_code_relocate(FILES src/test_file3.c LOCATION RAM_DATA)
zephyr_code_relocate(FILES src/test_file3.c LOCATION SRAM2_BSS)


zephyr_code_relocate(FILES ${ZEPHYR_BASE}/kernel/sem.c ${RAM_PHDR} LOCATION RAM)
# Test NOKEEP support. Placing both KEEP and NOKEEP symbols in the same location
# (this and test_file2.c in RAM) should work fine.
zephyr_code_relocate(FILES ${ZEPHYR_BASE}/kernel/sem.c ${RAM_PHDR} LOCATION RAM NOKEEP)

if (CONFIG_RELOCATE_TO_ITCM)
zephyr_code_relocate(FILES ${ZEPHYR_BASE}/lib/libc/minimal/source/string/string.c
Expand Down