缺少 extern const float 的 ELF 符号?

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

我见过 使用 GDB 时缺少 ELF 符号“var”?,但这是一个不同的问题。

我在 openocd 上使用带有 RP2040 的 gdb。不幸的是,我无法提供重现该问题的完整代码,但在

.h
文件中我有:

extern const float kLDC;

...在

.c
文件中我有:

const float kLDC = (100-0)/(255-0);

当我通过 openocd 使用程序的调试版本启动 gdb 会话时,我可以

p
rint 几乎任何全局变量,但是对于
kLDC
,我得到:

(gdb) p kLDC
Missing ELF symbol "kLDC".

发生什么事了?是否期望声明为 extern const float 的符号不能在

gdb
中打印?我用:

$ gdb-multiarch.exe --version
GNU gdb (GDB) 14.2

感谢评论者指出

(100-0)/(255-0)
表达式为整数有错误;我自己最终意识到,当我第一次删除
const
时,我可以检查 gdb 中的值。有了这个声明:

float kLDC = (100.0-0)/(255-0);

...我确认该值约为0.3921;记下使用该变量获得的计算结果,然后将其设置回

const
。我可以确认计算结果是相同的,但是我再次得到
Missing ELF symbol "kLDC".
。构建过程生成了一个
.map
文件,它输出:

$ grep kLDC myprogram.elf.map
 .rodata.kLDC   0x00000000        0x4 CMakeFiles/myprogram.dir/my_function.c.obj

我也尝试过:

$ arm-none-eabi-objdump -g myprogram.elf | grep kLDC
    <23e00>   DW_AT_name        : (indirect string, offset: 0x7ae4): kLDC
  0x00007ae0 70657100 6b4c4443 00475049 4f5f4f56 peq.kLDC.GPIO_OV

(我不太明白上面的内容,但令我惊讶的是看到

kLDC
接近任何名为
GPIO
的东西 - 它根本不直接与代码中的 GPIO 一起使用)

我仍然无法理解这一点 - .elf 中有 kLDC 的痕迹,我可以想象编译器可能“知道”一些其他初始化的只读内存,其内容与 kLDC = 0.39 相同...,因此,通过不费心专门为 kLDC var 分配新内存,而是重新使用现有内存来“优化” - 但现在我费心声明“extern”(并使用

-g
/Debug 构建),不应该编译器至少尝试让这个常量在
gdb
中可用,这样我就可以打印它的值?至少,我想了解构建过程决定可以“错过”ELF 中的“符号”的条件 - 或者相反,如果我可以使用任何其他规范来强制该值可读在
gdb
,即使是
const
...

c gdb cortex-m openocd
1个回答
0
投票

映射文件显示包含所需对象的部分的地址为 0x00000000,这意味着它已被链接器从最终的二进制文件中删除。

它这样做是因为您的构建过程包含链接器标志

--gc-sections
。 这告诉它删除任何未引用的部分。

您可以删除此标志,但这将使您的二进制文件变得巨大,其中包含各种未使用的垃圾。 这在嵌入式开发中不是一个好主意。

声明变量

extern
会阻止编译器对其进行优化,但这并没有帮助,因为这里的垃圾收集是由链接器完成的。 您可以通过将标志
--gc-keep-exported
添加到链接器(如果您通过 gcc 调用 ld,则为
-Wl,--gc-keep-exported
)来获得您期望的行为。

或者,您只需要让程序以无法优化的方式使用变量,例如:

printf("%08X", (unsigned int)&kLDC);

您还可以通过将

KEEP()
添加到链接器脚本来告诉链接器保留此特定部分,但这可能很难维护。

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