Having that very little project:
func2.cpp:
#include <iostream>
void myfunc2()
{
std::cout << "Func2 called" << std::endl;
}
func.cpp:
#include <iostream>
#include "func.h"
void myfunc()
{
std::cout << "Hallo func " << std::endl;
}
main.cpp:
#include "func.h"
#include "func2.h"
int main()
{
//myfunc(); // intentionally moved away!
//myfunc2();
}
The .h files only have a definition of the needed funcs.
The Makefile:
all: go
%.o: %.cpp
g++ -O3 -fdata-sections -ffunction-sections $< -c
go: main.o func.h func.o func2.o func2.h
g++ -fdata-sections -ffunction-sections main.o func.o func2.o -o go -Wl,--gc-sections
If I do a dissasembly of my generated executable I got still two unneeded functions:
0000000000400560 <_GLOBAL__sub_I__Z6myfuncv>:
400560: 48 83 ec 08 sub $0x8,%rsp
400564: bf 31 10 60 00 mov $0x601031,%edi
400569: e8 c2 ff ff ff callq 400530 <std::ios_base::Init::Init()@plt>
40056e: ba 30 07 40 00 mov $0x400730,%edx
400573: be 31 10 60 00 mov $0x601031,%esi
400578: bf 40 05 40 00 mov $0x400540,%edi
40057d: 48 83 c4 08 add $0x8,%rsp
400581: e9 9a ff ff ff jmpq 400520 <__cxa_atexit@plt>
400586: 66 2e 0f 1f 84 00 00 nopw %cs:0x0(%rax,%rax,1)
40058d: 00 00 00
0000000000400590 <_GLOBAL__sub_I__Z7myfunc2v>:
400590: 48 83 ec 08 sub $0x8,%rsp
400594: bf 32 10 60 00 mov $0x601032,%edi
400599: e8 92 ff ff ff callq 400530 <std::ios_base::Init::Init()@plt>
40059e: ba 30 07 40 00 mov $0x400730,%edx
4005a3: be 32 10 60 00 mov $0x601032,%esi
4005a8: bf 40 05 40 00 mov $0x400540,%edi
4005ad: 48 83 c4 08 add $0x8,%rsp
4005b1: e9 6a ff ff ff jmpq 400520 <__cxa_atexit@plt>
4005b6: 66 2e 0f 1f 84 00 00 nopw %cs:0x0(%rax,%rax,1)
4005bd: 00 00 00
It looks like every file which needs iostream objects generate a function which is called during initialization. The section and the generated function gets the name from the first defined function in that file.
And if I don't use that function and it is not linked in the final executable, these _GLOBAL__sub_I__xxxx
functions are still present. How can I remove them?
It looks very mysterious to me that every user of a an iostream object like cout
will generate a additional initializer function. Is there any trick to get rid of it? I feel it is only needed once per executable but I see it multiple times. How to avoid it in general?
The culprit is the std::ios_base::Init::Init()
constructor which is called from every source file that includes <iostream>
. The call guarantees that the streams are properly initialized before first use.
And because of the "static initialization order fiasco" this initialization has to be present in all files potentially using the streams, because we don't know the order of initialization between different source files.