代码与数据重定位
概述
此功能可将所需文件中的 .text、.rodata、.data 和 .bss 段重定位到所需内存区域。内存区域和文件以字符串形式传给 scripts/build/gen_relocate_app.py 脚本,该脚本始终由 CMake 内部调用。
此脚本提供一种可靠的方法,无需修改代码即可重新安排内存内容。简单来说,它为一组文件统一完成 __attribute__((section("name"))) 的工作。
可以使用正则表达式过滤器,仅选择需要重定位的段。
详情
内存区域和文件通过一个文件传给 scripts/build/gen_relocate_app.py 脚本,其中每行指定要放入给定区域的文件列表。
此类文件的示例如下:
SRAM2:/home/xyz/zephyr/samples/hello_world/src/main.c, SRAM1:/home/xyz/zephyr/samples/hello_world/src/main2.c,
脚本使用以下参数调用:python3 gen_relocate_app.py -i input_file -o generated_linker -c generated_code
在 prj.conf 中启用 Kconfig 选项 CONFIG_CODE_DATA_RELOCATION 后,就会调用此脚本并执行所需的重定位。
此脚本还会触发生成 linker_relocate.ld 和 code_relocation.c 文件。linker_relocate.ld 创建适当的段,并链接所有选定文件中所需的函数或变量。
备注
主链接器脚本中的 text 段分为两部分:第一部分包含向量表及其他调试相关信息,第二部分包含完整的 text 段。这样才能强制将所需函数和数据变量放到正确位置。这是由链接器行为决定的:链接器只执行一次链接,因此必须拆分 text 段,为生成的链接器脚本留出位置。
code_relocation.c 文件包含初始化 data 段和复制 text 段(启用 XIP 时)所需的代码,还包含将 bss 清零以及将数据从 ROM 复制到所需内存类型的代码。
启用此功能的步骤如下:
在
prj.conf文件中启用CONFIG_CODE_DATA_RELOCATION。在项目的
CMakeLists.txt文件中指定所有需要重定位的文件。zephyr_code_relocate(FILES src/main.c LOCATION SRAM2)其中,第一个参数指定一个或多个文件,第二个参数指定其必须放置的内存。
备注
可按需多次调用
zephyr_code_relocate()函数。
其他配置
本节介绍可在 CMakeLists.txt 中设置的其他配置选项。
如果内存为
SRAM1、SRAM2、CCD或AON,则将整个目标文件放入相应的段。例如:zephyr_code_relocate(FILES src/file1.c LOCATION SRAM2) zephyr_code_relocate(FILES src/file2.c LOCATION SRAM1)
如果内存类型后附加
_DATA、_TEXT、_RODATA、_BSS或_NOINIT,则仅将所选部分放入所需内存区域。例如:zephyr_code_relocate(FILES src/file1.c LOCATION SRAM2_DATA) zephyr_code_relocate(FILES src/file2.c LOCATION SRAM2_TEXT)
也可以同时附加多个区域,例如
SRAM2_DATA_BSS_NOINIT。这会将所有数据,包括按值初始化、零初始化及未初始化的数据,都放入SRAM2。可以向
FILES参数传入多个文件,或使用 CMake 生成器表达式重定位以逗号分隔的文件列表。file(GLOB sources "file*.c") zephyr_code_relocate(FILES ${sources} LOCATION SRAM2) zephyr_code_relocate(FILES $<TARGET_PROPERTY:my_tgt,SOURCES> LOCATION SRAM2)
段过滤
默认情况下,指定文件的所有段都会被重定位。使用 FILTER 时,可提供正则表达式,仅选择需要重定位的段。
正则表达式匹配段名称。当文件使用 -ffunction-sections 和 -fdata-sections 构建时,可以借此选择文件中的符号;默认情况下就是如此。
zephyr_code_relocate(FILES src/file1.c FILTER ".*\\.func1|.*\\.func2" LOCATION SRAM2_TEXT)
上述示例只会重定位文件 src/file1.c 中的 func1() 和 func2()。
NOKEEP 标志
默认情况下,生成 linker_relocate.ld 时,所有重定位的函数和变量都会标记为 KEEP()。因此,如果输入文件含有未使用的符号,即使使用 --gc-sections 调用链接器,也不会丢弃它们。要覆盖此行为,可向 zephyr_code_relocate() 调用传入 NOKEEP。
zephyr_code_relocate(FILES src/file1.c LOCATION SRAM2_TEXT NOKEEP)
上述示例有助于确保 file1.c 的 .text 段中未使用的代码不会保留在 SRAM2 中。
NOCOPY 标志
向 zephyr_code_relocate() 函数传入 NOCOPY 选项后,就不会在 code_relocation.c 中生成重定位代码。需要将特定文件或一组文件的内容移入 XIP 区域时,可以使用此标志。
此示例将 xip_external_flash.c 文件的 .text 段放入 EXTFLASH 内存区域,并直接从该区域执行(XIP)。.data 段则照常重定位到 SRAM。
zephyr_code_relocate(FILES src/xip_external_flash.c LOCATION EXTFLASH_TEXT NOCOPY) zephyr_code_relocate(FILES src/xip_external_flash.c LOCATION SRAM_DATA)
重定位库
可以通过 zephyr_code_relocation() 的 LIBRARY 参数指定库名称来重定位库。例如,以下代码片段会将串口驱动程序重定位到 SRAM2:
zephyr_code_relocate(LIBRARY drivers__serial LOCATION SRAM2)
提示
重定位 kernel/arch 文件时需要谨慎,其中某些文件包含在代码重定位之前执行的早期初始化代码。
可能需要额外配置 MPU/MMU,以确保目标内存区域允许执行代码。
示例与测试
展示此功能的测试位于 $ZEPHYR_BASE/tests/application_development/code_relocation。
此测试展示如何使用代码重定位功能。
此测试使用从 include/zephyr/arch/arm/cortex_m/scripts/linker.ld 派生的自定义链接器文件,将三个文件中的 .text、.data 和 .bss 放入 SRAM 的不同位置。
展示 NOCOPY 标志的示例位于:无需复制的代码重定位。