Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
611 views
in Technique[技术] by (71.8m points)

arm - GNU Linker Map File Giving Unexpected Load Addresses

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

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

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.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...