Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Sharing a global/static variable between a process and DLL

I'd like to share a static/global variable only between a process and a dll that is invoked by the process. The exe and dll are in the same memory address space. I don't want the variable to be shared among other processes.


Elaboration of the problem:

Say that there is a static/global variable x in a.cpp. Both the exe foo.exe and the dll bar.dll have a.cpp, so the variable x is in both images.

Now, foo.exe dynamically loads (or statically) bar.dll. Then, the problem is whether the variable x is shared by the exe and dll, or not.

In Windows, these two guys never share the x: the exe and dll will have a separate copy of x. However, in Linux, the exe and dll do share the variable x.

Unfortunately, I want the behavior of Linux. I first considered using pragma data_seg on Windows. However, even if I correctly setup the shared data segment, foo.exe and bar.dll never shares the x. Recall that bar.dll is loaded into the address space of foo.exe. However, if I run another instance of foo.exe, then x is shared. But, I don't want x to be shared by different processes. So, using data_seg was failed.

I may it use a memory-mapped file by making an unique name between exe and dll, which I'm trying now.


Two questions:

  1. Why the behavior of Linux and Windows is different? Can anyone explain more about this?
  2. What would be most easiest way to solve this problem on Windows?
like image 600
minjang Avatar asked Feb 06 '11 06:02

minjang


People also ask

Can global variables be shared between processes?

Global variables are still global within its own process. So the answer is no, global variables are not shared between processes after a call to fork().

Can program access the global variables value of DLL or dynamic library?

In reality, "yes" the processes do have full "access" to the globals, at the very least through the funtion calls to the library.

Are static variables shared between processes?

No. It is not possible. Each process is in a separate address space. One process cannot see anything in another processes address space.

Can a static global variable be accessed in other files?

Static variables in C have the following two properties: They cannot be accessed from any other file. Thus, prefixes “ extern ” and “ static ” cannot be used in the same declaration. They maintain their value throughout the execution of the program independently of the scope in which they are defined.


1 Answers

To get the behavior of linux where both the main program and a dll share the same x, you can export that variable from either the dll, or the main program. The other module must import that variable.

You do this by using DEF files (see microsoft's documentation), or by marking the uses with the variable with __declspec(dllexport) where it's defined, and __declspec(dllimport) in any other module it's used (see microsoft's documentation). This is the same as how any function, object, or variable is shared between modules in windows.

In the case where you'd like a program to load a library at runtime, but the main program may have to use the variable before the library is loaded, the program should export the variable, and the dll should import it. There is a little bit of a chicken and egg problem here because the dll depends on the main program, and the main program depends on the dll. See http://www.lurklurk.org/linkers/linkers.html#wincircular

I've written an example of how you can do this using both Microsoft's compiler and mingw (gcc in windows), including all the different ways a program and a library can link to each other (statically, dll loaded at program start, dll loaded during runtime)

main.h

#ifndef MAIN_H #define MAIN_H  // something that includes this // would #include "linkage_importing.h" // or #include "linkage_exporting.h" // as appropriate  #ifndef EXPLICIT_MAIN LINKAGE int x; #endif // EXPLICIT_MAIN  #endif // MAIN_H 

main.c

#ifdef EXPLICIT_DLL #include "dyn_link.h" #endif // EXPLICIT_DLL #include <stdio.h> #include "linkage_exporting.h" #include "main.h" #include "linkage_importing.h" #include "dll.h"  FNCALL_DLL get_call_dll(void);  int main(int argc, char* argv[]) {    FNCALL_DLL fncall_dll;    fncall_dll = get_call_dll();    if (fncall_dll)    {       x = 42;       printf("Address of x as seen from main() in main.c: %p\n", &x);       printf("x is set to %i in main()\n", x);       fncall_dll();       // could also be called as (*fncall_dll)();       // if you want to be explicit that fncall_dll is a function pointer       printf("Value of x as seen from main() after call to call_dll(): %i\n", x);    }    return 0; }  FNCALL_DLL get_call_dll(void) { #ifdef EXPLICIT_DLL    return get_ptr("dll.dll", "call_dll"); #else    return call_dll; #endif // EXPLICIT_DLL } 

