GCC LD NOLOAD linker section generates loadable segment
Asked Answered
D

1

4

I'm working on an Arm bare-metal application and I've marked some sections with NOLOAD. According to the explanation in Understanding linker script NOLOAD sections in embedded software , I expected the resulting ELF file to not have a loadable segment (program header) for these sections, but it does.

Is this correct? Why are those sections marked as loadable in the ELF file?

As the linker is still placing the data in .bss, how a loader is supposed to know that the sections shouldn't be loaded? Or am I missing the meaning of 'load' in the sense that NOLOAD only makes sense for initialized symbols (which would normally be placed into .data)?

This is a part of my linker script:

    .bss (NOLOAD) :
    {
        . = ALIGN(4);
        __bss_start__ = .;
        *(.bss_begin .bss_begin.*)

        *(.bss .bss.*)
        *(COMMON)

        *(.bss_end .bss_end.*)
        . = ALIGN(4);
        __bss_end__ = .;
    } >DRAM

    .noinit (NOLOAD) :
    {
        . = ALIGN(4);
        __noinit_start__ = .;

        *(.noinit .noinit.*)

         . = ALIGN(4) ;
        __noinit_end__ = .;
    } > DRAM
    
    /* Check if there is enough space to allocate the main stack */
    ._stack (NOLOAD) :
    {
        . = ALIGN(4);
        
        . = . + __Main_Stack_Size ;
        
        . = ALIGN(4);
    } >DRAM

This is the output ELF file:

arm-none-eabi-readelf.exe -l test.elf

Elf file type is EXEC (Executable file)
Entry point 0x601b9
There are 2 program headers, starting at offset 52

Program Headers:
  Type           Offset   VirtAddr   PhysAddr   FileSiz MemSiz  Flg Align
  LOAD           0x010000 0x00060000 0x00060000 0x06840 0x06840 RWE 0x10000
  LOAD           0x020000 0x20010000 0x20010000 0x00000 0x06084 RW  0x10000

 Section to Segment mapping:
  Segment Sections...
   00     .text .ARM.exidx.reset .data
   01     .systemclock .bss ._stack

Why are the .bss and ._stack sections there?

Thanks!!

Dissolve answered 22/1, 2021 at 15:28 Comment(5)
Can you clarify the problem / your question, I recently worked on linker scripts but I can't see the issue hereDeclassify
The NOLOAD keyword tells a loader that a given section isn't supposed to be loaded. My expectation is that any section with NOLOAD should NOT appear in the ELF output file program header with the LOAD flag, but they do. I'd like to know why.Dissolve
The other stack overflow question that you referred to quotes the definition of NOLOAD (output section type). This definition explicitly says that the linker will process the section normally, which would then result in no change in ELF w.r.t. this section (except and added attribute for loader). It is the loader than that takes care of not loading these sections.Cooksey
OK, but then the question becomes: how is the loader supposed to know that these shouldn't be loaded? When a symbol is placed in the .noinit section, the linker moves it from .bss to .noload, I was expecting something similar here?Dissolve
Maybe you have to actually move the section to a dedicated segment which is then not loaded? IIRC the section table is optional in ELF executables...Phototonus
O
2

The FileSiz of the second segment is 0 which means that there is no data that will be loaded from the elf file into this segment.

The reason why this segment exists in the table is that on a non-embedded system, the program loader would still need to request memory for sections in that segment and mark the relevant pages with the relevant attributes (readable and writable in this case).

Edit: After reading the question again, I did a bit more experimenting and it seems that all (NOLOAD) seems to do is to set the type of the section in the output file to SHT_NOBITS. The elf specification calls that a section that occupies no space in the file but is still part of the program's memory image.

If the goal is to link against code that is already present in the rom before the program is loaded, those symbols should be defined in the linker script outside of any section. E.g. already_present_code = 0x06000000; SECTIONS { .text : {*(.text*)} /* ... */}. That seems to have the desired effect.

Orang answered 31/10, 2021 at 13:1 Comment(8)
Yes, but MemSiz is not zero, which means that even on an embedded system that memory range has to be filled with zeros.Dissolve
.bss will usually be filled with zeros because that is where global variables that are initialized with zero live. I am pretty sure that is done by the C runtime and not by the program loader though. (I unfortunately don't have anything to test verify this myself right now but this post shows that GDB says nothing about .bss and my startup code has a loop that initializes it).Orang
(that is what the __bss_start__ and __bss_end__ symbols are for). The other sections should not be initialized. You could verify that by defining a symbol e.g. in .noinit in the linker script and writing some code to read out the memory at that location, incrementing it, writing it back and printing it.Orang
You're missing the point of my question, adding NOLOAD to .bss didn't make a difference on the program header table as the .bss section is marked to be "loaded". I'd like to understand why. Revisiting this, it seems that NOLOAD won't affect the sections that I marked because they don't have code.Dissolve
Did you actually verify the claim that gdb will write something to the NOLOAD sections when you load your program? I'm fairly certain that it doesn't and I'll check this myself once I have access to hardware again in ~13 hours.Orang
Because various object files want to refer to symbols in the NOLOAD sections, the linker needs to place them somewhere in memory and because it doesn't assume that the program will run directly on physical memory addresses, it specifies the memory range so that the loader can make sure that it is accessible. You could edit the elf header and change the number of program headers from 2 to 1 and everything would still load and work fine on your microcontroller. The linker won't do that for you because it doesn't change anything.Orang
You were right, I was missing the point and have edited my answer to explain what NOLOAD actually seems to do (which is make a section essentially equivalent to .bss) and how to get symbols in memory areas that won't show up in the elf file (by declaring those symbols outside of any section)Orang
Thanks for the update!Dissolve

© 2022 - 2024 — McMap. All rights reserved.