从Zephyr代码和数据重定位–1使用方法一文中“基本概念介绍”我们知道代码和数据的重定位是通过修改linker.ld和启动代码拷贝完成,Zephyr的实现就是将这一过程自动化,主要的流程如下cmake函数zephyr_code_relocate调用gen_relocate_app.py生成如下文件:
- linker_relocate.ld
- linker_sram_data_relocate.ld
- linker_sram_bss_relocate.ld
- code_relocation.c
 *.ld文件将被include到- linker.ld,- code_relocation.c提供的拷贝函数- data_copy_xip_relocation被- zephyr/kernel/xip.c调用,提供bss初始化函数- bss_zeroing_relocation被- zephyr/kernel/init.c调用。
文件生成
在CMakeList.txt中使用zephyr_code_relocate指定文件被重定位的地方1
zephyr_code_relocate(FILES file1.c file2.c LOCATION SRAM_TEXT)
zephyr_code_relocate定义在cmake/modules/extensions.cmake内,实现解析如下1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73function(zephyr_code_relocate)
  set(options NOCOPY) #可选参数
  set(single_args LIBRARY LOCATION PHDR)	//单一参数
  set(multi_args FILES)						//多参数
  cmake_parse_arguments(CODE_REL "${options}" "${single_args}"
    "${multi_args}" ${ARGN})
  #解析参数后生成
  #CODE_REL_FILES=file1.c file2.c
  #CODE_REL_LOCATION=_TEXT
  #CODE_REL_NOCOPY没有
  # 参数验证
  if(CODE_REL_UNPARSED_ARGUMENTS)
    message(FATAL_ERROR "zephyr_code_relocate(${ARGV0} ...) "
      "given unknown arguments: ${CODE_REL_UNPARSED_ARGUMENTS}")
  endif()
  if((NOT CODE_REL_FILES) AND (NOT CODE_REL_LIBRARY))
    message(FATAL_ERROR
      "zephyr_code_relocate() requires either FILES or LIBRARY be provided")
  endif()
  if(CODE_REL_FILES AND CODE_REL_LIBRARY)
    message(FATAL_ERROR "zephyr_code_relocate() only accepts "
      "one argument between FILES and LIBRARY")
  endif()
  if(NOT CODE_REL_LOCATION)
    message(FATAL_ERROR "zephyr_code_relocate() requires a LOCATION argument")
  endif()
  #库和文件的结果都解析出来放到file_list中,
  if(CODE_REL_LIBRARY)
    # Use cmake generator expression to convert library to file list
    set(genex_src_dir "$<TARGET_PROPERTY:${CODE_REL_LIBRARY},SOURCE_DIR>")
    set(genex_src_list "$<TARGET_PROPERTY:${CODE_REL_LIBRARY},SOURCES>")
    set(file_list
      "${genex_src_dir}/$<JOIN:${genex_src_list},$<SEMICOLON>${genex_src_dir}/>")
  else()
    # Check if CODE_REL_FILES is a generator expression, if so leave it
    # untouched.
    string(GENEX_STRIP "${CODE_REL_FILES}" no_genex)
    if(CODE_REL_FILES STREQUAL no_genex)
      # no generator expression in CODE_REL_FILES, check if list of files
      # is absolute
      foreach(file ${CODE_REL_FILES})
        if(NOT IS_ABSOLUTE ${file})
          set(file ${CMAKE_CURRENT_SOURCE_DIR}/${file})
        endif()
        list(APPEND file_list ${file})
      endforeach()
    else()
      # Generator expression is present in file list. Leave the list untouched.
      set(file_list ${CODE_REL_FILES})
    endif()
  endif()
  # 是否复制的标记放在copy_flag中
  if(NOT CODE_REL_NOCOPY)
    set(copy_flag COPY)
  else()
    set(copy_flag NOCOPY)
  endif()
  if(CODE_REL_PHDR)
    set(CODE_REL_LOCATION "${CODE_REL_LOCATION}\ :${CODE_REL_PHDR}")
  endif()
  #最后的的结果放在code_data_relocation_target中
  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}")
endfunction()
生成的结果放在code_data_relocation_target变量中1
SRAM_TEXT:COPY:file1.c;file2.c
在执行toolchain_ld_relocation时使用.zephyr/CMakeLists.txt在启用CONFIG_CODE_DATA_RELOCATION的情况下调用toolchain_ld_relocation1
2
3
4if(CONFIG_CODE_DATA_RELOCATION)
  # @Intent: Linker script to relocate .text, data and .bss sections
  toolchain_ld_relocation()
endif()
zephyr/cmake/linker/ld/target_relocation.cmake中定义了宏toolchain_ld_relocation,在该宏中调用脚本gen_relocate_app.py,实现解析如下1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31macro(toolchain_ld_relocation)
  set(MEM_RELOCATION_LD   "${PROJECT_BINARY_DIR}/include/generated/linker_relocate.ld")
  set(MEM_RELOCATION_SRAM_DATA_LD
       "${PROJECT_BINARY_DIR}/include/generated/linker_sram_data_relocate.ld")
  set(MEM_RELOCATION_SRAM_BSS_LD
       "${PROJECT_BINARY_DIR}/include/generated/linker_sram_bss_relocate.ld")
  set(MEM_RELOCATION_CODE "${PROJECT_BINARY_DIR}/code_relocation.c")
  set(MEM_REGION_DEFAULT_RAM RAM)
#调用gen_relocate_app.py 按照code_data_relocation_target生成重定位相关文件
  add_custom_command(
    OUTPUT ${MEM_RELOCATION_CODE} ${MEM_RELOCATION_LD}
    COMMAND
    ${PYTHON_EXECUTABLE}
    ${ZEPHYR_BASE}/scripts/build/gen_relocate_app.py
    $<$<BOOL:${CMAKE_VERBOSE_MAKEFILE}>:--verbose>
    -d ${APPLICATION_BINARY_DIR}
    -i \"$<TARGET_PROPERTY:code_data_relocation_target,COMPILE_DEFINITIONS>\"
    -o ${MEM_RELOCATION_LD}
    -s ${MEM_RELOCATION_SRAM_DATA_LD}
    -b ${MEM_RELOCATION_SRAM_BSS_LD}
    -c ${MEM_RELOCATION_CODE}
    --default_ram_region ${MEM_REGION_DEFAULT_RAM}
    DEPENDS app kernel ${ZEPHYR_LIBS_PROPERTY}
    )
  add_library(code_relocation_source_lib  STATIC ${MEM_RELOCATION_CODE})
  target_include_directories(code_relocation_source_lib PRIVATE
	${ZEPHYR_BASE}/kernel/include ${ARCH_DIR}/${ARCH}/include)
  target_link_libraries(code_relocation_source_lib zephyr_interface)
