为什么 Cortex-M 需要它的第一个字作为初始堆栈指针?
Why Cortex-M requires its first word as initial stack pointer?
假设我正在编写一个根本不使用堆栈的汇编语言程序。
为什么 Cortex-M 要求堆栈指针?即使我不使用它,CPU 对这个堆栈指针有什么作用(CPU 是否需要 SP 才能运行?我不认为 SP 对于 CPU 功能。) ?
我把要执行的第一条指令或程序开始的地址放在第一个地址是有意义的。
CPU 在技术上不需要堆栈指针指向 运行。但是,它确实需要堆栈指针才能正确处理中断和异常。它在服务中断之前将某些信息放在堆栈上,以便系统状态可以在中断后恢复。理论上您可能会在启动后的第一条指令中遇到异常,因此需要在开始执行之前设置 SP。
另外,你对向量table熟悉吗?通常,处理器中的前几个地址无论如何都是为向量 table 保留的。向量 table 包含硬件在处理中断和异常时引用的跳转地址。
非常欢迎您使用自己的处理器制作自己的芯片,也欢迎您许可 ARMs 产品并可能对其进行修改。
cortex-m 与全尺寸手臂的对比非常有意义。 arm 在此设计中努力使您不必拥有任何汇编语言,或者至少不需要那么多。 bootstrap 必须做两件事才能让您从事件处理程序的第一条指令(重置是一个事件)到 C 函数来处理该事件。一是栈,二是保存状态(最好把进入下一层函数前必须保存的寄存器保存在栈上)。他们现在用硬件来做这两件事。初始堆栈指针绝对不是必需的,但该地址不能改变用途,如果你不想在那里放一个堆栈地址,那就不要,但无论你放在那里什么都会加载到 r13,这就是硬件的工作方式,不要喜欢它找到另一个处理器。其次,与全尺寸臂不同,矢量现在是矢量而不是指令,所以它们是一个地址,所以你不能只把你的指令放在地址 0x4 上。现在,如果您想了解这个问题,您可以将第一条指令放在地址 0x000 上,只要地址 0x4 上的 32 位值全为零即可。所以就像一个全尺寸的手臂一样,前 32 位在这种情况下必须是一个跳跃。
当然,更明智的做法是为向量保留一点空间 table,也许您的程序集实际上想要处理一些中断(好吧,也许您不需要堆栈,因为硬件喜欢不喜欢就用栈指针写,不喜欢就找别的处理器)。然后在这个保留 space 之后放置你的第一个指令集、机器代码等等,并让重置向量指向这个地址,就像大多数其他处理器系列一样。大多数都有一个向量 table 某处并不总是地址为零,而是某处指向代码所在的其他地方。
您可以在程序前面的 8 个字节内完成此操作
.cpu cortex-m4
.thumb
.word 0
.word _start
.thumb_func
.globl _start
_start:
/* code starts here*/
或者我愿意打赌这也能奏效,而且只会花费你 4 个字节而不是 8 个字节。(从技术上讲,它会花费你 4 个或 6 个字节或 8 个字节,具体取决于你的计算方式)。
.cpu cortex-m4
.thumb
.thumb_func
.globl _start
_start:
b over
.word _start
over:
/* code continues here*/
只要分支肯定生成两条16位指令即可。
Disassembly of section .text:
00000000 <_start>:
0: e001 b.n 6 <over>
2: 00000000 andeq r0, r0, r0
00000006 <over>:
6: e7fe b.n 6 <over>
不行,不行,怎么样
.cpu cortex-m4
.thumb
.thumb_func
.globl _start
_start:
b over
.align
.word _start
over:
/* code continues here*/
b .
啊,好多了。
00000000 <_start>:
0: e002 b.n 8 <over>
2: bf00 nop
4: 00000001 andeq r0, r0, r1
00000008 <over>:
8: e7fe b.n 8 <over>
a: bf00 nop
如果你最终真的想做足够多的汇编来做一些有用的事情,那么你可能会想要堆栈,它们通过让你在重置时加载堆栈指针而不是必须编写代码来为你节省一些字节在重置处理程序中执行此操作。
组装意味着你可以做任何你想做的事,这里看起来很明显,尽管他们是为了迎合大众 (C) 让他们的生活更轻松一点,一堆,大多数时候你现在可以直接将地址放入您的 C 处理程序函数,bootstrap 可以消失。使用全尺寸和之前的手臂解决方案无法做到的事情。
假设我正在编写一个根本不使用堆栈的汇编语言程序。
为什么 Cortex-M 要求堆栈指针?即使我不使用它,CPU 对这个堆栈指针有什么作用(CPU 是否需要 SP 才能运行?我不认为 SP 对于 CPU 功能。) ?
我把要执行的第一条指令或程序开始的地址放在第一个地址是有意义的。
CPU 在技术上不需要堆栈指针指向 运行。但是,它确实需要堆栈指针才能正确处理中断和异常。它在服务中断之前将某些信息放在堆栈上,以便系统状态可以在中断后恢复。理论上您可能会在启动后的第一条指令中遇到异常,因此需要在开始执行之前设置 SP。
另外,你对向量table熟悉吗?通常,处理器中的前几个地址无论如何都是为向量 table 保留的。向量 table 包含硬件在处理中断和异常时引用的跳转地址。
非常欢迎您使用自己的处理器制作自己的芯片,也欢迎您许可 ARMs 产品并可能对其进行修改。
cortex-m 与全尺寸手臂的对比非常有意义。 arm 在此设计中努力使您不必拥有任何汇编语言,或者至少不需要那么多。 bootstrap 必须做两件事才能让您从事件处理程序的第一条指令(重置是一个事件)到 C 函数来处理该事件。一是栈,二是保存状态(最好把进入下一层函数前必须保存的寄存器保存在栈上)。他们现在用硬件来做这两件事。初始堆栈指针绝对不是必需的,但该地址不能改变用途,如果你不想在那里放一个堆栈地址,那就不要,但无论你放在那里什么都会加载到 r13,这就是硬件的工作方式,不要喜欢它找到另一个处理器。其次,与全尺寸臂不同,矢量现在是矢量而不是指令,所以它们是一个地址,所以你不能只把你的指令放在地址 0x4 上。现在,如果您想了解这个问题,您可以将第一条指令放在地址 0x000 上,只要地址 0x4 上的 32 位值全为零即可。所以就像一个全尺寸的手臂一样,前 32 位在这种情况下必须是一个跳跃。
当然,更明智的做法是为向量保留一点空间 table,也许您的程序集实际上想要处理一些中断(好吧,也许您不需要堆栈,因为硬件喜欢不喜欢就用栈指针写,不喜欢就找别的处理器)。然后在这个保留 space 之后放置你的第一个指令集、机器代码等等,并让重置向量指向这个地址,就像大多数其他处理器系列一样。大多数都有一个向量 table 某处并不总是地址为零,而是某处指向代码所在的其他地方。
您可以在程序前面的 8 个字节内完成此操作
.cpu cortex-m4
.thumb
.word 0
.word _start
.thumb_func
.globl _start
_start:
/* code starts here*/
或者我愿意打赌这也能奏效,而且只会花费你 4 个字节而不是 8 个字节。(从技术上讲,它会花费你 4 个或 6 个字节或 8 个字节,具体取决于你的计算方式)。
.cpu cortex-m4
.thumb
.thumb_func
.globl _start
_start:
b over
.word _start
over:
/* code continues here*/
只要分支肯定生成两条16位指令即可。
Disassembly of section .text:
00000000 <_start>:
0: e001 b.n 6 <over>
2: 00000000 andeq r0, r0, r0
00000006 <over>:
6: e7fe b.n 6 <over>
不行,不行,怎么样
.cpu cortex-m4
.thumb
.thumb_func
.globl _start
_start:
b over
.align
.word _start
over:
/* code continues here*/
b .
啊,好多了。
00000000 <_start>:
0: e002 b.n 8 <over>
2: bf00 nop
4: 00000001 andeq r0, r0, r1
00000008 <over>:
8: e7fe b.n 8 <over>
a: bf00 nop
如果你最终真的想做足够多的汇编来做一些有用的事情,那么你可能会想要堆栈,它们通过让你在重置时加载堆栈指针而不是必须编写代码来为你节省一些字节在重置处理程序中执行此操作。
组装意味着你可以做任何你想做的事,这里看起来很明显,尽管他们是为了迎合大众 (C) 让他们的生活更轻松一点,一堆,大多数时候你现在可以直接将地址放入您的 C 处理程序函数,bootstrap 可以消失。使用全尺寸和之前的手臂解决方案无法做到的事情。