Resolve unresolved DLL symbols with definitions in .obj's for an EXE  
Author Message
Rob Conn





PostPosted: Visual C++ Language, Resolve unresolved DLL symbols with definitions in .obj's for an EXE Top

I have a complex application that I am trying to convert to VC++. I have reduced a run-time problem occuring in that application to the following sample code. I have tried this code under VC++ 6.0 SP6 on W2K, and VC++ 2005 Express on XP SP2, both with the same results.

The general structure of the code is a very simple DLL and EXE. There is a single header file, and the DLL and EXE each have one cpp file.

Header file "linkme.h":

#ifdef _EXPORTING_LINKME_H

#define DLL_DIRECTIVE __declspec(dllexport)

#else

#define DLL_DIRECTIVE

#endif

DLL_DIRECTIVE void printValue();

extern int value; // declaration of value

// as having external linkage

CPP file "linkme.cpp" is the basis for the DLL:

#include <stdio.h>

#define _EXPORTING_LINKME_H

#include "linkme.h"

void printValue() {

printf("DLL thinks value = %d, &value = 0x%x\n",

value, &value);

}

CPP file "linkme_test.cpp" is the basis for the EXE:

#include <stdio.h>

#include "linkme.h"

int value; // global definition of value

// with external linkage

int main() {

value = 7;

printf("EXE thinks value = %d, &value = 0x%x\n",

value, &value);

printValue();

return 0;

}

When the DLL is linked, the /FORCE:UNRESOLVED switch is required as the variable "value" has only a declaration at that time (no definition). The DLL is linked as:

cl.exe /nologo /TP /EHsc /MD /Za /GR -c linkme.cpp

link.exe /nologo /DEBUG /INCREMENTAL:yes /FIXED:NO

/FORCE:UNRESOLVED /DLL linkme.obj

When the EXE is linked, no special switches are required as the global "value" declared in linkme_test.cpp seems to satisfy the unresolved "value" symbol in the DLL. The EXE is linked as:

cl.exe /nologo /TP /EHsc /MD /Za /GR -c linkme_test.cpp

link.exe /nologo /DEBUG /INCREMENTAL:yes /FIXED:NO

linkme.lib linkme_test.obj -out:linkme_test.exe

At run-time, the output will be something like (the 0x405128 and the 9460301 need not be the same):

EXE thinks value = 7, &value = 0x405128

DLL thinks value = 9460301, &value = 0x10000000

The DLL seems to have its own, essentially unresolved version of "value". I have tried a large variety of combinations of __declspec, extern "C", and extern qualifiers, with no success. I have tried varying the order of linkme.lib and linkme_test.obj on the EXE link line, but the results do not change.

My question is: How do I make the linker try to resolve any unresolved global DLL symbols with global symbols defined in the .obj's for the EXE

Very Respectfully,

Rob Conn.



Visual C++4  
 
 
Viorel.





PostPosted: Visual C++ Language, Resolve unresolved DLL symbols with definitions in .obj's for an EXE Top

As I known, the usual way of exporting and importing symbols is:

 

#ifdef _EXPORTING_LINKME_H

 

    #define DLL_DIRECTIVE __declspec(dllexport) // in DLL

 

#else

 

    #define DLL_DIRECTIVE __declspec(dllimport) // in EXE

 

#endif

 

It must be added to your variable too:< xml:namespace prefix = o ns = "urn:schemas-microsoft-com:office:office" />

 

extern DLL_DIRECTIVE int value;

 

I hope it works.

 


 
 
Rob Conn





PostPosted: Visual C++ Language, Resolve unresolved DLL symbols with definitions in .obj's for an EXE Top

Hi Viorel,

Thanks for the reply. Unfortunately, I need the variable definition (actual storage) to be in the EXE, not the DLL.

Sincerely,

Rob Conn.


 
 
Viorel.





PostPosted: Visual C++ Language, Resolve unresolved DLL symbols with definitions in .obj's for an EXE Top

I do not think you can export a variable from EXE to DLL. If you really cannot allocate your variable in DLL, maybe you should allocate a pointer in DLL, and initialize it at startup, after loading DLL, using a function exported from DLL

 

Alternatively pass a reference to DLL’s functions. For example:

void printValue( const int & value)

{

    . . .

}

I hope this makes sense.

 


 
 
Rob Conn





PostPosted: Visual C++ Language, Resolve unresolved DLL symbols with definitions in .obj's for an EXE Top

Hi Viorel,

> I do not think you can export a variable from EXE to DLL.

