__do_global_ctors_aux未显示在 objdump 中
__do_global_ctors_aux not shown in objdump
请考虑以下代码:
#include <stdio.h>
void __attribute__ ((constructor)) a_constructor()
{
printf("%sn", __func__);
}
void __attribute__ ((constructor)) b_constructor()
{
printf("%sn", __func__);
}
int main()
{
printf("%sn",__func__);
}
我将上面的代码编译为:gcc -ggdb prog2.c -o prog2
。代码按预期运行。
a_constructor
b_constructor
main
但是当我看到它的转储使用 objdump -d prog2 > f
.既没有呼吁__do_global_ctors_aux
_init
或其他任何地方的任何地方,也没有__do_global_ctors_aux
的定义。那么,构造函数是如何被调用的呢?__do_global_ctors_aux
的定义在哪里?这是一些优化吗?
我也尝试在没有像这样的优化的情况下编译它:gcc -ggdb -O0 prog2.c -o prog2
.请澄清。编译是在 32 位 Linux 机器上完成的。
编辑
我从 gdb bt 输出的是:
Breakpoint 1, a_constructor () at prog2.c:5
5 printf("%sn", __func__);
(gdb) bt
#0 a_constructor () at prog2.c:5
#1 0x080484b2 in __libc_csu_init ()
#2 0xb7e31a1a in __libc_start_main (main=0x8048445 <main>, argc=1, argv=0xbffff014, init=0x8048460 <__libc_csu_init>,
fini=0x80484d0 <__libc_csu_fini>, rtld_fini=0xb7fed180 <_dl_fini>, stack_end=0xbffff00c) at libc-start.c:246
#3 0x08048341 in _start ()
那么,构造函数是如何被调用的呢?
如果你看一下用gcc -g -O0 -S -fverbose-asm prog2.c -o prog2.s
产生的拆卸,有以下几点:
.text
.Ltext0:
.globl a_constructor
.type a_constructor, @function
a_constructor:
.LFB0:
.file 1 "test.c"
.loc 1 4 0
.cfi_startproc
pushq %rbp #
.cfi_def_cfa_offset 16
.cfi_offset 6, -16
movq %rsp, %rbp #,
.cfi_def_cfa_register 6
.loc 1 5 0
movl $__func__.2199, %edi #,
call puts #
.loc 1 6 0
popq %rbp #
.cfi_def_cfa 7, 8
ret
.cfi_endproc
.LFE0:
.size a_constructor, .-a_constructor
.section .init_array,"aw"
.align 8
.quad a_constructor
在上面,函数a_constructor
放在.text
部分。指向该函数的指针也附加到.init_array
部分。在调用main
之前,glibc 会遍历此数组并调用在那里找到的所有构造函数。
详细信息是特定于实现的,您不会提及您的实现。
某些实现使用的一个完全有效的策略是创建一个运行时库,其中包含程序的实际入口点。该真正的入口点首先调用所有构造函数,然后调用main
。如果您的程序是动态链接的,并且该真实入口点背后的代码驻留在共享库中(例如,libc
),那么清楚地反汇编程序不可能显示构造函数的调用位置。
来源的一种简单方法是在调试器中加载程序,在其中一个构造函数上设置断点,并在命中断点时请求调用堆栈。例如,在Cygwin上:
$ gdb ./testGNU gdb (GDB) 7.8版权所有 (C) 2014 自由软件基金会公司。许可证 GPLv3+:GNU GPL 版本 3 或更高版本这是自由软件:您可以自由更改和重新分发它。在法律允许的范围内,没有保证。 键入"显示复制"和"显示保修"了解详细信息。此 GDB 配置为"i686-pc-cygwin"。键入"显示配置"以获取配置详细信息。有关错误报告说明,请参阅:.在线查找 GDB 手册和其他文档资源:.如需帮助,请键入"帮助"。键入"apropos word"以搜索与"word"相关的命令...正在从 ./test 中读取符号...做。(GDB) b a_constructor0x4011c6处的断点 1:文件 test.cc,第 5 行。(GDB) 运行起始程序:/home/Harald van Dijk/test[新线程 4440.0x1734][新线程 4440.0xa8c]b_constructor断点 1,a_constructor () 在 test.cc:5 处5 printf("%s", __func__);(GDB) 英国电信#0 a_constructor () 在 test.cc:5#1 0x61006986 in __main () 来自/usr/bin/cygwin1.dll#2 0x004011f6在主 () 中 test.cc:14(分行)这表明在 Cygwin
上,使用了我提到的策略的变体:真正的入口点是 main
函数,但编译器在开始时插入对特定于 Cygwin 的 __main
函数的调用,并且该函数__main
搜索所有构造函数并直接调用它们。
(顺便说一下,如果递归调用main
显然会中断:构造函数将第二次运行。这就是为什么C++不允许递归调用main
的原因。C 确实允许它,但是,标准 C 没有构造函数。
你可以得到一个提示,说明__main
函数如何搜索它们,方法是不反汇编可执行程序,而是要求编译器提供生成的程序集:
$ gcc -S test.c -o -
我不会在此处复制整个程序集列表,但它表明在此特定实现中,构造函数在.ctors
段中发出,因此__main
函数很容易简单地调用该段中的所有函数,而无需编译器逐个枚举每个此类函数。
- 比较并显示使用最小值(a,b)和最大值(a、b)升序排列的4个数字
- C++,OpenCV,尝试显示图像时"OpenCV(4.3.0) Error: Assertion failed (size.width>0 && size.height>0)"此错误
- 字符串-C++后显示的随机字符
- 继承期间显示未知行为的子类
- 仅使用绝对值对数组进行排序,并在C++中显示实际值
- 程序崩溃并显示"std::out_of_range"错误
- 如何在C++中用std::cout正确显示带十六进制的字符串文本
- 为什么在C的循环中使用printf的Rust代码不显示输出,而在C++的循环中显示std::cout
- 从数据库实时显示QT c++中的数据
- 当使用比格式支持的精度更高的精度来显示数字时,会写出什么数据
- 显示错误输出的简单数组排序程序
- Qt自定义QPush按钮未显示在布局上
- C++射线示踪剂ppm表示没有足够的数据来显示图像
- 显示基于用户输入的整数的字符
- 使用QTreeView,如何通过调用函数只突出显示特定的行/列
- 应用程序崩溃并显示"symbol _ZdlPvm, version Qt_5 not defined in file libQt5Core.so.5 with link time reference"
- 示例外壳应用程序显示的 V8 "segmentation fault (core dumped)"错误
- objdump 不显示机器代码,但显示 ASM
- __do_global_ctors_aux未显示在 objdump 中
- objdump 不显示 ostream 类的大小