当前页面链接:https://www.cnblogs.com/oloroso/p/6273295.html

运行时加载动态库的一个小问题

简要说明#

大致情况是这样的:
程序program引用动态库libAlibB。其中libAlibB都引用动态库libShared和静态库libStatic。在libSharedlibStatic中都含有静态变量。现在就是看这个静态变量是否存在两份。

Copy Highlighter-hljs
program (可以隐式链接,也可以显示动态链接A和B)
| |
libStatic-> libA libB <- libStatic
| | (隐式链接Shared)
libShared

因为libAlibB都链接了静态库libStatic,所以libStatic的内容会存在两份。在映射到program的进程空间的时候,这部分就会存在映射到不同地址的两份。在windows上的测试结果确实是如此,在linux上的测试结果中,如果是显示动态链接libAlibB也是,但是如果是隐式链接,那么结果却是只有一份。

因为libShared是动态库,在libA和libB中都不存在,所以在第一个映射到program的进程空间之后,第二次引用的时候就不会再去映射一次了。

这里的一个结论就是,如果一个静态库被多处引用,那么这个静态库在最终程序的进程空间可能会存在多份。如果这个静态库中含有静态变量或全局变量,那么这个变量也会存在多份。如果这个变量是一个类对象,那么变量初始化的时候,每一份都会调用构造函数。因为VS编译的时候默认是不导出符号的,而gcc默认是导出的,也可能是这个原因。但libA和libB都是动态库,这两者中应该都是含有引用的libStatic部分的全部内容的。

所以,在静态库中最好不要去存放全局变量,也不要在这里创建单例对象等。如果对程序文件大小有要求,最好使用动态库。

实验代码#

实验代码包括六个部分,libA/libB/libShared/libStaic/test/test2。其中test测试的是显示动态链接,test2测试的是隐式链接。

源代码下载LoadLibraryTest.7z
可以使用QtCreator工具打开。

libStatic#

libStatic.hpp

Copy Highlighter-hljs
#ifndef LIBSTATIC_HPP
#define LIBSTATIC_HPP
void func_Static();
#endif // LIBSTATIC_HPP

libStatic.cpp

Copy Highlighter-hljs
#include "LibStatic.hpp"
#include <stdio.h>
#include <stdlib.h>
void func_Static()
{
static char buf[1024] =
"这个是libStatic里的buffer。<---->";
printf("func_Static 地址 %p|",&func_Static);
printf("buf 地址 %p\n\t%s\t",&buf,buf);
static int x = 0;
if(x == 0) x = rand();
sprintf(buf,"libStatic的buffer被修改 %d",x);
printf("%s\n--------------------------\n",buf);
}

libShared#

libshared_global.hpp

Copy Highlighter-hljs
#ifndef LIBSHARED_GLOBAL_HPP
#define LIBSHARED_GLOBAL_HPP
#ifdef _WIN32
#if defined(LIBSHARED_LIBRARY)
# define LIBSHAREDSHARED_EXPORT extern "C" __declspec(dllexport)
#else
# define LIBSHAREDSHARED_EXPORT extern "C" __declspec(dllimport)
#endif
#else
# define LIBSHAREDSHARED_EXPORT extern "C"
#endif
#endif // LIBSHARED_GLOBAL_HPP

libShared.hpp

Copy Highlighter-hljs
#ifndef LIBSHARED_HPP
#define LIBSHARED_HPP
#include "libshared_global.hpp"
LIBSHAREDSHARED_EXPORT void func_Shared();
#endif // LIBSHARED_HPP

libShared.cpp

Copy Highlighter-hljs
#include "LibShared.hpp"
#include <stdio.h>
#include <stdlib.h>
void func_Shared()
{
static char buf[1024] =
"这个是libShared里的buffer。<---->";
printf("func_Shared 地址 %p|",&func_Shared);
printf("buf 地址 %p\n\t%s\t",&buf,buf);
static int x = 0;
if(x == 0) x = rand();
sprintf(buf,"libShared的buffer被修改 %d",x);
printf("%s\n--------------------------\n",buf);
}

libA#

libA_global.hpp

