内容主要来自<<M3内核权威指南>>
汇编程序中的最低有效位(Least Significant Bit)。LSB是二进制数中最右边的位,它代表了数值中的最小单位。在汇编程序中,LSB通常用于表示数据的最小精度或者作为标志位。
-----------在执行 PUSH 和 POP 操作时,那个通常被称为 SP(R13或写作 SP) 的地址寄存器,会自动被调整, 以避免后续的操作破坏先前的数据。
--------------------------------
(;后面是注释,前面是汇编)
subroutine_1
PUSH {R0-R7, R12, R14} ; 保存寄存器列表
… ; 执行处理
POP {R0-R7, R12, R14} ; 恢复寄存器列表
BX R14 ; 返回到主调函数
---------------------------------
subroutine_1
这是一个标签,标识了子程序subroutine_1
的开始位置。其他地方的代码可以通过跳转到这个标签来执行这个子程序。
PUSH {R0-R7, R12, R14}
PUSH
指令用于将寄存器的内容压入堆栈。在这里,它压入了R0
到R7
(连续的八个寄存器),R12
,和R14
这三个寄存器的当前值到堆栈上。这样做是为了在子程序执行期间保存这些寄存器的原始值,防止子程序修改这些值影响到调用它的代码。
…
这里省略了子程序中的其他指令或代码
POP {R0-R7, R12, R14}
POP
指令用于从堆栈中弹出值并加载到寄存器中。这里,它恢复了之前通过PUSH
指令压入堆栈的寄存器的值。这样,当子程序返回时,这些寄存器的值就像子程序从未被调用过一样。
BX R14
BX
指令用于跳转到由寄存器指定的地址。在这里,它跳转到R14
寄存器中存储的地址。在ARM汇编中,R14
(通常称为LR
,Link Register)通常用于存储子程序返回地址。因此,这条指令实际上是使子程序返回到它被调用的地方。
-------------- R14 是连接寄存器(LR)
main ;主程序
…
BL function1 ; 使用“分支并连接”指令呼叫 function1 ; PC= function1,并且 LR=main 的下一条指令地址
…
Function1
… ; function1 的代码
BX LR ; 函数返回(如果 function1 内部还要使用 LR,必须在使用前 PUSH, ; 否则返回时程序就可能跑飞了——译注)
------------------------------------
- main ;主程序
这表示主程序的入口点。
2. …
表示省略了一些代码或指令。
3. BL function1
BL
是一个指令,用于跳转到function1
。在汇编语言中,BL
(或类似的指令)用于调用子程序或函数。在这里,它调用了一个名为function1
的函数或子程序。
4. …
再次表示省略了一些代码或指令。
6. Function1
是function1
的开始。在汇编语言中,函数或子程序通常有一个标签来标识它们的开始,这样其他代码可以跳转到这个标签来执行该函数的代码。
7. … ;
function1 的代码
8. BX LR
BX
和LR
是指令和寄存器。BX
通常用于跳转到某个地址,而LR
(Link Register)通常用于存储返回地址。在许多架构中,当从子程序返回时,LR
会存储调用子程序之前的地址,这样程序可以继续执行。
所以BX LR
,用于从function1
返回到之前调用它的地方(即BL function1
之后的代码)。
----------------R15 是程序计数器(PC)
0x1000: MOV R0, PC ; R0 = 0x1004
0x1000
是这条指令本身的地址。当 MOV R0, PC
执行时,它会把 PC
的当前值(即这条指令后面的地址)移动到 R0
寄存器中。
通常情况下,在指令 MOV R0, PC
执行后,PC
的值已经自增到了下一条指令的地址。因此,如果 MOV R0, PC
这条指令位于地址 0x1000
,那么 PC
的值(在执行这条指令时)将会是 0x1004(
(假设每条指令占用 4 个字节的空间)
这里的逻辑是:PC
总是指向下一条要执行的指令,所以当 MOV R0, PC
执行时,它实际上是把下一条指令的地址(即 0x1004
)存到了 R0
寄存器中。
------------------------
PUSH/POP 指令支持一次操作多个寄存器。像这样:
PUSH {R0-R2} ;压入 R0-R2
PUSH {R3-R5,R8, R12} ;压入 R3-R5,R8,以及 R12
在 POP 时,可以如下操作:
POP {R0-R2} ;弹出 R0-R2
POP {R3-R5,R8, R12} ;弹出 R3-R5,R8,以及 R12
注意:不管在寄存器列表中,寄存器的序号是以什么顺序给出的,汇编器都将把它们升 序排序。然后 PUSH 指令按照从大到小的顺序依次入栈,POP 则按从小到大的顺序依次出栈。 如果不按升序写寄存器,有些汇编器可能会给出一个语法错误。
PUSH/POP 对子还有这样一种特殊形式,形如
PUSH {R0-R3, LR}
POP {R0-R3, PC}
请注意:POP 的最后一个寄存器是 PC,并不是先前 PUSH 的 LR。这其实是一个返回的小 技巧。因为总要把先前 LR 的值弹出来,再使用此值返回,干脆绕过 LR,直接传给 PC! LR 在子程序返回时的唯一用处就是提供返回地址,在 返回后,先前保存的返回地址就没有利用价值了,所以只要 PC 得到了正确的值,不恢复也 没关系