dll.h

#ifndef DLL_H #define DLL_H  // something that includes this // would #include "linkage_importing.h" // or #include "linkage_exporting.h" // as appropriate  // declaration of type to hold a // pointer to the function typedef void(*FNCALL_DLL)(void);  #ifndef EXPLICIT_DLL LINKAGE void call_dll(void); #endif // EXPLICIT_DLL  #endif // DLL_H 

dll.c

#ifdef EXPLICIT_MAIN #include "dyn_link.h" #endif // EXPLICIT_MAIN #include <stdio.h> #include "linkage_importing.h" #include "main.h" #include "linkage_exporting.h" #include "dll.h"  int* get_x_ptr(void);  LINKAGE void call_dll(void) {    int* x_ptr;    x_ptr = get_x_ptr();    if (x_ptr)    {       printf("Address of x as seen from call_dll() in dll.c: %p\n", x_ptr);       printf("Value of x as seen in call_dll: %i()\n", *x_ptr);       *x_ptr = 31415;       printf("x is set to %i in call_dll()\n", *x_ptr);    } }  int* get_x_ptr(void) { #ifdef EXPLICIT_MAIN    return get_ptr("main.exe", "x");   // see note in dyn_link.c about using the main program as a library #else    return &x; #endif //EXPLICIT_MAIN } 

dyn_link.h

#ifndef DYN_LINK_H #define DYN_LINK_H  // even though this function is used by both, we link it // into both main.exe and dll.dll as necessary. // It's not shared in a dll, because it helps us load dlls :) void* get_ptr(const char* library, const char* object);  #endif // DYN_LINK_H 

dyn_link.c

#include "dyn_link.h" #include <windows.h> #include <stdio.h>  void* get_ptr(const char* library, const char* object) {    HINSTANCE hdll;    FARPROC ptr;    hdll = 0;    ptr = 0;     hdll = LoadLibrary(library);    // in a better dynamic linking library, there would be a    // function that would call FreeLibrary(hdll) to cleanup    //    // in the case where you want to load an object in the main    // program, you can use    // hdll = GetModuleHandle(NULL);    // because there's no need to call LoadLibrary on the    // executable if you can get its handle by some other means.     if (hdll)    {       printf("Loaded library %s\n", library);       ptr = GetProcAddress(hdll, object);       if (ptr)       {          printf("Found %s in %s\n", object, library);       } else {          printf("Could not find %s in %s\n", object, library);       }    } else {       printf("Could not load library %s\n", library);    }    return ptr; } 

linkage_importing.h

// sets up some macros to handle when to use "__declspec(dllexport)", // "__declspec(dllimport)", "extern", or nothing.  // when using the LINKAGE macro (or including a header that does): //    use "#include <linkage_importing.h>" to make the LINKAGE macro //    do the right thing for importing (when using functions, //    variables, etc...) // //    use "#include <linkage_exporting.h>" to make the LINKAGE macro //    do the right thing for exporting (when declaring functions, //    variables, etc). // //    You can include either file at any time to change the meaning of //    LINKAGE.  // if you declare NO_DLL these macros do not use __declspec(...), only // "extern" as appropriate  #ifdef LINKAGE #undef LINKAGE #endif #ifdef NO_DLL    #define LINKAGE extern #else    #define LINKAGE extern __declspec(dllimport) #endif 

linkage_exporting.h

// See linkage_importing.h to learn how this is used #ifdef LINKAGE #undef LINKAGE #endif #ifdef NO_DLL    #define LINKAGE #else    #define LINKAGE __declspec(dllexport) #endif 

build mingw explicit both.sh

