在引导加载程序中,我有一个未明确使用的版本字符串,但必须存在于 ROM 中的特定位置,以便由所述引导加载程序加载的应用程序访问。在源文件 version.cpp 中我有:
// Place version string at end of bootrom less 16 bytes
#define VERSION_STRING "090600.01.00.00"
#define MAX_VERSION_STRING_LENGTH 0x10
const char bootmainVersionString[MAX_VERSION_STRING_LENGTH] __attribute__((used)) = VERSION_STRING ;
并且通过分散文件来获取位置:
LR_VERSION_IROM1 0x08001FF0 0x00000010
{
VERSION_IROM1 0x08001FF0 0x00000010
{
version.o (+RO)
}
}
这可能看起来相当复杂,但基于 LLVM/Clang 的 v6 不再支持之前在 armcc v5 中有效的方法。
但是,虽然
__attribute__((used))
会阻止正常删除未使用的对象,但当启用 LTO(链接时优化)时,链接器会删除它。由于在这种情况下我试图将 bootrom 保持在 8Kb 以内,LTO 在其他方面很有用。
我收到链接器警告:
.\bootrom.sct(21): warning: L6314W: No section matches pattern version.o(RO).
so
VERSION_IROM1
为空,而在未启用 LTO 的情况下,它会根据需要定位,但在这种情况下不使用会增加约 560 字节的图像大小。
工具链详细信息:
Toolchain: MDK-ARM Plus Version: 5.36.0.0
C Compiler: ArmClang.exe V6.16
Linker/Locator: ArmLink.exe V6.16
有办法阻止 LTO 删除该目标文件吗?
我尝试使用
volatile
限定符,并在代码中包含虚拟引用,但无济于事。
此外,我还尝试了链接器选项
--keep=bootmainVersionString
,但这在启用LTO的情况下不起作用,并且没有效果,否则__attribute__((used))
无法实现。
但是我注意到该对象存在于链接中,但未根据分散文件找到。在地图文件中我有:
没有 LTO(按预期位置):
bootmainVersionString 0x08001ff0 Data 16 version.o(.rodata.bootmainVersionString)
使用 LTO(由链接器定位):
bootmainVersionString 0x0800130c Data 16 lto-llvm-dbc16f.o(.rodata)
. ootrom.sct(21):警告:L6314W:没有部分与模式 version.o(RO) 匹配。
启用 LTO 时,无法在分散文件中显式使用对象名称,因为链接器只能看到字节码而不是对象文件。
您可以通过以下方式解决问题:
__attribute__((section("version")))
修改 VERSION_STRING
LR_VERSION_IROM1 0x08001FF0 0x00000010 { VERSION_IROM1 0x08001FF0 0x00000010 { version (+RO, +FIRST) } }
我一直无法使用链接器指令解决这个问题 - LTO 每次都会击败它。然而,我设计了一种解决方法,其优点是独立于工具链,完全不依赖于工具链特定的链接器指令或链接器特定的脚本语法。
我的解决方案是:
srec_cat buildinfo -binary -fill 0x00 0x000 0x100 -o buildinfo.hex -Intel
srec_cat final.hex -Intel buildinfo.hex -Intel -offset %BUILD_INFO_ADDR% -o application.hex -Intel
这样做的缺点可能是,当调试器加载工具链编译/链接的目标代码时,定位的数据当然不包括在内,并且如果关联的闪存页面甚至可能存在来自先前构建的数据加载目标代码时不需要删除。