简体   繁体   English

动态链接 - Linux 与。 Windows

[英]Dynamic linking - Linux Vs. Windows

Under Windows, when I compile C/C++ code in a DLL project in MSVC I am getting 2 files:在 Windows 下,当我在 MSVC 的 DLL 项目中编译 C/C++ 代码时,我得到 2 个文件:

  1. MyDll.dll
  2. MyDll.lib

where as far as I understand MyDll.lib contains some kind of pointers table indicating functions locations in the dll.据我了解, MyDll.lib包含某种指针表,指示 dll 中的函数位置。 When using this dll, say in an exe file, MyDll.lib is embedded into the exe file during linkage so in runtime it "knows" where the functions are located in MyDll.dll and can use them.当使用这个 dll 时,比如说在一个 exe 文件中, MyDll.lib在链接期间嵌入到 exe 文件中,因此在运行时它“知道”函数位于MyDll.dll中的位置并可以使用它们。

But if I compile the same code under Linux I am getting only one file MySo.so without MySo.a (the equivalent to lib file in Linux) so how does an executable file under Linux knows where the functions are located in MySo.so if nothing is embedded into it during linking?但是,如果我在 Linux 下编译相同的代码,我只会得到一个没有MySo.a MySo.so相当于 Linux 中的lib文件),那么 Linux 下的可执行文件如何知道函数在MySo.so中的位置,如果链接期间没有嵌入任何内容?

The MSVC linker can link together object files (.obj) and object libraries (.lib) to produce an.EXE or a.DLL. MSVC linker 可以将 object 文件 (.obj) 和 object 库 (.lib) 链接在一起,以生成一个.EXE 或 a16AD70384E402759

To link with a DLL, the process in MSVC is to use a so-called import library (.LIB) that acts as a glue between the C function names and the DLL's export table (in a DLL a function can be exported by name or by ordinal - the latter was often used for undocumented APIs). To link with a DLL, the process in MSVC is to use a so-called import library (.LIB) that acts as a glue between the C function names and the DLL's export table (in a DLL a function can be exported by name or 按序数- 后者通常用于未记录的 API)。

However, in most cases the DLL export table has all the function names and thus the import library (.LIB) contains largely redundant information (" import function ABC -> exported function ABC ", etc). However, in most cases the DLL export table has all the function names and thus the import library (.LIB) contains largely redundant information (" import function ABC -> exported function ABC ", etc).
It is even possible to generate a.LIB from an existing.DLL.甚至可以从现有的.DLL生成.LIB。

Linkers on other platforms don't have this "feature" and can link with dynamic libraries directly.其他平台的链接器没有这个“特性”,可以直接链接动态库。

On Linux, the linker (not the dynamic linker) searches through the shared libraries specified at link time and creates references to them inside the executable.在 Linux 上,linker(不是动态链接器)搜索链接时指定的共享库,并在可执行文件中创建对它们的引用。 When the dynamic linker loads these executables it loads the shared libraries they require into memory and resolves the symbols, which allows the binaries to be run.当动态 linker 加载这些可执行文件时,它会将所需的共享库加载到 memory 并解析符号,从而允许运行二进制文件。

MySo.a , if created, would actually include the symbols to be linked directly into the binary instead of the "symbol lookup tables" used on Windows. MySo.a如果创建,实际上将包含要直接链接到二进制文件中的符号,而不是 Windows 上使用的“符号查找表”。

rustyx's answer explains the process on Windows more thoroughly than I can; rustyx 的回答比我更彻底地解释了 Windows 上的过程; it's been a long time since I've used Windows.我已经很久没有使用 Windows 了。

The difference you are seeing is more of an implementation detail - under the hood both Linux and Windows work similarly - you code calls a stub function which is statically linked in your executable and this stub then loads DLL/shlib if necessary (in case of delayed loading , otherwise library is loaded when program starts) and (on first call) resolves symbol via GetProcAddress / dlsym . The difference you are seeing is more of an implementation detail - under the hood both Linux and Windows work similarly - you code calls a stub function which is statically linked in your executable and this stub then loads DLL/shlib if necessary (in case of delayed loading ,否则在程序启动时加载库)和(在第一次调用时)通过GetProcAddress / dlsym解析符号。

