如何从 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 - const1
而 const6
的大小等于 0x1001013c - const6
.
然而,这一切都相当学术 - 您可以根据常量初始化程序的大小精确控制它。它们不是与您的代码无关的神奇创建的数据,我不相信您是您建议的 优化 的产物。无论优化选项如何,non-zero 初始化程序都必须存在,并且在任何情况下,优化主要影响大小 and/or 代码(.text
)的速度而不是数据。对数据大小的影响可能仅与填充和对齐有关,并且在调试版本中可能 "guard-space" 用于溢出检测。
不过你完全没必要去猜。您可以通过检查反汇编或在调试器中观察其执行(在指令级别)来确定如何使用此数据 - 以准确查看初始化变量从何处复制数据。您甚至可以在这些地址处放置一个 read-access break-point,您将直接确定哪些代码正在使用它们。
我正在为我的 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 - const1
而 const6
的大小等于 0x1001013c - const6
.
然而,这一切都相当学术 - 您可以根据常量初始化程序的大小精确控制它。它们不是与您的代码无关的神奇创建的数据,我不相信您是您建议的 优化 的产物。无论优化选项如何,non-zero 初始化程序都必须存在,并且在任何情况下,优化主要影响大小 and/or 代码(.text
)的速度而不是数据。对数据大小的影响可能仅与填充和对齐有关,并且在调试版本中可能 "guard-space" 用于溢出检测。
不过你完全没必要去猜。您可以通过检查反汇编或在调试器中观察其执行(在指令级别)来确定如何使用此数据 - 以准确查看初始化变量从何处复制数据。您甚至可以在这些地址处放置一个 read-access break-point,您将直接确定哪些代码正在使用它们。