如何链接ELF文件中的数据以在运行时显示? STM32

问题描述 投票:0回答:2

我一直试图让我的固件版本在运行时显示。

我尝试使用以下示例 gcc 是否有任何选项可以在 ELF 二进制文件中添加版本信息? 但没有运气。这是我到目前为止所拥有的。

在STM32CubeIDE(MacOS)上使用STM32L462

内部源文件:

static uint32_t git_commit __attribute__((section(".gitcommit"))) = 0xffffffff;
static uint32_t version_number __attribute__((section(".version"))) =
    0xffffffff;

在我的应用程序文件夹中,我有一个 version_number.txt,其中包含版本号(目前为 1.0.0)

代码成功编译后,将运行一个 python 脚本,该脚本从 version_number.txt 中获取版本号和 git 提交的哈希值,并使用 objcopy 将它们放入 elf 部分中。

"""This script get git commit and version number and push it to STM32 elf and bin
    file into specific section"""
import sys
import subprocess
import os
import binascii
import struct
import platform

def write_to_file_binary(file_name, data):
    """write data to binary file"""
    with open(file_name, 'w+b') as file_obj:
        data = binascii.unhexlify("0" + data)
        file_obj.write(data)

def get_git_revision_short_hash(dir_path):
    """get git commit number"""
    return subprocess.check_output(['git', 'rev-parse', '--short', 'HEAD'], cwd=dir_path)

def write_version_to_binary_file(version_array, file_path):
    """write version major minor patch commit to binary file"""
    version_major = version_array[0]
    version_minor = version_array[1]
    version_patch = version_array[2]
    with open(file_path, 'w+b') as file_obj:
        file_obj.write(struct.pack("B", int(version_major)))
        file_obj.write(struct.pack("B", int(version_minor)))
        file_obj.write(struct.pack("H", int(version_patch)))

def main(args):
    """This script connects to git and get the commit number of the project and write it
    to commit_number_file.txt,

    Then get the project version number from version_number.txt.

    Write binary to temp.txt file the version number and git commit number.

    Access to elf file and push git commit to .gitcommit and git version to .version section.

    Change the bin file.

    Change bin file name to contains version number and git commit number.
    """
    path_name = args[1]
    project_name = os.path.split(path_name)[-1]
    print("project name:" + project_name)
    debug_path_in_project = path_name + "/Debug"
    git_commit_number = get_git_revision_short_hash(path_name)[:-1].decode()
    commit_file_name = "commit_number_file.txt"
    commit_file_path = debug_path_in_project + "/" + commit_file_name
    write_to_file_binary(commit_file_path, git_commit_number)
    version_array = open(path_name + "/version_number.txt", "r").readline().split('.')
    version_file_temp = debug_path_in_project + "/temp.txt"
    print(version_file_temp)
    write_version_to_binary_file(version_array, version_file_temp)
    version = version_array[0] + '.' + version_array[1] + '.' + version_array[2] + \
        '.' + git_commit_number
    print("version: " + version)
    if(platform.system() == 'Darwin'):
        out = subprocess.check_output(['arm-none-eabi-objcopy', '--update-section', '.gitcommit=' + \
            commit_file_name, project_name + '.elf'], cwd=debug_path_in_project)
        print("out1:" ,out)
        out = subprocess.check_output(['arm-none-eabi-objcopy', '--update-section', '.version=' + \
            version_file_temp, project_name + '.elf'], cwd=debug_path_in_project)
        print("out2:" ,out)
        out = subprocess.check_output(['arm-none-eabi-objcopy', '-O', 'binary', project_name + '.elf', \
            project_name + '.bin'], cwd=debug_path_in_project)
        print("out3:" ,out)
    if(platform.system() == 'Windows'):
        subprocess.check_output(['arm-none-eabi-objcopy.exe', '--update-section', '.gitcommit=' + \
            commit_file_name, project_name + '.elf'], cwd=debug_path_in_project)
        subprocess.check_output(['arm-none-eabi-objcopy.exe', '--update-section', '.version=' + \
            version_file_temp, project_name + '.elf'], cwd=debug_path_in_project)
        subprocess.check_output(['arm-none-eabi-objcopy.exe', '-O', 'binary', project_name + '.elf', \
            project_name + '.bin'], cwd=debug_path_in_project)
    list_of_files_in_directory = os.listdir(debug_path_in_project)
    for file_in_list in list_of_files_in_directory:
        if file_in_list != (project_name + '.bin'):
            if file_in_list.endswith('.bin') and file_in_list is not project_name + '.bin':
                os.remove(file_in_list)
    os.rename(project_name + '.bin', project_name + '_' + version  + '.bin')
    os.remove(version_file_temp)
    os.remove(commit_file_path)

if __name__ == '__main__':
    main(sys.argv)

脚本完成后我就可以运行

objdump -s -j .gitcommit /Users/path/to/elf/Application.elf
objdump -s -j .version /Users/path/to/elf/Application.elf

输出将与 git 提交和 version_number.txt 中列出的版本匹配(更改 txt 中的数字将更改 objdump 的输出)。

但是,在运行时,当我尝试获取 version_number git_commit 的值时,我只得到默认的垃圾值。

跑步:

      software_version.major = version_number;
  software_version.minor = version_number >> 8;
  software_version.patch = version_number >> 16;
  software_version.commit = SWAP32(git_commit);

不起作用。

欢迎任何想法! 谢谢!

c stm32 elf objcopy custom-sections
2个回答
2
投票

对于任何感兴趣的人,
将以下行添加到 .rodata(~第 74 行)和 .ARM.extab(~第 82 行)之间的 STM32L4< x >_FLASH.ld 中,以正确链接 .gitcommit 和 .version 部分。

 .gitcommit :
  {
    . = ALIGN(4);
    KEEP (*(.gitcommit))         /* .gitcommit sections (constants, strings, etc.) */
    KEEP (*(.gitcommit*))        /* .gitcommit* sections (constants, strings, etc.) */
    . = ALIGN(4);
  } >FLASH

    .version :
  {
    . = ALIGN(4);
    KEEP (*(.version))         /* .version sections (constants, strings, etc.) */
    KEEP (*(.version*))        /* .version* sections (constants, strings, etc.) */
    . = ALIGN(4);
  } >FLASH

完整说明 - 如何将版本号和 git commit 保存在闪存上(STM32):

应用程序文件夹内:

将版本号保存在 version_number.txt 中 每次版本更新,都会更新文本文件。

在源文件中:
声明用于保存 git-commit 和版本号的变量,如下所示(根据需要更改部分名称,但请确保与名称一致)

static uint32_t git_commit __attribute__((section(".gitcommit"))) = 0xffffffff;
static uint32_t version_number __attribute__((section(".version"))) =
    0xffffffff;

链接器文件(STM32< MCU ID >_FLASH.ld):

插入以下行以链接变量和它们需要保存的值(如上所述 - 在 .rodata 和 .ARM.extab 部分之间)

 .gitcommit :
  {
    . = ALIGN(4);
    KEEP (*(.gitcommit))         /* .gitcommit sections (constants, strings, etc.) */
    KEEP (*(.gitcommit*))        /* .gitcommit* sections (constants, strings, etc.) */
    . = ALIGN(4);
  } >FLASH

    .version :
  {
    . = ALIGN(4);
    KEEP (*(.version))         /* .version sections (constants, strings, etc.) */
    KEEP (*(.version*))        /* .version* sections (constants, strings, etc.) */
    . = ALIGN(4);
  } >FLASH

最后,在构建后,运行 python 脚本以获取 version_number 和 git commit 并将它们插入到正确的部分!

"""This script gets git commit and version number and push it to STM32 elf and bin
    file into specific section"""
import sys
import subprocess
import os
import binascii
import struct
import platform

def write_to_file_binary(file_name, data):
    """write data to binary file"""
    with open(file_name, 'w+b') as file_obj:
        data = binascii.unhexlify("0" + data)
        file_obj.write(data)

def get_git_revision_short_hash(dir_path):
    """get git commit number"""
    return subprocess.check_output(['git', 'rev-parse', '--short', 'HEAD'], cwd=dir_path)

def write_version_to_binary_file(version_array, file_path):
    """write version major minor patch commit to binary file"""
    version_major = version_array[0]
    version_minor = version_array[1]
    version_patch = version_array[2]
    with open(file_path, 'w+b') as file_obj:
        file_obj.write(struct.pack("B", int(version_major)))
        file_obj.write(struct.pack("B", int(version_minor)))
        file_obj.write(struct.pack("H", int(version_patch)))