#! /bin/bash echo Building configuration where both main echo and dll link explicitly to each other rm -rf mingw_explicit_both mkdir -p mingw_explicit_both/obj cd mingw_explicit_both/obj  # compile the source code (dll created with position independent code) gcc -c -fPIC -DEXPLICIT_MAIN ../../dll.c gcc -c -DEXPLICIT_DLL ../../main.c gcc -c ../../dyn_link.c  #create the dll from its object code the normal way gcc -shared -odll.dll dll.o dyn_link.o -Wl,--out-implib,libdll.a  # create the executable gcc -o main.exe main.o dyn_link.o  mv dll.dll .. mv main.exe .. cd .. 

build mingw explicit dll.sh

#! /bin/bash echo Building configuration where main explicitly echo links to dll, but dll implicitly links to main rm -rf mingw_explicit_dll mkdir -p mingw_explicit_dll/obj cd mingw_explicit_dll/obj  # compile the source code (dll created with position independent code) gcc -c -fPIC ../../dll.c gcc -c -DEXPLICIT_DLL ../../main.c gcc -c ../../dyn_link.c  # normally when linking a dll, you just use gcc # to create the dll and its linking library (--out-implib...) # But, this dll needs to import from main, and main's linking library doesn't exist yet # so we create the linking library for main.o # make sure that linking library knows to look for symbols in main.exe (the default would be a.out) gcc -omain.exe -shared main.o -Wl,--out-implib,main.a  #note this reports failure, but it's only a failure to create main.exe, not a failure to create main.a  #create the dll from its object code the normal way (dll needs to know about main's exports) gcc -shared -odll.dll dll.o dyn_link.o main.a -Wl,--out-implib,libdll.a  # create the executable gcc -o main.exe main.o dyn_link.o  mv dll.dll .. mv main.exe .. cd .. 

build mingw explicit main.sh

#! /bin/bash echo Building configuration where dll explicitly echo links to main, but main implicitly links to dll rm -rf mingw_explicit_main mkdir -p mingw_explicit_main/obj cd mingw_explicit_main/obj  # compile the source code (dll created with position independent code) gcc -c -fPIC -DEXPLICIT_MAIN ../../dll.c gcc -c ../../main.c gcc -c ../../dyn_link.c  # since the dll will link dynamically and explicitly with main, there is no need # to create a linking library for main, and the dll can be built the regular way gcc -shared -odll.dll dll.o dyn_link.o -Wl,--out-implib,libdll.a  # create the executable (main still links with dll implicitly) gcc -o main.exe main.o -L. -ldll  mv dll.dll .. mv main.exe .. cd .. 

build mingw implicit.sh

#! /bin/bash echo Building configuration where main and echo dll implicitly link to each other rm -rf mingw_implicit mkdir -p mingw_implicit/obj cd mingw_implicit/obj  # compile the source code (dll created with position independent code) gcc -c -fPIC ../../dll.c gcc -c ../../main.c  # normally when linking a dll, you just use gcc # to create the dll and its linking library (--out-implib...) # But, this dll needs to import from main, and main's linking library doesn't exist yet # so we create the linking library for main.o # make sure that linking library knows to look for symbols in main.exe (the default would be a.out) gcc -omain.exe -shared main.o -Wl,--out-implib,main.a  #note this reports failure, but it's only a failure to create main.exe, not a failure to create main.a  # create the dll from its object code the normal way (dll needs to know about main's exports) gcc -shared -odll.dll dll.o main.a -Wl,--out-implib,libdll.a  # create the executable (exe needs to know about dll's exports) gcc -o main.exe main.o -L. -ldll  mv dll.dll .. mv main.exe .. cd .. 

build mingw static.sh

