int main(void)
{
int a = 123;
0x0800021E : MOVS r1,#0x7B
int b = 456;
0x08000220 : MOV r2,#0x1CB
int result = a + b;
0x08000224 : ADDS r3,r1,r2
return 0;
0x08000226 : MOVS r0,#0x00
}
上述代码的汇编语言涉及到的寄存器都是通用寄存器,通过 C 语言代码我们也可以知道对应的汇编代码的意思,这也印证了前面所说的通用寄存器的功能就是用于数据操作的。
那上述程序是如何运行的呢,这时之前说到的程序计数器,也就是我们所说的 PC 指针就要排上用场了,如下图片展示了程序计数器在上述指令运行过程中的一个变化。
通过上图可以看出,左边是即将执行的指令,中间是指令存储的位置,那么 PC 存储的值一直是即将执行的下一条指令的地址,这样程序也就可以顺序的执行下去了。
条件分支
条件分支是根据条件执行任意地址的指令,也就是说程序不是向上述一样顺序执行了,那 CPU 又如何处理这种情况呢?我们来看一个简单 if 语句例子:
int main(void)
{
int a = 123;
0x0800021E : MOVS r1,#0x7B
int b = 456;
0x08000220 : MOV r2,#0x1CB
int result = a - b;
0x08000224 : SUBS r1,r2,r3
if (result > 0)
0x08000226 : CMP r1,#0x00
0x08000228 : BLE 0x0800022E
result = result + 1;
0x0800022A : ADDS r1,r1,#1
else
result = 1 - result;
0x0800022E : RSB r1,r1,#0x01
return 0;
0x08000232 : MOVS r0,#0x00
}
上述的汇编与 C 语言一一对应,很容易知道每条指令的意思,在这里笔者单独拿出来两个与语句跳转相关的指令说一下:
CMP : 比较(比较两数并且更新标志)
BLE : 当比较结果小于或者等于的时候,跳转到某个指令的地址执行
现在来看汇编代码,比较关键的地方就是使用 CMP 判断,判断结果小于 0 ,所以跳转到 0x0800022E 地址对应的指令进行执行,也就是执行 result = 1 - result; 同样的,我们也用示意图的形式表示一下在这个过程 PC 值的变化。
如上图所示,由于使用了条件分支,程序在执行到地址为 0x08000228 的时候,下一条要执行的指令地址并不是 0x0800022A,而是直接跳转到地址为 0x0800022E 的指令进行执行,那 PC 值的变化也就是图中左侧所示,因为没有没有执行一条指令,所以 PC 的变化次数也就比总的指令数少一条。
总结
上述就是涉及到的顺序执行,条件分支,和函数调用的相关内容。可以看到无论是哪一种形式,其实本质就是 PC 值的变化,PC 值永远存储的是即将运行的下一条指令的地址,控制这个值就能够控制程序的走向。另外需要注意的一点是,对于 ARM Cortex M3 系列的内核来说,涉及到一级函数调用的时候,不需要进行压栈操作,涉及到多级函数调用的时候,才会使用到堆栈。