使用 GCC 生成连续的 Hex 文件

Contiguous Hex file generation using GCC

我有一个 STM32F427 的十六进制文件,它是使用 GCC(gcc-arm-none-eabi) 4.6 版构建的,具有连续的内存地址。我编写了用于加载该十六进制文件的引导加载程序,并且还添加了校验和功能以确保在启动应用程序之前十六进制文件是正确的。 Hex 文件片段:

:1005C80018460AF02FFE07F5A64202F1D00207F5F9 :1005D8008E4303F1A803104640F6C821C2F2000179 :1005E8001A460BF053F907F5A64303F1D003184652 :1005F8000BF068F907F5A64303F1E80340F6FC1091 :10060800C2F2000019463BF087FF07F5A64303F145 :10061800E80318464FF47A710EF092FC07F5A643EA :1006280003F1E80318460EF03DFC034607F5A64221 :1006380002F1E0021046194601F0F2FC07F56A5390

如您所见,所有地址都是连续的。然后我们将编译器更改为 4.8 版,我得到了相同类型的 Hex 文件。

但是现在我们使用的是6.2版本的编译器,生成的Hex文件不是连续的。有点像这样:

:10016000B9BC0C08B9BC0C08B9BC0C08B9BC0C086B
:10017000B9BC0C08B9BC0C08B9BC0C08B9BC0C085B
:08018000B9BC0C08B9BC0C0865
:1001900081F0004102E000BF83F0004330B54FEA38
:1001A00041044FEA430594EA050F08BF90EA020FA5

如您所见,0188 之后它从 0190 开始,这意味着其余 8 个字节(0189 到 018F)为 0xFF,因为它们没有闪烁。

现在引导加载程序有点笨,我们只传递起始地址和字节数来计算校验和。

有没有办法像编译器 4.6 和编译器 4.8 那样以连续的方式制作 hex 文件?代码在所有三个时间都是相同的。

许多可能的方法之一:

  • 使用 v6.2 制作 hex 文件,例如 foo.hex
  • 用这个 Perl oneliner 对其进行后处理:

    perl -pe 'if(m/^:(..)(.*)$/) { my $rest=16-hex(); $_ = ":10" .  . ("FF" x $rest) . "\n"; }' foo.hex > foo2.hex
    

现在 foo2.hex 将拥有所有 16 字节的行

注意:所有这一切 是 FF-pad 到 0x10 字节。它不检查地址或其他任何内容。

说明

perl -pe '<some script>' <input file><input file> 的每一行运行 <some script> 并打印结果。脚本是:

if(m/^:(..)(.*)$/) {         # grab the existing byte count into 
    my $rest=16 - hex();   # how many bytes of 0xFF we need
    $_ = ":10" .  . ("FF" x $rest) . "\n";  # make the new 16-byte line
# existing bytes-^^   ^^^^^^^^^^^^^^-pad bytes
}

如果post-处理hex文件是一个选项,您可以考虑使用IntelHex python库。这使您可以操作十六进制文件数据(即忽略 'markup';记录类型、地址、校验和等)而不是作为行,例如将使用正确的行校验和创建输出。

一个快速的方法和 运行 可能是使用捆绑的便利脚本 hex2bin.py and bin2hex.py:

python hex2bin.py --pad=FF noncontiguous.hex tmp.bin
python bin2hex.py tmp.bin contiguous.hex

第一行将输入文件noncontiguous.hex转换为二进制文件,在没有数据的地方用FF填充。第二行将二进制文件转换回十六进制文件。

结果会是

:08018000B9BC0C08B9BC0C0865

变成

:10018000B9BC0C08B9BC0C08FFFFFFFFFFFFFFFF65

如您所见,在输入没有任何数据的地方添加了填充字节,相当于将输入文件写入设备并读回。输入文件中的字节保持相同 - 并且位于相同的地址。 校验和也是正确的,因为将长度字节从 0x08 更改为 0x10 可以补偿额外的 0xFF 字节。如果你用其他东西填充,IntelHex 会输出正确的校验和

您可以通过以下方式跳过临时文件的创建:省略第一行中的 tmp.bin 并在第二行中将其替换为 -

python hex2bin.py --pad=FF noncontiguous.hex | python bin2hex.py - contiguous.hex

另一种方法是拥有一个包含所有 FF 的基础文件,并使用 hexmerge.py 便捷脚本将 gcc 的输出与 --overlap=replace

合并到它上面

更长、更灵活的方法是使用 IntelHex API 实现您自己的工具。我已经在与您类似的情况下使用它取得了很好的效果 - 调整十六进制文件以满足更改成本高昂的工具,但只能按照编写工具时的方式处理十六进制文件。

另一种解决方案是更改链接描述文件以确保前面的 .isr_vector 部分以 16 字节对齐方式结束,因为映射文件显示后面的 .text 部分是 16 字节对齐的。 这将确保两个部分之间没有未编程的闪存字节

您可以使用 bincopy 将所有空白 space 填充为 0xff。

$ pip install bincopy
$ bincopy fill foo.hex