x86-64汇编语言 🔗
汇编器命令 🔗
.section 🔗
定义内存段
.section .data
定义数据段
.section .bss
定义bss段(一般在代码段之前),在运行时初始值均为0
.section .text
定义代码段
.globl symbol 🔗
使连接器 ld
能够访问 symbol
.globl _start
使_start能被连接器访问
.ascii 🔗
文本字符串
.asciz/.string 🔗
以0x00结尾的文本字符串
.byte 🔗
1字节
.short/.word/.hword 🔗
2字节
.long/.int 🔗
4字节
.quad 🔗
8字节
.octa 🔗
16字节
.single/.float 🔗
单精度浮点数
.double 🔗
双精度浮点数
.lcomm symbol, length 🔗
为本地通用符号 symbol
预留 length
字节的内存
在.bss段中分配,只能在本程序中访问
.comm symbol, length 🔗
声明通用符号 symbol,
如发现同名符号,则并入,且按照最大的length值分配内存
与 .lcomm symbol, length
功能相同,但可以在外部程序中访问
.fill repeat[, size=1, value=0] 🔗
反复 repeat
次拷贝 size
个字节
size
字节中低4字节置为 value
,如有高位字节则置0
size不能超过8
.set/equ symbol, expression 🔗
设置symbol为expression相同的值和类型
.rept count […] .endr 🔗
将中间的行重复 count
次
.space size[, fill=0] 🔗
保留size字节空间,每个字节的值为fill
.type label, @function 🔗
todo
x86-32寄存器 🔗
通用寄存器 🔗
- EAX:累加器,常用于算术逻辑运算
- EBX:基址寄存器,常用于存放存储器地址
- ECX:计数器
- EDX:数据寄存器
- ESI:源变址寄存器,常用于作为源操作数指向字符串或数组
- EDI:目的变址寄存器,常用于作为目的操作数指向字符串或数组
- EBP:基址指针,指向程序栈区域
- ESP:堆栈指针,指向程序栈顶
均可以去掉E访问低16位,EAX到EDX可以使用XH访问8到15位,使用XL访问低8位.
指令指针EIP 🔗
指向主存中将要执行的指令,程序只能通过控制指令间接读取/修改EIP的值
段寄存器 🔗
- CS:代码段,程序指令必须存放在此
- SS:堆栈段,程序使用的堆栈一定在堆栈段
- DS:数据段,程序数据默认存放在此
- ES,FS,GS:附加段,同数据段
均为16位
标志寄存器EFLAGS 🔗
- CF=EFLAGS[0]:进位/借位标志(无符号数)
- OF=EFLAGS[11]:溢出标志(有符号数,结果错误与实际结果符号相反)
- ZF=EFLAGS[6]:零标志
- SF=EFLAGS[7]:符号标志(运算结果最高有效位)
- PF=EFLAGS[2]:奇偶标志(运算结果最低字节1的个数为偶数)
- AF=EFLAGS[4]:辅助进位标志
- DF:方向标志
- IF:中断允许标志
- TF:陷阱标志
其他寄存器 🔗
- 系统地址寄存器GDTR, IDTR, LDTR, TR
- 控制寄存器CRn 5个
- 调试寄存器DRn 8个
- 测试寄存器TRn 5个
浮点寄存器 🔗
- 单精度:32位
- 双精度:64位
- 拓展精度:80位
- 浮点数据寄存器FPRn 8个, 均为80位
- 自动转换类型
- 后进先出(栈)
- 浮点状态寄存器
- 浮点控制寄存器
多媒体寄存器 🔗
MMX指令 - MMX寄存器mm0-mm7, 64位
SSE指令 - SIMD浮点数据寄存器xmm0-xmm7, 128位 与 控制状态寄存器MXCSR
统称SIMD指令
IA-32特性 🔗
小端方式 🔗
地址对齐 🔗
分段管理 🔗
一个存储单元有一个唯一的物理地址和多个逻辑地址
段基地址:偏移地址
- 指令 CS:EIP
- 堆栈 SS:ESP
- 数据 DS/ES/FS/GS + 各种寻址方式
存储模型 🔗
平展存储模型:线性地址空间4GB 🔗
段式存储模型:一组段,每个段容量4GB 🔗
实空间存储模型:老东西 🔗
工作方式 🔗
实地址模式(实方式) 🔗
- 只使用低20位地址线,寻址空间1MB,段长最大64KB
保护方式 🔗
可以使用32位段
可以使用分页
可以使用平展或段式存储模型
虚拟8086方式:老东西 🔗
寻址方式 🔗
- 立即数
- 寄存器
- 存储器 base_address(offset_address,index,size) base_address + offset_address + index * size
- 存储器 - 直接寻址方式 只有base_address
- 存储器 - 寄存器间接寻址方式 只有offset_address(寄存器保存)
- 存储器 - 寄存器相对寻址方式 base_address(offset_address)
- 存储器 - 变址寻址方式 含全部参数(size省略即为1)
AT&T语法 🔗
立即数
$4
寄存器
%eax
操作数顺序/数据长度
movl $4,%eax
长跳转/调用/返回
ljmp $section,$offset
lcall $section,$offset
lret $n
存储器寻址
base_address(offset_address,index,size)
Intel语法 🔗
立即数
4
寄存器
eax
操作数顺序/数据长度
mov eax,4
长跳转/调用/返回
jmp far section:offset
call far section:offset
ret n
存储器寻址
[base_address + offset_address + index * size]
as汇编器(todo) 🔗
ld连接器(todo) 🔗
gdb调试器(todo) 🔗
gcc编译器(todo) 🔗
objdump反汇编器(todo) 🔗
IA32指令 🔗
movx src,dest 🔗
xchg src,dest 🔗
push src 🔗
SS:esp = src; esp = esp - 4
pop dest 🔗
dest = SS:esp; esp = esp + 4
pusha 🔗
将8个通用寄存器压栈
popa 🔗
pusha的逆操作
标志传送指令 🔗
pushf 🔗
将eflags压栈
popf 🔗
栈顶弹出至eflags
lahf 🔗
标志寄存器低字节->%ah
sahf 🔗
%ah -> 标志寄存器低字节
clc/stc/cmc 🔗
复位/置位/求反CF
cld/std 🔗
复位/置位DF
cli/sti 🔗
复位/置位IF
lea mem,r32 🔗
将存储器操作数的段内偏移地址传送到16或32位通用寄存器,通常用于获取汇编阶段无法确定的偏移地址
lds/les/lfs/lgs/lss 🔗
指针传送指令,很少使用
movzx r8/m8,r16 🔗
movzx r8/m8/r16/m16,r32 🔗
零扩展
movsx r8/m8,r16 🔗
movsx r8/m8/r16/m16,r32 🔗
符号扩展
算术运算指令:注意影响标志位 🔗
addx src,dest 🔗
影响全部状态标志位
adcx src,dest 🔗
dest = dest + src + eflags.CF
与add结合实现多精度数加法
影响全部状态标志位
incx reg/mem 🔗
影响除CF外全部状态标志位
subx src,dest 🔗
影响全部状态标志位
sbbx src,dest 🔗
dest = dest - src - eflags.CF
影响全部状态标志位
decx reg/mem 🔗
影响除CF外全部状态标志位
negx reg/mem 🔗
reg/mem = 0 - reg/mem
同用0做减法的subx指令
影响全部状态标志位
cmpx src,dest 🔗
!!!dest - src!!!
影响全部状态标志位
mulx src<al/ax/eax><ax/dx:ax/edx:eax> 🔗
无符号乘法
ax = al * r8/m8
dx:ax = ax * r16/m16
edx:eax = eax * r32/m32
基本乘法指令中,OF=CF=乘积高一半是否含有效数字
,其他标志位含义未定义
imulx src<al/ax/eax><ax/dx:ax/edx:eax> 🔗
有符号乘法
ax = al * r8/m8
dx:ax = ax * r16/m16
edx:eax = eax * r32/m32
imulx src=r16/r32/m16/m32,dest=r16/r32 🔗
dest = dest * src
小心溢出
imulx imm=i8/i16/i32,src=r16/r32/m16/m32,dest=r16/r32 🔗
dest = src * imm
divx divisor=r8/r16/r32/m8/m16/m32<ax/dx:ax/edx:eax><ax/dx:ax/edx:eax> 🔗
idivx divisor=r8/r16/r32/m8/m16/m32<ax/dx:ax/edx:eax><ax/dx:ax/edx:eax> 🔗
注意被除数长度,是否除以0,以及除法溢出
十进制调整指令daa/das/aaa/aas/aam/aad 🔗
BCD码相关
逻辑运算指令 🔗
andx src,dest 🔗
orx src,dest 🔗
notx reg/mem 🔗
xorx src,dest 🔗
test src,dest 🔗
移位指令 🔗
shl/shr reg/mem 🔗
逻辑移位:reg/mem左/右移1位,最低/高位补0,最高/低位进入CF
shl/shr r8/i8 reg/mem 🔗
逻辑移位:reg/mem左/右移r8/i8位,最低/高位补0,最高/低位进入CF
sal/sar reg/mem 🔗
算术移位
sal/sar r8/i8 reg/mem 🔗
算术移位
rol/ror r8/i8 reg/mem 🔗
循环移位,不带进位
rcl/rcr r8/i8 reg/mem 🔗
循环移位,带进位
串操作指令 🔗
movsx 🔗
rep…movsx 🔗
repz/repe/repnz/repne… 🔗
lodsx 🔗
stos 🔗
cmps 🔗
scasx 🔗
分支程序结构指令 🔗
jmp 🔗
jz/je/jnz/jne/js/jns/jp/jpe/jnp/jpo/jo/jno/jc/jb/jnae/jnc/jnb/jae/jbe/jna/jnbe/ja/jl/jnge/jnl/jge/jle/jng/jnle/jg 🔗
循环程序结构指令 🔗
loop label 🔗
子程序 🔗
call 🔗
push 下一条指令地址
jmp 子程序
ret 🔗
pop 返回地址
jmp 返回地址
现场保护和现场恢复 🔗
一般在子程序中完成
子程序传参方式 🔗
- 寄存器
- 全局变量
- 堆栈:最后压入第一个参数
- 压栈入口参数:从后向前压入参数
- 压入断点
- 跳转
- push %ebp:保存主函数的ebp
- movl %esp,%ebp:设置子函数的新ebp
- sub $N,%esp:定义函数局部变量空间
- 执行函数,要求规范使用堆栈.
- (%ebp):原ebp的值
- 4(%ebp):返回地址
- 8,12,16…(%ebp):函数参数1,2,3…
- -4,-8,-12…(%ebp):局部变量1,2,3…
- 返回,返回值保存到ax
- addl $N,%esp
- mov %ebp,%esp
- pop %ebp
- ret
- 消除参数占用的堆栈空间