Skip to content

dot does not advance as expected in linker script #140514

Open
@shuffle2

Description

@shuffle2

(Apologies for the vague title, there's probably a better description that should be used for someone more familiar with lld internals)

Consider this dummy code and linker script:

int a() { return 1; }
int b() { return 2; }
int c() { return 3; }
const char * d() { return "d"; }
void _start() {
    a();
    b();
    c();
    d();
}
MEMORY {
    v : ORIGIN = 0x0000000010000000, LENGTH = 0x80000000
    p : ORIGIN = 0x1000000000000000, LENGTH = 0x80000000
}
SECTIONS {
    va_pad = CONSTANT(MAXPAGESIZE);
    vaddr = ORIGIN(v);
    vaddr += va_pad;
    paddr = ORIGIN(p);
    .a vaddr : AT(paddr) { *(.text.a) } >v
    vaddr += va_pad;
    paddr += SIZEOF(.a);
    .b vaddr : AT(paddr) { *(.text.b); . += va_pad * 3; } >v
    /* on gnu ld, can use "." throughout instead of "vaddr", and don't need to explicitly add SIZEOF(.b) to virt addr here */
    vaddr += SIZEOF(.b) + va_pad;
    paddr += SIZEOF(.b);
    .c vaddr : AT(paddr) { *(.text.c) } >v
    vaddr += va_pad;
    paddr += SIZEOF(.c);
    .d vaddr : AT(paddr) { *(.text.d) } >v
}

The idea with the linker script is to have VMA and LMA increase alongside each other, however VMA can skip forward sometimes. The above form of the script works on lld and gnu ld. However, the same script also works on ld if vaddr is replaced with .. This is advantageous as it adheres to customary understanding of how . works in the linker script - as you list output sections, the value of dot increases. On lld, this seems to not be the case.

As example, this form of the script would be preferred (partially because code already exists which is written this way), and results in same output as above on gnu ld, but not lld:

SECTIONS {
    va_pad = CONSTANT(MAXPAGESIZE);
    . = ORIGIN(v);
    . += va_pad;
    paddr = ORIGIN(p);
    .a . : AT(paddr) { *(.text.a) } >v
    . += va_pad;
    paddr += SIZEOF(.a);
    .b . : AT(paddr) { *(.text.b); . += va_pad * 3; } >v
    /* on gnu ld, can use "." throughout instead of "vaddr", and don't need to explicitly add SIZEOF(.b) to virt addr here */
    . += va_pad;
    paddr += SIZEOF(.b);
    .c . : AT(paddr) { *(.text.c) } >v
    . += va_pad;
    paddr += SIZEOF(.c);
    .d . : AT(paddr) { *(.text.d) } >v
}

Testing with e.g.

clang --target=riscv64-unknown-elf -o test.elf -nostdlib -ffunction-sections -T test.ld test.c -Wl,--print-map && llvm-readelf-21 -Wa test.elf

You will notice that on lld, VMA does not advance as expected.

Desired output (first script):

Section Headers:
  [Nr] Name              Type            Address          Off    Size   ES Flg Lk Inf Al
  [ 0]                   NULL            0000000000000000 000000 000000 00      0   0  0
  [ 1] .a                PROGBITS        0000000010001000 001000 000012 00  AX  0   0  2
  [ 2] .b                PROGBITS        0000000010002000 002000 003012 00  AX  0   0  2
  [ 3] .c                PROGBITS        0000000010006012 005012 000012 00  AX  0   0  2
  [ 4] .d                PROGBITS        0000000010007012 006012 000018 00  AX  0   0  2
Program Headers:
  Type           Offset   VirtAddr           PhysAddr           FileSiz  MemSiz   Flg Align
  LOAD           0x001000 0x0000000010001000 0x1000000000000000 0x000012 0x000012 R E 0x1000
  LOAD           0x002000 0x0000000010002000 0x1000000000000012 0x003012 0x003012 R E 0x1000
  LOAD           0x005012 0x0000000010006012 0x1000000000003024 0x000012 0x000012 R E 0x1000
  LOAD           0x006012 0x0000000010007012 0x1000000000003036 0x000038 0x000038 R E 0x1000

actual output (second script, using .):

Section Headers:
  [Nr] Name              Type            Address          Off    Size   ES Flg Lk Inf Al
  [ 0]                   NULL            0000000000000000 000000 000000 00      0   0  0
  [ 1] .a                PROGBITS        0000000010000000 001000 000012 00  AX  0   0  2
  [ 2] .b                PROGBITS        0000000010000012 001012 003012 00  AX  0   0  2
  [ 3] .c                PROGBITS        0000000010003024 004024 000012 00  AX  0   0  2
  [ 4] .d                PROGBITS        0000000010003036 004036 000018 00  AX  0   0  2

Program Headers:
  Type           Offset   VirtAddr           PhysAddr           FileSiz  MemSiz   Flg Align
  LOAD           0x001000 0x0000000010000000 0x1000000000000000 0x000012 0x000012 R E 0x1000
  LOAD           0x001012 0x0000000010000012 0x1000000000000012 0x003012 0x003012 R E 0x1000
  LOAD           0x004024 0x0000000010003024 0x1000000000003024 0x000012 0x000012 R E 0x1000
  LOAD           0x004036 0x0000000010003036 0x1000000000003036 0x000038 0x000038 R E 0x1000

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions