2013-03-20 54 views
2

我想在C++文件中计算静态初始值设定项。如何计算ELF文件中的静态初始值设定项?

我已经拥有的解决方案(曾经使用gcc-4.4)正在查看.ctors ELF部分的大小。

升级到gcc-4.6后,这似乎不再返回有效结果(计算出的静态初始值设定项数为0,与实际值不符,例如由nm返回)。

现在的问题是我想解决方案即使在没有符号的情况下也能工作(否则我会用nm)。

下面是一个例子可执行的readelf -SW的输出:

有35个区段标题,起始于偏移0x4f39820:

Section Headers: 
    [Nr] Name    Type   Addr  Off Size ES Flg Lk Inf Al 
    [ 0]     NULL   00000000 000000 000000 00  0 0 0 
    [ 1] .interp   PROGBITS  00000174 000174 000013 00 A 0 0 1 
    [ 2] .note.ABI-tag  NOTE   00000188 000188 000020 00 A 0 0 4 
    [ 3] .note.gnu.build-id NOTE   000001a8 0001a8 000024 00 A 0 0 4 
    [ 4] .gnu.hash   GNU_HASH  000001cc 0001cc 000918 04 A 5 0 4 
    [ 5] .dynsym   DYNSYM   00000ae4 000ae4 00a5e0 10 A 6 1 4 
    [ 6] .dynstr   STRTAB   0000b0c4 00b0c4 00ef72 00 A 0 0 1 
    [ 7] .gnu.version  VERSYM   0001a036 01a036 0014bc 02 A 5 0 2 
    [ 8] .gnu.version_r VERNEED   0001b4f4 01b4f4 000450 00 A 6 13 4 
    [ 9] .rel.dyn   REL    0001b944 01b944 268480 08 A 5 0 4 
    [10] .rel.plt   REL    00283dc4 283dc4 0048c8 08 A 5 12 4 
    [11] .init    PROGBITS  0028868c 28868c 00002e 00 AX 0 0 4 
    [12] .plt    PROGBITS  002886c0 2886c0 0091a0 04 AX 0 0 16 
    [13] .text    PROGBITS  00291860 291860 3ac5638 00 AX 0 0 16 
    [14] malloc_hook  PROGBITS  03d56ea0 3d56ea0 00075a 00 AX 0 0 16 
    [15] google_malloc  PROGBITS  03d57600 3d57600 008997 00 AX 0 0 16 
    [16] .fini    PROGBITS  03d5ff98 3d5ff98 00001a 00 AX 0 0 4 
    [17] .rodata   PROGBITS  03d5ffc0 3d5ffc0 ffa640 00 A 0 0 64 
    [18] .eh_frame_hdr  PROGBITS  04d5a600 4d5a600 0004b4 00 A 0 0 4 
    [19] .eh_frame   PROGBITS  04d5aab4 4d5aab4 001cb8 00 A 0 0 4 
    [20] .gcc_except_table PROGBITS  04d5c76c 4d5c76c 0003ab 00 A 0 0 4 
    [21] .tbss    NOBITS   04d5df0c 4d5cf0c 000014 00 WAT 0 0 4 
    [22] .init_array  INIT_ARRAY  04d5df0c 4d5cf0c 000090 00 WA 0 0 4 
    [23] .ctors   PROGBITS  04d5df9c 4d5cf9c 000008 00 WA 0 0 4 
    [24] .dtors   PROGBITS  04d5dfa4 4d5cfa4 000008 00 WA 0 0 4 
    [25] .jcr    PROGBITS  04d5dfac 4d5cfac 000004 00 WA 0 0 4 
    [26] .data.rel.ro  PROGBITS  04d5dfc0 4d5cfc0 1b160c 00 WA 0 0 32 
    [27] .dynamic   DYNAMIC   04f0f5cc 4f0e5cc 000220 08 WA 6 0 4 
    [28] .got    PROGBITS  04f0f7ec 4f0e7ec 00a800 04 WA 0 0 4 
    [29] .data    PROGBITS  04f1a000 4f19000 0206b8 00 WA 0 0 32 
    [30] .bss    NOBITS   04f3a6c0 4f396b8 04c800 00 WA 0 0 32 
    [31] .comment   PROGBITS  00000000 4f396b8 00002a 01 MS 0 0 1 
    [32] .shstrtab   STRTAB   00000000 4f396e2 00013e 00  0 0 1 
    [33] .symtab   SYMTAB   00000000 4f39d98 4ff960 10  34 140163 4 
    [34] .strtab   STRTAB   00000000 54396f8 144992a 00  0 0 1 
Key to Flags: 
    W (write), A (alloc), X (execute), M (merge), S (strings) 
    I (info), L (link order), G (group), T (TLS), E (exclude), x (unknown) 
    O (extra OS processing required) o (OS specific), p (processor specific) 

我应该看的.init或.init_array代替?你能指点我相应的文档,解释gcc或链接器版本之间的变化吗?

+1

为什么你到底在问什么? – 2013-03-20 19:25:06

回答

7

静态构造函数可以由三个部分.init,.ctors.init_array(按照该顺序最早到最新)中的任何一个来触发。 .init包含一段代码,.ctors.init_array包含指向代码的指针。 .ctors.init_array之间的区别与构造函数的执行顺序有关。据我所知,除了代码注释和邮件列表文章以外,其他地方都没有文档记录,但可能需要检查ELF ABI文档(g-和ps-两者)。

无法这些部分的任何大小推断在文件中静态构造函数的数量。对于编译器来说,允许并且通常会生成一个调用文件中所有构造函数的特殊函数,并且只使用它所使用的任何部分中的那个函数。所有您可以确切知道的内容(无需检查各部分的内容,应用重定位,将指针/调用指令放入.text段并对所调用的对象进行逆向工程)为:,其中包含目标文件,如果其中至少有一个部分具有非零大小,那么文件中至少有一个文件或全局范围构造函数;如果所有三个部分都是空的,那么没有。 (在一个可执行文件中,所有三个部分总是非空的,因为他们定义的数据结构需要标题和尾部,并在链接时自动添加。)

还要注意,用于块范围的静态对象的构造函数不是从任何这些部分引用;他们在第一次控制达到他们的声明时被调用。

+0

没有人禁止'main()'在其开始时调用构造函数(或者甚至在它之前运行的代码中),没有任何部分shenanigans。有一天海湾合作委员会做到了这一点,或者是另一种方式是他们的业务。 – vonbrand 2013-03-22 22:44:57

+1

@vonbrand C++标准允许您正在考虑的技术,但许多年来没有人这样做过,并且在共享库的存在下无法正常工作。编译器的业务也不仅仅是它如何实现静态构造函数; ELF ABI文档确实指定了'.init','.ctors'和'.init_array'部分的功能。 – zwol 2013-03-22 23:59:05

0

我假设你有权访问你的应用程序的所有源代码(也可能是所有它被称为的库)。自由软件显然是这样的。

然后,您可以在编译时(使用GCC的最新版本,例如4.7或4.8)编译时更精确地测量您的应用程序。你可以用MELT(这是一个高级别的域特定语言来扩展GCC)或用C++编写的痛苦的GCC插件来扩展它来测量这些事情。

我不完全确定你的问题具有确切的意义。如果您的申请是例如链接到一些使用可见性技巧隐藏其静态构造函数的共享库,了解库调用的静态构造函数没有真正定义。

相关问题