1

I have many cpp files, some of which have functions to self-subscribe to events. Unfortunately, most linkers will eliminate all symbols from compilation units if there is no apparent function call into them. Is there a way to force linking of these subscription functions? I do not want to disable dead code stripping entirely, because I might miss a lot of opportunities from the other translation units.

Subscriber.cpp:

Event &someEvent();

void doSomething()
{
  printf("doing something\n");
}

class Initializer
{
  public: Initializer()
  {
    // I need this function to be kept
    someEvent().subscribe(&doSomething);
  }
} initializer;

Main.cpp:

Event &someEvent();

int main()
{
  someEvent().dispatch();
}

Thanks

EDIT:

Here is a repro build: https://github.com/malytomas/deadCodeElimination (Thanks Ayjay for help, even if his/her example does not reproduce the problem.)

The problem happens only with libraries. (Thanks Employed Russian for bringing this up.)

Tomas
  • 105
  • 7
  • 2
    "most linkers" - What *specific* code in the first list is incorrectly being... "eliminated" ? Also, linkers don't eliminate code from "compilation units"; they strip it from link targets. only after ensuring it isn't referenced. `doSomething` is clearly referred to in the first listing, so which code are you actually talking about? A *real* [mcve] would probably go a long way in amplifying your question. – WhozCraig Oct 09 '19 at 22:46
  • 1
    After playing around with this code to get it to actually compile (why didn't you do this?), it seems to work fine. [Godbolt](https://godbolt.org/z/GegCyT). What's your actual issue and can you link a code sample that actually demonstrates the problem? – Ayjay Oct 09 '19 at 23:00
  • I have created actually working example. It requires multiple files (and apparently also a library), which is why I did not write it in the first place. I apologize for confusing you. – Tomas Oct 10 '19 at 20:48

1 Answers1

3

Unfortunately, most linkers will eliminate all symbols from compilation units if there is no apparent function call into them.

You are mistaken: a linker that would do that would be a broken linker. Linkers do not garbage-collect code that registers global constructors or destructors.

What most likely happens is that your object files aren't even selected into the link (not pulled from archive libraries) in the first place. This post has a good explanation of the algorithm many linkers use to determine what is and isn't selected.

Update:

Now that we can see a repro, your actual question has nothing to do with dead code elimination. As I suspected, subscriber.o is simply not pulled in from libsubscriber.a, because the linker finds no reason to do so.

Here is the actual link command:

/usr/bin/c++ -rdynamic CMakeFiles/main.dir/main.cpp.o  -o main libsubscriber.a

Here is the command you want to have:

/usr/bin/c++ -rdynamic CMakeFiles/main.dir/main.cpp.o  -o main \
  -Wl,--whole-archive libsubscriber.a -Wl,--nowhole-archive

I don't know how to achieve that with CMake, sorry.

Alternatively, you could also achieve desired effect with:

/usr/bin/c++ -rdynamic CMakeFiles/main.dir/main.cpp.o  -o main \
 -u _Z19forceLinkSubscriberv libsubscriber.a
Employed Russian
  • 199,314
  • 34
  • 295
  • 362
  • Thanks, I will carefully read the article asap. The question remains: what can I do about it? I know I can add dummy functions (as demonstrated in the new linked repro build), but i would prefer something less cumbersome. Like a function attributes or similar. – Tomas Oct 10 '19 at 20:55
  • Thanks for the update. I did not know about the difference before you pointed it out yesterday. I have really hoped that there is some way to _mark_ the object to _always pull it_ from the code. I guess I will have to stick with what I have. It is inconvenient, but modifying link commands (especially from cmake) would be even worse. Thanks :D – Tomas Oct 11 '19 at 08:54