共享库:Windows与Linux方法

时间:2013-05-24 14:27:25

标签: linux windows shared-libraries

我有一个关于Windows共享库(DLL)与Linux共享库(SO)的快速提问。

为什么在创建Windows DLL时,它要求客户端程序也链接到静态库(.lib文件),但在Linux中创建的应用程序不需要对这种静态库进行任何链接。

是否与代码重定位等有关?感谢。

3 个答案:

答案 0 :(得分:32)

  

为什么在创建Windows DLL时,它要求客户端程序也链接到静态库(.lib文件),但在Linux中创建的应用程序不需要对这种静态库进行任何链接。

这是Microsoft做出的历史性设计决策,因此链接器可以将DLL引用添加到可执行文件中,而不会在链接时出现DLL的特定版本。原因是,总有不同版本的Windows,不同版本的DLL。当时微软还在OS / 2上与IBM合作,计划是,Windows程序也可以在OS / 2上执行。好吧,微软决定通过推出基于NT内核的专业级操作系统来“反弹”OS / 2。但这意味着,对于开发,您希望开发人员能够链接到系统DLL,而无需提供DLL的所有不同变体。相反,动态链接“模板”将用于创建DLL和可执行文件(都是PE格式),这些是特定的.lib文件,它们根本不是库,而只是符号和序数表(这是一个鲜为人知的事实,但PE二进制符号不仅可以通过字符串标识符加载,还可以加载整数,即所谓的序数。)

序数的副作用是,它们允许隐藏人类可读符号,这样只有在你知道序数←→函数关系时才可以使用DLL。

在Unix中,传统是,“你在系统上构建它,你将在”上运行它,或者“你有所有目标系统文件”。所以从来没有激励这么独立的图书馆和联系信息。从技术上讲,同样适用于DLL也是如此。 PE可以导出符号和重定位表,这些DLL可以执行,并且链接器可以从中获取所需的所有信息,就好了。

如果要使用Unix共享对象隐藏符号,通常使用带有所有函数指针的单个struct,并且只按名称导出此结构的全局常量实例,其中包含许多未明确命名的指针。但是,您可以对Windows DLL执行完全相同的操作。

TL; DR:其原因不是技术问题,而是营销和分销决策。

答案 1 :(得分:23)

实际上没有代码重定位,这是一个完全不同的问题。它与建筑有所不同:

  • 在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链接器可以做到这一点。

答案 2 :(得分:3)

在Windows中,客户端程序无需链接静态库即可访问DLL中的函数。动态链接可以完全在运行时发生,而客户端程序甚至在编译时都不知道DLL的存在。

例如,如果要在名为“bar.dll”的DLL中调用函数名“foo”,则可以编写如下代码:

HINSTANCE 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的人都必须通过序数手动链接到这些函数,或者使用组合名称生成自己的静态库。