I think it's really from a .obj to a DLL, but I understand your point. Evidence is mounting that the VC++ linker doesn't consider global symbols in the .obj's to resolve global symbols in an existing DLL.

For my actual application, I have about 500 DLLs and about 100 EXEs (about 1.5M lines of code). The (various) writers of the code assumed that global symbols can be resolved anywhere, in the manner shown in my small example. So while restructuring the code is an option, it is not an attractive one.

It is quite frustrating that the global symbol definition is present in the .obj, which is on the same link line as the dll, but the linker won't look in the .obj for that purpose.

Sincerely,

Rob Conn.


 
 
Sahir Shah





PostPosted: Visual C++ Language, Resolve unresolved DLL symbols with definitions in .obj's for an EXE Top

 

    cl.exe /nologo /TP /EHsc /MD /Za /GR -c linkme.cpp

     link.exe /nologo /DEBUG /INCREMENTAL:yes /FIXED:NO

          /FORCE:UNRESOLVED /DLL linkme.obj

 -----------------------------------------------------------

    cl.exe /nologo /TP /EHsc /MD /Za /GR -c linkme_test.cpp

     link.exe /nologo /DEBUG /INCREMENTAL:yes /FIXED:NO

          linkme.lib linkme_test.obj -out:linkme_test.exe

It is quite frustrating that the global symbol definition is present in the .obj, which is on the same link line as the dll, but the linker won't look in the .obj for that purpose.

 But,  when the dll was being linked  linkme_test.obj did not exist.


 
 
einaros





PostPosted: Visual C++ Language, Resolve unresolved DLL symbols with definitions in .obj's for an EXE Top

I think it's really from a .obj to a DLL, but I understand your point. Evidence is mounting that the VC++ linker doesn't consider global symbols in the .obj's to resolve global symbols in an existing DLL.

No, the dll isn't being linked with the exe's obj file, so that's not going to happen. If you want to expose variables in the .exe to a dll, you will have to instruct the dll where to find these values, either through GetProcAddress or by use of an exposed pointer or setter-function in the dll.

For dlls to depend on variables being exported from the exe isn't too good a practice in my humble opinion, regardless of whether or not it's possible.

It is quite frustrating that the global symbol definition is present in the .obj, which is on the same link line as the dll, but the linker won't look in the .obj for that purpose.

These are dynamic libraries. They can be loaded in any application you wish, and they aren't designed to, and shouldn't, depend on neither import libraries nor the object files of the actual applications they are to be used in. Applications should depend on dlls, not the other way around.

My condolances for the needed structural changes. Hopefully you will get there without too much toil.



 
 
Rob Conn





PostPosted: Visual C++ Language, Resolve unresolved DLL symbols with definitions in .obj's for an EXE Top

Hi Einar,

Thanks for the reply. I understand what link.exe is doing now. Once it has made a DLL, link.exe doesn't attempt any further resolution of symbols, even if that DLL is used on another link line. Essentially, the DLL is "done" once it's file has been written. The page http://www.iecc.com/linker/linker10.html (and in particular the section "Comparison of dynamic linking approaches") was very helpful for me.

The code base I'm working with was written for a system that uses ELF linking, which tries to preserve the language semantics (e.g., of global externs) regardless of whether libraries are used or not, and if libraries are used, regardless of whether they are static or dynamic. In particular, the ELF linker continues trying to resolve symbols through successive links all the way up to the final link of the executable. I understand, though, that dynamic libraries are not part of the language definition, so there is no compulsion to follow that path.

I agree that having the global extern data is not great (in fact, I could have stopped at "global"), but much of the code is 15+ years old. The DLLs need certain objects to exist, and to be shared among all the DLLs for a given executable, but each executable initializes those objects differently. In addition, the list of DLLs used by an executable (or by another DLL, for that matter) changes frequently.

Given that I cannot replicate the ELF behavior with the VC++ compiler/linker tools, I'll will have to update the code. For each object that needs to be globally shared among DLLs but different on a per-executable basis, I'll define a DLL to hold a pointer to the object. That new DLL will export functions to get and set the object. All of the other DLLs can be modified to get and hold a reference to the object at runtime, and each executable can set the object to whatever is needed. These extra "container" DLLs can be linked to the other DLLs in the "link-and-forget" scheme, and the DLLs still will not need any direct knowledge of the executable. If I'm lucky, maybe the data types used by the global extern objects will be declared in an order such that I can define more than one "global" in a DLL (I'd prefer to have just a small number of "container" DLLs).

Obviously, I am still learning my way around the tools in VC++. If you know of any reason why the above scheme won't work, please let me know.

Sincerely,

Rob Conn.