Search code examples
gccldarm64linker-scripts

linked output sections overlap in address


I have this link script test.ld :

/* write for machine virt */
ENTRY(_Reset)

MEMORY
{
rm(rx) : ORIGIN = 0x00000000, LENGTH = 0x80000
ram (rwx) : ORIGIN = 0x40000000, LENGTH = 0x40000000
}

SECTIONS
{
 . = 0x10000;
 .startup . : { startup.o(.startup) }
 .text : { *(.text) }
 .data : { *(.data) }
 .bss : { *(.bss COMMON) }
 . = ALIGN(8);
 . = . + 0x1000; /* 4kB of stack memory */
 stack_top = .;
}

and startup code startup.s :

.section .startup
.global _Reset
_Reset:
ldr x5, stack_top
msr sp_el0, x5
bl c_entry
b .

and test.c for print :

volatile unsigned int * const UART0DR = (unsigned int *)0x09000000;

void print_uart0(const char *s) {

 while(*s != '\0') { /* Loop until end of string */
 *UART0DR = (unsigned int)(*s); /* Transmit char */
 s++; /* Next char */
 }
}

void c_entry() {
 print_uart0("Hello world!\n");
}

This is how I compiled and linked the program.

aarch64-elf-as startup.s -o startup.o
aarch64-elf-gcc -c -g test.c -o test.o
aarch64-elf-ld -T test.ld test.o startup.o -o test.elf
aarch64-elf-objcopy -O binary test.elf test.bin

When I do objdump for the final result by aarch64-none-elf-objdump -D test.elf, I see this result:

test.elf:     file format elf64-littleaarch64


Disassembly of section .startup:

0000000000010000 <_Reset>:
   10000:       58f88405        ldr     x5, 1080 <stack_top>
   10004:       d5184105        msr     sp_el0, x5
   10008:       97ffc00f        bl      44 <c_entry>
   1000c:       14000000        b       1000c <_Reset+0xc>

Disassembly of section .text:

