Search code examples
c++ld

I see a lot of _GLOBAL__sub_I__ also from unused and stripped functions, how to remove them


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?


Solution

  • 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.