我们的代码在终端设备上是这样的过程:
-
汇编语言
与机器语言
一一对应,每一条机器指令都有与之对应的汇编指令 -
汇编语言
可以通过编译得到机器语言
,机器语言
可以通过反汇编得到汇编语言
-
高级语言
可以通过编译得到汇编语言 \ 机器语言
,但是汇编语言 \ 机器语言
几乎不可能还原成高级语言
汇编语言的特点
- 可以直接反问,控制各种硬件设备,比如
存储器
、CPU
等,能最大限度地发挥硬件的功能 - 能够不受编译器的限制,对生成的二进制代码惊醒完全的控制
- 目标代码简短,占用内存少,执行速度快
- 汇编指令是机器指令的助记符,同机器指令一一对应。每一种
CPU
都有自己的机器指令集\汇编指令集
- 知识点过多,开发者需要对
CPU
等硬件结构有所了解,不易于编写、调试、维护 - 不区分大小写,比如
mov
和MOV
是一样的
汇编的用途
- 编写驱动程序、操作系统(比如
Linux
内核的某些关键部分) - 对性能要求极高的程序或者代码片段,可以与高级语言混合使用(内联汇编)
- 软件安全
1、病毒分析与防治
2、逆向、加壳、脱壳、破解、外挂、免杀、加密解密、漏洞、黑客 - 理解整个计算机系统的最佳起点和最有效途径
- 为编写高效代码打下基础
- 弄清代码的本质
1、函数的本质究竟是什么?
2、++a
+++a
+++a
底层如何执行的?
3、编译器到底帮我们干了什么?
4、DEBUG
模式和RELEASE
模式有什么关键的地方被我们忽略
......
汇报语言的种类
- 目前讨论比较多的汇编语言有:
1、8086汇编(8086处理器是16bit的CPU)
2、Win32汇编
3、Win64汇编
4、ARM汇编(嵌入式、Mac、iOS)
...... - 我们的iPhone里面用到的是
ARM
汇编,但是不同的设备也有差异,因为CPU
架构不同。
架构 | 设备 |
---|---|
armv6 | iPhone, iPhone2, iPhone3G, 第一代、第二代 iPod Touch |
armv7 | iPhone3GS, iPhone4, iPhone4S,iPad, iPad2, iPad3(The New iPad), iPad mini, iPod Touch 3G, iPod Touch4 |
armv7s | iPhone5, iPhone5C, iPad4(iPad with Retina Display) |
arm64 | iPhone5S 以后 iPhoneX , iPad Air, iPad mini2以后 |
-
APP/程序的执行过程
- 硬件相关最为重要的是
CPU
/内存
- 在汇编中,大部分指令都是和
CPU
&内存
相关的
总线
- 每个
CPU
芯片都有需要管脚,这些管脚和总线相连,CPU
通过总线跟外部器件进行交互 - 总线:一根一根导线的集合
-
总线的分类:
1、地址总线
2、数据总线
3、控制总线
-
地址总线
1、它的宽度决定了CPU
的寻址能力
2、8086的地址总线宽度是20,所以寻址能力是1M
(220) -
数据总线
1、它的宽度决定了CPU
的单词数据传送量,也就是数据的传送速度
2、8086的数据总线宽度是16
,所以单词最大传递2个字节
的数据 -
控制总线
1、它的宽度决定了CPU
对其他器件的控制能力,能有多少种控制
数据的宽度
数学上的数字是没有大小限制的,可以无限的大。但是计算机中,由于受硬件的制约,数据都是有长度限制的(我们称之为数据宽度),超出最大宽度的数据会被丢弃。
计算机中常见的数据宽度
- 位(Bit):1个位就是1个二进制位。0或者1
- 字节(Byte):1个字节由8个
Bit
组成(8位)。内存中的最小单元Byte
- 字(Word):1个字由2个字节组成(16位),这2个字节分贝称为
高字节
&低字节
- 双字节(Doubleword):1个双字节由两个字组成(32位)
计算机存储的数据分为有符号数
& 无符号数
。:
无符号数 --- 直接换算 --- 有符号数:
正数 0 1 2 3 4 5 6 7 负数 F E D B C A 9 8 结果 -1 -2 -3 -4 -5 -6 -7 -8
CPU & 寄存器
-
内部部件之间由总线链接
-
CPU
除了有控制器、运算器还有寄存器。其中寄存器的作用就是进行数据的临时存储。
CPU
的运算速度是非常快的;为了性能,CPU
在内部开辟一小块临时存储区域,并在进行运算的时候先将数据从内存赋值到这一小块临时存储区域中,运算时就在这一小块临时存储区域内进行。我们称这一小块临时存储区域为寄存器
。
对于arm64
系的CPU
来说,如果寄存器以x
开头,则表明的是一个64位的寄存器;如果以w
开头则表明是一个32位的寄存器,在系统中没有提供16位和8位的寄存器供访问和使用。其中32位的寄存器是64位寄存器的低32部分,并不是独立存在的。
- 对于程序员来说,
CPU
中最主要的部件是寄存器
,可以通过改变寄存器的内容来实现对CPU
的控制。- 不容的
CPU
,寄存器的个数、结构是不相同的。
浮点和向量寄存器
因为浮点数的存储以及其运算的特殊性,CPU
中专门提供了浮点寄存器来处理浮点数:
- 浮点寄存器 64为:D0 - D31 ; 32位:S0 - S31
现在的CPU
支持向量运算(向量运算在图形处理相关的领域用的非常多),为了支持向量计算,系统也提供了众多的向量寄存器: - 向量寄存器 128位:V0 - V31
通用寄存器
- 通用寄存器也称为
数据地址寄存器
,通常用来做数据计算的临时存储、做累加,计数,地址保存等功能。定义这些寄存器的作用主要是用于在CPU
指令中保存操作数,在CPU
中当做一些常规变量来使用。 -
ARM64
拥有32个64位的通用寄存器x0
到x30
,以及XZR(0️⃣寄存器)
,这些通用寄存器有时也有特定用途
i
:那么w0
到w28
这些是32位的,因为64位CPU
可以兼容32位,所以可以只使用64位寄存器的低32位。
ii
:比如w0
就是x0
的低32位。 - 通常,
CPU
会先将内存中的数据存储到通用寄存器中,然后再对通用寄存器中的数据进行运算 - 假设内存中又块红色存储空间的值是
3
,现在想把它的值加1
,并将结果存储到蓝色内存空间:
1、CPU
首先会将红色内存空间的值放到x0
寄存器中:mov x0,红色内存空间
2、然后让x0
寄存器与1
相加:add x0,1
3、最后将值赋值给内存空间:mov 蓝色内存空间,x0
pc寄存器(program counter)
- 为指令指针寄存器,它指示了
CPU
当前要读取指令的地址 - 在内存或磁盘上,指令和数据没有任何区别,都是二进制信息
-
CPU
在工作的时候把有的信息看做指令
,有的信息看做数据
,为同样的信息赋予了不同的意义
比如1110 0000 0000 0011 0000 1000 1010 1010
可以当做数据0xE003008AA
也可以单做指令mov x0, x8
-
CPU
根据什么将内存中的信息看做指令的呢?
i
:CPU
将pc
寄存器指向的内存单元的内容看做指令。
ii
:如果内存中的某段内容曾被CPU
执行过,那么它所在的内存单元必然被pc
指向过。
高速缓存
iPhoneX上搭载的ARM
处理器A11
,它的1级缓存
的容量是64KB,2级缓存
的容量是8M
CPU
每执行一条指令前,都需要从内存中将指令读取到CPU
内并执行。而寄存器的运行速度相比内存的读写要快很多,为了性能,CPU
还继承了一个高速缓存存储区域
。当程序在运行的时候,先将要执行的指令代码以及数据复制到高速缓存
中去(由操作系统完成),CPU
直接从高速缓存
依次读取指令来执行。
bl指令
-
CPU
从何处执行指令有pc
中的内容决定,我们可以通过改变pc
的内容来控制CPU
执行目标指令 -
ARM64
提供了一个mov
指令(传送指令),可以用来修改大部分寄存器的值,比如:
mov x0,#10
mov x1,#20
- 但是,
mov
指令不能用于设置pc
的值,ARM64
也没有提供这样的功能。 -
ARM64
通过了另外的指令来修改pc
的值,这些指令统称为转移指令,最简单的就是
bl`指令
_A:
mov x0,#0xa0
mov x1,#0x00
add x1, x0, #0x14
mov x0,x1
bl _B
mov x0,#0x0
ret
_B:
add x0, x0, #0x10
ret
-
bl _B
代表执行到这一行的时候,进入_B
函数。