跳到主要内容

ARM架构简明教程

硬件架构与汇编​

ARM架构​

ARM芯片属于精简指令集计算机(RISC:Reduced Instruction Set Computing),它所用的指令比较简单,有如下特点:

① 对内存只有读、写指令

② 对于数据的运算是在CPU内部实现

③ 使用RISC指令的CPU复杂度小一点,易于设计

对于上图所示的加法运算a = a + b,在RISC中要使用4条汇编指令:

① 读内存a

② 读内存b

③ 计算a+b

④ 把结果写入内存

问题:在CPU内部,用什么来保存a、b、a+b ?

CPU内部都有R0、R1、……、R15等寄存器;它们可以用来“暂存”数据。

对于R13、R14、R15,还另有用途:

  • R13:别名SP(Stack Pointer),栈指针

  • R14:别名LR(Link Register),用来保存返回地址

  • R15:别名PC(Program Counter),程序计数器,表示当前指令地址,写入新值即可跳转

无论是cortex-M3/M4,还是cortex-A7,CPU内部都有R0、R1、……、R15寄存器;它们可以用来“暂存”数据。下图是cortex-M3/M4、cortex-A7处理器内部的寄存器:

对于R13、R14、R15,还另有用途:

R13:别名SP(Stack Pointer),栈指针

R14:别名LR(Link Register),用来保存返回地址

R15:别名PC(Program Counter),程序计数器,表示当前指令地址,写入新值即可跳转。

汇编指令​

常用汇编指令如下:

  • 读内存:Load

# 示例

LDR R0, [R1, #4] ; 读地址"R1+4", 得到的4字节数据存入R0

  • 写内存:Stroe

# 示例

STR R0, [R1, #4] ; 把R0的4字节数据写入地址"R1+4"

  • 加减
ADD R0, R1, R2 ; R0=R1+R2

ADD R0, R0, \#1 ; R0=R0+1

SUB R0, R1, R2 ; R0=R1-R2

SUB R0, R0, \#1 ; R0=R0-1

  • 比较

CMP R0, R1 ; 结果保存在PSR(程序状态寄存器)

  • 跳转

B main ; Branch, 直接跳转

BL main ; Branch and Link, 先把返回地址保存在LR寄存器里再跳转

C函数内部机制​

对于一个C函数,它的本质是各类汇编指令对内存的操作:

  • 在内存(栈)里保存寄存器、返回地址

  • 在内存(栈)里分配局部变量

  • 使用机器码读写内存、计算、跳转

C函数的汇编代码分析​

看视频。逐个指令分析一个C函数的汇编码

参数调用规则​

在arm中有个ATPCS规则(ARM-THUMB procedure call standard(ARM-Thumb过程调用标准)。约定r0-r15寄存器的用途:

  • r0-r3:

调用者和被调用者之间传参数

  • r4-r11

在函数里面可能会使用这些寄存器,如果要使用的话,在函数的入口保存它们,在函数的出口恢复它们。

  • <img src="C:\Users\MeiHao\AppData\Local\Temp\dsh_docx\pandoc\media/media/image243.png" title="fig:" style="width:4.73056in;height:3.24792in" />

代码示例:

## int delay(unsigned int d) { while (d--); return 0; }

在汇编里调用delay:

ldr r0, =1000000 /* 给delay函数传参数,保存在r0里 */ bl delay cmp r0, #0 /* 返回值保存在r0中 */​

栈的作用​

栈里面会保存:必要的寄存器(比如LR寄存器)、局部变量。

汇编代码里的__stack_chk_guard​

__stack_chk_guard是GCC编译器为了实现栈溢出保护(Stack Smashing Protection,SSP,也称为 ProPolice)而引入的一个关键机制,用于检测栈缓冲区溢出(如缓冲区溢出导致的栈破坏)。

原理为:在栈帧中插入一个随机生成的 “保护值”(guard value),函数返回前检查该值是否被篡改。若被篡改,说明发生了栈溢出,程序会立即终止(避免攻击得逞)。

当编译器启用栈保护(默认在 -O2 及以上优化级别,或显式通过 -fstack-protector 系列选项开启)时,会在函数的栈帧中(通常位于缓冲区和返回地址之间)插入 __stack_chk_guard 的副本。