Copy Highlighter-hljs
#ifndef LIBA_GLOBAL_HPP
#define LIBA_GLOBAL_HPP
#ifdef _WIN32
#if defined(LIBA_LIBRARY)
# define LIBASHARED_EXPORT extern "C" __declspec(dllexport)
#else
# define LIBASHARED_EXPORT extern "C" __declspec(dllimport)
#endif
#else
# define LIBASHARED_EXPORT extern "C"
#endif
#endif // LIBA_GLOBAL_HPP

libA.hpp

Copy Highlighter-hljs
#ifndef LIBA_HPP
#define LIBA_HPP
#include "liba_global.hpp"
LIBASHARED_EXPORT int func_A();
#endif // LIBA_HPP

libA.cpp

Copy Highlighter-hljs
#include "LibA.hpp"
#include "LibShared.hpp"
#include "LibStatic.hpp"
#include <stdio.h>
int func_A()
{
static char buf[] =
"这个是libA里的buffer。---------";
printf("func_A 地址 %p|",&func_A);
printf("buf 地址 %p\n\t%s\n\n",&buf,buf);
func_Shared();
func_Static();
return 0;
}

libB#

libB_global.hpp

Copy Highlighter-hljs
#ifndef LIBB_GLOBAL_HPP
#define LIBB_GLOBAL_HPP
#ifdef _WIN32
#if defined(LIBB_LIBRARY)
# define LIBBSHARED_EXPORT extern "C" __declspec(dllexport)
#else
# define LIBBSHARED_EXPORT extern "C" __declspec(dllimport)
#endif
#else
# define LIBBSHARED_EXPORT extern "C"
#endif
#endif // LIBB_GLOBAL_HPP

libB.hpp

Copy Highlighter-hljs
#ifndef LIBB_HPP
#define LIBB_HPP
#include "libb_global.hpp"
LIBBSHARED_EXPORT int func_B();
#endif // LIBB_HPP

libB.cpp

Copy Highlighter-hljs
#include "LibB.hpp"
#include "LibShared.hpp"
#include "LibStatic.hpp"
#include <stdio.h>
int func_B()
{
static char buf[] =
"这个是libB里的buffer。---------";
printf("func_B 地址 %p|",&func_B);
printf("buf 地址 %p\n\t%s\n\n",&buf,buf);
func_Shared();
func_Static();
return 0;
}

test#

main.cpp

Copy Highlighter-hljs
#include <iostream>
#ifdef _WIN32
#include <Windows.h>
#else
#include <dlfcn.h>
#endif
using namespace std;
typedef int(func)();
#ifndef _WIN32
#define LoadLibraryA(dllpath) \
dlopen(dllpath,RTLD_LAZY)
// RTLD_LAZY 暂缓解出,需要时解
#define FreeLibrary(hdll) \
dlclose(hdll)
#define GetProcAddress dlsym
#define HMODULE void*
#endif
class dylib{
public:
dylib(const char* dllpath,const char* funcname)
{
hdll = LoadLibraryA(dllpath);
if(hdll){
f = (func*)GetProcAddress(hdll,funcname);
if(f == NULL){
cout<<funcname<<" 函数查找失败"<<endl;
#ifdef _WIN32
cout<<"错误码:"<<GetLastError()<<endl;
#else
cout<<"错误信息:"<<dlerror()<<endl;
#endif
}
}else{
cout<<dllpath<<" 加载失败"<<endl;
f = NULL;
}
}
~dylib()
{
if(hdll){
FreeLibrary(hdll);
}
}
int operator()()
{
return (f == NULL)?-1:f();
}
private:
HMODULE hdll;
func* f;
};
int main(int argc, char *argv[])
{
#ifdef _WIN32
dylib dA("libA.dll","func_A");
dylib dB("libB.dll","func_B");
#else
dylib dA("./liblibA.so","func_A");
dylib dB("./liblibB.so","func_B");
#endif
dA();
dB();
dA();
dB();
return 0;
}

test2#

main.cpp

Copy Highlighter-hljs
#include <iostream>
#include "LibA.hpp"
#include "LibB.hpp"
using namespace std;
int main(int argc, char *argv[])
{
func_A();
func_B();
func_A();
func_B();
return 0;
}

实验结果#

Windows上VS2015编译x64版本运行结果#

test 运行结果#

为了便于观察,这里多加了换行

