csapp(第三章)
程序的机器级表示
程序编码
机器级代码
计算机系统利用抽象模型产生细节
1.指令集体系结构或指令级架构(它是软硬件之间的“合同”):定义了处理器状态、指令的格式、指令对状态的影响
2.使用的内存地址是虚拟地址:机器代码将内存看成一个按字节寻址的数组
程序处理器:给出将要执行的下一条指令在内存中的地址
整数寄存器文件包含16个命名的位置,分别储存64位的值。(可以储存地址或者整数数据)
条件码寄存器保存着最近算数或逻辑的指令的状态信息。(可用来实现if while函数)
一组向量寄存器可以储存一个或者多个整数或者浮点数值
操作系统负责管理虚拟地址空间,将虚拟地址翻译成实际处理器中的物理地址
代码具体
先创建一个c代码
1 | touch +“文件名”.c |
vim “文件名”.c
1
2
3 gcc -Og -S ""//预处理代码,可生成.s后缀的文件
gcc -Og -c ""//编译并汇编代码,可生成.o后缀的文件
objdump -d ""//objdump是一种反汇编程序,反汇编该代码
链接器的任务之一就是为函数找到匹配的可执行代码的位置
反汇编后
所有以”.”开头的为伪指令,可以忽略
数据格式
数据传送指令
movb(字节)
movw(字)
movl(双字)
movq(四字)
movabsq(传输绝对的四字)
49:20
访问信息
一个CPU包含了一组16个储存64位值的通用寄存器
以%r 开头的
在指令以寄存器作为目标时,对于生成小于8字节的指令:
生成1字节和2字节数字的指令会保持剩下的字节的不变
生成4字节数字的指令会把高位4个字节设置位零
操作数指示符
1.立即数
用来表示常数值
书写方式为:“$”后面跟着一个标准C表示的整数
2.寄存器
表示某个寄存器的内容
16寄存器的低位1字节,2字节,4字节,8字节中的一个作为一个操作数,其分别对应8位,16位,32位,64位
3.内存引用
根据计算出来的地址(有效地址)访问一些位置
当Imm(,ri,s),寻址的位置为:Imm+ri*s
就是括号里三个寻址对象是,第二个和第三个相乘
:::::就是汇编语言中寻址的方式:::::
数据传输指令
X86-64 系统的限制:传输指令的两个操作数不能都指向内存位置
在将较小的源值复制到较大的目的时:
movz类
把传输到目的的中剩余的字节填充为0
movzbw 后两个字符分别代表第一个字符指定的源大小,和目的位置的源大小
movs类
就是进行符号填充,把源操作的最高位进行复制
movl
把4字节的源值拓展到8字节
%rax(64)=%eax(32)+%ax(16)+%ah(8)+%al(8)
压入和弹出数据
栈向下增长,栈顶的地址是栈中元素地址中最低的。栈指针 rsp 保存栈顶元素的地址
栈指令:
1 | pushq s //R[%rsp]=R[%rsp]-8 |
使用 mov 指令和标准的内存寻址方法可以访问栈内的任意位置,而非仅限于栈顶
算数和逻辑操作
加载有效地址
指令leaq:加载有效地址,就是mov指令的变形
1 | long scale(long x,long y,long z) |
1 | scale: |
其他的指令如上图
特殊的算数运算
要求被乘数放在了%rax中
imulp:计算结果存放(%rdx高位 %rax低位)用于有符号数
mulp:用于无符号数
控制
条件码
单个位的条件码寄存器:(判断状态)
CF :进位标志(检测无符号溢出)
ZF :零标志
SF:符号标志
OF:溢出标志(正溢出,负溢出)
访问条件码
三种使用方法
1.根据条件码的某种组合,将第一个字节设置为0或者1
2.条件跳转到其他的程序部分
3.有条件的传送数据
SET指令
跳跃指令
无条件跳转:jump
其他跳转指令
跳转指令在反汇编中的值为跳转到的那个指令的地址,也就是跳转指令后面的那个地址
C语言的if-else通用式转化在汇编中实现模板
1 | if(test-expr) |
1 | t=test-expr; |
条件传送: