您没有提供足够的信息。使用加一而不是或一是不好的,因为当您获得正确的地址时,它会被加一修改并且是错误的。无论如何,您永远不需要做加一。这是一个非常简单的工作示例,您可以填补现有与此之间的空白。
所以.s
.thumb
.thumb_func
.global _start
_start:
stacktop: .word 0x20001000
.word reset
.word hang
.word hang
.word hang
.word hang
.word hang
.word hang
.word hang
.word hang
.word hang
.word hang
.word hang
.word hang
.word hang
.word hang
.thumb_func
reset:
@bl notmain
b hang
.thumb_func
hang: b .
so.ld
MEMORY
{
rom : ORIGIN = 0x00000000, LENGTH = 0x1000
ram : ORIGIN = 0x20000000, LENGTH = 0x1000
}
SECTIONS
{
.text : { *(.text*) } > rom
.rodata : { *(.rodata*) } > rom
.bss : { *(.bss*) } > ram
}
构建
arm-none-eabi-as so.s -o so.o
arm-none-eabi-ld -o so.elf -T so.ld so.o
arm-none-eabi-objdump -D so.elf > so.list
arm-none-eabi-objcopy so.elf so.bin -O binary
arm-whatever-linux-whatever 也可以...
00000000 <_start>:
0: 20001000
4: 00000041
8: 00000043
c: 00000043
10: 00000043
14: 00000043
18: 00000043
1c: 00000043
20: 00000043
24: 00000043
28: 00000043
2c: 00000043
30: 00000043
34: 00000043
38: 00000043
3c: 00000043
00000040 <reset>:
40: e7ff b.n 42 <hang>
00000042 <hang>:
42: e7fe b.n 42 <hang>
将 _start 移到最前面并不是使它与零对齐的原因,在 ld 命令行上首先使用 so.o 就是这样做的,因为没有其他对象,它是命令行上唯一的对象,但是如果链接器脚本没有调用特定的文件名,然后它属于命令行排序。对于这种工作,你不关心 _start 在哪里,你关心向量表在哪里。入口点由芯片定义,您不是从使用 _start 作为入口点的操作系统加载这些程序。
.thumb_func 是告诉汇编程序下一个标签是一个函数的最便宜的方法(因此地址与 1 或),您可以使用更详细的语法来声明一个过程或函数,检查程序集C 编译函数的输出,以查看更详细的执行方式并选择您喜欢的方式。
.thumb 与 .code 16 应该可以互换。最终,如果使用 cortex-m3 或 m4 或(更大的数字,不是 cortex-m0 或 m1),您将需要指定
.cpu cortex-m3
或
-mcpu=cortex-m3
在 gas 和 gcc 命令行上。
似乎您的链接器脚本移动了 _start,或者您的二进制文件中有其他内容您没有向我们展示,或者您可能有多个文件来创建您向我们展示的内容,但不知道您没有提供足够的信息。我们应该能够接受您提供的内容并能够重复...
编辑
对于一个使用 cortex-m 芯片的特定品牌,用户闪存实际上位于 0x08000000,当您以该模式启动时,他们将其映射到 0x00000000。窗口不知道有多大,所以你可以为 .text 地址空间为 0x00000000 或 0x08000000 构建它,这显示了更改链接描述文件如何更改输出。
flash.s
.thumb
.thumb_func
.global _start
_start:
stacktop: .word 0x20001000
.word reset
.word hang @ NMI
.word hang @ HardFault
.word hang @ MemManage
.word hang @ BusFault
.word hang @ UsageFault
.word hang @ 7
.word hang @ 8
.word hang @ 9
.word hang @ 10
.word hang @ SVCall
.word hang @ DebugMonitor
.word hang @ Reserved
.word hang @ PendSV
.word hang @ SysTick
.word hang @ External interrupt 0
.word hang @ External interrupt 1
.word hang @ External interrupt 2
.thumb_func
reset:
bl notmain
b hang
.thumb_func
hang: b .
.thumb_func
.globl dummy
dummy:
bx lr
notmain.c
extern void dummy ( unsigned int );
void notmain ( void )
{
unsigned int ra;
for(ra=0;ra<100;ra++) dummy(ra);
}
flash.ld
MEMORY
{
rom : ORIGIN = 0x08000000, LENGTH = 0x1000
ram : ORIGIN = 0x20000000, LENGTH = 0x1000
}
SECTIONS
{
.text : { *(.text*) } > rom
.rodata : { *(.rodata*) } > rom
.bss : { *(.bss*) } > ram
}
构建
arm-none-eabi-gcc -Wall -O2 -nostdlib -nostartfiles -ffreestanding -mcpu=cortex-m0 -mthumb -c notmain.c -o notmain.o
arm-none-eabi-ld -o notmain.elf -T flash.ld flash.o notmain.o
arm-none-eabi-objdump -D notmain.elf > notmain.list
arm-none-eabi-objcopy notmain.elf notmain.bin -O binary
此外,它还包含一些链接的 C 代码。
因为 flash.o 在链接器命令行上位于 notmain.o 之前,所以它首先进入 .text(使用这种通用的链接器脚本)。
08000000 <_start>:
8000000: 20001000 andcs r1, r0, r0
8000004: 0800004d stmdaeq r0, {r0, r2, r3, r6}
8000008: 08000053 stmdaeq r0, {r0, r1, r4, r6}
800000c: 08000053 stmdaeq r0, {r0, r1, r4, r6}
8000010: 08000053 stmdaeq r0, {r0, r1, r4, r6}
8000014: 08000053 stmdaeq r0, {r0, r1, r4, r6}
8000018: 08000053 stmdaeq r0, {r0, r1, r4, r6}
800001c: 08000053 stmdaeq r0, {r0, r1, r4, r6}
8000020: 08000053 stmdaeq r0, {r0, r1, r4, r6}
8000024: 08000053 stmdaeq r0, {r0, r1, r4, r6}
8000028: 08000053 stmdaeq r0, {r0, r1, r4, r6}
请注意,.text 现在从链接描述文件的 0x08000000 开始。这很好,因为它会被这个硬件映射到 0x00000000,它将读取地址 0x00000004 处的值,即 0x0800004d 并跳转到 0x0800004c
0800004c <reset>:
800004c: f000 f804 bl 8000058 <notmain>
8000050: e7ff b.n 8000052 <hang>
08000052 <hang>:
8000052: e7fe b.n 8000052 <hang>
08000054 <dummy>:
8000054: 4770 bx lr
...
08000058 <notmain>:
8000058: b510 push {r4, lr}
800005a: 2400 movs r4, #0
800005c: 1c20 adds r0, r4, #0
800005e: 3401 adds r4, #1
8000060: f7ff fff8 bl 8000054 <dummy>
8000064: 2c64 cmp r4, #100 ; 0x64
8000066: d1f9 bne.n 800005c <notmain+0x4>
8000068: bd10 pop {r4, pc}
800006a: 46c0 nop ; (mov r8, r8)
现在,如果您删除 hang 和 dummy 前面的 .thumb_func,那么使用 dummy 我们很幸运,它可以解决
8000060: f7ff fff8 bl 8000054
因为使用了分支链接,所以假设是相同的模式,但是 hang 前面的那个导致向量表错误
08000000 <_start>:
8000000: 20001000 andcs r1, r0, r0
8000004: 0800004d stmdaeq r0, {r0, r2, r3, r6}
8000008: 08000052 stmdaeq r0, {r1, r4, r6}
800000c: 08000052 stmdaeq r0, {r1, r4, r6}
8000010: 08000052 stmdaeq r0, {r1, r4, r6}
在 gcc 命令行上使用 -c 并将我自己与我自己的链接器脚本链接和/或使用 -Xlinker gcc 选项为链接器提供链接器脚本(并注意 gcc 命令行上的文件排序)你可以控制您必须在此处执行的链接器脚本,因为在我看来,您的目标是针对 cortex-m 处理器而不是编写 arm linux 应用程序。可以对编译器和汇编器进行一般处理,但您希望避免使用默认引导程序(gnu 世界中的 crt0.o)和链接器脚本,除非您的 gnu 构建直接针对您的特定平台(默认适用于您的平台)。如果需要,如果您使用 C 库,则可以在构建 C 库时执行此操作。使用裸机,您没有一个系统来调用如此多的 C 库崩溃。