Copy Highlighter-hljs
func_A 地址 00007FFF756910AA|buf 地址 00007FFF75699000
这个是libA里的buffer。---------
func_Shared 地址 00007FFF73E610FA|buf 地址 00007FFF73E69000
这个是libShared里的buffer。<----> libShared的buffer被修改 41
--------------------------
func_Static 地址 00007FFF7569109B|buf 地址 00007FFF75699030
这个是libStatic里的buffer。<----> libStatic的buffer被修改 18467
--------------------------
func_B 地址 00007FFF71B810AA|buf 地址 00007FFF71B89000
这个是libB里的buffer。---------
func_Shared 地址 00007FFF73E610FA|buf 地址 00007FFF73E69000
libShared的buffer被修改 41 libShared的buffer被修改 41
--------------------------
func_Static 地址 00007FFF71B8109B|buf 地址 00007FFF71B89030
这个是libStatic里的buffer。<----> libStatic的buffer被修改 6334
--------------------------
func_A 地址 00007FFF756910AA|buf 地址 00007FFF75699000
这个是libA里的buffer。---------
func_Shared 地址 00007FFF73E610FA|buf 地址 00007FFF73E69000
libShared的buffer被修改 41 libShared的buffer被修改 41
--------------------------
func_Static 地址 00007FFF7569109B|buf 地址 00007FFF75699030
libStatic的buffer被修改 18467 libStatic的buffer被修改 18467
--------------------------
func_B 地址 00007FFF71B810AA|buf 地址 00007FFF71B89000
这个是libB里的buffer。---------
func_Shared 地址 00007FFF73E610FA|buf 地址 00007FFF73E69000
libShared的buffer被修改 41 libShared的buffer被修改 41
--------------------------
func_Static 地址 00007FFF71B8109B|buf 地址 00007FFF71B89030
libStatic的buffer被修改 6334 libStatic的buffer被修改 6334
--------------------------

这里可以看到func_Afunc_B调用的func_Shared是同一个,但是func_Static却不是同一个。

test2运行结果#

Copy Highlighter-hljs
func_A 地址 00007FFF756910AA|buf 地址 00007FFF75699000
这个是libA里的buffer。---------
func_Shared 地址 00007FFF73E610FA|buf 地址 00007FFF73E69000
这个是libShared里的buffer。<----> libShared的buffer被修改 41
--------------------------
func_Static 地址 00007FFF7569109B|buf 地址 00007FFF75699030
这个是libStatic里的buffer。<----> libStatic的buffer被修改 18467
--------------------------
func_B 地址 00007FFF758810AA|buf 地址 00007FFF75889000
这个是libB里的buffer。---------
func_Shared 地址 00007FFF73E610FA|buf 地址 00007FFF73E69000
libShared的buffer被修改 41 libShared的buffer被修改 41
--------------------------
func_Static 地址 00007FFF7588109B|buf 地址 00007FFF75889030
这个是libStatic里的buffer。<----> libStatic的buffer被修改 6334
--------------------------
func_A 地址 00007FFF756910AA|buf 地址 00007FFF75699000
这个是libA里的buffer。---------
func_Shared 地址 00007FFF73E610FA|buf 地址 00007FFF73E69000
libShared的buffer被修改 41 libShared的buffer被修改 41
--------------------------
func_Static 地址 00007FFF7569109B|buf 地址 00007FFF75699030
libStatic的buffer被修改 18467 libStatic的buffer被修改 18467
--------------------------
func_B 地址 00007FFF758810AA|buf 地址 00007FFF75889000
这个是libB里的buffer。---------
func_Shared 地址 00007FFF73E610FA|buf 地址 00007FFF73E69000
libShared的buffer被修改 41 libShared的buffer被修改 41
--------------------------
func_Static 地址 00007FFF7588109B|buf 地址 00007FFF75889030
libStatic的buffer被修改 6334 libStatic的buffer被修改 6334

test测试结果一致。

linux上运行测试结果#

test运行测试结果#