The only difference is that on Linux the these stub functions (which are called PLT stubs) are generated dynamically when you link your app with dynamic library (library contains enough information to generate them), whereas on Windows they are instead generated when DLL itself is created, in a separate .lib file.唯一的区别是,在 Linux 上,这些存根函数(称为 PLT 存根)是在您将应用程序与动态库链接时动态生成的(库包含足够的信息来生成它们),而在 Windows 上,它们是在 Z58540E40D711AD 本身为在单独的.lib文件中创建。

The two approaches are so similar that it's actually possible to mimic Windows import libraries on Linux (see Implib.so project).这两种方法非常相似,实际上可以在 Linux 上模仿 Windows 导入库(参见Implib.so项目)。

On Linux, you pass MySo.so to the linker and it is able to extract only what is needed for the link phase, putting in a reference that MySo.so is needed at run time.在 Linux 上,您将MySo.so传递给 linker,它能够仅提取链接阶段所需的内容,并提供运行时需要MySo.so的引用。

.dll or .so are shared libs (linked in runtime), while .a and .lib is a static library (linked in compile time). .dll.so是共享库(在运行时链接),而.a.lib是 static 库(在编译时链接)。 This is no difference between Windows and Linux.这在 Windows 和 Linux 之间没有区别。

The difference is, how are they handled.不同之处在于,它们是如何处理的。 Note: the difference is only in the customs, how are they used.注意:区别仅在于海关,它们是如何使用的。 It wouldn't be too hard to make Linux builds on the Windows way and vice versa, except that practically no one does this.使 Linux 建立在 Windows 方式上并不会太难,反之亦然,但实际上没有人这样做。

If we use a dll, or we call a function even from our own binary, there is a simple and clear way.如果我们使用 dll,或者甚至从我们自己的二进制文件中调用 function,则有一种简单明了的方法。 For example, in C, we see that:例如,在 C 中,我们看到:

int example(int x) {
  ...do_something...
}

int ret = example(42);

However, on the asm level, there could be many differences.但是,在 asm 级别上,可能存在许多差异。 For example, on x86, a call opcode is executed, and the 42 is given on the stack.比如在x86上,执行了一个call操作码,栈上给出了42 Or in some registers.或在某些寄存器中。 Or anywhere.或任何地方。 No one knows that before writing the dll , how it will be used.没有人知道在写 dll 之前,它将如何使用。 Or how the projects will want to use it, possible written with a compiler (or in a language.) which doesn't even exist now (or is it unknown for the developers of the dll).或者项目将如何使用它,可能是用现在甚至不存在的编译器(或语言)编写的(或者对于 dll 的开发人员来说是未知的)。

For example, by default, both C and Pascal puts the arguments (and gets the return values) from the stack - but they are doing it in different order .例如,默认情况下,C 和 Pascal 都会从堆栈中放入 arguments (并获取返回值) -但它们的执行顺序不同 You can also exchange arguments between your functions in the registers by some - compiler-dependent - optimization.您还可以通过一些 - 编译器相关 - 优化在寄存器中的函数之间交换 arguments。

As you see correctly, the Windows custom is that building a dll, we also create a minimal .a / .lib with it.如您所见,Windows 自定义是构建 dll,我们还使用它创建了一个最小的.a / .lib This minimal static library is only a wrapper, the symbols (functions) of that dll are reached through it.这个最小的 static 库只是一个包装器,通过它可以到达 dll 的符号(函数)。 This makes the required asm-level calling conversions.这会进行所需的 asm 级调用转换。

Its advantage is the compatibility.它的优点是兼容性。 Its disadvantage is that if you have only a.dll, you can have a hard time to figure out, how its functions want to be called.它的缺点是,如果你只有一个.dll,你可能很难弄清楚它的函数是如何被调用的。 This makes the usage of dlls a hacking task, if the developer of the dll does not give you the .a .如果 dll 的开发人员没有给您.a ,这会使 dll 的使用成为一项黑客任务。 Thus, it serves mainly closedness purposes, for example so is it easier to get extra cash for the SDKs.因此,它主要服务于封闭性目的,例如,更容易为 SDK 获得额外的现金。

Its another disadvantage is than even if you use a dynamical library, you need to compile this little wrapper statically.它的另一个缺点是即使您使用动态库,也需要静态编译这个小包装器。

In Linux, the binary interface of the dlls is standard and follows the C convention.在 Linux 中,dll 的二进制接口是标准的,遵循 C 约定。 Thus, no .a is required and there is binary compatibility between the shared libs, in exchange we don't have the advantages of the microsoft custom.因此,不需要.a并且共享库之间存在二进制兼容性,作为交换,我们没有 microsoft 自定义的优势。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM