• Advertisement
Sign in to follow this  

I tricked the linker :(

This topic is 4346 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

I wrote a piece of code that during construction will register itself to a factory. Unfortunately, the instance of the object I put in its own object file. This causes a seperate .obj file that will never be referenced anywhere else in the code base. Since the .obj file doesn't get referenced it doesn't get linked into the main executable. This causes the static instance never to be constructed and the factory never gets registered. Is there anyway to tell the main executable, using cl.exe, to give a hint that it needs the .obj? The code I've come up with is really clean and elegant and I'd like to avoid hacking it up just to get it to link. Any suggetions?

Share this post


Link to post
Share on other sites
Advertisement
What good is the object if you never access it? I guess it depends on what it does, exactly - so what's it do?

Share this post


Link to post
Share on other sites
How does the registration process for your factory work? If you're using a static instance of some sort I would have expected the linker to include the .obj file.

Share this post


Link to post
Share on other sites
Quote:
Original post by joanusdmentia
How does the registration process for your factory work? If you're using a static instance of some sort I would have expected the linker to include the .obj file.



// .h
class DerivedFactory : BaseFactory
public:

virtual Memory* AllocationScheme() { return new int; }

// .cpp file
static FactoryInstaller<DerivedFactory> factory;


What happens is in FactoryInstaller's ctor it registers itself, and the dtor removes itself. The allocation scheme is part of BaseFactory so DerivedFactory never needs to be explicitly referenced.

In short: Factory installer adds Derived Factory and all the functionality you need is through base class functionality. This causes DerivedFactory to be compiled but never linked because no one references any of its functionality.






Share this post


Link to post
Share on other sites
Hmm..... seems strange to me. I've never had any trouble with this scenario before. Are you doing anything else nonstandard with the linker?

Share this post


Link to post
Share on other sites
Could you put the FactoryInstaller<DerivedFactory> object in the source file for DerivedFactory? Or anywhere else that has referenced code? This IS typical behavior, but I'm not sure if there's a way to override it.

Share this post


Link to post
Share on other sites
Quote:
Original post by RDragon1
Could you put the FactoryInstaller<DerivedFactory> object in the source file for DerivedFactory? Or anywhere else that has referenced code? This IS typical behavior, but I'm not sure if there's a way to override it.


That is the solution I have found to work, unfortunately it's not something I find acceptable. What ends up happening is you have to manage a .cpp/.h file that has a list of all factories. In my opinion having a seperate module that can be moved/linked in is much cleaner.

I'm hoping there is a way to tell the linker that this obj file needs to be linked in. I suppose I can compile the .obj file as a .lib and statically link it in.

Share this post


Link to post
Share on other sites
Quote:
Original post by Sneftel
Hmm..... seems strange to me. I've never had any trouble with this scenario before. Are you doing anything else nonstandard with the linker?


Really? There is no possible way that the linker can know that the object file is actually needed without hints from the programmer.

Though, no I'm not doing anything non-standard.

Share this post


Link to post
Share on other sites
Guest Anonymous Poster
I was thinking "volatile", but that won't affect the linker, only the compiler, right? What compiler are you using, by the way?

Share this post


Link to post
Share on other sites
I've had similar problems before. The simple solution is to turn off the linker option that rips out unreferenced code ;)

Another solution that may work for you is to put the static variable declaraion in the header file. This isn't ideal, but it helps the linker to realize specifically that you want a template instantiation of that type, and not to rip it out (as there's technically a global variable floating around now... put it in a namespace or something to make it prettier).

I experimented with making the static variable instance a member of the class itself, but the linker rips that one out too...

Share this post


Link to post
Share on other sites
Quote:
Original post by AndyTX
I've had similar problems before. The simple solution is to turn off the linker option that rips out unreferenced code ;)
Haha, I do like to keep my link times relatively short :)

Quote:
Another solution that may work for you is to put the static variable declaraion in the header file. This isn't ideal, but it helps the linker to realize specifically that you want a template instantiation of that type, and not to rip it out (as there's technically a global variable floating around now... put it in a namespace or something to make it prettier).

Unfortunately, I'll have to wait till tommorow to test out this theory, but I can't imagine it working because the header file isn't included from anywhere. How would it make any difference?

Share this post


Link to post
Share on other sites
I suspect that it's the static keyword confusing things. static in this context says 'do no make this symbol visible outside of this translation unit', so the generated .obj file will have no symbols in it and thus not included by the linker. Try removing the static keyword and placing the declaration inside an anonymous namespace instead.


