Understanding the Location Counter of GNU Linker Scripts

This question also troubled me, Give my understanding:

.ramvect : {                        /* used for vectors remapped to RAM */
    __ram_start = .;
    . = 0x40;
} >RAM

The above statement tells the linker to place the __ram_start symbol at location counter, that is at the start of the .ramvect segment.

Since the __ram_start symbol is located at the head of the .ramvect segment, when the C code is used to get the __ramvect address, it will get the starting address of the.ramvect segment, i.e. its absolute address.


The placement of the section is determined by the memory region after the closing brace (>RAM AT>ROM). So the execution address is in RAM at 0x00200000 and following, but the load address is in ROM (flash) at 0x00100000. The startup code must copy the .fastcode output section from its load to its execution address, that's what the symbols are for.

Note that these need not be at address 0, because the AT91SAM7S remaps either RAM or ROM to address 0. Usually it starts up with ROM mapped, and the startup code switches that to RAM.


I think I may have figured out the answer to my own question. I'm not sure I'm right, but it's the first explanation I've been able to think of that actually makes sense. What made me rethink things was this page of the documentation. Particularly this quote:

Addresses and symbols may be section relative, or absolute. A section relative symbol is relocatable. If you request relocatable output using the `-r' option, a further link operation may change the value of a section relative symbol. On the other hand, an absolute symbol will retain the same value throughout any further link operations.

and this quote:

You can use the builtin function ABSOLUTE to force an expression to be absolute when it would otherwise be relative. For example, to create an absolute symbol set to the address of the end of the output section .data:

 SECTIONS
   {
     .data : { *(.data) _edata = ABSOLUTE(.); }
   }

If ABSOLUTE were not used, _edata would be relative to the .data section.

I had read them before, but this time I saw them from a new perspective.

So I think my misinterpretation was thinking that a symbol, when assigned a relative byte offset address, is simply set to the value of that offset while the base address information is lost.

That was based on this quote from my original question:

Note: . actually refers to the byte offset from the start of the current containing object. Normally this is the SECTIONS statement, whose start address is 0, hence . can be used as an absolute address. If . is used inside a section description however, it refers to the byte offset from the start of that section, not an absolute address.

Instead what I now understand to be happening is that the base address information is not lost. The symbol does not simply get assigned the value of the offset from the base address. The symbol will still eventually resolves to an absolute address, but only when there's no chance its base address can change.

So where I thought that something like __stack_start__ = . ; should have to be changed to __stack_start__ = ABSOLUTE(.) ;, which does work, I now think it is unnecessary. What's more, I understand from the first quote in this response that you can relink an ELF file?

So if I used __stack_start__ = ABSOLUTE(.) ;, ran the linker script to create the ELF executable, then tried to relink it and moved the .stack section somewhere else, the __stack_start__ symbol would still be pointing to the same absolute address from the first link, and thus be incorrect.

This is probably hard to follow, but I've written it as articulately as I could. I suspect I've got close to the right idea, but I still need someone who actually knows about this stuff to confirm or deny this.