Skip to content

Commit 460b6ef

Browse files
57300carlescufi
authored andcommitted
code_relocation: Add NOKEEP option
When using the code and data relocation feature, every relocated symbol would be marked with `KEEP()` in the generated linker script. Therefore, if any input files contained unused code, then it wouldn't be discarded by the linker, even when invoked with `--gc-sections`. This can cause unexpected bloat, or other link-time issues stemming from some symbols being discarded and others not. On the other hand, this behavior has been present since the feature's introduction, so it should remain default for the users who rely on it. This patch introduces support for `zephyr_code_relocate(... NOKEEP)`. This will suppress the generation of `KEEP()` statements for all symbols in a particular library or set of files. Much like `NOCOPY`, the `NOKEEP` flag is passed to `gen_relocate_app.py` in string form. The script is now equipped to handle multiple such flags when passed from CMake as a semicolon-separated list, like so: "SRAM2:NOCOPY;NOKEEP:/path/to/file1.c;/path/to/file2.c" Documentation and tests are updated here as well. Signed-off-by: Grzegorz Swiderski <[email protected]>
1 parent bccec3c commit 460b6ef

File tree

4 files changed

+67
-29
lines changed

4 files changed

+67
-29
lines changed

cmake/modules/extensions.cmake

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1330,9 +1330,11 @@ endmacro()
13301330
# The following optional arguments are supported:
13311331
# - NOCOPY: this flag indicates that the file data does not need to be copied
13321332
# at boot time (For example, for flash XIP).
1333+
# - NOKEEP: suppress the generation of KEEP() statements in the linker script,
1334+
# to allow any unused code in the given files/library to be discarded.
13331335
# - PHDR [program_header]: add program header. Used on Xtensa platforms.
13341336
function(zephyr_code_relocate)
1335-
set(options NOCOPY)
1337+
set(options NOCOPY NOKEEP)
13361338
set(single_args LIBRARY LOCATION PHDR)
13371339
set(multi_args FILES)
13381340
cmake_parse_arguments(CODE_REL "${options}" "${single_args}"
@@ -1392,21 +1394,25 @@ function(zephyr_code_relocate)
13921394
endif()
13931395
endif()
13941396
if(NOT CODE_REL_NOCOPY)
1395-
set(copy_flag COPY)
1397+
set(flag_list COPY)
13961398
else()
1397-
set(copy_flag NOCOPY)
1399+
set(flag_list NOCOPY)
1400+
endif()
1401+
if(CODE_REL_NOKEEP)
1402+
list(APPEND flag_list NOKEEP)
13981403
endif()
13991404
if(CODE_REL_PHDR)
14001405
set(CODE_REL_LOCATION "${CODE_REL_LOCATION}\ :${CODE_REL_PHDR}")
14011406
endif()
1402-
# We use the "|" character to separate code relocation directives instead
1403-
# of using CMake lists. This way, the ";" character can be reserved for
1404-
# generator expression file lists.
1407+
# We use the "|" character to separate code relocation directives, instead of
1408+
# using set_property(APPEND) to produce a ";"-separated CMake list. This way,
1409+
# each directive can embed multiple CMake lists, representing flags and files,
1410+
# the latter of which can come from generator expressions.
14051411
get_property(code_rel_str TARGET code_data_relocation_target
14061412
PROPERTY COMPILE_DEFINITIONS)
14071413
set_property(TARGET code_data_relocation_target
14081414
PROPERTY COMPILE_DEFINITIONS
1409-
"${code_rel_str}|${CODE_REL_LOCATION}:${copy_flag}:${file_list}")
1415+
"${code_rel_str}|${CODE_REL_LOCATION}:${flag_list}:${file_list}")
14101416
endfunction()
14111417

14121418
# Usage:

doc/kernel/code-relocation.rst

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,22 @@ This section shows additional configuration options that can be set in
9797
zephyr_code_relocate(FILES ${sources} LOCATION SRAM)
9898
zephyr_code_relocate(FILES $<TARGET_PROPERTY:my_tgt,SOURCES> LOCATION SRAM)
9999
100+
NOKEEP flag
101+
===========
102+
103+
By default, all relocated functions and variables will be marked with ``KEEP()``
104+
when generating ``linker_relocate.ld``. Therefore, if any input file happens to
105+
contain unused symbols, then they will not be discarded by the linker, even when
106+
it is invoked with ``--gc-sections``. If you'd like to override this behavior,
107+
you can pass ``NOKEEP`` to your ``zephyr_code_relocate()`` call.
108+
109+
.. code-block:: none
110+
111+
zephyr_code_relocate(FILES src/file1.c LOCATION SRAM2_TEXT NOKEEP)
112+
113+
The example above will help ensure that any unused code found in the .text
114+
sections of ``file1.c`` will not stick to SRAM2.
115+
100116
NOCOPY flag
101117
===========
102118

