您为什么不能静态链接动态库?

时间:2019-01-29 14:58:57

标签: static-linking dynamic-linking

使用外部库时,通常必须确定是使用静态版本还是动态版本。通常,您不能交换它们:如果该库是作为动态库构建的,则无法对其进行静态链接。

为什么会这样?

示例:我正在Windows上构建C ++程序,并使用一个库,该库为链接器提供一个小的.lib文件,而在运行可执行文件时必须提供一个大的.dll文件。如果.dll中的库代码可以在运行时解析,为什么不能在编译时解析并将其直接放入我的可执行文件中?

1 个答案:

答案 0 :(得分:2)

  

为什么会这样?

大多数接头(AIX接头是一个显着的例外)丢弃在连接的过程中的信息。

例如,假设您有foo.ofoo,其中bar.obar。假设foo呼叫bar

在链接foo.obar.o在一起成为一个共享库,链接器合并代码和数据段,并解析的引用。从foobar的呼叫变成CALL $relative_offset。完成此操作后,您将无法再分辨来自foo.o的代码与来自bar.o的代码之间的边界,也无法分辨CALL $relative_offsetfoo.o中使用的名称。 - 重定位条目已被丢弃

假设现在您想将foobar.so与您的main.o静态链接,并假设main.o已经定义了自己的bar

如果您有libfoobar.a,那将是微不足道的:链接器将从存档中提取foo.o,将使用存档中的bar.o,并且解决从foo.obarmain.o的呼叫。

但是应该清楚,foobar.so不能满足以上要求-呼叫已经解决了 other bar,您不能放弃从来到代码bar.o,因为你不知道在哪里的代码是

在AIX上,有可能(或者至少在十年前曾经有过这种可能性)“取消链接”共享库,然后将其转回归档文件,然后可以将其静态链接到另一个共享库或主可执行文件中。

  

如果将foo.obar.o链接到foobar.so中,那么从foobar的调用总是解析为bar.o中的那个?

这是UNIX共享库与Windows DLL有很大不同的地方。在UNIX上(在通常情况下),从foobar的调用将解析为主要可执行文件中的bar

这允许一个例如在主要malloc中实现freea.out,并且对malloc all 调用使用 one 堆实现始终如一。在Windows上,您必须始终跟踪“此内存来自哪个堆实现”。

在UNIX模型是不是没有缺点虽然,作为共享库不是自包含的大部分密封单元(不同于一个Windows DLL)。

  

您为什么要将其解析为bar中的另一个main.o

如果您不解决对main.o的调用,则与针对libfoobar.a的链接相比,您将得到一个完全不同的程序。