Давайте посмотрим на некоторый минимальный пример, который ведет себя аналогично:
1 #include <iostream>
2
3 int global_int = 42;
4
5 int main(int argc, const char *argv[])
6 {
7 std::cout << "global_int = " << global_int << "\n";
8 }
(gdb) bt
#0 global constructors keyed to global_int() () at global.cxx:8
#1 0x0804875d in __do_global_ctors_aux ()
#2 0x080484ec in _init ()
#3 0x080486f9 in __libc_csu_init (argc=1, argv=0xbffff0c4, envp=0xbffff0cc) at elf-init.c:79
#4 0xb7d2069c in __libc_start_main () from /lib/libc.so.6
#5 0x08048591 in _start () at ../sysdeps/i386/elf/start.S:119
Эта обратная трассировка должна дать нам хотя бы кое-что для Google.Это конструкторы для глобальных значений.
191 080486b1 <_GLOBAL__I_global_int>:
192 80486b1: 55 push %ebp
193 80486b2: 89 e5 mov %esp,%ebp
194 80486b4: 83 ec 18 sub $0x18,%esp
195 80486b7: c7 44 24 04 ff ff 00 movl $0xffff,0x4(%esp)
196 80486be: 00
197 80486bf: c7 04 24 01 00 00 00 movl $0x1,(%esp)
198 80486c6: e8 a6 ff ff ff call 8048671 <_Z41__static_initialization_and_destruction_0ii>
199 80486cb: c9 leave
200 80486cc: c3 ret
Разборка здесь не делает нас намного умнее, она вызывает функцию __static_initialization_and_destruction_0(int,int)
, которая немного интереснее:
171 08048671 <_Z41__static_initialization_and_destruction_0ii>:
172 8048671: 55 push %ebp
173 8048672: 89 e5 mov %esp,%ebp
174 8048674: 83 ec 18 sub $0x18,%esp
175 8048677: 83 7d 08 01 cmpl $0x1,0x8(%ebp)
176 804867b: 75 32 jne 80486af <_Z41__static_initialization_and_destruction_0ii+0x3e>
177 804867d: 81 7d 0c ff ff 00 00 cmpl $0xffff,0xc(%ebp)
178 8048684: 75 29 jne 80486af <_Z41__static_initialization_and_destruction_0ii+0x3e>
179 8048686: c7 04 24 d4 a0 04 08 movl $0x804a0d4,(%esp)
180 804868d: e8 9e fe ff ff call 8048530 <_ZNSt8ios_base4InitC1Ev@plt>
181 8048692: b8 50 85 04 08 mov $0x8048550,%eax
182 8048697: c7 44 24 08 20 a0 04 movl $0x804a020,0x8(%esp)
183 804869e: 08
184 804869f: c7 44 24 04 d4 a0 04 movl $0x804a0d4,0x4(%esp)
185 80486a6: 08
186 80486a7: 89 04 24 mov %eax,(%esp)
187 80486aa: e8 61 fe ff ff call 8048510 <__cxa_atexit@plt>
188 80486af: c9 leave
189 80486b0: c3 ret
Важная часть здесьчто есть функция, зарегистрированная в atexit (), которая находится в 0x8048550
и называется std::ios_base::Init::~Init()
, но только когда параметрами для этих функций являются 0x1
и 0xffff
.И эта функция затем также вызывает ctor std::ios_base::Init::Init()
, который инициализирует глобальный материал, необходимый для использования std :: cout.
Теперь мы знаем, что он делает, но не почему.Здесь кто-то с начальными знаниями gcc будет знать больше, но я предполагаю, что именно так gcc гарантирует, что всякий раз, когда некоторый код, вызываемый для инициализации некоторых глобальных / статических переменных (который выполняется перед main), также ctor для i /o Подсистема называется, так что вы всегда можете использовать std::cout
там.
Относительно того, почему это так часто вызывается в вашем коде, и почему это занимает так много времени, я не могу сказать много, может бытьВы можете узнать больше об установке некоторой точки останова в отладчике.Может быть, это также неправильный учет этой функции из-за оптимизации.