程序的机器级表示 | CSAPP笔记
程序的机器级表示
数据格式
C声明 | Intel数据类型 | 汇编代码后缀 | 大小(字节) |
---|---|---|---|
char | 字节 | b | 1 |
short | 字 | w | 2 |
int | 双字 | l | 4 |
long | 四字 | q | 8 |
char*(地址,指针) | 四字 | q | 8 |
float | 单精度 | s | 4 |
double | 双精度 | l | 8 |
- 八字>四字>双字>字>字节
+++
访问信息(通用寄存器)
-
返回值寄存器: %rax
-
参数寄存器
-
第一个参数: %rdi
-
第二个参数:%rsi
-
第三个参数:%rdx
-
第四个参数:%rcx
-
第五个参数:%r8
-
第六个参数:%r9
-
-
栈指针:%rsp
+++
操作数指示符
-
立即数
-
格式:$Imm
-
操作数值:Imm
-
表示常数值
-
-
寄存器
- 格式:r
- 操作数值:R[r]
- 表示某个寄存器的内容——数值或者一个指向内存位置的地址数
-
内存引用
-
引用组成部分:
- 立即数偏移:Imm
- 基址寄存器:r
b - 变址寄存器:r
i - 比例因子 :s
-
操作数值:
-
表达式
$$ Imm(r_b,r_i,s) $$
$$ =M[Imm+R[r_b]+R[r_i]*s] $$
-
-
***M[ ]***即是在内存中寻找相对应的地址内的值
-
单独%~~ 寄存器则是在R[%~~]中获取对应的值。
-
+++
数据传送指令
-
MOV类
-
MOVZ类
-
无符号扩展数据传送指令,将剩余字节填充为0
-
指令 效果 描述 MOVZ (S ,R) R←符号扩展(S) 以符号扩展进行传送 movzbw 将做了符号扩展的字节传送到字 movzbl 将做了符号扩展的字节传送到双字 movzwl 将做了符号扩展的字传送到双字 movzbq 将做了符号扩展的字节传送到四字 movzwq 将做了符号扩展的字传送到四字 -
对无符号数使用
-
-
MOVS类
-
符号扩展数据传送指令
-
指令 效果 描述 MOVS (S ,R) R←符号扩展(S) 传送符号扩展的字节 movzbw 将做了符号扩展的字节传送到字 movzbl 将做了符号扩展的字节传送到双字 movzwl 将做了符号扩展的字传送到双字 movzbq 将做了符号扩展的字节传送到四字 movzwq 将做了符号扩展的字传送到四字 cltq4 %rax←符号扩展(%eax) 把%eax符号扩展到%rax -
对有符号数使用
-
-
MOVS/MOVZ 类后跟 源数据大小(b、w、l) 和 目标数据大小(w、l、q) 一般都是从小的到大的
+++
压入和弹出栈数据
-
栈:一种数据结构。遵循后进先出原则。
-
push:将数据压入栈中
-
pop :删除栈顶数据,弹出到数据目的
-
栈的形式:栈是向下增长的,栈顶元素的地址是所有栈中元素地址最低的 。压栈时,栈顶指针会减少$8,而新栈顶指针会从下到上填满$8的空间。
-
用栈指针%rsp保存着栈顶元素的地址。
指令 效果 描述 pushq S R[%rsp]←R[%rsp]-85
M[R[%rsp]]←S将四字压入栈 popq D D←M[R[%rsp]];
R[%rsp]←R[%rsp]+8将四字弹出栈 -
pushq %rbp 等价于 subq $8,%rsp //栈顶指针往下移动(减$8) movq %rbp,(%rsp) //将栈顶元素指针填入$8个字节
-
popq %rax 等价于 movq (%rsp),%rax //将栈顶元素指针传送到数据目的 addq $8, %rsp //栈顶指针往上移动(加$8)
+++
算术和逻辑操作
-
加载有效地址
-
指令 效果 描述 leaq S,D D←&S 加载有效地址 -
*加载有效地址(load effective address)*指令 leaq是 movq的变形。但它没有引用内存 ,而是将有效地址写入到目标操作数(&s) 为后面的内存引用 产生指针。
-
leaq的特殊用法: 若%rdx的值为 X,那么指令 **leaq 7(%rdx,%rdx,4),%rax ** 等同于将%rax的值设为 5X+7。
- 因为寄存器%rdx存储的是立即数X,但**M[R[%rdx]]本质是用寄存器%rdx内的值 X 作为地址引用 ** 到内存M[X],而内存 **M[X]**的地址就是 X本身,所以可以用此作为一种简洁的算术操作。
-
-
一元操作
-
只有一个操作数
-
指令 效果 描述 INC D D←D+1 加1 DEC D D←D-1 减1 NEG D D← -D 取负 NOT D D←~D 取补
-
-
二元操作
-
有两个操作数
-
指令 效果 描述 ADD S,D D←D+S 加 SUB S,D D←D-S 减 IMUL S,D D←D*S 乘 XOR S,D D←D^S 异或 OR S,D D←D|S 或 AND S,D D←D&S 与
-
-
移位操作
-
指令 效果 描述 SAL k,D D←D«k 左移 SHL k,D D←D«k 左移(等同于SAL) SAR k,D D←D» Ak算术右移 SHR k,D D←D» Lk逻辑右移 -
k是移位量,D是要移位的数。
-
移位量可以是 立即数 也可以是 放在单字节寄存器%cl6中,不管放在寄存器哪个字节,只有最低的m位才会起作用。一个字节(2bits)位移量能达到2^8^ -1=255。对w位长的数据操作,位移量由%cl寄存器的低m位决定,2^m^ = w 。高位会被忽略。
-
每个移位指令都有相对应的 b\w\l\q 后缀,对应不同的要移位的数的大小。
-
+++
特殊的算数操作
-
两个64位有无符号的整数相乘,得到的乘积需要128位来表示。x86-64对 128位(16bits)数提供支持。 将一对寄存器 %rdx , %rax 组成一个128位 的八字。
-
R[%rdx]:R[%rax] 储存八字,包括乘积的结果和 被除数。
-
特别的,在除法中,**R[%rax]储存除法的结果R[%rdx]**储存除法的余数。
-
指令 效果 描述 imulq S
mulq SR[%rdx]:R[%rax]←S×R[%rax] 有符号全乘法
无符号全乘法cqto R[%rdx]:R[%rax]←符号扩展(R[%rax]) 转换为八字7 idivq S
divq SR[%rdx]←R[%rdx]:R[%rax] mod S
R[%rax]←R[%rdx]:R[%rax] ÷ S有符号除法
无符号除法 -
对于 unsigned __int128类型储存乘积。
1 2 3
void store_uprod(uint128_t *dest,uint64_t x,uint64_t y){ *dest=x*(uint128_t)y; }
- 汇编代码是
1 2 3 4 5 6
//dest in %rdi, x in %rsi, y in %rdx movq %rsi,%rax //乘数放入%rax mulq %rdx //y与%rax的数相乘,放入R[%rdx]:R[%rax] movq %rax,(%rdi) //(小端法)低位放在小地址上 movq %rdx,8(%rdi)//(小端法)高位放大地址上
- 存储乘积需要两个movq指令。
-
对于除法
- 通常来说被除数是64位的值。所以%rdx中的位应该是全0(无符号运算) 或者是 %rax的符号位(有符号元素)。%rdx的值会默认设置为0,当进行有符号运算时,需要用cqto7 符号扩展%rax的数。**R[%rax]储存除法的结果R[%rdx]**储存除法的余数。
+++
控制
-
条件码
-
等价于t=a+b 用ADD指令
条件码 表达式示例 效果 描述 标志 CF (unsigned)t <(unsigned)a 无符号溢出 最近的操作最高位产生了进位,
可用来检测无符号溢出进位标志 ZF t==0 零 最近操作的结果为0 零标志 SF t<0 负数 最近的操作得到的结果为负数 符号标志 OF (a<0==b<0)&&(t<0!=a<0) 有符号溢出 最近的操作导致补码溢出(正/负 溢出标志 -
条件码寄存器是在CPU中维护的一组但各位寄存器。
-
可以描述最近的算术或逻辑操作的属性。可以用来检测这些寄存器来执行条件分支指令。
-
除了leaq指令不会改变任何条件码,因为只进行地址计算。除此之外其他指令都会设置条件码。
-