scripts: code_relocate: support section filter
One might want to select the symbols to be relocated inside a file or a library. To do this, one can use the FILTER argument of zephyr_code_relocate which must contain a regular expression of the section names to be selected for relocation. The test_function_in_sram2 test case in `tests/application_development/code_relocation` has been updated to verify that only one function `function_in_sram()` is relocated to ram and that the function `function_not_relocated()` is not being relocated when using relocation filter. Signed-off-by: Sylvain Chouleur <sylvain.chouleur@gmail.com> Signed-off-by: Torsten Rasmussen <Torsten.Rasmussen@nordicsemi.no>
This commit is contained in:
parent
cb8f99ab7a
commit
4454734d12
6 changed files with 96 additions and 27 deletions
|
@ -1453,7 +1453,7 @@ endmacro()
|
|||
# - PHDR [program_header]: add program header. Used on Xtensa platforms.
|
||||
function(zephyr_code_relocate)
|
||||
set(options NOCOPY NOKEEP)
|
||||
set(single_args LIBRARY LOCATION PHDR)
|
||||
set(single_args LIBRARY LOCATION PHDR FILTER)
|
||||
set(multi_args FILES)
|
||||
cmake_parse_arguments(CODE_REL "${options}" "${single_args}"
|
||||
"${multi_args}" ${ARGN})
|
||||
|
@ -1530,7 +1530,7 @@ function(zephyr_code_relocate)
|
|||
PROPERTY INTERFACE_SOURCES)
|
||||
set_property(TARGET code_data_relocation_target
|
||||
PROPERTY INTERFACE_SOURCES
|
||||
"${code_rel_str}\n${CODE_REL_LOCATION}:${flag_list}:${file_list}")
|
||||
"${code_rel_str}\n${CODE_REL_LOCATION}:${flag_list}:${file_list},${CODE_REL_FILTER}")
|
||||
endfunction()
|
||||
|
||||
# Usage:
|
||||
|
|
|
@ -14,15 +14,23 @@ This script provides a robust way to re-order the memory contents without
|
|||
actually having to modify the code. In simple terms this script will do the job
|
||||
of ``__attribute__((section("name")))`` for a bunch of files together.
|
||||
|
||||
A regular expression filter can be used to select only the required sections to be relocated.
|
||||
|
||||
Details
|
||||
*******
|
||||
The memory region and file are given to the :ref:`gen_relocate_app.py` script in the form of a string.
|
||||
The memory region and file are given to the :ref:`gen_relocate_app.py` script
|
||||
through a file where each line specifies a list of files to be placed in the
|
||||
given region.
|
||||
|
||||
An example of such a string is:
|
||||
``SRAM2:/home/xyz/zephyr/samples/hello_world/src/main.c,SRAM1:/home/xyz/zephyr/samples/hello_world/src/main2.c``
|
||||
An example of such a file is:
|
||||
|
||||
.. code-block:: none
|
||||
|
||||
SRAM2:/home/xyz/zephyr/samples/hello_world/src/main.c,
|
||||
SRAM1:/home/xyz/zephyr/samples/hello_world/src/main2.c,
|
||||
|
||||
This script is invoked with the following parameters:
|
||||
``python3 gen_relocate_app.py -i input_string -o generated_linker -c generated_code``
|
||||
``python3 gen_relocate_app.py -i input_file -o generated_linker -c generated_code``
|
||||
|
||||
Kconfig :kconfig:option:`CONFIG_CODE_DATA_RELOCATION` option, when enabled in
|
||||
``prj.conf``, will invoke the script and do the required relocation.
|
||||
|
@ -97,6 +105,24 @@ 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)
|
||||
|
||||
Section Filtering
|
||||
=================
|
||||
|
||||
By default, all sections of the specified files will be relocated. If
|
||||
``FILTER`` is used, a regular expression is provided to select only
|
||||
the sections to be relocated.
|
||||
|
||||
The regular expression applies to sections names which can be used to
|
||||
select the file's symbols when this one has been built with
|
||||
``-ffunction-sections`` and ``-fdata-sections`` which is the case by
|
||||
default.
|
||||
|
||||
.. code-block:: none
|
||||
|
||||
zephyr_code_relocate(FILES src/file1.c FILTER ".*\\.func1|.*\\.func2" LOCATION SRAM2_TEXT)
|
||||
|
||||
The example above will only relocate ``func1()`` and ``func2()`` of file ``src/file1.c``
|
||||
|
||||
NOKEEP flag
|
||||
===========
|
||||
|
||||
|
|
|
@ -8,21 +8,22 @@
|
|||
"""
|
||||
This script will relocate .text, .rodata, .data and .bss sections from required files
|
||||
and places it in the required memory region. This memory region and file
|
||||
are given to this python script in the form of a string.
|
||||
are given to this python script in the form of a file.
|
||||
A regular expression filter can be applied to select only the required sections from the file.
|
||||
|
||||
Example of such a string would be::
|
||||
Example of content in such an input file would be::
|
||||
|
||||
SRAM2:COPY:/home/xyz/zephyr/samples/hello_world/src/main.c,\
|
||||
SRAM1:COPY:/home/xyz/zephyr/samples/hello_world/src/main2.c, \
|
||||
FLASH2:NOCOPY:/home/xyz/zephyr/samples/hello_world/src/main3.c
|
||||
SRAM2:COPY:/home/xyz/zephyr/samples/hello_world/src/main.c,.*foo|.*bar
|
||||
SRAM1:COPY:/home/xyz/zephyr/samples/hello_world/src/main2.c,.*bar
|
||||
FLASH2:NOCOPY:/home/xyz/zephyr/samples/hello_world/src/main3.c,
|
||||
|
||||
One can also specify the program header for a given memory region:
|
||||
|
||||
SRAM2\\ :phdr0:COPY:/home/xyz/zephyr/samples/hello_world/src/main.c
|
||||
SRAM2\\ :phdr0:COPY:/home/xyz/zephyr/samples/hello_world/src/main.c,
|
||||
|
||||
To invoke this script::
|
||||
|
||||
python3 gen_relocate_app.py -i input_string -o generated_linker -c generated_code
|
||||
python3 gen_relocate_app.py -i input_file -o generated_linker -c generated_code
|
||||
|
||||
Configuration that needs to be sent to the python script.
|
||||
|
||||
|
@ -45,6 +46,7 @@ import sys
|
|||
import argparse
|
||||
import os
|
||||
import glob
|
||||
import re
|
||||
import warnings
|
||||
from collections import defaultdict
|
||||
from enum import Enum
|
||||
|
@ -225,7 +227,7 @@ def region_is_default_ram(region_name: str) -> bool:
|
|||
return region_name == args.default_ram_region
|
||||
|
||||
|
||||
def find_sections(filename: str) -> 'dict[SectionKind, list[OutputSection]]':
|
||||
def find_sections(filename: str, symbol_filter: str) -> 'dict[SectionKind, list[OutputSection]]':
|
||||
"""
|
||||
Locate relocatable sections in the given object file.
|
||||
|
||||
|
@ -243,6 +245,9 @@ def find_sections(filename: str) -> 'dict[SectionKind, list[OutputSection]]':
|
|||
out = defaultdict(list)
|
||||
|
||||
for section in sections:
|
||||
if not re.search(symbol_filter, section.name):
|
||||
# Section is filtered-out
|
||||
continue
|
||||
section_kind = SectionKind.for_section_named(section.name)
|
||||
if section_kind is None:
|
||||
continue
|
||||
|
@ -501,9 +506,10 @@ def get_obj_filename(searchpath, filename):
|
|||
|
||||
|
||||
# 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)
|
||||
# <mem_region>[\ :program_header]:<flag_1>[;<flag_2>...]:<file_1>[;<file_2>...][,filter]
|
||||
# Returns a 5-tuple with them: (mem_region, program_header, flags, files, filter)
|
||||
# If no `program_header` is defined, returns an empty string
|
||||
# If no `filter` is defined, returns an empty string
|
||||
def parse_input_string(line):
|
||||
# Be careful when splitting by : to avoid breaking absolute paths on Windows
|
||||
mem_region, rest = line.split(':', 1)
|
||||
|
@ -513,13 +519,19 @@ def parse_input_string(line):
|
|||
mem_region = mem_region.rstrip()
|
||||
phdr, rest = rest.split(':', 1)
|
||||
|
||||
# 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, flag_list, file_list
|
||||
flag_list, rest = rest.split(':', 1)
|
||||
flag_list = flag_list.split(';')
|
||||
|
||||
|
||||
# Create a dict with key as memory type and files as a list of values.
|
||||
# Split file list by semicolons, in part to support generator expressions
|
||||
file_list, symbol_filter = rest.split(',', 1)
|
||||
file_list = file_list.split(';')
|
||||
|
||||
return mem_region, phdr, flag_list, file_list, symbol_filter
|
||||
|
||||
|
||||
# Create a dict with key as memory type and (files, symbol_filter) tuple
|
||||
# as a list of values.
|
||||
# Also, return another dict with program headers for memory regions
|
||||
def create_dict_wrt_mem():
|
||||
# need to support wild card *
|
||||
|
@ -529,11 +541,12 @@ def create_dict_wrt_mem():
|
|||
input_rel_dict = args.input_rel_dict.read().splitlines()
|
||||
if not input_rel_dict:
|
||||
sys.exit("Disable CONFIG_CODE_DATA_RELOCATION if no file needs relocation")
|
||||
|
||||
for line in input_rel_dict:
|
||||
if ':' not in line:
|
||||
continue
|
||||
|
||||
mem_region, phdr, flag_list, file_list = parse_input_string(line)
|
||||
mem_region, phdr, flag_list, file_list, symbol_filter = parse_input_string(line)
|
||||
|
||||
# Handle any program header
|
||||
if phdr != '':
|
||||
|
@ -556,12 +569,15 @@ def create_dict_wrt_mem():
|
|||
if args.verbose:
|
||||
print("Memory region ", mem_region, " Selected for files:", file_name_list)
|
||||
|
||||
# Apply filter on files
|
||||
file_name_filter_list = [(f, symbol_filter) for f in file_name_list]
|
||||
|
||||
mem_region = "|".join((mem_region, *flag_list))
|
||||
|
||||
if mem_region in rel_dict:
|
||||
rel_dict[mem_region].extend(file_name_list)
|
||||
rel_dict[mem_region].extend(file_name_filter_list)
|
||||
else:
|
||||
rel_dict[mem_region] = file_name_list
|
||||
rel_dict[mem_region] = file_name_filter_list
|
||||
|
||||
return rel_dict, phdrs
|
||||
|
||||
|
@ -585,13 +601,13 @@ def main():
|
|||
for memory_type, files in rel_dict.items():
|
||||
full_list_of_sections: 'dict[SectionKind, list[OutputSection]]' = defaultdict(list)
|
||||
|
||||
for filename in files:
|
||||
for filename, symbol_filter in files:
|
||||
obj_filename = get_obj_filename(searchpath, filename)
|
||||
# the obj file wasn't found. Probably not compiled.
|
||||
if not obj_filename:
|
||||
continue
|
||||
|
||||
file_sections = find_sections(obj_filename)
|
||||
file_sections = find_sections(obj_filename, symbol_filter)
|
||||
# Merge sections from file into collection of sections for all files
|
||||
for category, sections in file_sections.items():
|
||||
full_list_of_sections[category].extend(sections)
|
||||
|
|
|
@ -17,7 +17,7 @@ endif()
|
|||
# Code relocation feature
|
||||
zephyr_code_relocate(FILES src/test_file1.c ${SRAM2_PHDR} LOCATION SRAM2)
|
||||
|
||||
zephyr_code_relocate(FILES ${CMAKE_CURRENT_SOURCE_DIR}/src/test_file2.c ${RAM_PHDR} LOCATION RAM)
|
||||
zephyr_code_relocate(FILES ${CMAKE_CURRENT_SOURCE_DIR}/src/test_file2.c ${RAM_PHDR} LOCATION RAM FILTER ".*sram")
|
||||
|
||||
# Add custom library that we can relocate code for
|
||||
add_subdirectory(test_lib)
|
||||
|
|
|
@ -23,12 +23,15 @@ __in_section(rodata, sram2, var) const uint32_t var_sram2_rodata = 100U;
|
|||
__in_section(custom_section, static, var) uint32_t var_custom_data = 1U;
|
||||
|
||||
extern void function_in_sram(int32_t value);
|
||||
extern void function_not_relocated(int32_t value);
|
||||
void function_in_custom_section(void);
|
||||
|
||||
#define HAS_SRAM2_DATA_SECTION (CONFIG_ARM)
|
||||
|
||||
ZTEST(code_relocation, test_function_in_sram2)
|
||||
{
|
||||
extern uintptr_t __ram_text_reloc_start;
|
||||
extern uintptr_t __ram_text_reloc_end;
|
||||
extern uintptr_t __sram2_text_reloc_start;
|
||||
extern uintptr_t __sram2_text_reloc_end;
|
||||
extern uintptr_t __sram2_data_reloc_start;
|
||||
|
@ -64,7 +67,20 @@ ZTEST(code_relocation, test_function_in_sram2)
|
|||
"var_sram2_bss not in sram2_bss region");
|
||||
|
||||
/* Print values from sram */
|
||||
printk("Address of function_in_sram %p\n", &function_in_sram);
|
||||
zassert_between_inclusive((uintptr_t)&function_in_sram,
|
||||
(uintptr_t)&__ram_text_reloc_start,
|
||||
(uintptr_t)&__ram_text_reloc_end,
|
||||
"function_in_sram is not in ram region");
|
||||
function_in_sram(var_sram2_data);
|
||||
|
||||
/* Print values from non-relocated function */
|
||||
printk("Address of function_not_relocated %p\n", &function_not_relocated);
|
||||
zassert_between_inclusive((uintptr_t)&function_not_relocated,
|
||||
(uintptr_t)&__text_region_start,
|
||||
(uintptr_t)&__text_region_end,
|
||||
"function_not_relocated is not in flash region");
|
||||
function_not_relocated(var_sram2_data);
|
||||
/* Call library function */
|
||||
relocated_library();
|
||||
|
||||
|
|
|
@ -19,3 +19,14 @@ void function_in_sram(int32_t value)
|
|||
printk("Address of memcpy %p\n\n", &memcpy);
|
||||
zassert_mem_equal(src, dst, 8, "memcpy compare error");
|
||||
}
|
||||
|
||||
void function_not_relocated(int32_t value)
|
||||
{
|
||||
char src[8] = "data\n";
|
||||
char dst[8];
|
||||
|
||||
printk("Hello World! %s\n", CONFIG_BOARD);
|
||||
memcpy(dst, src, 8);
|
||||
printk("Address of memcpy %p\n\n", &memcpy);
|
||||
zassert_mem_equal(src, dst, 8, "memcpy compare error");
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue