Search code examples
cstm32elfobjcopycustom-sections

How to link Data in ELF file to show up during run time? STM32


I am stuck trying to have my FW version show up at run-time.

I have tried using the example from Does gcc have any options to add version info in ELF binary file? But with no luck. Here is what i have so far.

Using STM32L462 on STM32CubeIDE (MacOS)

Inside source file:

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

Inside my Application folder, I have a version_number.txt which contains the version number (for now 1.0.0)

Once the code successfully compies, a python script runs which takes the version number from the version_number.txt and the hash of the git commit and places them inside the elf sections using objcopy.

"""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)

Once the script finishes i can run

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

And the outputs will match the git commit and the version that is listed in the version_number.txt (changing the number in txt will change the output for objdump).

However, during run-time when I try to get the value of version_number or git_commit I get only default garbage values.

Running:

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

Does not work.

Any ideas are welcome! Thank you!


Solution

  • For Anyone who is interested,
    adding the following lines to the STM32L4< x >_FLASH.ld between the .rodata (~line 74) and the .ARM.extab (~line 82) links the .gitcommit and .version section properly.

     .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
    

    Full Explanation - How to have version number and git commit saved on flash (STM32):

    Inside the Application Folder:

    Keep the version number inside a version_number.txt Every version update, update the text file.

    Within the source files:
    Declare your variables for holding the git-commit and version number as follows (change section names as you wish but be sure to be consistent with the names)

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

    linker file (STM32< MCU ID >_FLASH.ld):

    insert the following lines to link between the variables and the values they need to hold (as mentioned above - between the .rodata and .ARM.extab sections)

     .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
    

    Finally, as post-build, run the python script to take the version_number and git commit and insert them into the proper sections!

    """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)
    

    That's it, when running the code you should have git commit hold the hash value and version_number hold the version number.

    Good Luck