Dynamic vs Static Linking regarding addresses

Is every address for function calls, global variables etc. known and set after the linking? I mean while link time, so before run time?

I know that there is a dynamic Linker/Loader, which is responsible for relocations. He works on run time, so when we actually want to start the executable and he will determine the missing addresses, because before runtime we could not know where the libraries are in the virtual address space.

But I thought the dynamic Linker (ld.so) is only needed when we used dynamic linking. But is he also used for static linking? Or are every addresses set after static linking?

It might be worth noting that my response is all specific to Linux -- I suspect that's what you're asking about, but if you're on some other *nix system, some of this might not apply. Also, there's tons of info already out there on the web. At the bottom are some (hopefully) helpful links. Not all are related to your specific question, but they're worth reading if you want to get deeper into all of this.

Originally Posted by ANSI-C

Regarding static linking:

Is every address for function calls, global variables etc. known and set after the linking? I mean while link time, so before run time?

Yes, that's the gist of it. When the linker is done, the addresses of all the symbols are fixed, but only within the context of the executable file. ld.so does not come into play when running a purely statically linked binary. It's the kernel that reads the executable file into memory and turns the file-based address into addresses that correspond to memory1.

Originally Posted by ANSI-C

But I thought the dynamic Linker (ld.so) is only needed when we used dynamic linking. But is he also used for static linking? Or are every addresses set after static linking?

ld.so is not used for static linking, only dynamic. It is itself something of a shared library that is bootstrapped and helps load other shared libraries.

Great links so far! What I'm going to say is all Linux specific, but here we go. Object files (.o) created by the compiler, executable files created by the linker, and shared libraries (.so) are all ELF files. They all have sections that can be loaded into memory, with different permissions (usually read/write and read/execute), and may contain unresolved relocations and unresolved symbols ("please put the address of this here once you know it"). These are values which must be filled in somehow before the code is actually executable. For instance, a hello world program might have an unresolved external reference to the function "printf" or "puts" (try "nm program" to see). One object file might reference a global variable declared in another file, whose address is not known. Actually, object files have a lot of addresses which are not known because they all have a base address of zero. The linker's job is to put them all together into one program, such that there aren't any overlapping regions. Only at this point is the actual address of a function decided upon and thus any relocations that refer to the function may be resolved.

There's a lot of symmetry between these systems. The linker takes object files and resolves many (but not all) relocations to produce executables and libraries. The loader chooses an actual base address for a library (which can otherwise be loaded anywhere) and resolves all remaining relocations. So a statically linked executable, with all of its code inside the same ELF and all of its relocations already known, does not need a loader at all. But a normal executable does in order to handle its shared libraries. [It is also possible to create a position-independent executable, which acts much like a library in that its selection of a base address can be deferred until runtime. Like I said, there's a lot of symmetry here.]

The best part? The loader itself is an ELF file, statically linked of course, which simply knows how to open other ELF files and fix their relocations.

tl;dr the linker resolves relocations at link-time, and unless you made a static executable, there will be some relocations left which are resolved by the loader (or "dynamic linker") at runtime.

[edit] If you want to see more, try running "readelf -Wa program". [/edit]

dwk

Seek and ye shall find. quaere et invenies.

"Simplicity does not precede complexity, but follows it." -- Alan Perlis
"Testing can only prove the presence of bugs, not their absence." -- Edsger Dijkstra
"The only real mistake is the one from which we learn nothing." -- John Powell