4
votes

I'm working on an embedded program where I have a custom linker script. The program works, but I have noticed that there is possibly something amiss with how the linker is placing a couple of sections in memory.

Here are the relevant parts of the linker script:

MEMORY {
    ROM (rx)    : ORIGIN = 0x00100000, LENGTH = 16k
    RAM (rwx)   : ORIGIN = 0x00200000, LENGTH = 4k
}

SECTIONS {
    /* Other sections go here. */
    .data : {
...
    } >RAM AT>ROM

    .bss : {
...
    } >RAM

    .stack : {
...
    } >RAM
...
}

And here is the relevant part of the MAP file:

.data           0x00200040        0x0 load address 0x001003d4
                0x001003d4                __data_load = LOADADDR (.data)
                0x00200040                __data_start = .
 *(.data)
 *(.data*)
                0x00200040                . = ALIGN (0x4)
                0x00200040                _edata = .

.igot.plt       0x00200040        0x0 load address 0x001003d4
 .igot.plt      0x00000000        0x0 ./debug/sam7s_startup.o

.bss            0x00200040        0x0 load address 0x001003d4
                0x00200040                __bss_start__ = .
 *(.bss)
 *(.bss*)
 *(COMMON)
                0x00200040                . = ALIGN (0x4)
                0x00200040                _ebss = .
                0x00200040                __bss_end__ = .
                0x00200040                PROVIDE (end, _ebss)
                0x00200040                PROVIDE (_end, _ebss)
                0x00200040                PROVIDE (__end__, _ebss)

.stack          0x00200040      0x200 load address 0x001003d4
                0x00200040                __stack_start__ = .

So from the map file it looks to me like the .bss and .stack sections are getting load addresses in ROM. I think this because of these two lines:

.bss 0x00200040 0x0 load address 0x001003d4
.stack 0x00200040 0x200 load address 0x001003d4

This isn't good, because there's no point in them taking up space in ROM. The .bss section, although empty right now, will contain uninitialised global variables that will be set to zero in code. The stack is also just a part of RAM that will be initialised in code. So there's no need for either of these sections to be taking up space in ROM.

So my question is, what is the correct way to stop .bss and .stack from being loaded into ROM? Do I have to change the end of the .bss and .stack sections from >RAM to >RAM AT>RAM? This seems a bit redundant.

After testing out some things I have found the following:

(1) Using the (NOLOAD) attribute (e.g. by replacing .stack : with .stack (NOLOAD) :) still results in the map file showing a ROM load address for the .stack and .bss sections.

(2) Specifying RAM AT>RAM, as mentioned above, does indeed stop the map output from showing ROM load addresses for the .stack and .bss sections.

(3) When the map file shows load addresses for the .bss and .stack sections, it appears that they do not actually take up space in ROM. The .stack section, although 0x200 bytes long, does not seem to actually take up that space in ROM, even if I specify fill values for it and place a section after it in the linker script. The section that follows it in the linker script does not get moved around with different stack sizes.

So perhaps the map file output doesn't mean what I think it means, and the .stack and .bss sections aren't actually being given load addresses in ROM at all. After trying out a few things it would certainly appear this way. It would still be interesting to know why the map output makes it appear as though the sections are given ROM load addresses though, especially when (NOLOAD) is used. Could this just be a bug in how LD generates its map output files?

See Also: Understanding the Location Counter of GNU Linker Scripts

1
To summarise: - binutils version 2.23.1 from the YAGARTO toolchain - Using NOLOAD made no difference to the map file. I used NOLOAD by simply replacing .bss : with .bss (NOLOAD) : and .stack : with .stack (NOLOAD) : in the linker script. - You were correct about placing a section after the stack. I moved the .text section there, and the stack did not take up any load space. - Yes, the whole question is about the map output. It suggests to me that the linker is trying to give .bss and .stack a load address in ROM (although we just found this doesn't actually happen).Adam Goodwin
I have attempted to tidy up the question alsoAdam Goodwin

1 Answers

5
votes

You are looking for NOLOAD. See Gnu LD output section type. I read your whole post now and I see you postulated about NOLOAD. With NOLOAD, all of the addresses are defined. If you use them within your 'C' code, they will load from that address. You must provide some start-up code, usually in assembler that clears the BSS area. Usually, you don't expect your stack to be initialized.

A NOLOAD section is like a compile/link time malloc(). You get the memory to use, just don't expect anything there. For BSS you define __bss_start__ and __bss_end__ in your linker script and write a short initialization routine to clear this memory using those variables/addresses.

Note: everything shows up in the map file. It won't show up in a generated binary or have data in an ELF. Just the section meta information will be held in the ELF.

Edit: The load address in the map file is like a location counter for loading. The load address is where ld is set to put stuff. ld is not really putting things there if they take zero size. The map output is not linguistically un-ambiguious; I can see how it is confusing, but ld does things correctly in creating the output binary. BSS is normally marked NOLOAD by gcc in the object files, so in the example only the stack section would need NOLOAD. For a something like stack, a section is not really needed and just a set of symbols declarations would work.