x86-64汇编语言

· 3009字 · 7分钟

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 返回地址

现场保护和现场恢复 🔗

一般在子程序中完成

子程序传参方式 🔗

  • 寄存器
  • 全局变量
  • 堆栈:最后压入第一个参数
  1. 压栈入口参数:从后向前压入参数
  2. 压入断点
  3. 跳转
  4. push %ebp:保存主函数的ebp
  5. movl %esp,%ebp:设置子函数的新ebp
  6. sub $N,%esp:定义函数局部变量空间
  7. 执行函数,要求规范使用堆栈.
  8. (%ebp):原ebp的值
  9. 4(%ebp):返回地址
  10. 8,12,16…(%ebp):函数参数1,2,3…
  11. -4,-8,-12…(%ebp):局部变量1,2,3…
  12. 返回,返回值保存到ax
  13. addl $N,%esp
  14. mov %ebp,%esp
  15. pop %ebp
  16. ret
  17. 消除参数占用的堆栈空间