1.两种抽象
指令集体系结构或指令集架构(ISA)来定义机器级程序的格式和行为
使用的内存地址是虚拟地址,看上去是一个非常大的字节数组
2.数据格式
![](https://img-blog.csdnimg.cn/img_convert/5f014ee008b02cc838d9dd32cb7d02e4.jpeg)
byte、word、quad words
3.16个寄存器
![](https://img-blog.csdnimg.cn/img_convert/834e9429d2e69a3dd994dfbd8b42628f.png)
4.三种操作数
立即数、寄存器、内存引用
![](https://img-blog.csdnimg.cn/img_convert/622be83adb4a0188f805fb605cfd925f.jpeg)
AT&T:
第一个是源操作数,第二个是目的操作数
movzbq 将做了零拓展的字节传送到四字
movsbq 将做了符号拓展的字节传送到四字
cltq 总是以%eax为源,%rax为符号拓展的目的,编码更紧凑
5.数据传送示例
![](https://img-blog.csdnimg.cn/img_convert/83043576b7bcb469130a7e24f3d19b4c.jpeg)
C的指针其实就是地址。间接引用指针,就是把指针放在寄存器中,然后在内存引用中使用这个寄存器
像x这样的局部变量通常保存在寄存器中,而不是内存中,访问更快。
6.压入和弹出栈数据
pushq %rbq等价于
subq $8,%rsp
movq %rbp,(%rsp)
popq %rax等价于
movq (%rsp),%rax
addq $8,%rsp
7.算术和逻辑操作
7.1 整数算术操作
![](https://img-blog.csdnimg.cn/img_convert/a65b65d029a433b7f0f4f8774ee3b02e.jpeg)
subq %rax,%rdx 从%rdx中减去%rax
第一个是源操作数,第二个是目的操作数
7.2 加载有效地址leaq
(load effective address)
根本没有引用内存,不是从指定的位置读入数据,而是把有效地址写入到目的操作数
![](https://img-blog.csdnimg.cn/img_convert/f44713d636a0dabdad426830a2e2411b.jpeg)
7.3 逻辑操作
![](https://img-blog.csdnimg.cn/img_convert/3f7e12ca4b1407ea59f1e984e6ea34d5.jpeg)
7.4 乘除法
![](https://img-blog.csdnimg.cn/img_convert/27c3e2afb370f802f549d69a09168e35.jpeg)
乘法
![](https://img-blog.csdnimg.cn/img_convert/cbea631cae460d58ea685daaff738f83.jpeg)
![](https://img-blog.csdnimg.cn/img_convert/d6949be19deff2aa1a8c41046fc9cb61.jpeg)
存储需要两个movq指令,一个存储帝8位字节(第4行),一个存储高8位字节(第5行)
针对小端法机器,高位字节存储在大地址,如8(%redi)
除法
![](https://img-blog.csdnimg.cn/img_convert/9d89e8c785d82b72e8405dfb3453c844.jpeg)
![](https://img-blog.csdnimg.cn/img_convert/98d61f9f6085404b13eb881a8645a4c9.jpeg)
除法需要用%rdx,因此需要先把qp保存到另一个寄存器中
准备被除数:复制并符号拓展x
寄存器%rax中的商保存在qp,寄存器%rdx中的余数保存在rp
8.控制
8.1 实现机制
两种基本的低级机制实现有条件的行为
测试数据值,根据测试的结果来改变控制流或者数据流
8.2 条件码
CF:进位标志。最近的操作使最高位产生进位,检查无符号操作的溢出
ZF:零标志。最近的操作得到的结果为0
SF:符号标志。最近的操作得到的结果是负数
OF:溢出标志。最近的操作导致一个补码溢出,检查有符号操作的溢出
![](https://img-blog.csdnimg.cn/img_convert/b2f3f3912664fcee703c2c4eb6f7ec13.jpeg)
只设置条件码,不更新目的寄存器
CMP~SUB TEST~AND
8.3 条件码的使用
根据条件码的组合,设置字节为0或1,即SET指令
条件跳转
条件数据传送
8.3.1 SET指令
![](https://img-blog.csdnimg.cn/img_convert/27df7aa85dea4872a6e8c56dee19a6a1.jpeg)
示例
![](https://img-blog.csdnimg.cn/img_convert/ca301886d47e0fc834d92250841bbabc.jpeg)
a-b
8.3.2 跳转指令
![](https://img-blog.csdnimg.cn/img_convert/5543012cc6aae39ed255583f43f872b4.png)
直接跳转
movq $0,%rax
jmp .L1
movq (%rax),%rdx
.L1:
popq %rdx
间接跳转
jmp *%rax 用%rax中的值作为跳转目标
jmp*(%rax) 以%rax中的值作为读地址,从内存中读出跳转目标
跳转指令的编码:
PC相对寻址:将目标指令的地址,和紧跟在跳转指令后的那条指令的地址的差,作为编码
给出绝对地址,直接指出目标
PC相对寻址 示例
![](https://img-blog.csdnimg.cn/img_convert/71f9cb6396d4a683543dcfdca15d50a2.jpeg)
第一条跳转指令的目标编码是0X03(第二个字节),加上下一个指令的编码0X5,得到跳转目标地址0X8(第4行指令的地址)
第二条跳转指令的目标编码是0Xf8(十进制为-8),加上下一个指令的编码0Xd,得到跳转目标地址0X5(第3行指令的地址)
8.3.3 条件数据传送
基于条件数据传送比基于条件控制转移的代码性能好
因为流水线,分支预测错误处罚主导这个函数的性能
条件数据传送,处理器无需预测测试的结果就可以执行
![](https://img-blog.csdnimg.cn/img_convert/6e45cd608a3ab32201bd75239aa815e4.jpeg)
8.4 循环
用条件测试和跳转,组合实现循环
8.4.1 while循环
while循环的两种翻译方法
第一种:jump to middle
执行一个无条件跳转到循环结尾处的测试,以此来执行初始的测试
![](https://img-blog.csdnimg.cn/img_convert/f2478e9f59f81cdaacb084f6bc24b2db.jpeg)
第二种:guarded-do
先条件分支,若初始条件不成立则跳出,变换为do-while
![](https://img-blog.csdnimg.cn/img_convert/2ed21a3ed75037de6706fb23809f3418.jpeg)
8.4.2 for循环
把for变成while
8.4.3 switch
跳转表:
一个数组,表项i是一个代码段的地址,这个代码段实现当开关索引值等于i时,程序应采取的动作
优点是执行开关语句的时间和开关情况的数量无关
当开关情况数量比较多,并且值的范围跨度比较小时,适合使用
![](https://img-blog.csdnimg.cn/img_convert/35c7b4278a85ed2c4a75399f9260b9a2.png)
![](https://img-blog.csdnimg.cn/img_convert/00bcfb7945fc08bfd6ae9963576e3c5b.jpeg)
9.过程
过程是一种抽象,提供一种封装代码的方式,用一组指定的参数和一个可选的返回值实现某种功能
包括:函数(function)、方法(method)、子例程(subroutine)、处理函数(handler)
共有的特性:传递控制、传递数据、分配和释放内存
运行时栈:
使用栈数据结构的LIFO内存管理原则
当过程需要的存储空间超出寄存器能存放的大小,就会在栈上分配空间,称为栈帧
转移控制:
将控制函数P转移到函数Q,只需要把PC设置为Q的代码的起始位置
数据传送:
x86-64中,可以通过寄存器最多传递6个整型参数,超出的部分用栈来传递
![](https://img-blog.csdnimg.cn/img_convert/cb887b3ce997e631eb832ba8a1910efd.jpeg)
![](https://img-blog.csdnimg.cn/img_convert/cf00375d012e288c5aabe75913e2ad47.png)
栈上的局部存储:
根据惯例,%rbx、%rbp和%r12~%r15被划分为 被调用者保存寄存器
所有其他的寄存器(除了栈指针%rsp)都被划分为 调用者保存寄存器
%rbxp作为基指针(base pointer),管理变长栈帧
![](https://img-blog.csdnimg.cn/img_convert/d10742a83219f15528d99f61bc2a3e70.png)
10.数组的分配与访问
movl (%rdx,%rcx,4),%eax
对于E[i],E的地址存放在%rdx,i存放在%rcx
11.浮点代码
![](https://img-blog.csdnimg.cn/img_convert/9c745d11b6fec51f25945d990367b21e.jpeg)
![](https://img-blog.csdnimg.cn/img_convert/0b83d03733eef5977484498091d923a1.png)
vcvtsi2sdq %rax,%xmm1,%xmm1
通常,第二个源的值只影响结果的高位字节,和目的操作数是相同的
vunpcklps %xmm0,%xmm0,%xmm0
交叉放置来自两个XMM寄存器的值,把它们存储到第三个寄存器中
![](https://img-blog.csdnimg.cn/img_convert/a831e7b94ef7ba516014b68d299d619a.jpeg)
浮点常数
![](https://img-blog.csdnimg.cn/img_convert/28d1eff1fc49b7e590283915b6fd3c8f.jpeg)
对于LC2:
3435973837(0Xcccccccd)、1073532108(0X3ffccccc)
高位抽取指数字段0X3ff(1023),减去偏移1023,得到0
低位连接得到小数字段(0Xccccccccccccd),二进制小数为0.8,加上隐含的1得到1.8
浮点比较
三个条件码:
ZF:零标志位
CF:进位标志位
PF:奇偶标志位
对于整数操作,最近的一次算术或逻辑运算产生的值的最低位字节是偶校验的(有偶数个1)
对于浮点比较,当两个操作数中任一个是NaN
当任一个操作数为NaN时,会出现无序
![](https://img-blog.csdnimg.cn/img_convert/01c85fcf2f3749e371e645ea6e529d74.jpeg)