程序如何在CPU中运行(二)

前言

回顾 上一节说的 《程序如何在cpu中运行(一)》

上一次讲了CPU的基本架构 ,控制器获取pc指针后 判断他的工作目的和工作方向 
在根据他的操作数 的来源和单位运算结果存储位置,从而完成cpu指针要求。
那么指令是如何有序运行的呢?我们利用点时间来讲讲.

寄存器组的介绍

寄存器

在这里插入图片描述
大概分析图上意思

寄存器通常分为41 通用寄存器:用于数据操作
2 堆栈指针:堆栈指针两个 但是某个时间点只能用一个 
主堆栈指针:用于系统异常和系统内核处理   也就是我们说的复位功能。
3 连接寄存器:当呼叫一个子程序时,连接到R14 储存子程序的返回地址。
4 程序计数器:存储下一个即将远行的指令地址 (也就是我们上一篇讲的PC指针)

寄存器组介绍的差不多了 我们继续往下看

顺序执行

下面的代码是顺序执行的例子 汇编的冒号前的 是对应指令的地址 下面的代码都是储存在通用寄存器

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指针 也不断在变化。

条件分支

条件分支 不想 顺序结构 一样 是有规律执行,当他满足任意任意一个条件 会跳转到任意的地方…
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
}

首先 我们先 理解以下两个元素的意思

CMP:当前一个和前一个比较  当前一个:第一个if的往下一个
BLE:比较结果 小于或者等于 就会发生跳转。

结合图 看代码
在这里插入图片描述

首先 我们先看第一点 : 利用 “PC指针存放的是下一个指令的地址“的知识点 并且关键字 CMP 是两者比较的意思 
最后 我们就可以知道 226228 相比的 到了第二点 跳转了位置  为什么呢 
BLP是比较结果 小于或者等于 就会发生跳转。的意思  因为226<228 所以会跳变到228存储的位置 
因为发生了跳转 PC  指针也会相应少了一个指令地址  

一级函数调用

函数调用设计到一个概念,函数调用时会把函数的返回地址存入堆栈里  函数返回执行时再把他取出。

例子
在这里插入图片描述

第一步就是  发生了 调用 把返回地址存入堆栈中 
第二步 返回执行函数时把入口参数 取出 
在处理一级函数调用时 ,并没有对函数返回地址 进行存入堆栈 ,
而是直接把它存入到R14 寄存器了 函数返回时在把它取出就行了

在这里插入图片描述

1 在R14 取出地址 直接操作函数了 并没先进行函数调用时把返回地址存入堆栈当中,当他操作完0X0800019A
之后 把 0X0800019A 存入R14 又取出 返回函数点操作  操作完成之后  因为 PC 指针 是存放下一个的地址 
所以 又指向了0X08000234 (因为0x8000230 执行完了 ) 
也就印证了 R14 是用来存放子函数返回地址的 

二级函数 调用

二级调用和多级调用原理是一样的 但不同于一级通用 它会涉及到 两个子函数的返回地址 
但是R14 只能存储一个子函数的返回地址 那么我们现在就引入堆栈的机制概念来解决问题 
堆栈的特征是先进后出 ,在函数的嵌套调用当中,先通用函数的返回地址 后 返回函数  
先返回函数 后 返回地址 这样刚好对应堆栈的特征

同样代码 要和 图结合

int MyFunc2(int a)
{
	int temp;
	0x080001AC MOV      r1,r0
	temp = a + 1;
	return temp;
	0x080001AE ADDS     r0,r1,#1
	0x080001B0 BX       lr
}

int MyFunc(int a,int b)
{
	int temp;
	0x0800019A PUSH     {r4-r5,lr}
	0x0800019C MOV      r4,r0
	0x0800019E MOV      r5,r1
    temp = MyFunc2(temp);
    0x080001A0 MOV      r0,r3
    0x080001A2 BL.W     MyFunc2 (0x080001AC)
    0x080001A6 MOV      r3,r0
	return temp;
	0x080001A8 MOV      r0,r3
	0x080001AA POP      {r4-r5,pc}
}

int main(void)
{
	int a = 123;
	0x08000238 MOVS     r4,#0x7B
	int b = 456;
	0x0800023A MOV      r5,#0x1C8
	int result = a - b;
	0x0800023E SUBS     r6,r4,r5
	result = MyFunc(a,b);
	0x08000240 MOV      r1,r5
	0x08000242 MOV      r0,r4
	0x08000244 BL.W     MyFunc (0x0800019A)
	0x08000248 MOV      r6,r0
    return 0;
    0x0800024A MOVS     r0,#0x00
}

相对 这一个会复杂 点
在这里插入图片描述
我们先按堆栈机制来看
堆栈的 进栈 过程

1------5 的变化 过程
在R14 取出第一个地址 返回 函数 执行(第一个地址相当于第一个元素) -----2 跳转了0X0800019A (第二个元素)---3 这时因为PC指针存放下一个地址的指令 所以继续往前 ---4  z之后 也2 的思路 ---5 (最后一个)

5位进栈的最后一个 到了下一轮进栈为第一个 也就符合了 “先进后出”的规律

5----9
Pc 指针是存放下一个地址的指令的 所以5的先进 先指向 0X80001A66-----7):PC指针又往前-----8)指向第一个函数的下一个地址--------9) 这时PC指针又往前

总结

不管哪种变化 PC指针永远是最前的一个 在发生一级调用时 并没有进入地址的存入堆栈中
 而是直接把他存入R14当中 当函数返回时再取出. 
 二级调用时 因为R14只能存一个子函数的返回地址  所以要引入堆栈“先进后出”的机制 来解决这个问题.

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值