当动态链接时,共享库中的全局变量和静态变量会发生什么? [英] What happens to global and static variables in a shared library when it is dynamically linked?

查看:2450
本文介绍了当动态链接时,共享库中的全局变量和静态变量会发生什么?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我试图理解当全局变量和静态变量动态链接到应用程序时会发生什么。
通过模块,我的意思是每个项目在一个解决方案(我的工作很多与visual studio!)。这些模块内置在* .lib或* .dll或* .exe本身中。



我理解应用程序的二进制文件包含全部和所有




  • 当数据段中的个别翻译单元(目标文件)此应用程序使用带有加载时动态链接的模块A?我假设DLL有一个部分为其全局和静态。操作系统是否加载它们?


  • 当应用程序使用具有运行时动态链接的模块B时会发生什么?

    / li>
  • 如果我的应用程序中有两个模块都使用A和B,是如下所述创建的A和B的全局变量的副本(如果他们是不同的进程)?




  • b

    (请说明您的原因)



    引用 MSDN


    在DLL源代码文件中声明为全局的变量被编译器和链接器视为全局变量,但每个加载给定DLL的进程都会获得该DLL的全局变量的副本。静态变量的范围限于声明静态变量的块。因此,默认情况下,每个进程都有自己的DLL全局变量和静态变量。


    此处


    链接模块,可以不清楚不同的库是否有自己的全局变量实例或者是否共享全局变量。


    p>

    解决方案

    这是Windows和类Unix系统之间的一个非常着名的区别。



    无论如何:




    • 每个进程都有自己的地址空间,

    • 一个定义规则(ODR)仍然适用,这意味着您可以只有链接时可见的全局变量的一个定义(静态或动态链接)。





    在所有情况下,全局变量(或函数)都是 static 从模块外部不可见(dll / so或可执行)。 C ++标准要求这些具有内部链接,这意味着它们在翻译单元(它变成一个目标文件)之外是不可见的。



    复杂的是当你有 extern 全局变量时。



    在Windows(.exe和.dll)的情况下, extern 全局变量不是导出符号的一部分。换句话说,不同的模块不知道在其他模块中定义的全局变量。这意味着,如果您尝试创建一个应该使用在DLL中定义的 extern 变量的可执行文件,那么您将会遇到链接器错误,因为这是不允许的。您需要提供一个具有该extern变量定义的对象文件(或静态库),并将它与可执行文件和DLL静态链接,从而产生两个不同的全局变量(一个属于可执行文件和一个属于DLL的文件)。



    要在Windows中实际导出全局变量,必须使用类似于export / import语法的语法,

      #ifdef COMPILING_THE_DLL 
    #define MY_DLL_EXPORT externC__declspec(dllexport)
    #else
    #define MY_DLL_EXPORT externC__declspec(dllimport)
    #endif

    MY_DLL_EXPORT int my_global;

    当这样做时,全局变量被添加到导出符号列表,所有其他函数。



    在类Unix环境(如Linux)的情况下,动态库称为共享对象扩展 .so export all extern 全局变量(或函数)。在这种情况下,如果您从任何位置到共享对象文件进行加载时链接,那么全局变量是共享的,即链接在一起。基本上,类Unix系统被设计成使得它与静态或动态库链接之间几乎没有区别。同样,ODR适用于所有模块: extern 全局变量将跨模块共享,这意味着它应该在所有加载的模块中只有一个定义。



    最后,在这两种情况下,对于Windows或类Unix系统,您可以对动态库进行运行时链接,即使用 LoadLibrary() / GetProcAddress() / FreeLibrary() c $ c> dlopen() / dlsym() / dlclose()。在这种情况下,您必须手动获取指向您要使用的每个符号的指针,并且包括要使用的全局变量。对于全局变量,您可以使用 GetProcAddress() dlsym()全局变量是导出的符号列表的一部分(按照前面段落的规则)。



    当然,作为必要的最后一点注意: global应避免变量。我相信你引用的文本(关于事情不清楚)完全是指我刚刚解释的平台特定的差异(动态库没有真正由C ++标准定义,这是平台特定的领域,意味着是不太可靠/便携)。


    I'm trying to understand what happens when modules with globals and static variables are dynamically linked to an application. By modules, I mean each project in a solution (I work a lot with visual studio!). These modules are either built into *.lib or *.dll or the *.exe itself.

    I understand that the binary of an application contains global and static data of all the individual translation units (object files) in the data segment (and read only data segment if const).

    • What happens when this application uses a module A with load-time dynamic linking? I assume the DLL has a section for its globals and statics. Does the operating system load them? If so, where do they get loaded to?

    • And what happens when the application uses a module B with run-time dynamic linking?

    • If I have two modules in my application that both use A and B, are copies of A and B's globals created as mentioned below (if they are different processes)?

    • Do DLLs A and B get access to the applications globals?

    (Please state your reasons as well)

    Quoting from MSDN:

    Variables that are declared as global in a DLL source code file are treated as global variables by the compiler and linker, but each process that loads a given DLL gets its own copy of that DLL's global variables. The scope of static variables is limited to the block in which the static variables are declared. As a result, each process has its own instance of the DLL global and static variables by default.

    and from here:

    When dynamically linking modules, it can be unclear whether different libraries have their own instances of globals or whether the globals are shared.

    Thanks.

    解决方案

    This is a pretty famous difference between Windows and Unix-like systems.

    No matter what:

    • Each process has its own address space, meaning that there is never any memory being shared between processes (unless you use some inter-process communication library or extensions).
    • The One Definition Rule (ODR) still applies, meaning that you can only have one definition of the global variable visible at link-time (static or dynamic linking).

    So, the key issue here is really visibility.

    In all cases, static global variables (or functions) are never visible from outside a module (dll/so or executable). The C++ standard requires that these have internal linkage, meaning that they are not visible outside the translation unit (which becomes an object file) in which they are defined. So, that settles that issue.

    Where it gets complicated is when you have extern global variables. Here, Windows and Unix-like systems are completely different.

    In the case of Windows (.exe and .dll), the extern global variables are not part of the exported symbols. In other words, different modules are in no way aware of global variables defined in other modules. This means that you will get linker errors if you try, for example, to create an executable that is supposed to use an extern variable defined in a DLL, because this is not allowed. You would need to provide an object file (or static library) with a definition of that extern variable and link it statically with both the executable and the DLL, resulting in two distinct global variables (one belonging to the executable and one belonging to the DLL).

    To actually export a global variable in Windows, you have to use a syntax similar to the function export/import syntax, i.e.:

    #ifdef COMPILING_THE_DLL
    #define MY_DLL_EXPORT extern "C" __declspec(dllexport)
    #else
    #define MY_DLL_EXPORT extern "C" __declspec(dllimport)
    #endif
    
    MY_DLL_EXPORT int my_global;
    

    When you do that, the global variable is added to the list of exported symbols and can be linked like all the other functions.

    In the case of Unix-like environments (like Linux), the dynamic libraries, called "shared objects" with extension .so export all extern global variables (or functions). In this case, if you do load-time linking from anywhere to a shared object file, then the global variables are shared, i.e., linked together as one. Basically, Unix-like systems are designed to make it so that there is virtually no difference between linking with a static or a dynamic library. Again, ODR applies across the board: an extern global variable will be shared across modules, meaning that it should have only one definition across all the modules loaded.

    Finally, in both cases, for Windows or Unix-like systems, you can do run-time linking of the dynamic library, i.e., using either LoadLibrary() / GetProcAddress() / FreeLibrary() or dlopen() / dlsym() / dlclose(). In that case, you have to manually get a pointer to each of the symbols you wish to use, and that includes the global variables you wish to use. For global variables, you can use GetProcAddress() or dlsym() just the same as you do for functions, provided that the global variables are part of the exported symbol list (by the rules of the previous paragraphs).

    And of course, as a necessary final note: global variables should be avoided. And I believe that the text you quoted (about things being "unclear") is referring exactly to the platform-specific differences that I just explained (dynamic libraries are not really defined by the C++ standard, this is platform-specific territory, meaning it is much less reliable / portable).

    这篇关于当动态链接时,共享库中的全局变量和静态变量会发生什么?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