LLD vs LD section type: PROGBITS vs NOBITS

I see a difference in behavior regarding what section type is created by the binutils/bfd linker and LLD. Here is a reduced test case:

$ cat test.ld
    SRAM (RWX) : ORIGIN = 0, LENGTH = 0x1000

    .stack : {
        . = 0x100;
    } > SRAM

$ cat test.sh

rm -f test.s
touch test.s

riscv32-unknown-elf-clang -T test.ld -nostdlib test.s -mno-relax -o test-ld.elf
riscv32-unknown-elf-clang -T test.ld -nostdlib test.s -mno-relax -o test-lld.elf -fuse-ld=lld

readelf -WS test-ld.elf  | grep ".stack"
readelf -WS test-lld.elf | grep ".stack"

$ ./test.sh
ld.lld: warning: cannot find entry symbol _start; defaulting to 0x100
  [ 1] .stack            NOBITS          00000000 001000 000100 00  WA  0   0  1
  [ 1] .stack            PROGBITS        00000000 001000 000100 00   A  0   0  1

Do you have any insight about what type of section should be generated for .stack, given the provided linker script? Is LLD doing the wrong thing when it emits PROGBITS? Whether this is correct LLD behavior or not, how should the linker script be modified to obtain NOBITS, like LD generates?

Thank you so much.


Sadly this is an area of linker scripts that isn’t really covered by the documentation. The script says increase the location counter. Was the intent to have those padding bytes be read-only, read-write, bss? I’m not sure if there is enough information to know for sure.

From the information available in the script I think both GNU ld and LLD’s interpretations of increase the loction counter are reasonable. I think you can force LLD to use NOBITS by adding (NOLOAD)
For example:

    .stack (NOLOAD) : {
        . = 0x100;
    } > SRAM

My first post on discourse, so hopefully it formats OK.


Would LLD accept patches to match LD behavior in cases like this, where both are within the (underspecified) spec but diverge in behavior?

Thank you! I had found that in the meanwhile. I was also concerned that the section flags (permissions) didn’t match LD. It turns out that that didn’t matter for my specific use case. Still, I’m curious. Is it possible to tweak my reduced linker script to also change the section flags to RW? I was mostly curious about achieving that purely within the linker script but I’m not even sure how to do that with the help of a .s. When I tried to assemble .section .stack, "w" (or "d", "r" is supposed to be read-only) and link that didn’t produce a RW section.

It came out perfect! (You do have a preview zone you can use to double check)

Would LLD accept patches to match LD behavior in cases like this, where both are within the (underspecified) spec but diverge in behavior?

I think it depends on the situation. In general we like to be close to GNU ld, although in some cases ld behaviour may not be desirable, or might be difficult to replicate without consequences.

In this particular case we’d need to work out if the GNU ld behaviour is intentional and likely to be stable or it just drops out from the particular implementation. For example can we derive what the rules are for when assigning the location counter, is it when the Output Section is empty, follows nothing or the previous Output Section was ZI, could it be that .stack is recognised as a special name?

Usually the type and flags of an OutputSection are derived from a combination of the type and flags of the InputSections. Without any sections I think LLD just uses the default type, although NOLOAD will set the type to SHT_NOBITS.