我有一个关于Windows共享库(DLL)和Linux共享库(SO)的问题。
为什么当你创建一个 Windows DLL 时,它需要客户端程序链接静态库(.lib 文件),但是在 Linux 中创建的应用程序不需要链接任何静态库。
这是否与代码重定位等有关呢?谢谢。
我有一个关于Windows共享库(DLL)和Linux共享库(SO)的问题。
为什么当你创建一个 Windows DLL 时,它需要客户端程序链接静态库(.lib 文件),但是在 Linux 中创建的应用程序不需要链接任何静态库。
这是否与代码重定位等有关呢?谢谢。
struct
,并仅通过名称导出全局常量实例,其中包含许多未明确命名的指针。你也可以用同样的方法来处理Windows DLLs。这实际上与代码重定位无关,它涉及到不同的体系结构:
在Windows中,DLL就像可执行文件(EXE)一样。 EXE和DLL之间的主要区别是EXE具有入口点(main/WinMain函数),因此可以用于启动进程,而DLL只能加载到预先存在的进程中。但参见(1)
在Linux中,.so类似于静态库(.a)。主要区别在于.so文件可以链接到正在运行的程序,而.a文件只能在编译程序时链接。
这种方法的一个后果是,在Linux中,同一个文件可以用来构建和运行程序。但在Windows中,您需要一个适当的库(LIB)来链接程序。实际上,对应于DLL的lib通常仅包含函数名称以满足链接器以及执行重定位的存根。但参见(2)
(1)好吧,DLL也有入口点,但它不像主函数那样使用,而仅用作某种初始化/终止挂接点。
(2)一些链接器足够聪明,能够在某些简单情况下仅使用DLL本身来链接到DLL,而无需额外的LIB文件。我认为至少MinGW链接器可以做到这一点。
.so
库和一个静态库(.a
)是完全不同的。 - user149341.so
是一个 ELF 对象,外观类似于没有入口点的可执行文件。.a
是一个存档文件,其中包含多个 .o
文件;它的外观和行为更像是 tar 文件而不是库! 链接 .a
文件只是解压缩所有成员的 .o
文件并将它们引入,这与链接 .so
的方式完全不同。 - user149341HINSTANCE hinst = LoadLibrary("bar.dll");
FARPROC foo = GetProcAddress(hinst, "foo");
foo();
“foo”和“bar.dll”可能只是在运行时通过配置文件或其他用户输入获得的值。
静态库的目的是自动化这个动态加载的过程,通过创建存根来实现,从客户程序的角度看,它们就像是常规函数,但在运行时与DLL链接。通常这种链接发生在客户进程加载时,但也可以生成库以根据需要加载和链接,因此直到实际需要才会将DLL带入内存。静态库决定了链接发生的时间。
在大多数情况下,编译器可以自动生成这些库,因此在仅链接到DLL函数时技术上没有必要使用它们。然而,唯一的例外(我所知道的)是链接到共享变量。
在Windows DLL中,您可以创建一个共享数据段,并使用变量访问已加载该DLL的任何进程。关于这些变量的大小和类型的信息存储在相关的静态库中,并且无法仅从DLL中确定。为了访问这些变量,客户端程序必须链接到该DLL的静态库。
据我所知,Linux共享库不支持这种概念。
更新
在Windows上,可以创建仅按序数(编号)导出函数入口点的DLL。这可以视为一种数据隐藏形式,并且通常在实现者希望某些函数保持私有时使用。
具有静态库访问权限的人将能够按名称调用这些函数,因为该库将详细信息链接到函数名称对应的序数。只有DLL的用户将不得不通过序数手动链接到函数,或者生成自己的静态库并使用虚构名称。
GNU_SHR
部分。 - jww