Copy Highlighter-hljs
func_A 地址 0x7ffa3cdc47e0|buf 地址 0x7ffa3cfc5060
这个是libA里的buffer。---------
func_Shared 地址 0x7ffa3cbc2750|buf 地址 0x7ffa3cdc3060
这个是libShared里的buffer。<----> libShared的buffer被修改 1804289383
--------------------------
func_Static 地址 0x7ffa3cdc4830|buf 地址 0x7ffa3cfc50a0
这个是libStatic里的buffer。<----> libStatic的buffer被修改 846930886
--------------------------
func_B 地址 0x7ffa3c9c07e0|buf 地址 0x7ffa3cbc1060
这个是libB里的buffer。---------
func_Shared 地址 0x7ffa3cbc2750|buf 地址 0x7ffa3cdc3060
libShared的buffer被修改 1804289383 libShared的buffer被修改 1804289383
--------------------------
func_Static 地址 0x7ffa3c9c0830|buf 地址 0x7ffa3cbc10a0
这个是libStatic里的buffer。<----> libStatic的buffer被修改 1681692777
--------------------------
func_A 地址 0x7ffa3cdc47e0|buf 地址 0x7ffa3cfc5060
这个是libA里的buffer。---------
func_Shared 地址 0x7ffa3cbc2750|buf 地址 0x7ffa3cdc3060
libShared的buffer被修改 1804289383 libShared的buffer被修改 1804289383
--------------------------
func_Static 地址 0x7ffa3cdc4830|buf 地址 0x7ffa3cfc50a0
libStatic的buffer被修改 846930886 libStatic的buffer被修改 846930886
--------------------------
func_B 地址 0x7ffa3c9c07e0|buf 地址 0x7ffa3cbc1060
这个是libB里的buffer。---------
func_Shared 地址 0x7ffa3cbc2750|buf 地址 0x7ffa3cdc3060
libShared的buffer被修改 1804289383 libShared的buffer被修改 1804289383
--------------------------
func_Static 地址 0x7ffa3c9c0830|buf 地址 0x7ffa3cbc10a0
libStatic的buffer被修改 1681692777 libStatic的buffer被修改 1681692777
--------------------------

这里结果也是一样的,func_Static存在两份。

test2运行结果#

Copy Highlighter-hljs
func_A 地址 0x7fbeb43087e0|buf 地址 0x7fbeb4509060
这个是libA里的buffer。---------
func_Shared 地址 0x7fbeb39e0750|buf 地址 0x7fbeb3be1060
这个是libShared里的buffer。<----> libShared的buffer被修改 1804289383
--------------------------
func_Static 地址 0x7fbeb450a830|buf 地址 0x7fbeb470b0a0
这个是libStatic里的buffer。<----> libStatic的buffer被修改 846930886
--------------------------
func_B 地址 0x7fbeb450a7e0|buf 地址 0x7fbeb470b060
这个是libB里的buffer。---------
func_Shared 地址 0x7fbeb39e0750|buf 地址 0x7fbeb3be1060
libShared的buffer被修改 1804289383 libShared的buffer被修改 1804289383
--------------------------
func_Static 地址 0x7fbeb450a830|buf 地址 0x7fbeb470b0a0
libStatic的buffer被修改 846930886 libStatic的buffer被修改 846930886
--------------------------
func_A 地址 0x7fbeb43087e0|buf 地址 0x7fbeb4509060
这个是libA里的buffer。---------
func_Shared 地址 0x7fbeb39e0750|buf 地址 0x7fbeb3be1060
libShared的buffer被修改 1804289383 libShared的buffer被修改 1804289383
--------------------------
func_Static 地址 0x7fbeb450a830|buf 地址 0x7fbeb470b0a0
libStatic的buffer被修改 846930886 libStatic的buffer被修改 846930886
--------------------------
func_B 地址 0x7fbeb450a7e0|buf 地址 0x7fbeb470b060
这个是libB里的buffer。---------
func_Shared 地址 0x7fbeb39e0750|buf 地址 0x7fbeb3be1060
libShared的buffer被修改 1804289383 libShared的buffer被修改 1804289383
--------------------------
func_Static 地址 0x7fbeb450a830|buf 地址 0x7fbeb470b0a0
libStatic的buffer被修改 846930886 libStatic的buffer被修改 846930886
--------------------------

这里运行结果与windows上不一样,func_Static只存在一份。这里说明libStatic在进程空间仅存在一份,虽然它同时存在于libAlibB中。通过strings程序查看libAlibB,发现前一部分是一样的,也许这就是在链接的时候只存留一份的依据吧。

posted @   乌合之众  阅读(2561)  评论(1编辑  收藏  举报
编辑推荐:
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
阅读排行:
· winform 绘制太阳,地球,月球 运作规律
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· AI与.NET技术实操系列(五):向量存储与相似性搜索在 .NET 中的实现
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
clear
点击右上角即可分享
微信分享提示
CONTENTS