0000000000000000 <print_uart0>:
   0:   d10043ff        sub     sp, sp, #0x10
   4:   f90007e0        str     x0, [sp, #8]
   8:   14000008        b       28 <print_uart0+0x28>
   c:   f94007e0        ldr     x0, [sp, #8]
  10:   39400001        ldrb    w1, [x0]
  14:   d2a12000        mov     x0, #0x9000000                  // #150994944
  18:   b9000001        str     w1, [x0]
  1c:   f94007e0        ldr     x0, [sp, #8]
  20:   91000400        add     x0, x0, #0x1
  24:   f90007e0        str     x0, [sp, #8]
  28:   f94007e0        ldr     x0, [sp, #8]
  2c:   39400000        ldrb    w0, [x0]
  30:   7100001f        cmp     w0, #0x0
  34:   54fffec1        b.ne    c <print_uart0+0xc>  // b.any
  38:   d503201f        nop
  3c:   910043ff        add     sp, sp, #0x10
  40:   d65f03c0        ret

0000000000000044 <c_entry>:
  44:   a9bf7bfd        stp     x29, x30, [sp, #-16]!
  48:   910003fd        mov     x29, sp
  4c:   90000000        adrp    x0, 0 <print_uart0>
  50:   9101c000        add     x0, x0, #0x70
  54:   97ffffeb        bl      0 <print_uart0>
  58:   d503201f        nop
  5c:   a8c17bfd        ldp     x29, x30, [sp], #16
  60:   d65f03c0        ret

Disassembly of section .rodata:

0000000000000068 <UART0DR>:
  68:   09000000        .inst   0x09000000 ; undefined
  6c:   00000000        .inst   0x00000000 ; undefined
  70:   6c6c6548        ldnp    d8, d25, [x10, #-320]
  74:   6f77206f        umlal2  v15.4s, v3.8h, v7.h[3]
  78:   21646c72        .inst   0x21646c72 ; undefined
  7c:   Address 0x000000000000007c is out of bounds.

I don't know why the _Reset is located rightly at 0x10000, but the print_uart0 and c_entry functions are located at 0x00000000. According to the linker script, shouldn't the .text section placed right after the .startup section?


Solution

  • _Reset is located at 0x10000 because your script explicitly requested it with the . = 0x10000; statement.

    And you probably should tell the linker that .startup should be put with, and at the beginning at, all .text related stuff:

    /* write for machine virt */
    ENTRY(_Reset)
    
    MEMORY
    {
    rm(rx) : ORIGIN = 0x00000000, LENGTH = 0x80000
    ram (rwx) : ORIGIN = 0x40000000, LENGTH = 0x40000000
    }
    
    SECTIONS
    {
     .text : {
      *(.startup)
      *(.text)
      }
     .data : { *(.data) }
     .bss : { *(.bss COMMON) }
     . = ALIGN(8);
     . = . + 0x1000; /* 4kB of stack memory */
     stack_top = .;
    }
    

    The result will be:

    test.elf:     file format elf64-littleaarch64
    
    
    Disassembly of section .text:
    
    0000000000000000 <_Reset>:
       0:   58008485    ldr x5, 1090 <stack_top>
       4:   d5184105    msr sp_el0, x5
       8:   94000014    bl  58 <c_entry>
       c:   14000000    b   c <_Reset+0xc>
    
    0000000000000010 <print_uart0>:
      10:   d10043ff    sub sp, sp, #0x10
      14:   f90007e0    str x0, [sp, #8]
      18:   14000008    b   38 <print_uart0+0x28>
      1c:   f94007e0    ldr x0, [sp, #8]
      20:   39400001    ldrb    w1, [x0]
      24:   d2a12000    mov x0, #0x9000000              // #150994944
      28:   b9000001    str w1, [x0]
      2c:   f94007e0    ldr x0, [sp, #8]
      30:   91000400    add x0, x0, #0x1
      34:   f90007e0    str x0, [sp, #8]
      38:   f94007e0    ldr x0, [sp, #8]
      3c:   39400000    ldrb    w0, [x0]
      40:   7100001f    cmp w0, #0x0
      44:   54fffec1    b.ne    1c <print_uart0+0xc>  // b.any
      48:   d503201f    nop
      4c:   d503201f    nop
      50:   910043ff    add sp, sp, #0x10
      54:   d65f03c0    ret
    
    0000000000000058 <c_entry>:
      58:   a9bf7bfd    stp x29, x30, [sp, #-16]!
      5c:   910003fd    mov x29, sp
      60:   90000000    adrp    x0, 0 <_Reset>
      64:   91020000    add x0, x0, #0x80
      68:   97ffffea    bl  10 <print_uart0>
      6c:   d503201f    nop
      70:   a8c17bfd    ldp x29, x30, [sp], #16
      74:   d65f03c0    ret
    
    Disassembly of section .rodata:
    
    0000000000000078 <UART0DR>:
      78:   09000000    .inst   0x09000000 ; undefined
      7c:   00000000    udf #0
      80:   6c6c6548    ldnp    d8, d25, [x10, #-320]
      84:   6f77206f    umlal2  v15.4s, v3.8h, v7.h[3]
      88:   21646c72    .inst   0x21646c72 ; undefined
      8c:   Address 0x000000000000008c is out of bounds.
    

    Please note that if you want your code to start from 0x40000000, you have to specify it in the linker script by adding > ram the the definition for the .textsection (same thing for the .data section):

    /* write for machine virt */
    ENTRY(_Reset)
    
    MEMORY
    {
    rm(rx) : ORIGIN = 0x00000000, LENGTH = 0x80000
    ram (rwx) : ORIGIN = 0x40000000, LENGTH = 0x40000000
    }
    
    SECTIONS
    {
     .text : {
      *(.startup)
      *(.text)
      } > ram
     .data : {
      *(.data)
      } > ram
     .bss : { *(.bss COMMON) }
     . = ALIGN(8);
     . = . + 0x1000; /* 4kB of stack memory */
     stack_top = .;
    }
    

    The result will then be:

    test.elf:     file format elf64-littleaarch64
    
    
    Disassembly of section .text:
    
    0000000040000000 <_Reset>:
        40000000:   58008485    ldr x5, 40001090 <stack_top>
        40000004:   d5184105    msr sp_el0, x5
        40000008:   94000014    bl  40000058 <c_entry>
        4000000c:   14000000    b   4000000c <_Reset+0xc>
    
    0000000040000010 <print_uart0>:
        40000010:   d10043ff    sub sp, sp, #0x10
        40000014:   f90007e0    str x0, [sp, #8]
        40000018:   14000008    b   40000038 <print_uart0+0x28>
        4000001c:   f94007e0    ldr x0, [sp, #8]
        40000020:   39400001    ldrb    w1, [x0]
        40000024:   d2a12000    mov x0, #0x9000000              // #150994944
        40000028:   b9000001    str w1, [x0]
        4000002c:   f94007e0    ldr x0, [sp, #8]
        40000030:   91000400    add x0, x0, #0x1
        40000034:   f90007e0    str x0, [sp, #8]
        40000038:   f94007e0    ldr x0, [sp, #8]
        4000003c:   39400000    ldrb    w0, [x0]
        40000040:   7100001f    cmp w0, #0x0
        40000044:   54fffec1    b.ne    4000001c <print_uart0+0xc>  // b.any
        40000048:   d503201f    nop
        4000004c:   d503201f    nop
        40000050:   910043ff    add sp, sp, #0x10
        40000054:   d65f03c0    ret
    
    0000000040000058 <c_entry>:
        40000058:   a9bf7bfd    stp x29, x30, [sp, #-16]!
        4000005c:   910003fd    mov x29, sp
        40000060:   90000000    adrp    x0, 40000000 <_Reset>
        40000064:   91020000    add x0, x0, #0x80
        40000068:   97ffffea    bl  40000010 <print_uart0>
        4000006c:   d503201f    nop
        40000070:   a8c17bfd    ldp x29, x30, [sp], #16
        40000074:   d65f03c0    ret
    
    Disassembly of section .rodata:
    
    0000000040000078 <UART0DR>:
        40000078:   09000000    .inst   0x09000000 ; undefined
        4000007c:   00000000    udf #0
        40000080:   6c6c6548    ldnp    d8, d25, [x10, #-320]
        40000084:   6f77206f    umlal2  v15.4s, v3.8h, v7.h[3]
        40000088:   21646c72    .inst   0x21646c72 ; undefined
        4000008c:   Address 0x000000004000008c is out of bounds.