endmacro()
gen_relocate_app.py的路径为zephyr/scripts/build/gen_relocate_app.py主要参数:
- -d 指向编译结果目录
- -i 传入code_data_relocation_target,也就是这种形式SRAM_TEXT:COPY:file1.c;file2.c
- -o 输出linker_relocate.ld
- -s 输出linker_sram_data_relocate.ld
- -b 输出linker_sram_bss_relocate.ld
- -c 输出code_relocation.c
- –default_ram_region 指定默认RAM区的名称为:RAM,如果不指定该参数默认为SRAM,该名称应出现在linker.ld的MEMORY中
gen_relocate_app.py的内容比较多,不列出分析,说明主要流程
get_obj_filename找出要重定位文件对应的obj文件find_sections 找出obj中的sectionassign_to_correct_mem_region 根据内存区域的段信息参数(_section, 例如SDRAM2_TEXT中的_TEXT)提取出需要的section信息generate_linker_script 根据提取的section信息生成ld文件generate_memcpy_code 根据提取的section文件生成拷贝c文件内容,同时会参考no_copy参数dump_header_file 将c文件内容写入文件
gen_relocate_app.py生成的文件放在构建目录build/zephyr/include/generated/下,生成的ld文件有
- linker_relocate.ld
- linker_sram_data_relocate.ld
- linker_sram_bss_relocate.ld
 主要就是做section的放置,这里不列出细节。
 生成的- code_relocation.c主要内容如下, 可以看到就是各个section的拷贝:- 1 
 2
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43- void data_copy_xip_relocation(void) 
 {
 z_early_memcpy(&__dtcm_data_start, &__dtcm_data_rom_start,
 (size_t) &__dtcm_data_size);
 z_early_memcpy(&__itcm_text_start, &__itcm_text_rom_start,
 (size_t) &__itcm_text_size);
 z_early_memcpy(&__ram_text_start, &__ram_text_rom_start,
 (size_t) &__ram_text_size);
 z_early_memcpy(&__ram_rodata_start, &__ram_rodata_rom_start,
 (size_t) &__ram_rodata_size);
 z_early_memcpy(&__sram2_text_start, &__sram2_text_rom_start,
 (size_t) &__sram2_text_size);
 z_early_memcpy(&__sram2_rodata_start, &__sram2_rodata_rom_start,
 (size_t) &__sram2_rodata_size);
 z_early_memcpy(&__sram2_data_start, &__sram2_data_rom_start,
 (size_t) &__sram2_data_size);
 }
 void bss_zeroing_relocation(void)
 {
 z_early_memset(&__dtcm_bss_start, 0,
 (size_t) &__dtcm_bss_size);
 z_early_memset(&__sram2_bss_start, 0,
 (size_t) &__sram2_bss_size);
 }
生成文件的引用
ld文件的引用
不同soc在自己的linker.ld中引用生成ld文件,例如可以在zephyr/include/zephyr/arch/arm/aarch32/cortex_m/scripts/linker.ld中可以看到如下内容1
2
3
4
5
6
7
8
9
10
11
12
13#ifdef CONFIG_CODE_DATA_RELOCATION
#include <linker_sram_bss_relocate.ld>
#endif
#ifdef CONFIG_CODE_DATA_RELOCATION
#include <linker_relocate.ld>
#endif /* CONFIG_CODE_DATA_RELOCATION */
#ifdef CONFIG_CODE_DATA_RELOCATION
#include <linker_sram_data_relocate.ld>
#endif
c文件的应用
在zephyr/cmake/linker/ld/target_relocation.cmake中通过下面方式将code_relocation.c加入构建1
2
3
4
5set(MEM_RELOCATION_CODE "${PROJECT_BINARY_DIR}/code_relocation.c")
add_library(code_relocation_source_lib  STATIC ${MEM_RELOCATION_CODE})
target_include_directories(code_relocation_source_lib PRIVATE
	${ZEPHYR_BASE}/kernel/include ${ARCH_DIR}/${ARCH}/include)
target_link_libraries(code_relocation_source_lib zephyr_interface)
code_relocation.c内的函数在启动代码中的调用如下:
在zephyr/kernel/xip.c中执行代码和数据段拷贝1
2
3
4
5
6
7
8void z_data_copy(void)
{
#ifdef CONFIG_CODE_DATA_RELOCATION
	extern void data_copy_xip_relocation(void);
	data_copy_xip_relocation();
#endif	/* CONFIG_CODE_DATA_RELOCATION */
}
在zephyr/kernel/init.c中执行bss初始化1
2
3
4
5
6
7
8void z_bss_zero(void)
{
#ifdef CONFIG_CODE_DATA_RELOCATION
	extern void bss_zeroing_relocation(void);
	bss_zeroing_relocation();
#endif	/* CONFIG_CODE_DATA_RELOCATION */
}
参考
https://docs.zephyrproject.org/latest/kernel/code-relocation.html
