我正在为我的 C 程序编写一些代码大小分析工具,使用输出 ELF
文件。
我正在使用 readelf -debug-dump=info
生成 Dwarf 格式文件
。
我注意到我的编译器正在将 Dwarf 文件中没有的新常量添加到 .rodata
部分,作为优化的一部分。
所以.rodata
部分大小包括它们的大小,但我在Dwarf
中没有它们的大小。
这是 map 文件的示例:
*(.rodata)
.rodata 0x10010000 0xc0 /<.o file0 path>
0x10010000 const1
0x10010040 const2
.rodata 0x100100c0 0xa /<.o file1 path>
fill 0x100100ca 0x6
.rodata 0x100100d0 0x6c /<.o file2 path>
0x100100d0 const3
0x100100e0 const4
0x10010100 const5
0x10010120 const6
fill 0x1001013c 0x4
在上面的 file1 中,虽然我没有声明 const 变量 - 编译器做了声明,但这个 const 占用了 .rodata 中的空间,但没有它的符号/名称。
这是生成它的某个函数内的代码:
uint8 arr[3][2] = {{146,179},
{133, 166},
{108, 141}} ;
因此编译器添加一些常量值来优化数组的负载。
如何从数据部分中提取这些隐藏的添加内容?
我希望能够完全表征我的代码 - 每个文件使用了多少空间等...
最佳答案
我在这里猜测 - 它将取决于链接器,但是当您有如下代码时:
uint8 arr[3][2] = {{146,179},
{133, 166},
{108, 141}} ;
arr
在运行时存在于读/写内存中,但其初始化程序将位于R/O内存中,并在数组初始化时复制到读/写内存中。链接器只需要提供地址,因为该大小将在本地被称为作为初始化代码中的文字嵌入的编译时常量。因此,大小信息不会出现在映射中,因为链接器会丢弃该信息。
但是,长度是由填充空间的相邻对象的地址隐含的。例如:
例如,const1
的大小等于 const2 - const1
,对于 const6
来说,它是 0x1001013c - const6
>.
.text
) 的大小和/或速度,而不是数据。对数据大小的影响可能仅与填充和对齐有关,并且在调试版本中可能与溢出检测的“保护空间”有关。
但是你完全没有必要猜测。您可以通过在调试器中检查反汇编或观察其执行(在指令级别)来确定如何使用此数据 - 以准确查看初始化变量从何处复制数据。您甚至可以在这些地址处放置一个读取访问断点,然后您将直接确定哪些代码正在使用它们。
关于c - 如何从 ELF 文件中提取通过编译器优化添加的常量地址?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49430840/