X86-64系统的汇编指令
提示:这里有汇编的核心思维模型,心理表征
1.编译系统
2.汇编的本质
汇编的本质是 内存和寄存器之间的数据交换。
寄存器本质是一个存储空间。
2.1 常用寄存器
dis dxc r 8 9
第一死
递茶C
289
参数寄存器 (记住) | 描述 |
---|---|
%rdi | 参数1,64位寄存器 |
%rsi | 参数2,64位寄存器 |
%rdx | 参数3,64位寄存器 |
%rcx | 参数4,64位寄存器 |
%r8 | 参数5,64位寄存器 |
%r9 | 参数6,64位寄存器 |
放到栈上 | 参数7-,64位寄存器 |
寄存器名称 | 描述 |
---|---|
%rax | retrun 返回值,64位寄存器 |
返回值寄存器 | 描述 |
---|---|
%rsp | 栈指针,64位寄存器 |
栈指针寄存器 | 描述 |
---|---|
%rsp | 栈顶指针,64位寄存器 |
无固定含义寄存器 | 描述 |
---|---|
%rbx | 变量,用于存储中间数据 |
%rbp | 栈底,栈基准地址,64位寄存器 |
参数过多放在栈上
2.2 寄存器不同位数的表示方法
64位(r) -32位(e)-16为(取e)-8位(结尾l)
8位(三个字母去l,二个字母l改成x)
列如: bl -> bx->rbx
dil -> di -> rdi
bpl ->bp-> rbp
3.常用的指令
3.1 指令的组成
指令 = 操作码+操作数
操作数:立即数 + 寄存器 + 内存引用
立即数:$常数 :一个常数
寄存器:%rax :寄存器指针中的值或者空间 ,寄存器的空间
内存引用:( ) :一个地址的解引用,是内存空间
movl $0x4050 %eax 将立即数0x4050放入%eax寄存器空间中
movw %bp %sp 将%eax寄存器空间的值放入%sp寄存器中
movq %rax -12(%rbp) 将%rax寄存器空间的值放入到 (%rbp-12)作为地址的内存中:m[%rbp-12]
(%rbp-12)作为地址的内存中:m[%rbp-12] m[R[rbp]-12]
注意:%rbp 表示rbp寄存器中的值,R[rbp]也是这个意思
此处rbp想一个指向该寄存器的指针,通过解引用获取其中的值。
%和( )都可以视作*解引用
关于指针的再理解,
3.2 内存引用
地址计算公式:
例子:-12(%rbp) -> 地址为:%rbp-12
12(%rdi,%rcx,4) -> 地址为:12+ %rbp +%rcx * 4
注意公式计算的结果是地址
3.3 movq S(源操作数) D(目的操作数)
movq 指令不能直接将数据从内存S移动到另一个内存地址D。
指令 | 操作数大小(字节) | 描述 | 备注 |
---|---|---|---|
movb | 1 8位 | 将1个字节的数据从一个位置复制到另一个位置。 | 操作的是字节数据。 |
movw | 2 16 位 | 将2个字节(Word)的数据从一个位置复制到另一个位置。 | 操作的是字数据。 |
movl | 4 32位 | 将4个字节(Double word)的数据从一个位置复制到另一个位置。 | 操作的是双字数据,写入寄存器时,高位字节将被清零。 |
movq | 8 64位 | 将8个字节(Quad word)的数据从一个位置复制到另一个位置。 | 操作的是四字数据,但是立即数作为源操作数时只能表示32位。 |
movabsq | 8 | 将一个绝对的64位立即数移动到寄存器中。 | 只能以寄存器作为目的地,可以操作任意64位立即数。 |
movabsq $0x0011223344556677 %rax
movb $-1 %al
movw $-1 %ax
movl $-1 %eax
3.4.pushq和popq 出栈和入栈
3.4.1 栈帧的描述
3.4.2 pushq %rax
pushq %rax,表示将%rax中值保存到栈中。等效于
shuq $8,%rsp
movq %rax,(%rsp)
3.4.3 popq %rax
popq %rax,弹出栈顶元素,放入%rax中。等效于:
movq %rax,(%rsp)
addq $8,%rsp
3.3 leaq S,D
把地址保存到D中
用法:1.加载有效地址 2.做计算
例子:
leaq 7(%rdx,%rdx,4) %rax
将 7+%rdx+%rdx*4这个地址放入%rax中,
不是将7+%rdx+%rdx*4这个地址中的值放入%rax。
3.4 其他指令
一元操作指令 | 效果 | 描述 |
---|---|---|
inc d | d←d+1 | d自增1 |
dec d | d←d-1 | d自减1 |
nec d | d← - d | 取负 |
not d | d← ~d | 取反 |
二元操作指令 | 效果 | 描述 |
---|---|---|
add s,d | d←d+s | 加法 |
sub s,b | d←d-s | 减法subtract |
imul | d← d*s | 乘法 multiply |
xor s,d | d← d^s | 异或 |
or d | d← d |d | 取反 |
and s,d | d← d & s | 乘法 multiply |
移位操作指令 | 效果 | 描述 |
---|---|---|
sal s,d | d←d<<s | 左移 |
shl s,b | d←d<<s | 左移 |
sar s,d | d← d>>s | 算数右移,用于有符号数 |
shr s,d | d← 左移 | 逻辑右移。用于无符号数 |
4.c语言中的if和while对于的汇编(条件码寄存器)
4.1 条件码寄存器
几个例子:
unsigned char a = 255;
unsigned char b =1;
unsigned char t= a + b;// >>>发生cf无符号数的溢出
int a = 1;
int b = -1;
int t = a + b;//>>>发生zf 出现0
4.2 部分指令不仅更新目的寄存器,也更新条件码寄存器
4.2 部分指令不仅更新目的寄存器,也更新条件码寄存器
inc
:增加指令,将目的寄存器的值增加1。dec
:减少指令,将目的寄存器的值减少1。neg
:取反指令,将目的寄存器的值取反(即乘以-1)。not
:按位取反指令,对目的寄存器的每一位进行取反操作。add
:加法指令,将源寄存器的值加到目的寄存器上。sub
:减法指令,将源寄存器的值从目的寄存器中减去。imul
:有符号乘法指令,将源寄存器的值与目的寄存器相乘。or
:按位或指令,对源寄存器和目的寄存器的值进行按位或操作。xor
:按位异或指令,对源寄存器和目的寄存器的值进行按位异或操作。and
:按位与指令,对源寄存器和目的寄存器的值进行按位与操作。sal
:算术左移指令,将目的寄存器的值向左移动指定位数。shl
:逻辑左移指令,将目的寄存器的值向左移动指定位数。sar
:算术右移指令,将目的寄存器的值向右移动指定位数。shr
:逻辑右移指令,将目的寄存器的值向右移动指定位数。
4.3 testq和cmpq指令
cmpq %rax %rdx // 根据%rdx- %rax的结果,去改变条件码寄存器的结果
subq %rax %rdx // %rdx = %rdx -%rax 去改变条件码寄存器的结果
特性 | cmpq | subq |
---|---|---|
功能 | 比较两个操作数大小,不保存结果到目的寄存器中,只更新条件码寄存器 | 从第一个操作数减去第二个操作数,保存结果并更新条件码寄存器 |
结果保存 | 目的寄存器中保存结构 | 将结果保存在第一个操作数(目的寄存器)中 |
条件码更新 | 是 | 是 |
典型用法 | 用于条件分支判断,比较操作数大小 | 用于实际的减法计算,需要结果值 |
testq %rax %rdx // 根据%rdx & %rax的结果,去改变条件码寄存器的结构
andq %rax %rdx // %rdx = %rdx &%rax 去改变条件码寄存器的结构
特性 | testq | andq |
---|---|---|
功能 | 对两个操作数进行逻辑与运算,不保存结果,只更新条件码寄存器 | 对两个操作数进行逻辑与运算,保存结果并更新条件码寄存器 |
结果保存 | 不保存计算结果 | 将结果保存在目的寄存器中 |
条件码更新 | 是 | 是 |
典型用法 | 用于检查位是否设置,例如检查寄存器中特定位的状态 | 用于需要逻辑与操作结果的场景,例如位屏蔽 |
影响的标志位 | 通常只影响ZF和SF标志位 | 影响所有相关的标志位,包括ZF、SF、PF、CF和OF |
4.4 sete jl cmovge 等指令
作用:(读条件码,并根据根据推荐码来判断是否执行命令)
符号后缀含义 :条件 | 含义 | 结果 |
---|---|---|
e | equal | 等于(=0) |
g | greater | 大于(>0) |
l | less | 小于(<0) |
ge | greater equal | 大于等于(>=0) |
le | less equal | 小于等于(<=0) |
int comp(long a, long b)
{
return (a==b);
}
cmpq:
cmpq %rsi,%rdi //计算%rdi-%rsi的值,并设置所有可能得条件码。
sete %al; //根据条件码。判断%rdi-%rsi的值是否=0;如果=0,则将%al=1;
movzbl %al,%eax//将%al的值放入%eax中,
ret //返回%eax
sete %al 结果符合条件(=0),将%al赋值为1, 结果不符合条件,将%al赋值为0;
jl.L4 结果符合条件(<0),跳转到L4位置,结果不符合条件,不跳转
cmovge %rdx %rax 结果符合条件(<=0),将%rdx中值放入%rax中, 结果不符合条件,什么都不干。
4.5 testq和cmpq指令 和 sete jl cmovge 等指令结合实现循环,判断
cmpq %rsi,%rdi //计算%rdi-%rsi的结果,
cmovge %rdx,%rax //根据上面计算的结果,判断是否>=0,成立,则执行mov指令。
testq %rsi,%rdi //计算%rdi&%rsi的结果,
cmovge %rdx,%rax //根据上面计算的结果,判断是否>=0,成立,则执行mov指令。