80x86寄存器
通用寄存器
- AX,BX,CX,DX 称作为数据寄存器:
AX (Accumulator):累加寄存器,也称之为累加器;
BX (Base):基地址寄存器;
CX (Count):计数器寄存器;
DX (Data):数据寄存器;
- SP 和 BP 又称作为指针寄存器:
SP (Stack Pointer):堆栈指针寄存器;
BP (Base Pointer):基指针寄存器;
- SI 和 DI 又称作为变址寄存器
SI (Source Index):源变址寄存器;
DI (Destination Index):目的变址寄存器;
控制寄存器
IP (Instruction Pointer):指令指针寄存器;
FLAG:标志寄存器;
段寄存器
CS (Code Segment):代码段寄存器;
DS (Data Segment):数据段寄存器;
SS (Stack Segment):堆栈段寄存器;
ES (Extra Segment):附加段寄存器;
FS(Data Segment):数据段寄存器;
GS(Data Segment):数据段寄存器;
内存管理寄存器
GDTR:全局描述符表寄存器
IDTR:中断描述符表寄存器
LDTR:局部描述符表寄存器
TR:任务寄存器
段选择符结构
RPL:请求特权级
TI:表指示标志,=0表示描述符在GDT中,=1表示描述符在LDT中
Index:索引值
逻辑地址、线性地址和物理地址之间的变换,分段机制把逻辑地址转换成线性地址,而分页则把线性地址转换成物理地址。
控制寄存器
CR0:控制处理器模式和状态的系统控制标志
CR1:保留
CR2:含有导致页错误的线性地址
CR3:含有页目录表物理内存基地址
系统指令
LLDT/SLDT:加载/保存局部描述符寄存器LDTR
LGDT/SGDT:加载/保存全局描述符表寄存器GDTR
LTR/STR:加载/保存任务寄存器TR,把TR中的TSS加载到任务寄存器中/保存到内存或通用寄存器中
LIDT/SIDT:加载/保存中断描述符表寄存器IDTR
MOV CRn:加载和保存控制寄存器CR0、CR1、CR2和CR3
LMSW/SMSW:加载/保存机器状态字,用于兼容80286处理器
CLTS:清除CR0中的任务已切换标志TS,用于处理设备不存在异常
LSL:加载段限长
HLT:停止处理器执行
寻址方式
立即数寻址/寄存器寻址
MOV AX, 1 ;AX = 1
MOV AX, BX ;AX = BX
直接寻址
MOV AX, [1234H];BX、SI、DI默认段DS,BP默认使用段SS,AX = *(DS << 4 + 1234H)
MOV AX, ES:[1234H];AX = *(ES << 4 + 1234H),把ES数据段中偏移地址为1234H数据复制
寄存器直接寻址
MOV AX, [BX];AX = *(DS << 4 + BX),把DS段中BX指向的字单元复制
MOV AX, CS:[BX];AX = *(CS << 4 + BX)
寄存器相对寻址
MOV AX, [BX + 1234H];AX = *(DS << 4 + (BX + 1234H))
MOV AX, 100H[BX]; AX = *(DS << 4 + (BX + 100H)),把DS段中BX+100H的字单元复制
基址变址寻址
基址变址寻址就是使用两个寄存器{BX/BP} + {SI/DI}(一组只能出现一个),如果出现BP寄存器则默认使用SS寄存器
MOV AX, [BX + SI];AX = *(DS << 4 + (BX + SI))
相对基址变址寻址
MOV AX, [BX + SI + 1234H]; AX = *(DS << 4 + (BX + SI +1234H))
地址属性修饰符
BYTE PTR、WORD PTR和DWORD PTR是属性修饰符,指明地址对应的数据属性
MOV BYTE PTR[BP], 20H;把立即数20H放到DS段中对应BP偏移处,即 *(DS << 4 + BP) = 20H
指令系统
数据传送指令
t通用数据传送指令:MOV、PUSH、POP、XCHG
累加器专用传送指令:IN、OUT、XLAT
地址传送指令:LEA、LDS、LES
标志寄存器传送指令:LAHF、SAHF、PUSHF、 POPF
算术指令
加法指令:ADD、ADC、INC
减法指令:SUB、SBB、DEC、NEG、CMP
乘法指令:MUL、IMUL
除法指令:DIV、IDIV
符号扩展指令:CBW、CWD
十进制调正指令:DAA、DAS、AAA、AAM、AAD
逻辑指令
逻辑运算指令:AND、OR、NOT、XOR、TEST
移位指令:SHL、SAL、SHR、SAR、ROL、ROR、RCL、RCR
串处理指令
设置方向标志指令:CLD、STD
串处理指令:MOVSB/MOVSW、STOSB/STOSW、LODSB/LODSW、CMPSB/CMPSW、SCASB/SCASW
串重复前缀:REP、REPE/REPZ、REPNE/REPNZ
控制转移指令
无条件转移指令:JMP
条件转移指令:JZ/JE、JNZ/JNE、JS、JNS、JO、JNO、JP、JNP、JB、JNB、JBE、JNBE、JL、JNL、JLE、JNLE、JCXZ
循环指令:LOOP、LOOPZ/LOOPE、LOOPNZ、LOOPNE
子程序调用何返回指令:CALL、RET
中断与中断返回指令:INT、INTO、IRET
处理器控制指令
标志位处理指令:CLC、CMC、STC、CLD、STD、CLI、STI
处理机控制指令:NOP、HLT、WAIT、ESC、LOCK
嵌入汇编格式
asm( “汇编语句”
:输出寄存器
:输入寄存器
:会被修改的寄存器);
输入输出寄存器编号
顺序从输出寄存器序列从左到右从上到下以“%0”开始,分别记为%0,%1,…,%9
常用寄存器加载代码说明
“a” 使用寄存器eax
“b” 使用寄存器ebx
“c” 使用寄存器ecx
“d” 使用寄存器edx
“S” 使用esi
“D” 使用edi
“q” 使用动态分配字节可寻址寄存器(eax、ebx、ecx或edx)
“r” 使用任意动态分配的寄存器
“g” 使用通用有效的地址即可(eax、ebx、ecx、edx或内存变量)
“m” 使用内存地址
“o” 使用内存地址并可以加偏移量
“I” 使用常数0-31
“J” 使用常数0-63
“K” 使用常数0-255
“L” 使用常数0-65535
“M” 使用常数0-3
“N” 使用1字节常数(0-255)
“O” 使用常数0-31
“A” 使用eax与edx联合(64位)
“+” 表示操作数可读可写
“=” 输出操作数,输出值将替换前值
“&” 早期会变得操作数,表示使用完操作数之前,内容会被修改
案例
#define get_seg_byte(seg, addr)
({
register char __res;
asm(“push %%fs;
mov %%ax, %%fs;
movb %%fs:%2, %%a1;
:”=a"(__res)
:“0”(seg), “m”(*(addr))); __res;
})
栈帧结构
寄存器ebp(帧指针) 寄存器esp(斩指针),因此函数对大部分数据得访问都基于帧指针ebp进行。
对于函数A调用函数B,转递给B的参数(入栈顺序与函数申明的参数顺序相反,即函数最后一个参数首先压入栈中,第一个参数则是最后一个入栈)包含在A的栈帧中,函数A的返回地址被压入栈,该位置也指明A栈帧的结束处。而B的栈帧从随后的栈部分开始,即图中保存栈帧指针ebp的地方开始,随后用于保存寄存器以及函数的临时值。
80x64寄存器
新增寄存器
新增加寄存器r8到r15,加上x86的原有8个(rax,rbx,rcx,rdx,esi,edi,rbp,rsp),一共16个寄存器。
其中在gcc编译器下:
- rax 作为函数返回值使用
- rsp 栈指针寄存器,指向栈顶
- fastcall规范参数传递规范,使用rcx、rdx、r8、r9寄存器传递函数所需的前4个参数(实数型数据XMM0、XMM1、XMM2、XMM3),并用栈传递其余参数
- System V AMD64 ABI(泛指Linux、各种BSD和Mac OS X)系统的函数调用使用rdi,rsi,rdx,rcx,r8,r9 作函数参数,依次对应第1参数,第2参数。。。,如果参数超出寄存器,使用栈传递
- rbx,rbp,r12,r13,r14,r15 用作数据存储,遵循被调用者使用规则,简单说就是随便用,调用子函数之前要备份它,以防他被修改
- r10,r11 用作数据存储,遵循调用者使用规则,简单说就是使用之前要先保存原值
- r8~ r15寄存器可以使用相应的32位(r8d~ r15d)、16位(r8w~ r15w)、8位(r8l~ r15l)助记符
- 平台的指针都是64位指针
- MSVC使用ECX寄存器传递this指针,而GCC则把this指针作为被调用方函数的第一个参数传递
栈帧结构
MSVC未开启优化选项,会把传递参数的寄存器和帧重新推送到被调用函数帧栈中,这种现象叫做“阴影空间”,具有两个优点:1)避免浪费寄存器资源;2)便于调试器中断时找到函数参数。大型参数可能把输入参数保存在阴影空间里,但是小型函数可能就不会使用阴影空间。