汇编语言的发展过程
机器语言
由0和1组成的机器指令
为什么要用二进制作为机器语言?
因为用0和1表示有电没电是最稳定的
汇编语言
使用助记符号代替机器语言,助记符号就是使用特定的单词或者字母组合表示一组机器码
高级语言
C/C++/Java/OC等更加接近人类的自然语言
高级语言执行过程
从图解我们可以得到以下结论:
1、高级语言可以通过编译得到汇编语言,但是汇编语言几乎不可能还原成高级语言,我们只能通过推算得到高级语言的算法逻辑,不能完完全全还原高级语言
2、汇编语言可以编译成机器语言,机器语言也可以通过反汇编得到汇编语言
汇编语言的特点
可以直接访问、控制各种硬件设备
能够不受编译器的限制,对生成的二进制代码进行完全的控制
目标代码简短,占用内存少,执行速度快
汇编指令是机器指令的助记符,同机器指令一一对应。每一种CPU都有自己的机器指令集\汇编指令集,所以汇编语言不具备可移植性
知识点过多,开发者需要对CPU等硬件结构有所了解,不易于编写、调试、维护
不区分大小写
总线
每一个CPU芯片都有许多管脚,这些管脚和总线相连,CPU通过总线跟外部器件进行交互
总线:一根根导线的集合
总线的分类
地址总线:CPU在内存中读取或写入数据进行操作的地址查找器
数据总线:CPU在内存中进行数据读取或者写入时的传输器
控制总线:CPU在内存中进行数据读取还是写入的控制器
寄存器
浮点和向量寄存器
通用寄存器
pc寄存器:主要存贮下一条指令操作地址
寄存器主要研究ARM64,因为现在手机系统都是ARM64的,然后分为32位和64位操作系统,相对于iOS来说,5s以前都是32位操作系统,从5s开始都是64位操作系统,所以之后我的文章也是正对ARM64的64位系统下进行探索。64位系统对32位系统进行了兼容,所以在32位系统上的app可以运行在64位系统上。
64位:在64位系统中X0~X30,XZR(零寄存器),以X开头的寄存器说明就是64位的
32位:在32位系统中W0~W30,WZR(零寄存器),以W开头的寄存器说明是32位的
在64位系统中,32的寄存器是64位寄存器的低32位部分,并不是独立存在的
栈
栈是一种居有特殊访问方式的存储空间,遵循先进后出的原则,拥有两个特殊寄存器SP和FP。
在ARM64里面,对栈的操作是16字节对齐的
栈需要一直保持栈的平衡,即开辟了栈空间,使用完成后就必须释放栈空间,在这里所说的开辟和释放正对于CPU来说,就是移动SP寄存器存储的地址
针对内存来说,地址空间的分配是从低地址向高地址分配
正对于栈空间来说,地址是从高地址向低地址扩展的一块连续的内存区域
栈的开辟以及释放都是系统进行维护
对栈溢出:是因为栈是向低地址扩展,而堆是向高地址的扩展,当两个区域碰撞的时候,就是我们所说的对栈溢出
SP和FP寄存器
SP寄存器在任意时刻都会保存我们栈顶的地址
FP寄存器也称为x29寄存器,属于通用寄存器,但是在某些时刻我们利用他保存栈底的地址
在ARM64下,函数的参数是存放在X0到X7(W0到W7)这8个寄存器中,如果超过8个参数,就会入栈,函数的返回值是存放在X0寄存器里面的。我们验证一下是否正确,所以声明并实现如下函数,并在ViewDidLoad方法里面进行调用
int sum(int a,int b,int c,int d,int e,int f,int g,int h){
return a+b+c+d+e+f+g+h;
}
- (void)viewDidLoad {
[super viewDidLoad];
int l = sum(1, 2, 3, 4, 5, 6, 7, 8);
printf("%d\n",l);
}
然后我们在调用函数的地方加上断点,运行程序,当程序运行起来后,走到断点,然后开启汇编模式,使用step into
进入到函数调用栈中,然后就可以看到寄存器中保存的值,如下:
从上图可以看到,寄存器x0~x7存储了传入的参数,然后进行一系列的运算后,最后的返回值保存在了x0当中,如下:
从以上实践我们验证了先前的说法,到此对于ARM64架构以及CPU和内存间的数据读取有了大概的了解。