Zephyr代码和数据重定位--2实现原理

本文说明Zephyr的代码和数据重定位功能实现原理。

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.ldcode_relocation.c提供的拷贝函数data_copy_xip_relocationzephyr/kernel/xip.c调用,提供bss初始化函数bss_zeroing_relocationzephyr/kernel/init.c调用。

文件生成 链接到标题

在CMakeList.txt中使用zephyr_code_relocate指定文件被重定位的地方

zephyr_code_relocate(FILES file1.c file2.c LOCATION SRAM_TEXT)

zephyr_code_relocate定义在cmake/modules/extensions.cmake内,实现解析如下

function(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变量中

SRAM_TEXT:COPY:file1.c;file2.c

在执行toolchain_ld_relocation时使用.zephyr/CMakeLists.txt在启用CONFIG_CODE_DATA_RELOCATION的情况下调用toolchain_ld_relocation

if(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,实现解析如下

macro(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中的section assign_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的拷贝:
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中可以看到如下内容

#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加入构建

set(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中执行代码和数据段拷贝

void 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初始化

void 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