还有无数其他网站和示例。数以千计甚至数万。有众所周知的c库,其中包含链接程序脚本和boostrap代码,特别是newlib和glibc,但您还可以找到其他库。用C引导C毫无意义。
您的问题已得到回答,您正在尝试对可能不完全精确的事物进行精确比较,它可能不会在已知边界上开始,也可能不在已知边界上结束。因此,您可以做不到的事情,但是如果代码无法通过精确的比较工作,则意味着您将.bss归零到下一节,这可能会或可能不会导致不好的事情发生,因此只需替换为less than isnt解决方案。
TL; DR就可以了。您无需使用该语言来引导语言,可以肯定地摆脱它,但是这样做时您会玩火。如果您只是在学习如何执行此操作,则需要保持谨慎的态度,而不是傻瓜运气或尚未发现的事实。
链接描述文件和引导程序代码之间有着非常密切的关系,它们是已婚的,并在髋关节处连接在一起,如果没有其他组件,您将无法发展,从而导致大量失败。不幸的是,链接器脚本是由链接器定义的,而汇编语言是由汇编器定义的,因此当您更改工具链时,期望它们都必须重新编写。为什么要使用汇编语言?它不需要引导程序,通常是编译语言。如果您不想限制对语言的使用,C会这样做,这是从一个非常简单的东西开始的,它只具有最低的工具链特定要求,您不要假设.bss变量为零(如果从未使用该语言初始化变量,则代码的可读性较低) ,请尝试避免这种情况,因为局部变量不是正确的,因此必须在使用时加以注意。那么,为什么我们要谈论.bss和.data ???(全局变量对此级别的工作很有用,但这是另一个主题)。简单解决方案的另一条规则是不要在声明中初始化变量,而要在代码中完成。是的,会消耗更多的闪存,通常您有很多闪存,并非所有变量都使用常量进行初始化,反而最终会消耗指令。
从cortex-m设计中可以看出,他们可能一直认为根本没有引导程序代码,因此没有.data和.bss支持。大多数使用全局变量的人不能没有这样的生活:
我可以使用gnu工具链为所有cortex-ms制作一个更小巧但最小的功能示例,我不记得可以通过当前的9.xx或更高版本从5.xx开始,还是在3左右切换链接器脚本。 xx或4.xx,因为我学到了更多,而gnu改变了一些使我的第一个摔坏的东西。
引导程序:
.thumb
.thumb_func
.global _start
_start:
stacktop: .word 0x20000800
.word reset
.word done
.word done
.word done
.thumb_func
reset:
bl centry
b done
.thumb_func
done: b .
.thumb_func
.globl bounce
bounce:
bx lr
C代码的入口点:
void bounce ( unsigned int );
unsigned int a;
int centry ( void )
{
a = 7;
bounce(a);
return(0);
}
链接描述文件。
MEMORY
{
rom : ORIGIN = 0x00000000, LENGTH = 0x1000
ram : ORIGIN = 0x20000000, LENGTH = 0x1000
}
SECTIONS
{
.text : { *(.text*) } > rom
.rodata : { *(.rodata*) } > rom
.bss : { *(.bss*) } > ram
}
所有这些可能都较小,并且仍然可以使用,在这里添加了一些额外的东西只是为了看看它在起作用。
优化的构建和链接。
00000000 <_start>:
0: 20001000
4: 00000015
8: 0000001b
c: 0000001b
10: 0000001b
00000014 <reset>:
14: f000 f804 bl 20 <centry>
18: e7ff b.n 1a <done>
0000001a <done>:
1a: e7fe b.n 1a <done>
0000001c <bounce>:
1c: 4770 bx lr
...
00000020 <centry>:
20: 2207 movs r2, #7
22: b510 push {r4, lr}
24: 4b04 ldr r3, [pc, #16] ; (38 <centry+0x18>)
26: 2007 movs r0, #7
28: 601a str r2, [r3, #0]
2a: f7ff fff7 bl 1c <bounce>
2e: 2000 movs r0, #0
30: bc10 pop {r4}
32: bc02 pop {r1}
34: 4708 bx r1
36: 46c0 nop ; (mov r8, r8)
38: 20000000 andcs r0, r0, r0
Disassembly of section .bss:
20000000 <a>:
20000000: 00000000 andeq r0, r0, r0
对于某些供应商,您希望使用0x08000000或0x01000000或其他类似的地址,因为闪存已映射到那里并在某些引导模式下镜像到0x00000000。有些仅在0x00000000处镜像了太多闪存,因此您希望向量表指向应用程序闪存空间不为零。由于它是基于向量表的,因此所有方法都有效。
首先请注意,cortex-ms是仅使用拇指的机器,无论出于何种原因,它们都强制使用了拇指函数地址,这意味着lsbit是奇数。知道您的工具后,.thumb_func指令会告诉gnu汇编程序下一个标签是thumb函数地址。在表中做+1事情会导致失败,不要被诱惑去做,正确地做。还有其他gnu汇编器方法来声明函数,这是最小的方法。
4: 00000015
8: 0000001b
c: 0000001b
10: 0000001b
如果您没有正确设置向量表,它将无法启动。
可以说,只需要堆栈指针向量(如果您希望自己在代码中设置堆栈指针,则可以在其中放置任何内容)和复位向量。我没有特殊原因就把四个放在这里。通常放16,但想简化此示例。
那么,C引导程序需要做的最少工作是什么?1.设置堆栈指针2.零.bss 3.复制.data 4.分支到或调用C入口点
C入口点通常称为main()。但是某些工具链会看到main()并向代码中添加额外的垃圾。我故意使用其他名称。YMMV。
如果全部基于ram,则不需要.data的副本。作为cortex-m微控制器,在技术上是可行的,但可能性不大,因此需要复制数据.....如果有数据。
我的第一个示例和编码风格是不依赖于.data或.bss,如本示例所示。Arm照顾了堆栈指针,因此剩下的唯一事情就是调用入口点。我喜欢这样,以便切入点可以返回,许多人认为您永远都不要这样做。您可以这样做:
.thumb_func
.global _start
_start:
stacktop: .word 0x20000800
.word centry
.word done
.word done
.word done
而不是从centry()返回,并且没有重置处理程序代码。
00000020 <centry>:
20: 2207 movs r2, #7
22: b510 push {r4, lr}
24: 4b04 ldr r3, [pc, #16] ; (38 <centry+0x18>)
26: 2007 movs r0, #7
28: 601a str r2, [r3, #0]
2a: f7ff fff7 bl 1c <bounce>
2e: 2000 movs r0, #0
30: bc10 pop {r4}
32: bc02 pop {r1}
34: 4708 bx r1
36: 46c0 nop ; (mov r8, r8)
38: 20000000 andcs r0, r0, r0
Disassembly of section .bss:
20000000 <a>:
20000000: 00000000
链接器已将内容放到我们要求的位置。总体而言,我们有一个功能齐全的程序。
因此,首先要处理链接描述文件:
MEMORY
{
bob : ORIGIN = 0x00000000, LENGTH = 0x1000
ted : ORIGIN = 0x20000000, LENGTH = 0x1000
}
SECTIONS
{
.text : { *(.text*) } > bob
.rodata : { *(.rodata*) } > bob
__data_rom_start__ = .;
.data : {
__data_start__ = .;
*(.data*)
} > ted AT > bob
__data_end__ = .;
__data_size__ = __data_end__ - __data_start__;
.bss : {
__bss_start__ = .;
*(.bss*)
} > ted
__bss_end__ = .;
__bss_size__ = __bss_end__ - __bss_start__;
}
强调名称rom和ram没有意义,它们仅连接部分之间链接器的点。
.thumb
.thumb_func
.global _start
_start:
stacktop: .word 0x20000800
.word reset
.word done
.word done
.word done
.thumb_func
reset:
bl centry
b done
.thumb_func
done: b .
.thumb_func
.globl bounce
bounce:
bx lr
.align
.word __data_rom_start__
.word __data_start__
.word __data_end__
.word __data_size__
添加一些项目,以便我们可以看到工具做了什么
void bounce ( unsigned int );
unsigned int a;
unsigned int b=4;
unsigned char c=5;
int centry ( void )
{
a = 7;
bounce(a);
return(0);
}
在这些部分中添加一些项目。并得到
Disassembly of section .text:
00000000 <_start>:
0: 20000800 andcs r0, r0, r0, lsl #16
4: 00000015 andeq r0, r0, r5, lsl r0
8: 0000001b andeq r0, r0, r11, lsl r0
c: 0000001b andeq r0, r0, r11, lsl r0
10: 0000001b andeq r0, r0, r11, lsl r0
00000014 <reset>:
14: f000 f80c bl 30 <centry>
18: e7ff b.n 1a <done>
0000001a <done>:
1a: e7fe b.n 1a <done>
0000001c <bounce>:
1c: 4770 bx lr
1e: 46c0 nop ; (mov r8, r8)
20: 0000004c andeq r0, r0, r12, asr #32
24: 20000000 andcs r0, r0, r0
28: 20000008 andcs r0, r0, r8
2c: 00000008 andeq r0, r0, r8
00000030 <centry>:
30: 2207 movs r2, #7
32: b510 push {r4, lr}
34: 4b04 ldr r3, [pc, #16] ; (48 <centry+0x18>)
36: 2007 movs r0, #7
38: 601a str r2, [r3, #0]
3a: f7ff ffef bl 1c <bounce>
3e: 2000 movs r0, #0
40: bc10 pop {r4}
42: bc02 pop {r1}
44: 4708 bx r1
46: 46c0 nop ; (mov r8, r8)
48: 20000008 andcs r0, r0, r8
Disassembly of section .data:
20000000 <c>:
20000000: 00000005 andeq r0, r0, r5
20000004 <b>:
20000004: 00000004 andeq r0, r0, r4
Disassembly of section .bss:
20000008 <a>:
20000008: 00000000 andeq r0, r0, r0
这是我们在该实验中寻找的东西(请注意没有理由真正加载或运行任何代码...知道您的工具,学习它们)
1c: 4770 bx lr
1e: 46c0 nop ; (mov r8, r8)
20: 0000004c andeq r0, r0, r12, asr #32
24: 20000000 andcs r0, r0, r0
28: 20000008 andcs r0, r0, r8
2c: 00000008 andeq r0, r0, r8
因此,我们在这里了解到的是,变量的位置在gnu链接器脚本中非常敏感。请注意data_rom_start与data_start的位置,但是为什么data_end起作用?病让你知道。已经理解为什么人们可能不想要弄乱链接描述脚本而只是简单编程...
因此,我们在这里了解到的另一件事是,链接器为我们对齐了data_rom_start,因此我们不需要ALIGN(4)。我们是否应该假设那将一直有效?
还要注意,在到达的过程中它填充了5个字节的.data,但是却将其填充了8个字节。没有任何ALIGN(),我们已经可以使用单词进行复制了。根据我们今天在计算机上使用此工具链所看到的情况,过去和将来是否可能如此?谁知道,即使ALIGN需要定期检查以确认某些新版本没有损坏,他们也会不时这样做。
为了安全起见,我们从该实验继续进行下去。
MEMORY
{
bob : ORIGIN = 0x00000000, LENGTH = 0x1000
ted : ORIGIN = 0x20000000, LENGTH = 0x1000
}
SECTIONS
{
.text : { *(.text*) } > bob
.rodata : { *(.rodata*) } > bob
. = ALIGN(4);
__data_rom_start__ = .;
.data : {
__data_start__ = .;
*(.data*)
. = ALIGN(4);
__data_end__ = .;
} > ted AT > bob
__data_size__ = __data_end__ - __data_start__;
. = ALIGN(4);
.bss : {
__bss_start__ = .;
*(.bss*)
. = ALIGN(4);
__bss_end__ = .;
} > ted
__bss_size__ = __bss_end__ - __bss_start__;
}
在内部移动末端以与其他人的行为保持一致。并没有改变它:
0000001c <bounce>:
1c: 4770 bx lr
1e: 46c0 nop ; (mov r8, r8)
20: 0000004c andeq r0, r0, r12, asr #32
24: 20000000 andcs r0, r0, r0
28: 20000008 andcs r0, r0, r8
2c: 00000008 andeq r0, r0, r8
另一项快速测试:
.globl bounce
bounce:
nop
bx lr
给予
0000001c <bounce>:
1c: 46c0 nop ; (mov r8, r8)
1e: 4770 bx lr
20: 0000004c andeq r0, r0, r12, asr #32
24: 20000000 andcs r0, r0, r0
28: 20000008 andcs r0, r0, r8
2c: 00000008 andeq r0, r0, r8
无需在弹跳和.align之间填充
哦,对了,我现在记得为什么我不把_end__放在里面。因为它不起作用。
MEMORY
{
bob : ORIGIN = 0x00000000, LENGTH = 0x1000
ted : ORIGIN = 0x20000000, LENGTH = 0x1000
}
SECTIONS
{
.text : { *(.text*) } > bob
.rodata : { *(.rodata*) } > bob
. = ALIGN(4);
__data_rom_start__ = .;
.data : {
__data_start__ = .;
*(.data*)
} > ted AT > bob
. = ALIGN(4);
__data_end__ = .;
__data_size__ = __data_end__ - __data_start__;
. = ALIGN(4);
.bss : {
__bss_start__ = .;
*(.bss*)
} > ted
. = ALIGN(4);
__bss_end__ = .;
__bss_size__ = __bss_end__ - __bss_start__;
}
一些简单但可移植的代码与该链接描述文件结合
.thumb
.thumb_func
.global _start
_start:
stacktop: .word 0x20000800
.word reset
.word done
.word done
.word done
.thumb_func
reset:
ldr r0,blen
cmp r0,#0
beq bss_zero_done
ldr r1,bstart
mov r2,#0
bss_zero:
stmia r1!,{r2}
sub r0,#4
bne bss_zero
bss_zero_done:
ldr r0,dlen
cmp r0,#0
beq data_copy_done
ldr r1,rstart
ldr r2,dstart
data_copy:
ldmia r1!,{r3}
stmia r2!,{r3}
sub r0,#4
bne data_copy
data_copy_done:
bl centry
b done
.thumb_func
done: b .
.thumb_func
.globl bounce
bounce:
nop
bx lr
.align
bstart: .word __bss_start__
blen: .word __bss_size__
rstart: .word __data_rom_start__
dstart: .word __data_start__
dlen: .word __data_size__
给予
Disassembly of section .text:
00000000 <_start>:
0: 20000800 andcs r0, r0, r0, lsl #16
4: 00000015 andeq r0, r0, r5, lsl r0
8: 0000003d andeq r0, r0, sp, lsr r0
c: 0000003d andeq r0, r0, sp, lsr r0
10: 0000003d andeq r0, r0, sp, lsr r0
00000014 <reset>:
14: 480c ldr r0, [pc, #48] ; (48 <blen>)
16: 2800 cmp r0, #0
18: d004 beq.n 24 <bss_zero_done>
1a: 490a ldr r1, [pc, #40] ; (44 <bstart>)
1c: 2200 movs r2, #0
0000001e <bss_zero>:
1e: c104 stmia r1!, {r2}
20: 3804 subs r0, #4
22: d1fc bne.n 1e <bss_zero>
00000024 <bss_zero_done>:
24: 480b ldr r0, [pc, #44] ; (54 <dlen>)
26: 2800 cmp r0, #0
28: d005 beq.n 36 <data_copy_done>
2a: 4908 ldr r1, [pc, #32] ; (4c <rstart>)
2c: 4a08 ldr r2, [pc, #32] ; (50 <dstart>)
0000002e <data_copy>:
2e: c908 ldmia r1!, {r3}
30: c208 stmia r2!, {r3}
32: 3804 subs r0, #4
34: d1fb bne.n 2e <data_copy>
00000036 <data_copy_done>:
36: f000 f80f bl 58 <centry>
3a: e7ff b.n 3c <done>
0000003c <done>:
3c: e7fe b.n 3c <done>
0000003e <bounce>:
3e: 46c0 nop ; (mov r8, r8)
40: 4770 bx lr
42: 46c0 nop ; (mov r8, r8)
00000044 <bstart>:
44: 20000008 andcs r0, r0, r8
00000048 <blen>:
48: 00000004 andeq r0, r0, r4
0000004c <rstart>:
4c: 00000074 andeq r0, r0, r4, ror r0
00000050 <dstart>:
50: 20000000 andcs r0, r0, r0
00000054 <dlen>:
54: 00000008 andeq r0, r0, r8
00000058 <centry>:
58: 2207 movs r2, #7
5a: b510 push {r4, lr}
5c: 4b04 ldr r3, [pc, #16] ; (70 <centry+0x18>)
5e: 2007 movs r0, #7
60: 601a str r2, [r3, #0]
62: f7ff ffec bl 3e <bounce>
66: 2000 movs r0, #0
68: bc10 pop {r4}
6a: bc02 pop {r1}
6c: 4708 bx r1
6e: 46c0 nop ; (mov r8, r8)
70: 20000008 andcs r0, r0, r8
Disassembly of section .data:
20000000 <c>:
20000000: 00000005 andeq r0, r0, r5
20000004 <b>:
20000004: 00000004 andeq r0, r0, r4
Disassembly of section .bss:
20000008 <a>:
20000008: 00000000 andeq r0, r0, r0
我们可以在那里停下来或继续前进。如果我们以与链接脚本相同的顺序进行初始化,那么我们可以进入下一件事就可以了,因为我们还没有到达那里。和stm / ldm仅要求/希望使用字对齐地址,因此,如果更改为:
ldr r0,blen
cmp r0,#0
beq bss_zero_done
ldr r1,bstart
mov r2,#0
mov r3,#0
mov r4,#0
mov r5,#0
bss_zero:
stmia r1!,{r2,r3,r4,r5}
sub r0,#16
ble bss_zero
bss_zero_done:
首先在链接描述文件中使用bss,是的,您想要ble而不是bls。
Disassembly of section .text:
00000000 <_start>:
0: 20000800 andcs r0, r0, r0, lsl #16
4: 00000015 andeq r0, r0, r5, lsl r0
8: 00000043 andeq r0, r0, r3, asr #32
c: 00000043 andeq r0, r0, r3, asr #32
10: 00000043 andeq r0, r0, r3, asr #32
00000014 <reset>:
14: 480d ldr r0, [pc, #52] ; (4c <blen>)
16: 2800 cmp r0, #0
18: d007 beq.n 2a <bss_zero_done>
1a: 490b ldr r1, [pc, #44] ; (48 <bstart>)
1c: 2200 movs r2, #0
1e: 2300 movs r3, #0
20: 2400 movs r4, #0
22: 2500 movs r5, #0
00000024 <bss_zero>:
24: c13c stmia r1!, {r2, r3, r4, r5}
26: 3804 subs r0, #4
28: ddfc ble.n 24 <bss_zero>
0000002a <bss_zero_done>:
2a: 480b ldr r0, [pc, #44] ; (58 <dlen>)
2c: 2800 cmp r0, #0
2e: d005 beq.n 3c <data_copy_done>
30: 4907 ldr r1, [pc, #28] ; (50 <rstart>)
32: 4a08 ldr r2, [pc, #32] ; (54 <dstart>)
00000034 <data_copy>:
34: c978 ldmia r1!, {r3, r4, r5, r6}
36: c278 stmia r2!, {r3, r4, r5, r6}
38: 3810 subs r0, #16
3a: ddfb ble.n 34 <data_copy>
0000003c <data_copy_done>:
3c: f000 f80e bl 5c <centry>
40: e7ff b.n 42 <done>
00000042 <done>:
42: e7fe b.n 42 <done>
00000044 <bounce>:
44: 46c0 nop ; (mov r8, r8)
46: 4770 bx lr
00000048 <bstart>:
48: 20000000 andcs r0, r0, r0
0000004c <blen>:
4c: 00000004 andeq r0, r0, r4
00000050 <rstart>:
50: 20000004 andcs r0, r0, r4
00000054 <dstart>:
54: 20000004 andcs r0, r0, r4
00000058 <dlen>:
58: 00000008 andeq r0, r0, r8
0000005c <centry>:
5c: 2207 movs r2, #7
5e: b510 push {r4, lr}
60: 4b04 ldr r3, [pc, #16] ; (74 <centry+0x18>)
62: 2007 movs r0, #7
64: 601a str r2, [r3, #0]
66: f7ff ffed bl 44 <bounce>
6a: 2000 movs r0, #0
6c: bc10 pop {r4}
6e: bc02 pop {r1}
70: 4708 bx r1
72: 46c0 nop ; (mov r8, r8)
74: 20000000 andcs r0, r0, r0
Disassembly of section .bss:
20000000 <a>:
20000000: 00000000 andeq r0, r0, r0
Disassembly of section .data:
20000004 <c>:
20000004: 00000005 andeq r0, r0, r5
20000008 <b>:
20000008: 00000004 andeq r0, r0, r4
这些循环会更快。现在,我不知道ahb总线是否可以为64位宽,但是对于全尺寸的臂,您将需要在64位边界上对齐这些东西。在32位边界而不是64位边界上的四个寄存器ldm / stm变成三个独立的总线事务,其中在64位边界上对齐的是单个事务,每个指令节省几个时钟。
因为我们正在做裸机,并且我们全权负责我们可以首先说bss的所有内容,然后对数据进行处理,然后如果有堆,那么堆栈会从上到下增长,所以如果我们将bss归零并溢出,只要我们从正确的地方,我们还没有使用该内存。然后我们将.data复制过来,并可能溢出到正常的堆中,无论堆是否存在,堆栈是否有足够的空间,因此我们不会踩任何人/任何东西(只要我们确保在链接程序脚本中这样做即可)。如果有问题,请增大ALIGN()的大小,以使我们始终将这些填充物放置在我们的空间内。
所以我的简单解决方案是接受还是放弃。欢迎修复所有错误,我没有在硬件或模拟器上运行此错误...
MEMORY
{
bob : ORIGIN = 0x00000000, LENGTH = 0x1000
ted : ORIGIN = 0x20000000, LENGTH = 0x1000
}
SECTIONS
{
.text : { *(.text*) } > bob
.rodata : { *(.rodata*) } > bob
. = ALIGN(8);
.bss : {
__bss_start__ = .;
*(.bss*)
} > ted
. = ALIGN(4);
__bss_end__ = .;
__bss_size__ = __bss_end__ - __bss_start__;
. = ALIGN(8);
__data_rom_start__ = .;
.data : {
__data_start__ = .;
*(.data*)
} > ted AT > bob
. = ALIGN(4);
__data_end__ = .;
__data_size__ = __data_end__ - __data_start__;
}
.thumb
.thumb_func
.global _start
_start:
stacktop: .word 0x20000800
.word reset
.word done
.word done
.word done
.thumb_func
reset:
ldr r0,blen
cmp r0,#0
beq bss_zero_done
ldr r1,bstart
mov r2,#0
mov r3,#0
mov r4,#0
mov r5,#0
bss_zero:
stmia r1!,{r2,r3,r4,r5}
sub r0,#16
ble bss_zero
bss_zero_done:
ldr r0,dlen
cmp r0,#0
beq data_copy_done
ldr r1,rstart
ldr r2,dstart
data_copy:
ldmia r1!,{r3,r4,r5,r6}
stmia r2!,{r3,r4,r5,r6}
sub r0,#16
ble data_copy
data_copy_done:
bl centry
b done
.thumb_func
done: b .
.thumb_func
.globl bounce
bounce:
nop
bx lr
.align
bstart: .word __bss_start__
blen: .word __bss_size__
rstart: .word __data_rom_start__
dstart: .word __data_start__
dlen: .word __data_size__
void bounce ( unsigned int );
unsigned int a;
unsigned int b=4;
unsigned char c=5;
int centry ( void )
{
a = 7;
bounce(a);
return(0);
}
arm-none-eabi-as --warn --fatal-warnings flash.s -o flash.o
arm-none-eabi-ld -o hello.elf -T flash.ld flash.o centry.o
arm-none-eabi-objdump -D hello.elf > hello.list
arm-none-eabi-objcopy hello.elf hello.bin -O binary
将它们放在一起,您将获得:
Disassembly of section .text:
00000000 <_start>:
0: 20000800 andcs r0, r0, r0, lsl #16
4: 00000015 andeq r0, r0, r5, lsl r0
8: 00000043 andeq r0, r0, r3, asr #32
c: 00000043 andeq r0, r0, r3, asr #32
10: 00000043 andeq r0, r0, r3, asr #32
00000014 <reset>:
14: 480d ldr r0, [pc, #52] ; (4c <blen>)
16: 2800 cmp r0, #0
18: d007 beq.n 2a <bss_zero_done>
1a: 490b ldr r1, [pc, #44] ; (48 <bstart>)
1c: 2200 movs r2, #0
1e: 2300 movs r3, #0
20: 2400 movs r4, #0
22: 2500 movs r5, #0
00000024 <bss_zero>:
24: c13c stmia r1!, {r2, r3, r4, r5}
26: 3810 subs r0, #16
28: ddfc ble.n 24 <bss_zero>
0000002a <bss_zero_done>:
2a: 480b ldr r0, [pc, #44] ; (58 <dlen>)
2c: 2800 cmp r0, #0
2e: d005 beq.n 3c <data_copy_done>
30: 4907 ldr r1, [pc, #28] ; (50 <rstart>)
32: 4a08 ldr r2, [pc, #32] ; (54 <dstart>)
00000034 <data_copy>:
34: c978 ldmia r1!, {r3, r4, r5, r6}
36: c278 stmia r2!, {r3, r4, r5, r6}
38: 3810 subs r0, #16
3a: ddfb ble.n 34 <data_copy>
0000003c <data_copy_done>:
3c: f000 f80e bl 5c <centry>
40: e7ff b.n 42 <done>
00000042 <done>:
42: e7fe b.n 42 <done>
00000044 <bounce>:
44: 46c0 nop ; (mov r8, r8)
46: 4770 bx lr
00000048 <bstart>:
48: 20000000 andcs r0, r0, r0
0000004c <blen>:
4c: 00000004 andeq r0, r0, r4
00000050 <rstart>:
50: 20000008 andcs r0, r0, r8
00000054 <dstart>:
54: 20000004 andcs r0, r0, r4
00000058 <dlen>:
58: 00000008 andeq r0, r0, r8
0000005c <centry>:
5c: 2207 movs r2, #7
5e: b510 push {r4, lr}
60: 4b04 ldr r3, [pc, #16] ; (74 <centry+0x18>)
62: 2007 movs r0, #7
64: 601a str r2, [r3, #0]
66: f7ff ffed bl 44 <bounce>
6a: 2000 movs r0, #0
6c: bc10 pop {r4}
6e: bc02 pop {r1}
70: 4708 bx r1
72: 46c0 nop ; (mov r8, r8)
74: 20000000 andcs r0, r0, r0
Disassembly of section .bss:
20000000 <a>:
20000000: 00000000 andeq r0, r0, r0
Disassembly of section .data:
20000004 <c>:
20000004: 00000005 andeq r0, r0, r5
20000008 <b>:
20000008: 00000004 andeq r0, r0, r4
请注意,这与arm-none-eabi-和arm-linux-gnueabi以及其他变体一起使用,因为没有使用酥油神器。
当您环顾四周时,您会发现人们会在他们的链接描述文件中疯狂地用酥油神仙的东西,巨大的厨房沉没物等疯狂。最好只是知道如何做(或者更好地掌握工具,以便您可以控制发生的事情),而不是依靠别人的东西而不知道它会在哪里破裂,因为您不了解和/或想研究它。
通常,不要以您希望使用较少引导程序的简单语言来引导具有相同语言的语言(在这种意义上,引导程序是指运行的代码未使用相同的编译器编译编译器)。这就是为什么C是在汇编中完成的,它没有引导程序要求,您只需从复位后的第一条指令开始即可。JAVA,请确保您可以用C编写jvm并使用asm引导该C,然后如果要使用C来引导该JAVA,但也可以在C中执行该JAVA。
因为我们在这些复制循环上控制假设,所以从定义上讲,它们比手动调整的memcpy / memset更紧密,更干净。
注意您的另一个问题是:
unsigned int * bss_start_p = &_BSS_START;
unsigned int * bss_end_p = &_BSS_END;
如果这些是局部的,没问题,如果这些是全局的,则需要首先初始化.data才能使它们工作,如果尝试使用该技巧来执行.data,则您将失败。局部变量,可以正常工作。如果您出于某种原因决定创建静态本地人(我喜欢称它们为本地全局人),那么您又会遇到麻烦。每次您在声明中进行赋值时,您都应该考虑一下它,它是如何实现的以及它是安全/合理的。每次当您声明一个未声明的变量为零时,要进行相同的处理,如果一个局部变量不被假定为零,则如果它是全局变量,则为零。如果您从不认为它们为零,那么您就不必担心。