why is there this difference? Why 2 different approaches?
What you described is lazy relocation.
You don't have to use it, and will not use it if e.g. LD_BIND_NOW=1
is set in the environment.
It's an optimization: it allows you to reduce the amount of work that the dynamic linker has to perform, when a particular program invocation does not exercise many possible program execution paths.
Imagine a program that can call foo()
, bar()
or baz()
, depending on arguments, and which calls exactly one of the routines in any given execution.
If you didn't use lazy relocation, the dynamic loader would have to resolve all 3 routines at program startup. Lazy relocation allows dynamic loader to only perform the one relocation that is actually required in any given execution (the one function that is getting called), and at exactly the right time (when the function is being called).
Now, why can't variables also be resolved that way?
Because there is no convenient way for the dynamic loader to know when to perform that relocation.
Suppose the globals are a
, b
and c
, and that foo()
references a
and b
, bar()
references b
and c
, and baz()
references a
and c
. In theory the dynamic loader could scan bodies of foo
, bar
and baz
, and build a map of "if calling foo
, then also resolve globals a
and b
", etc. But it's much simpler and faster to just resolve all references to globals at startup.