链接的输出部分地址重叠
linked output sections overlap in address
我有这个 link 脚本 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 = .;
}
和启动代码startup.s:
.section .startup
.global _Reset
_Reset:
ldr x5, stack_top
msr sp_el0, x5
bl c_entry
b .
和 test.c 用于打印:
volatile unsigned int * const UART0DR = (unsigned int *)0x09000000;
void print_uart0(const char *s) {
while(*s != '[=12=]') { /* Loop until end of string */
*UART0DR = (unsigned int)(*s); /* Transmit char */
s++; /* Next char */
}
}
void c_entry() {
print_uart0("Hello world!\n");
}
这就是我编译和link编辑程序的方式。
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
当我对 aarch64-none-elf-objdump -D test.elf
的最终结果进行 objdump 时,我看到了这个结果:
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.
我不知道为什么_Reset 正好位于 0x10000,但是 print_uart0 和 c_entry 函数位于 0x00000000。根据 linker 脚本,.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, [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.
请注意,如果您希望代码从 0x40000000
开始,您必须在链接描述文件中指定它,方法是在 .text
部分的定义中添加 > ram
( .data
部分也是如此):
/* 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 = .;
}
结果将是:
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.
我有这个 link 脚本 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 = .;
}
和启动代码startup.s:
.section .startup
.global _Reset
_Reset:
ldr x5, stack_top
msr sp_el0, x5
bl c_entry
b .
和 test.c 用于打印:
volatile unsigned int * const UART0DR = (unsigned int *)0x09000000;
void print_uart0(const char *s) {
while(*s != '[=12=]') { /* Loop until end of string */
*UART0DR = (unsigned int)(*s); /* Transmit char */
s++; /* Next char */
}
}
void c_entry() {
print_uart0("Hello world!\n");
}
这就是我编译和link编辑程序的方式。
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
当我对 aarch64-none-elf-objdump -D test.elf
的最终结果进行 objdump 时,我看到了这个结果:
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.
我不知道为什么_Reset 正好位于 0x10000,但是 print_uart0 和 c_entry 函数位于 0x00000000。根据 linker 脚本,.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, [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.
请注意,如果您希望代码从 0x40000000
开始,您必须在链接描述文件中指定它,方法是在 .text
部分的定义中添加 > ram
( .data
部分也是如此):
/* 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 = .;
}
结果将是:
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.