scripts/build/gen_relocate_app.py

Lines changed: 35 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,8 @@
3333
ignored.
3434
- COPY/NOCOPY defines whether the script should generate the relocation code in
3535
code_relocation.c or not
36+
- NOKEEP will suppress the default behavior of marking every relocated symbol
37+
with KEEP() in the generated linker script.
3638
3739
Multiple regions can be appended together like SRAM2_DATA_BSS
3840
this will place data and bss inside SRAM2.
@@ -94,12 +96,17 @@ def for_section_named(cls, name: str):
9496
class OutputSection(NamedTuple):
9597
obj_file_name: str
9698
section_name: str
99+
keep: bool = True
97100

98101

99102
PRINT_TEMPLATE = """
100103
KEEP(*{obj_file_name}({section_name}))
101104
"""
102105

106+
PRINT_TEMPLATE_NOKEEP = """
107+
*{obj_file_name}({section_name})
108+
"""
109+
103110
SECTION_LOAD_MEMORY_SEQ = """
104111
__{0}_{1}_rom_start = LOADADDR(.{0}_{1}_reloc);
105112
"""
@@ -274,10 +281,16 @@ def assign_to_correct_mem_region(
274281
if align_size:
275282
mpu_align[memory_region] = int(align_size)
276283

284+
keep_sections = '|NOKEEP' not in memory_region
285+
memory_region = memory_region.replace('|NOKEEP', '')
286+
277287
output_sections = {}
278288
for used_kind in use_section_kinds:
279289
# Pass through section kinds that go into this memory region
280-
output_sections[used_kind] = full_list_of_sections[used_kind]
290+
output_sections[used_kind] = [
291+
section._replace(keep=keep_sections)
292+
for section in full_list_of_sections[used_kind]
293+
]
281294

282295
return {MemoryRegion(memory_region): output_sections}
283296

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

309322

310323
def print_linker_sections(list_sections: 'list[OutputSection]'):
311-
return ''.join(PRINT_TEMPLATE.format(obj_file_name=section.obj_file_name,
312-
section_name=section.section_name)
313-
for section in sorted(list_sections))
314-
324+
out = ''
325+
for section in sorted(list_sections):
326+
template = PRINT_TEMPLATE if section.keep else PRINT_TEMPLATE_NOKEEP
327+
out += template.format(obj_file_name=section.obj_file_name,
328+
section_name=section.section_name)
329+
return out
315330

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

487502

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

495-
flag_sep = ':NOCOPY:' if ':NOCOPY' in line else ':COPY:'
496-
mem_region_phdr, copy_flag, file_name = line.partition(flag_sep)
497-
copy_flag = copy_flag.replace(':', '')
511+
phdr = ''
512+
if mem_region.endswith(' '):
513+
mem_region = mem_region.rstrip()
514+
phdr, rest = rest.split(':', 1)
498515

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

501-
return mem_region, phdr, copy_flag, file_name
519+
return mem_region, phdr, flag_list, file_list
502520

503521

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

518-
mem_region, phdr, copy_flag, file_list = parse_input_string(line)
536+
mem_region, phdr, flag_list, file_list = parse_input_string(line)
519537

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

524-
# Split file names by semicolons, to support generator expressions
525-
file_glob_list = file_list.split(';')
526542
file_name_list = []
527543
# Use glob matching on each file in the list
528-
for file_glob in file_glob_list:
544+
for file_glob in file_list:
529545
glob_results = glob.glob(file_glob)
530546
if not glob_results:
531547
warnings.warn("File: "+file_glob+" Not found")
@@ -534,14 +550,13 @@ def create_dict_wrt_mem():
534550
warnings.warn("Regex in file lists is deprecated, please use file(GLOB) instead")
535551
file_name_list.extend(glob_results)
536552
if len(file_name_list) == 0:
537-
warnings.warn("No files in string: "+file_list+" found")
538553
continue
539554
if mem_region == '':
540555
continue
541556
if args.verbose:
542557
print("Memory region ", mem_region, " Selected for files:", file_name_list)
543558

544-
mem_region = "|".join((mem_region, copy_flag))
559+
mem_region = "|".join((mem_region, *flag_list))
545560

546561
if mem_region in rel_dict:
547562
rel_dict[mem_region].extend(file_name_list)

tests/application_development/code_relocation/CMakeLists.txt

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,8 +37,9 @@ zephyr_code_relocate(FILES src/test_file3.c LOCATION SRAM2_TEXT)
3737
zephyr_code_relocate(FILES src/test_file3.c LOCATION RAM_DATA)
3838
zephyr_code_relocate(FILES src/test_file3.c LOCATION SRAM2_BSS)
3939

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

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

0 commit comments

Comments
 (0)