如何从 ELF 文件中提取由编译器优化添加的常量地址?

How can i extract constants' addresses,added by compiler optimization, from ELF file?

我正在为我的 C 程序编写一些代码大小分析工具,使用输出 ELF 文件。

我正在使用 readelf -debug-dump=info 生成 Dwarf format file

我注意到我的编译器正在将不在 Dwarf 文件中的新常量作为优化的一部分添加到 .rodata 部分。

所以 .rodata 部分大小包括它们的大小,但我在 Dwarf 中没有它们的大小。

这是地图文件的示例:

*(.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 

在上面的文件 1 中,虽然我没有声明 const 变量——编译器声明了,但是这个 const 在 .rodata 中使用了 space 但是没有 symbol/name 为它。

下面是一些生成它的函数中的代码:

uint8 arr[3][2] = {{146,179},
                   {133, 166},
                   {108, 141}} ;

所以编译器添加一些常量值来优化数组的加载。

如何从数据部分中提取这些隐藏的附加内容?

我希望能够完全表征我的代码 - 每个文件中使用了多少 space,等等...

要详细获取 elf 文件的大小,请使用

"您可以使用 nm 和 size 来获取函数和 ELF 部分的大小。

获取函数的大小(以及具有静态存储持续时间的对象):

$ nm --print-size --size-sort --radix=d tst.o 第二列显示函数和对象的十进制大小。

获取分区的大小:

$ 尺寸 -A -d tst.o 第二列显示各部分的十进制大小。"

Tool to analyze size of ELF sections and symbol

我在这里猜测 - 它将依赖于链接器,但是当你有如下代码时:

uint8 arr[3][2] = {{146,179},
                   {133, 166},
                   {108, 141}} ;

arr at run-time 存在于r/w 内存中,但它的初始化程序将位于R/O 内存中,当复制到R/W 内存时数组被初始化。链接器只需要提供地址,因为大小将在本地被称为 compile-time 常量,作为文字嵌入到初始化代码中。因此,大小信息不会出现在映射中,因为链接器会丢弃该信息。

然而,

长度隐含在 相邻 个对象的地址中 filled space。例如:

例如 const1 的大小等于 const2 - const1const6 的大小等于 0x1001013c - const6.

然而,这一切都相当学术 - 您可以根据常量初始化程序的大小精确控制它。它们不是与您的代码无关的神奇创建的数据,我不相信您是您建议的 优化 的产物。无论优化选项如何,non-zero 初始化程序都必须存在,并且在任何情况下,优化主要影响大小 and/or 代码(.text)的速度而不是数据。对数据大小的影响可能仅与填充和对齐有关,并且在调试版本中可能 "guard-space" 用于溢出检测。

不过完全没必要去猜。您可以通过检查反汇编或在调试器中观察其执行(在指令级别)来确定如何使用此数据 - 以准确查看初始化变量从何处复制数据。您甚至可以在这些地址处放置一个 read-access break-point,您将直接确定哪些代码正在使用它们。