// .cpp file
namespace
{
FactoryInstaller<DerivedFactory> factory;
}


Share this post


Link to post
Share on other sites
Can you try this?

int f()
{
FactoryInstaller<DerivedFactory>* factory = new FactoryInstaller<DerivedFactory>;
return rand();// you return anything you want
}

static int i = f();

Share this post


Link to post
Share on other sites
Guest Anonymous Poster
You can just simply, and evil-ly, add the .obj file to your project like it was a C or C++ file ;)

Share this post


Link to post
Share on other sites
Quote:
Original post by Anonymous Poster
You can just simply, and evil-ly, add the .obj file to your project like it was a C or C++ file ;)


Not only is that an incredibly bad idea, it won't even work.

Share this post


Link to post
Share on other sites
Quote:
Original post by joanusdmentia
I suspect that it's the static keyword confusing things. static in this context says 'do no make this symbol visible outside of this translation unit', so the generated .obj file will have no symbols in it and thus not included by the linker. Try removing the static keyword and placing the declaration inside an anonymous namespace instead.

*** Source Snippet Removed ***


Putting an object in an unnamed namespace means 'do no make this symbol visible outside of this translation unit'. In fact, using 'static' like that has been deprecated in favor of unnamed namespaces. So, that really doesn't change things [wink]

Share this post


Link to post
Share on other sites
Quote:
Original post by RDragon1
Quote:
Original post by joanusdmentia
I suspect that it's the static keyword confusing things. static in this context says 'do no make this symbol visible outside of this translation unit', so the generated .obj file will have no symbols in it and thus not included by the linker. Try removing the static keyword and placing the declaration inside an anonymous namespace instead.

*** Source Snippet Removed ***


Putting an object in an unnamed namespace means 'do no make this symbol visible outside of this translation unit'


Wrong. Take a look at the generated .obj file and the symbol will still be there, prefixed with a randomly generated string (the anonymous namespace) to make it impossible (well, nearly impossible) to reference externally but it's still there. Using the static keyword the symbol simply doesn't exist in the .obj file.

Share this post


Link to post
Share on other sites
Well, okay, that might be correct, but it's a very subtle difference, and it has the same effect - it can't be referenced from outside of the translation unit. And it doesn't help force the linker into including the static object when there is no other reference to the translation unit.

How could the symbol not exist? If you have some function that uses the object, does it exist then? Maybe you're just seeing the artifacts of the optimization...

Share this post


Link to post
Share on other sites
Quote:
How could the symbol not exist? If you have some function that uses the object, does it exist then? Maybe you're just seeing the artifacts of the optimization...


The symbol doesn't exist *external* to the translation unit. When compiling, whenever the symbol is seen in that translation unit it is replaced with an appropriate (relocatable) memory address that references into the .data section. However no symbol name is placed in the .obj file, therefore no other translation unit can reference that symbol.

Quote:
but it's a very subtle difference, and it has the same effect

Actually, it's a very significant difference. If the only symbol he has in that translation unit is the static FactoryInstaller instance then the .obj file will appear empty to the linker (containing only a block of data that can never be referenced). When using an anonymous namespace the linker will still see that there is a symbol within the .obj file, the linker doesn't care that the symbol has a randomly generated prefix so can't be referenced by another translation unit, there's still a symbol.

Now, I'm not saying this *will* work, but it's worth a shot (and besides, IIRC the standard recommends using an anonymous namespace instead of the static keyword).

Share this post


Link to post
Share on other sites
The thing that I want to know, though, is what's going on in the FactoryInstaller<> constructor.

If it references any code in another file/translation unit, the linker should know about it and link it in, right?

Share this post


Link to post
Share on other sites
Quote:
Original post by daerid
The thing that I want to know, though, is what's going on in the FactoryInstaller<> constructor.

If it references any code in another file/translation unit, the linker should know about it and link it in, right?


Not really - you don't need to be able to SEE the definition of any class's member functions in order to use an object of that type. You'll just run into problems if you do and they're not defined in -some- object file that you're linking in.

The point is, that THIS translation unit that the object is in is not referenced by any other translation unit, so the linker discards this the object, as nothing refers to it in any way.

Share this post


Link to post
Share on other sites
Quote:
Original post by daerid
If it references any code in another file/translation unit, the linker should know about it and link it in, right?


Well, in general no. If the constructor is never called from somewhere else then it doesn't matter what the constructor references, it can still be removed. In this case though the construct should be getting called implicitly at startup, but I'm guessing that if the linker can't see the symbol then it won't have any way of knowing this should happen, thus it never does.

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement