链接的输出部分地址重叠

问题描述

我有这个链接脚本 test.ld :

$ sudo docker container ps -a                                                                                                                                             
CONTAINER ID        IMAGE                         COMMAND                  CREATED             STATUS                      PORTS               NAMES
d207fd2d9dd8        my_qt_cross_win:qttools     "/bin/sh -c 'qmake /…"   11 minutes ago      Exited (2) 10 minutes ago                       musing_chebyshev

和启动代码 startup.s :

/* 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 = .;
}

和 test.c 用于打印:

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

这就是我编译和链接程序的方式。

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");
}

当我对 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 的最终结果做 objdump 时,我看到这个结果:

aarch64-none-elf-objdump -D test.elf

我不知道为什么 _Reset 正确地位于 0x10000,但 print_uart0 和 c_entry 函数位于 0x00000000。根据链接描述文件,.text 部分不应该紧跟在 .startup 部分之后吗?

解决方法

_Reset 位于 0x10000,因为您的脚本使用 . = 0x10000; 语句显式请求它。

并且您可能应该告诉链接器 .startup 应该与所有 .text 相关的内容放在一起,并且在开始时:

/* 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 = .;
}

结果将是:

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,#8]
  20:   39400001    ldrb    w1,[x0]
  24:   d2a12000    mov x0,#0x9000000              // #150994944
  28:   b9000001    str w1,[x0]
  2c:   f94007e0    ldr x0,#8]
  30:   91000400    add x0,x0,#0x1
  34:   f90007e0    str x0,#8]
  38:   f94007e0    ldr x0,#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,#0x10
  54:   d65f03c0    ret

0000000000000058 <c_entry>:
  58:   a9bf7bfd    stp x29,x30,#-16]!
  5c:   910003fd    mov x29,sp
  60:   90000000    adrp    x0,0 <_Reset>
  64:   91020000    add x0,#0x80
  68:   97ffffea    bl  10 <print_uart0>
  6c:   d503201f    nop
  70:   a8c17bfd    ldp x29,[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.

请注意,如果您希望您的代码从 0x40000000 开始,您必须通过在 > ram 部分的定义中添加 .text(同样的事情.data 部分):

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

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

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

结果将是:

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,#0x10
    40000014:   f90007e0    str x0,#8]
    40000018:   14000008    b   40000038 <print_uart0+0x28>
    4000001c:   f94007e0    ldr x0,#8]
    40000020:   39400001    ldrb    w1,[x0]
    40000024:   d2a12000    mov x0,#0x9000000              // #150994944
    40000028:   b9000001    str w1,[x0]
    4000002c:   f94007e0    ldr x0,#8]
    40000030:   91000400    add x0,#0x1
    40000034:   f90007e0    str x0,#8]
    40000038:   f94007e0    ldr x0,#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,#0x10
    40000054:   d65f03c0    ret

0000000040000058 <c_entry>:
    40000058:   a9bf7bfd    stp x29,#-16]!
    4000005c:   910003fd    mov x29,sp
    40000060:   90000000    adrp    x0,40000000 <_Reset>
    40000064:   91020000    add x0,#0x80
    40000068:   97ffffea    bl  40000010 <print_uart0>
    4000006c:   d503201f    nop
    40000070:   a8c17bfd    ldp x29,#16
    40000074:   d65f03c0    ret

Disassembly of section .rodata:

0000000040000078 <UART0DR>:
    40000078:   09000000    .inst   0x09000000 ; undefined
    4000007c:   00000000    udf #0
    40000080:   6c6c6548    ldnp    d8,#-320]
    40000084:   6f77206f    umlal2  v15.4s,v7.h[3]
    40000088:   21646c72    .inst   0x21646c72 ; undefined
    4000008c:   Address 0x000000004000008c is out of bounds.