Shared Libraries: Windows VS Linux Method

Shared Libraries: Windows vs Linux method

Not actually with code relocation, that's a totally different issue. It is about a difference in architecture:

  • In Windows, a DLL is just like a executables (EXE). The main difference between an EXE and a DLL is that the EXE has an entry point (main/WinMain function) and so it can be used to start a process, while DLLs can only be loaded into a pre-existing process. But see (1)

  • In Linux, a .so work similar to a static library (.a). The main difference is that the .so file can be linked with a running program, while the .a file can only be linked when compiling the program.

A consequence of this approach is that in linux the same file can be used to build and run the program. But in Windows you need a proper library (LIB) to link the program. Actually the lib that corresponds to a DLL usually have nothing more than the names of the functions, to satisfy the linker, and the stubs to do the relocation. But see (2)

(1) Well, DLLs have entry point too, but it is not used as the main function, just as some sort of initialization/finalization hook.

(2) Some linkers are smart enough to be able, in some simple cases, to link to a DLL by using the DLL itself, without the need of an additional LIB file. I think that at least the MinGW linker can do that.

Dynamic linking - Linux Vs. Windows

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. 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.

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.

rustyx's answer explains the process on Windows more thoroughly than I can; it's been a long time since I've used Windows.

Mixing debug and release libraries: Windows vs Linux, static vs shared

Yes Linux and Windows are different. I cannot tell much for Windows, but with Linux toolchains we don't really have a split Debug vs Release build.

What we have is several options:

  • which optimizations are enabled?
  • should debugging symbols be emitted?
  • some other less relevant stuff.

What build toolchain refer as "Release" or "Debug" is just a set of options. for instance, CMake's min-size release build uses -Os -DNDEBUG, while CMake's debug release uses -g. Distributions also add additional options when they package stuff.

But other than those options, the ABI is the same, so those are all compatible (except for options specifically marked[*] - but those are not used in typical builds). So it doesn't matter. You can mix "debug" or "release" objets, it will work.

As for 4), the way a lot of distributions do it is they build with split debugging symbols. That means debugging information is emitted in a separate file, and typically packaged independently. For instance:

ii  libc6:amd64       2.27-3ubuntu1  GNU C Library: Shared libraries
ii libc6-dbg:amd64 2.27-3ubuntu1 GNU C Library: detached debugging symbols

Second package is normally not installed. I installed it manually to step through libc6 with full debug info.


[*] For an exemple, check out GCC code generation options. You'll see those that generate incompatible objects have a warning on them.

Difference between shared objects (.so), static libraries (.a), and DLL's (.so)?

I've always thought that DLLs and shared objects are just different terms for the same thing - Windows calls them DLLs, while on UNIX systems they're shared objects, with the general term - dynamically linked library - covering both (even the function to open a .so on UNIX is called dlopen() after 'dynamic library').

They are indeed only linked at application startup, however your notion of verification against the header file is incorrect. The header file defines prototypes which are required in order to compile the code which uses the library, but at link time the linker looks inside the library itself to make sure the functions it needs are actually there. The linker has to find the function bodies somewhere at link time or it'll raise an error. It ALSO does that at runtime, because as you rightly point out the library itself might have changed since the program was compiled. This is why ABI stability is so important in platform libraries, as the ABI changing is what breaks existing programs compiled against older versions.

Static libraries are just bundles of object files straight out of the compiler, just like the ones that you are building yourself as part of your project's compilation, so they get pulled in and fed to the linker in exactly the same way, and unused bits are dropped in exactly the same way.

Are libraries built using the Linux subsystem in Windows 10 accessible to a Windows development environment?

You can run a Windows executable from a WSL console window or a Linux executable from Windows command line / power shell. And capture the output, pipe between applications etc. But the application must run entirely on one platform; you cannot mix a Windows executable with Linux libraries or vice-versa.

I don't know how you will connect to MongoDB but, if it has a socket interface like MySql, you could create a bash script on WSL which runs your QT application to access the database, wherever it is.

But if you're using QT as a GUI you're going to struggle. People have been able to get a Linux desktop running on WSL by installing an X server on the Windows host but you might find that more trouble than it's worth.

Why do some applications ship with shared libraries?

If someone want to write plugins for these application they can use a provided API which is usable by the shared libraries.

Also when you have multiple executables using the library in one software-package you can reduce the size of those binaries by shipping also a shared library instead of linking it staticly into each binary.

Architecturally what is the difference between a shared object (SO) and a dynamic link library (DLL)?

A Dll is pretty much the same mechanism as used by .so or .dylib (MacOS) files, so it is very hard to explain exactly what the differences are.

The core difference is in what is visible by default from each type of file. .so files export the language (gcc) level linkage - which means that (by default) all C & c++ symbols that are "extern" are available for linking when .so's are pulled in.
It also means that, as resolving .so files is essentially a link step, the loader doesn't care which .so file a symbol comes from. It just searches the specified .so files in some order following the usual link step rules that .a files adhere to.

Dll files on the other hand are an Operating system feature, completely separate to the link step of the language. MSVC uses .lib files for linking both static, and dynamic libraries (each dll file generates a paired .lib file that is used for linking) so the resulting program is fully "linked" (from a language centric point of view) once its built.

During the link stage however, symbols were resolved in the lib's that represents the Dlls, allowing the linker to build the import table in the PE file containing an explicit list of dlls and the entry points referenced in each dll. At load time, Windows does not have to perform a "link" to resolving symbols from shared libraries: That step was already done - the windows loader just loads up the dll's and hooks up the functions directly.



Related Topics



Leave a reply



Submit