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!!

Leonardo
  • 1,533
  • 17
  • 28
  • Can you clarify the problem / your question, I recently worked on linker scripts but I can't see the issue here – GabrielT Jan 22 '21 at 15:35
  • 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. – Leonardo Jan 22 '21 at 19:11
  • 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. – bbv Jan 29 '21 at 10:18
  • 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? – Leonardo Jan 29 '21 at 14:48
  • 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... – dyp Jan 29 '21 at 16:32

1 Answers1

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.

Niautanor
  • 103
  • 2
  • 8
  • Yes, but `MemSiz` is not zero, which means that even on an embedded system that memory range has to be filled with zeros. – Leonardo Nov 01 '21 at 15:59
  • .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](https://stackoverflow.com/questions/28588722/gdb-watch-point-does-not-work-on-gdb-load-command) shows that GDB says nothing about .bss and my startup code has a loop that initializes it). – Niautanor Nov 02 '21 at 16:32
  • (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. – Niautanor Nov 02 '21 at 16:36
  • 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. – Leonardo Nov 02 '21 at 16:43
  • 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. – Niautanor Nov 02 '21 at 18:06
  • 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. – Niautanor Nov 02 '21 at 18:11
  • 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) – Niautanor Nov 03 '21 at 08:31
  • Thanks for the update! – Leonardo Nov 03 '21 at 17:34