#! /bin/bash echo Building configuration where main and dll echo statically link to each other rm -rf mingw_static mkdir -p mingw_static/obj cd mingw_static/obj  # compile the source code gcc -c -DNO_DLL ../../dll.c gcc -c -DNO_DLL ../../main.c  # create the static library ar -rcs dll.a dll.o  # link the executable gcc -o main.exe main.o dll.a  mv main.exe ../ cd .. 

build msvc explicit both.bat

@echo off echo Building configuration where both main echo and dll link explicitly to each other rd /s /q win_explicit_both md win_explicit_both\obj cd win_explicit_both\obj  rem compile the source code cl /nologo /c /DEXPLICIT_MAIN ..\..\dll.c cl /nologo /c /DEXPLICIT_DLL ..\..\main.c cl /nologo /c ..\..\dyn_link.c  rem create the dll from its object code the normal way link /nologo /dll dll.obj dyn_link.obj  rem create the executable link /nologo main.obj dyn_link.obj  move dll.dll ..\ move main.exe ..\ cd .. 

build msvc explicit dll.bat

@echo off echo Building configuration where main explicitly echo links to dll, but dll implicitly links to main rd /s /q win_explicit_dll md win_explicit_dll\obj cd win_explicit_dll\obj  rem compile the source code cl /nologo /c ..\..\dll.c cl /nologo /c /DEXPLICIT_DLL ..\..\main.c cl /nologo /c ..\..\dyn_link.c  rem normally when linking a dll, you just use the link command rem that creates the dll and its linking library. rem But, this dll needs to import from main, and main's linking library doesn't exist yet rem so we create the linking library for main.obj rem make sure that linking library knows to look for symbols in main.exe (the default would be main.dll) lib /nologo /def /name:main.exe main.obj  rem create the dll from its object code the normal way (dll needs to know about main's exports) link /nologo /dll dll.obj main.lib  rem create the executable link /nologo main.obj dyn_link.obj  move dll.dll ..\ move main.exe ..\ cd .. 

build msvc explicit main.bat

@echo off echo Building configuration where dll explicitly echo links to main, but main implicitly links to dll rd /s /q win_explicit_main md win_explicit_main\obj cd win_explicit_main\obj  rem compile the source code cl /nologo /c /DEXPLICIT_MAIN ..\..\dll.c cl /nologo /c ..\..\main.c cl /nologo /c ..\..\dyn_link.c  rem since the dll will link dynamically and explicitly with main, there is no need rem to create a linking library for main, and the dll can be built the regular way link /nologo /dll dll.obj dyn_link.obj  rem create the executable (main still links with dll implicitly) link /nologo main.obj dll.lib  move dll.dll ..\ move main.exe ..\ cd .. 

build msvc implicit.bat

@echo off echo Building configuration where main and echo dll implicitly link to each other rd /s /q win_implicit md win_implicit\obj cd win_implicit\obj  rem compile the source code cl /nologo /c ..\..\dll.c cl /nologo /c ..\..\main.c  rem normally when linking a dll, you just use the link command rem that creates the dll and its linking library. rem But, this dll needs to import from main, and main's linking library doesn't exist yet rem so we create the linking library for main.obj rem make sure that linking library knows to look for symbols in main.exe (the default would be main.dll) lib /nologo /def /name:main.exe main.obj  rem create the dll from its object code the normal way (dll needs to know about main's exports) link /nologo /dll dll.obj main.lib  rem create the executable (exe needs to know about dll's exports) link /nologo main.obj dll.lib  move dll.dll ..\ move main.exe ..\ cd .. 

build msvc static.bat

@echo off echo Building configuration where main and dll echo statically link to each other rd /s /q win_static md win_static\obj cd win_static\obj  rem compile the source code cl /nologo /DNO_DLL /c ..\..\dll.c cl /nologo /DNO_DLL /c ..\..\main.c  rem create the static library lib /nologo dll.obj  rem link the executable link /nologo main.obj dll.lib  move main.exe ..\ cd .. 
like image 175
James Caccese Avatar answered Sep 20 '22 06:09

James Caccese