x86汇编
x86汇编语言是用于x86架构处理器的低级编程语言。它提供了对处理器硬件的直接访问,因此通常用于编写操作系统、驱动程序和需要高效执行的程序。以下是一些基本概念和指令介绍:
基本概念
-
寄存器:CPU内的高速存储单元,用于暂时存储数据和指令。
- 通用寄存器:AX, BX, CX, DX, SI, DI, BP, SP
- 段寄存器:CS, DS, ES, FS, GS, SS
- 指令指针寄存器:IP
- 标志寄存器:FLAGS
-
内存寻址:包括立即数寻址、寄存器寻址、直接寻址、基址变址寻址等。
-
指令格式:通常包括操作码(opcode)和操作数(operand)。
实模式(Real Mode)
实模式是x86处理器的默认模式,也是最基本的模式。在这种模式下,处理器可以直接访问1MB的内存,并且没有内存保护机制。通常用于早期的操作系统和一些嵌入式系统。
特点:
- 20位地址总线,可以访问最多1MB的内存。
- 没有内存保护机制,所有程序都可以访问所有内存区域。
- 主要用于DOS和一些BIOS功能。
在x86汇编语言的实模式(Real Mode)中,处理器可以访问1MB的内存,寄存器的使用对于编程至关重要。以下是实模式下的寄存器分类和说明:
通用寄存器(General Purpose Registers)
- AX(累加器寄存器):
- 用于算术运算和数据传输。
- 可以分为AH(高8位)和AL(低8位)。
- BX(基址寄存器):
- 通常用于存储基址(内存地址)。
- 可以分为BH(高8位)和BL(低8位)。
- CX(计数器寄存器):
- 常用于循环和字符串操作中的计数。
- 可以分为CH(高8位)和CL(低8位)。
- DX(数据寄存器):
- 用于I/O操作和乘除法指令。
- 可以分为DH(高8位)和DL(低8位)。
指针和索引寄存器(Pointer and Index Registers)
- SP(堆栈指针寄存器):
- 用于堆栈操作,指向堆栈顶。
- BP(基址指针寄存器):
- 常用于基址寻址,特别是访问函数参数和局部变量。
- SI(源变址寄存器):
- 常用于字符串操作,指向源数据。
- DI(目的变址寄存器):
- 常用于字符串操作,指向目的数据。
段寄存器(Segment Registers)
- CS(代码段寄存器):
- 指向当前执行代码的段基址。
- DS(数据段寄存器):
- 指向当前数据段的基址。
- SS(堆栈段寄存器):
- 指向当前堆栈段的基址。
- ES(附加段寄存器):
- 用于额外的数据段,特别是字符串操作。
指令指针寄存器(Instruction Pointer Register)
- IP(指令指针寄存器):
- 指向下一条将要执行的指令地址。
标志寄存器(Flags Register)
- FLAGS(标志寄存器):
- 存储处理器状态的标志位,用于条件判断和控制程序流。
- 主要标志位包括:
- CF(进位标志):表示最高位的进位或借位。
- ZF(零标志):结果为零时置位。
- SF(符号标志):结果为负数时置位。
- OF(溢出标志):有符号运算溢出时置位。
- PF(奇偶标志):结果低8位有偶数个1时置位。
- AF(辅助进位标志):用于BCD运算。
- DF(方向标志):控制字符串操作的方向。
示例代码:
保护模式(Protected Mode)
保护模式是80286及以后处理器支持的一种模式,提供了内存保护、多任务处理和更大的内存寻址空间。现代操作系统如Windows和Linux都运行在保护模式下。
特点:
- 32位地址总线,可以访问4GB的内存。
- 提供内存保护机制,防止程序之间互相干扰。
- 支持分页机制,扩展内存管理能力。
通用寄存器(General Purpose Registers)
这些寄存器用于各种通用的算术运算、逻辑运算和数据传输。
-
EAX(累加器寄存器):
- 用于算术运算和数据传输。
- 可以分为AX(低16位),以及AH(高8位)和AL(低8位)。
-
EBX(基址寄存器):
- 用于基址寻址。
- 可以分为BX(低16位),以及BH(高8位)和BL(低8位)。
-
ECX(计数器寄存器):
- 用于循环计数和字符串操作。
- 可以分为CX(低16位),以及CH(高8位)和CL(低8位)。
-
EDX(数据寄存器):
- 用于I/O操作和乘除法指令。
- 可以分为DX(低16位),以及DH(高8位)和DL(低8位)。
指针和索引寄存器(Pointer and Index Registers)
这些寄存器主要用于内存寻址。
-
ESP(堆栈指针寄存器):
- 用于堆栈操作,指向堆栈顶。
- 可以分为SP(低16位)。
-
EBP(基址指针寄存器):
- 用于基址寻址,特别是访问函数参数和局部变量。
- 可以分为BP(低16位)。
-
ESI(源变址寄存器):
- 用于字符串操作,指向源数据。
- 可以分为SI(低16位)。
-
EDI(目的变址寄存器):
- 用于字符串操作,指向目的数据。
- 可以分为DI(低16位)。
段寄存器(Segment Registers)
这些寄存器用于分段内存管理,每个寄存器指向一个段描述符。
-
CS(代码段寄存器):
- 指向当前执行代码的段基址。
-
DS(数据段寄存器):
- 指向当前数据段的基址。
-
SS(堆栈段寄存器):
- 指向当前堆栈段的基址。
-
ES(附加段寄存器):
- 用于额外的数据段,特别是字符串操作。
-
FS 和 GS:
- 额外的段寄存器,用于指向更多的数据段,通常用于特定用途。
控制寄存器(Control Registers)
这些寄存器用于控制处理器的操作模式和状态。
-
CR0:
- 控制寄存器0,包含启用和配置保护模式、分页等功能的控制位。
-
CR2:
- 存储导致页面错误的线性地址。
-
CR3:
- 存储页目录基地址,分页机制启用时使用。
-
CR4:
- 包含更多控制位,用于扩展功能,如PAE(物理地址扩展)和SSE(流SIMD扩展)支持。
调试寄存器(Debug Registers)
这些寄存器用于硬件调试。
-
DR0-DR3:
- 存储硬件断点的线性地址。
-
DR6:
- 存储调试状态信息。
-
DR7:
- 控制硬件断点功能。
浮点寄存器(Floating Point Registers)
用于浮点运算,属于x87 FPU(浮点运算单元)。
- ST0-ST7:
- 8个80位的浮点寄存器,组成一个栈结构。
示例代码:
长模式(Long Mode)
长模式是x86-64处理器的工作模式,支持64位地址空间和操作。长模式允许访问超过4GB的内存,是现代64位操作系统的基础。
特点:
- 64位地址总线,可以访问非常大的内存空间。
- 支持64位寄存器和操作,提高处理能力。
- 兼容32位保护模式的特性。
在x86-64架构的长模式(Long Mode)中,处理器支持64位操作,寄存器的数量和功能相较于32位保护模式有了显著扩展。以下是长模式下的主要寄存器分类及其功能:
扩展通用寄存器(Extended General Purpose Registers)
在64位模式下,原有的32位通用寄存器被扩展为64位,并增加了8个新的通用寄存器。
-
RAX(累加器寄存器):
- 用于算术运算和数据传输。
- 可以分为EAX(低32位),AX(低16位),以及AH(高8位)和AL(低8位)。
-
RBX(基址寄存器):
- 用于基址寻址。
- 可以分为EBX(低32位),BX(低16位),以及BH(高8位)和BL(低8位)。
-
RCX(计数器寄存器):
- 用于循环计数和字符串操作。
- 可以分为ECX(低32位),CX(低16位),以及CH(高8位)和CL(低8位)。
-
RDX(数据寄存器):
- 用于I/O操作和乘除法指令。
- 可以分为EDX(低32位),DX(低16位),以及DH(高8位)和DL(低8位)。
-
RSI(源索引寄存器):
- 用于字符串操作,指向源数据。
- 可以分为ESI(低32位)和SI(低16位)。
-
RDI(目标索引寄存器):
- 用于字符串操作,指向目标数据。
- 可以分为EDI(低32位)和DI(低16位)。
-
RBP(基址指针寄存器):
- 用于基址寻址,特别是访问函数参数和局部变量。
- 可以分为EBP(低32位)和BP(低16位)。
-
RSP(堆栈指针寄存器):
- 用于堆栈操作,指向堆栈顶。
- 可以分为ESP(低32位)和SP(低16位)。
-
R8-R15(新增加的通用寄存器):
- 这8个寄存器用于扩展操作。
- 每个寄存器也可以分为32位、16位和8位部分(例如,R8可以分为R8D(低32位),R8W(低16位),以及R8B(低8位))。
段寄存器(Segment Registers)
在长模式下,大多数段寄存器的功能有所简化,只有FS和GS段寄存器仍然可以用于基址访问。
-
CS(代码段寄存器):
- 指向当前执行代码的段基址。
-
DS(数据段寄存器):
- 通常为零,不用于段基址访问。
-
SS(堆栈段寄存器):
- 通常为零,不用于段基址访问。
-
ES、FS、GS:
- FS和GS段寄存器仍可以用于基址访问,特别是在访问线程本地存储(TLS)时。
控制寄存器(Control Registers)
控制寄存器用于控制处理器的操作模式和状态。
-
CR0:
- 包含启用和配置保护模式、分页等功能的控制位。
-
CR2:
- 存储导致页面错误的线性地址。
-
CR3:
- 存储页目录基地址,分页机制启用时使用。
-
CR4:
- 包含更多控制位,用于扩展功能,如PAE(物理地址扩展)和SSE(流SIMD扩展)支持。
-
CR8:
- 用于控制外部中断优先级。
调试寄存器(Debug Registers)
调试寄存器用于硬件调试。
-
DR0-DR3:
- 存储硬件断点的线性地址。
-
DR6:
- 存储调试状态信息。
-
DR7:
- 控制硬件断点功能。
浮点寄存器和SIMD寄存器
用于浮点运算和SIMD运算。
-
XMM0-XMM15:
- 128位的SIMD寄存器,支持SSE指令集。
-
YMM0-YMM15:
- 256位的SIMD寄存器,支持AVX指令集。
-
ZMM0-ZMM31:
- 512位的SIMD寄存器,支持AVX-512指令集。
示例代码:
Intel
数据传输指令
-
MOV:将数据从源操作数传送到目的操作数。
-
PUSH 和 POP:在堆栈中压入和弹出数据。
-
XCHG:交换两个操作数的值。
-
LEA:加载有效地址。
算术指令
-
ADD 和 SUB:加法和减法。
-
MUL 和 IMUL:无符号乘法和有符号乘法。
-
DIV 和 IDIV:无符号除法和有符号除法。
-
INC 和 DEC:自增和自减。
逻辑指令
-
AND、OR 和 XOR:按位与、或、异或。
-
NOT:按位取反。
-
SHL 和 SHR:逻辑左移和右移。
-
SAL 和 SAR:算术左移和右移。
控制流指令
-
JMP:无条件跳转。
-
条件跳转指令:根据特定条件进行跳转。
- JE/JZ:如果相等/零标志置位,跳转。
- JNE/JNZ:如果不相等/零标志未置位,跳转。
- JG/JNLE:如果大于/不小于等于,跳转。
- JL/JNGE:如果小于/不大于等于,跳转。
-
CALL 和 RET:调用和返回子程序。
字符串操作指令
-
MOVS:移动字符串。
-
CMPS:比较字符串。
-
SCAS:扫描字符串。
系统指令
-
NOP:空操作,不执行任何操作。
-
HLT:停止处理器,直到下一个外部中断到达。
-
INT:软件中断。
-
IRET:中断返回。
示例代码
以下是一个简单的示例,演示了如何使用x86汇编指令进行基本的数据传输和算术运算:
AT&T
AT&T语法是GNU Assembler(GAS)使用的一种汇编语言语法,与Intel语法相比有一些显著的差异。以下是一些常见的x86汇编指令及其在AT&T语法中的表示方法:
基本规则
-
操作数顺序:
- AT&T语法中,源操作数在前,目的操作数在后。
- Intel语法中,目的操作数在前,源操作数在后。
-
寄存器命名:
- AT&T语法使用前缀
%
来标识寄存器。 - Intel语法不使用前缀。
- AT&T语法使用前缀
-
立即数:
- AT&T语法使用前缀
$
来标识立即数。 - Intel语法直接使用数值。
- AT&T语法使用前缀
-
内存操作数:
- AT&T语法使用
()
和,
来标识内存操作数的基址、变址和比例因子。 - Intel语法使用
[]
。
- AT&T语法使用
-
指令后缀:
- AT&T语法通常在指令后使用
b
,w
,l
,q
来表示操作数的大小(8位,16位,32位,64位)。 - Intel语法不需要这样的后缀。
- AT&T语法通常在指令后使用
常见指令示例
数据传输指令
-
MOV(传送数据)
-
PUSH 和 POP(压栈和出栈)
算术指令
-
ADD 和 SUB(加法和减法)
-
MUL 和 IMUL(乘法)
-
DIV 和 IDIV(除法)
逻辑指令
-
AND、OR 和 XOR(按位与、或、异或)
-
NOT(按位取反)
控制流指令
-
JMP(无条件跳转)
-
条件跳转指令
- JE/JZ(相等时跳转)
- JNE/JNZ(不相等时跳转)
- JG/JNLE(大于时跳转)
- JL/JNGE(小于时跳转)
-
CALL 和 RET(调用和返回子程序)
内存操作指令
- MOV(内存到寄存器,寄存器到内存)
字符串操作指令
-
MOVS(移动字符串)
-
CMPS(比较字符串)
-
SCAS(扫描字符串)
其他指令
-
NOP(空操作)
-
HLT(停止处理器)
示例代码
以下是一个简单的示例,演示了如何使用AT&T语法进行基本的数据传输和算术运算:
NASM汇编伪指令
在NASM(Netwide Assembler)中,伪指令是汇编器提供的辅助指令,用于定义数据、控制段、控制汇编过程等。以下是一些常见的NASM汇编伪指令及其说明:
数据定义伪指令
这些伪指令用于定义各种类型的数据。
-
DB(Define Byte):定义一个或多个字节的数据。
-
DW(Define Word):定义一个或多个字的数据(2字节)。
-
DD(Define Double Word):定义一个或多个双字的数据(4字节)。
-
DQ(Define Quad Word):定义一个或多个四字的数据(8字节)。
-
DT(Define Ten Bytes):定义十个字节的数据(用于定义扩展精度的浮点数)。
段定义伪指令
这些伪指令用于定义代码段、数据段和堆栈段。
- SECTION 或 SEGMENT:定义一个段。
控制伪指令
这些伪指令用于控制汇编过程和设置程序入口点等。
-
ORG:设置起始地址。
-
EQU:定义常量。
-
ALIGN:对齐数据。
-
TIMES:重复数据或指令。
-
INCBIN:包含二进制文件的内容。
宏定义伪指令
这些伪指令用于定义和使用宏,以减少重复代码。
- %macro 和 %endmacro:定义一个宏。
条件编译伪指令
这些伪指令用于条件编译代码块。
-
%if、%elif、%else、%endif:条件编译代码块。
-
%ifdef、%ifndef、%endif:条件编译代码块(基于符号是否定义)。
重复定义伪指令
- REPT 和 ENDR:重复定义一段代码。
示例代码
以下是一个示例,演示了如何使用伪指令定义数据和段,并包含一个简单的程序入口点:
gcc汇编伪指令
as
是GNU Assembler的缩写,是GNU Binutils的一部分,用于将汇编代码转换为目标代码。as
支持许多伪指令,这些指令用于数据定义、段定义、控制汇编过程和其他特殊用途。以下是一些常见的GNU汇编器(as
)伪指令及其说明:
数据定义伪指令
-
.byte:定义字节数据。
-
.word:定义字数据(2字节)。
-
.long:定义双字数据(4字节)。
-
.quad:定义四字数据(8字节)。
-
.ascii:定义一个不带NULL结尾的字符串。
-
.asciz 或 .string:定义一个带NULL结尾的字符串。
-
.zero:分配指定字节数的零初始化空间。
段定义伪指令
-
.section:定义一个段。
-
.text、.data、.bss:分别定义代码段、数据段和BSS段。
控制伪指令
-
.global 或 .globl:定义全局符号。
-
.equ 或 .set:定义常量。
-
.align:对齐数据。
-
.org:设置起始地址。
-
.incbin:包含二进制文件的内容。
宏定义伪指令
- .macro 和 .endm:定义一个宏。
条件伪指令
-
.if、.else、.endif:条件汇编代码块。
-
.ifdef、.ifndef、.endif:条件汇编代码块(基于符号是否定义)。
重复伪指令
- .rept 和 .endr:重复一段代码。
示例代码
以下是一个示例,演示了如何使用GNU汇编器伪指令定义数据和段,并包含一个简单的程序入口点: