Search code examples
gcclinkerld

What is the difference between "load address" and "relocation address"?


Regarding the AT (...) directive for ld, this source states:

AT ( ldadr ) The expression ldadr that follows the AT keyword specifies the load address of the section. The default (if you do not use the AT keyword) is to make the load address the same as the relocation address. This feature is designed to make it easy to build a ROM image.

I've been searching but have not found a clear definition of what is meant by "load address" and "relocation address".

I understand that when object files are linked together, code is "relocated" in that jump addresses, etc. are rewritten to point to the correct offset within the combined machine code. So is the "relocation address" the offset within the resulting object code where a section begins? If so, how could the "load address" of a section possibly be something different?

How is the output of the linker affected if these 2 addresses are different?


Solution

  • Difference is crucial. Relocation address is addend to all relocs in section. So if it differ with load address, nothing will really work in this section -- all relocs inside section will be resolved to wrong values.

    So why do we need technique like this? Not so much applications, but suppose (from here) you do have on your architecture extremely fast memory at 0x1000

    Then you may take two sections to have relocation address 0x1000:

    .text0 0x1000 : AT (0x4000) { o1/*.o(.text) }
    __load_start_text0 = LOADADDR (.text0);
    __load_stop_text0 = LOADADDR (.text0) + SIZEOF (.text0);
    .text1 0x1000 : AT (0x4000 + SIZEOF (.text0)) { o2/*.o(.text) }
    __load_start_text1 = LOADADDR (.text1);
    __load_stop_text1 = LOADADDR (.text1) + SIZEOF (.text1);
    . = 0x1000 + MAX (SIZEOF (.text0), SIZEOF (.text1));
    

    Now at runtime go ahead and when you need text1, manage it by yourself to be copied on right address from its actual load address:

    extern char __load_start_text1, __load_stop_text1;
    memcpy ((char *) 0x1000, &__load_start_text1,
          &__load_stop_text1 - &__load_start_text1);
    

    And then use it, as it was loaded here naturally. This technique is called overlays.

    I think, example is pretty clear.