def main(args):
    """This script connects to git and gets the commit number of the project and writes it
    to commit_number_file.txt,

    Then get the project version number from version_number.txt.

    Write binary to temp.txt file the version number and git commit number.

    Access to elf file and push git commit to .gitcommit and git version to .version section.

    Change the bin file.

    Change the bin file name to contain the version number and git commit number.
    """
    path_name = args[1]
    project_name = os.path.split(path_name)[-1]
    print("project name:" + project_name)
    debug_path_in_project = path_name + "/Debug"
    git_commit_number = get_git_revision_short_hash(path_name)[:-1].decode()
    commit_file_name = "commit_number_file.txt"
    commit_file_path = debug_path_in_project + "/" + commit_file_name
    write_to_file_binary(commit_file_path, git_commit_number)
    version_array = open(path_name + "/version_number.txt", "r").readline().split('.')
    version_file_temp = debug_path_in_project + "/temp.txt"
    print(version_file_temp)
    write_version_to_binary_file(version_array, version_file_temp)
    version = version_array[0] + '.' + version_array[1] + '.' + version_array[2] + \
        '.' + git_commit_number
    print("version: " + version)
    if(platform.system() == 'Darwin'):
        out = subprocess.check_output(['arm-none-eabi-objcopy', '--update-section', '.gitcommit=' + \
            commit_file_name, project_name + '.elf'], cwd=debug_path_in_project)
        out = subprocess.check_output(['arm-none-eabi-objcopy', '--update-section', '.version=' + \
            version_file_temp, project_name + '.elf'], cwd=debug_path_in_project)
        out = subprocess.check_output(['arm-none-eabi-objcopy', '-O', 'binary', project_name + '.elf', \
            project_name + '.bin'], cwd=debug_path_in_project)
    if(platform.system() == 'Windows'):
        subprocess.check_output(['arm-none-eabi-objcopy.exe', '--update-section', '.gitcommit=' + \
            commit_file_name, project_name + '.elf'], cwd=debug_path_in_project)
        subprocess.check_output(['arm-none-eabi-objcopy.exe', '--update-section', '.version=' + \
            version_file_temp, project_name + '.elf'], cwd=debug_path_in_project)
        subprocess.check_output(['arm-none-eabi-objcopy.exe', '-O', 'binary', project_name + '.elf', \
            project_name + '.bin'], cwd=debug_path_in_project)
    list_of_files_in_directory = os.listdir(debug_path_in_project)
    for file_in_list in list_of_files_in_directory:
        if file_in_list != (project_name + '.bin'):
            if file_in_list.endswith('.bin') and file_in_list is not project_name + '.bin':
                os.remove(file_in_list)
    os.rename(project_name + '.bin', project_name + '_' + version  + '.bin')
    os.remove(version_file_temp)
    os.remove(commit_file_path)

if __name__ == '__main__':
    main(sys.argv)

就是这样,当运行代码时,你应该让 git commit 保存哈希值,version_number 保存版本号。

祝你好运


0
投票

只是为了简化一点,使用旧的 makefile 和 xxd 命令将提交转换为二进制文件

GIT_TARGET = commit.bin

$(GIT_TARGET):
    @echo $(shell git rev-parse HEAD) | xxd -r -p > $@
...
main.elf: $(OBJ) $(GIT_COMMIT)
    @$(CC) $(LDFLAGS) -Wl,-Map=$(notdir $(patsubst %.elf,%.map,$@)) -o $@ $(OBJ)
    @$(OBJCOPY) --update-section .git_commit=$(GIT_TARGET) $@
...

在链接器脚本上使用此行

...

  /* Constant data into "ROM" Rom type memory */
  .rodata :
  {
    . = ALIGN(4);
    *(.rodata)         /* .rodata sections (constants, strings, etc.) */
    *(.rodata*)        /* .rodata* sections (constants, strings, etc.) */
    . = ALIGN(4);
  } >FLASH

 .git_commit :
  {
    . = ALIGN(4);
    KEEP (*(.git_commit))         /* .git_commit sections (constants, strings, etc.) */
    KEEP (*(.git_commit*))        /* .git_commit* sections (constants, strings, etc.) */
    . = ALIGN(4);
  } >FLASH
...

并在源中配置变量

...
#define COMMIT_SIZE 20
uint8_t git_commit[COMMIT_SIZE] __attribute__((section(".git_commit")));
...

© www.soinside.com 2019 - 2024. All rights reserved.