X86 汇编指令

1、相关寄存器

  • X86 处理器中有 8 个 32 位的通用寄存器。
    在这里插入图片描述
  • 为了向后兼容,EAX、EBX、ECXEDX高两位字节和低两位字节可以独立使用,E 为 Extended 表示 32 位的寄存器;例如 EAX 的低两位字节称为 AX,而 AX 的高低字节又可分别作为两个 8 位寄存器,分别称 AH 和 AL。寄存器的名称大小写都可以。除 EBP 和 ESP 外,其他几个寄存器的用途是比较任意的

2、寻址模式和内存分配

1)寻址模式

  • X86 提供了一种灵活的内存寻址方式,以 mov 为例,mov 用于在内存和寄存器之间移动数据,它有两个参数:第一个是目的地地址,第二个是源地址,示例如下:
	mov eax, [ebx]                ;将 ebx 值指示的内存地址中的 4 字节传送到 eax
	mov [var], ebx                 ;将 ebx 值传送到 var 的值指示的内存地址中
	mov eax, [esi-4]              ;将 esi-4 值指示的内存地址中的 4 字节传送到 eax
	mov [esi+eax], cl;
	mov edx, [esi+4*ebx];

注意:最多只能利用两个 32 位寄存器和一个 32 位的有符号常数相加计算出一个内存地址

2)数据类型长度规定

  • 汇编语言中声明内存大小时,一般显式的使用 DB(D 表示 Data,B 表示 Byte)、DW(W 表示 Word,2Bytes)和DD(第二个字母 D 表示 Double World,4Bytes),这样就能指导编译器分配内存空间,但是对于:
	mov [ebx], 2;
  • 若无特殊标记,则不确定常数 2 是单字节、双字节还是双字,为此,X86 提供了三个指示规则标记:BYTE PTR, WORD PTR 和 DWORD PTR,则上述例子可写成:
	mov byte ptr [ebx], 2;      将 2 以单字节形式传输到 ebx 值指示的内存地址中
	mov word ptr [ebx], 2;    将 2 以双字节的形式传送到 ebx 值指示的内存地址中
	mov dword ptr [ebx], 2;  将 2 以四字节的形式传送到 ebx 值指示的内存地址中

3、常用指令

  • 汇编指令通常可以分为数据传送指令、逻辑计算指令和控制流指令
    以下用于操作数的标记分别表示寄存器、内存和常数:
<reg>:表示任意寄存器,若其后带有数字,则指定其位数,如 <reg32> 表示 32 位寄存器(EAX,EBX,ECX,EDX,ESI,EDI,ESP 或 EBP);<reg16> 表示 16 位寄存器(AX, BX, CX 或 DX);<reg8> 表示 8 位寄存器(AH、AL、BH、BL、CH、CL、DH、DL)。
<mem>:表示内存地址
<con>:表示 8 位、16 位或 32 位常数,<con8>表示 8 位常数。
  • X86 中的指令机器码长度位 1 字节,对同一指令的不同用途有多种编码方式,比如 mov 指令就有 28 种机内编码,用于不同操作数类型或用于特定寄存器,例如:
	mov ax, <con16>;    机器码为 B8H
	mov al, <con8>;    机器码为 B0H
	mov <reg16>/<mem16>, <reg16>;   机器码为 89H
	mov <reg8>, <reg8>/<mem8>;    机器码为 8AH
	mov <reg16>, <reg16>/<mem16>;  机器码为 8BH

1)数据传送指令

mov 指令
  • mov 指令将第二个操作数——寄存器的内容、内存中的内容或常数值,复制到第一个操作数——寄存器或内存,但不能用于直接从内存复制到内存,语法如下:
	mov <reg>, <reg>
	mov <reg>, <mem>
	mov <mem>, <reg>
	mov <reg>, <con>
	mov <mem>, <con>
	example:
	mov eax, ebx;
	mov byte ptr [var], 5;
push 指令
  • push 指令将操作数压入内存的栈,常用于函数调用。ESP 是栈顶,压栈前先将 ESP 值减 4,因为栈增长方向与内存地址增长方向相反,然后将操作数压入 ESP 指示的地址;栈中元素固定为 32 位。语法:
	push <reg32>
	push <mem>
	push <con32>
	example:
	push eax;
	push [var];    将 var 指示的内存地址的 4 字节值压入栈
pop 指令
  • pop 指令执行出栈工作,出栈前先将 ESP 指示的地址种内容取出栈,然后将 ESP 值加 4,语法如下:
	pop edi;    弹出栈顶元素送到 edi
	pop [ebx];   弹出栈顶元素送到 ebx 值指示的内存地址的 4 字节中

2)算术和逻辑运算指令

add/sub 指令
  • add 指令将两个操作数相加,相加的结果保存到第一个操作数中。sub 指令用于两个操作数相减,相减的结果保存到第一个操作数中,语法格式入下:
	add <reg>, <reg>
	add <reg>, <mem>
	add <mem>, <reg>
	add <reg>, <con>
	add <mem>, <con>
	sub <reg>, <reg>
	sub <reg>, <mem>
	sub <mem>, <reg>
	sub <reg>, <con>
	sub <mem>, <con>
	example:
	sub eax, 10     ;eax ←eax-10
	add byte ptr [var], 10    ;10 与 var 值指示的内存地址的一字节值相加,并将结果保存在与 var 值指示的内存地址的字节中
inc/dec 指令

inc、dec 指令分别表示操作数自加 1、自减 1,其语法格式如下:

	inc <reg>
	inc <mem>
	dec <reg>
	dec <mem>
	example:
	dec eax   ;eax 值自减 1
	inc dword ptr [var]   ;var 值指示的内存地址的 4 字节值自加 1
imul 指令
  • 带符号整数乘法指令,有两种格式:1)两个操作数,将两个操作数相乘,并将结果保存在第一个操作数中,第一个操作数必须为寄存器;2)三个操作数,将第二个和第三个操作数相乘,并将结果保存在第一个操作数中,第一个操作数必须为寄存器;语法格式如下:
	imul <reg32>,<reg32>
	imul <reg32>, <mem>
	imul <reg32>, <reg32>, <con>
	imul <reg32>, <mem>, <con>
	example:
	imul eax, [var]   ;eax←eax * [var]
	imul esi, edi, 25   ; esi←edi * 25
  • 乘法结果可能溢出,则编译器溢出标志 OF =1,以使 CPU 调出溢出异常处理程序。
idiv 指令
  • 带符号整数除法指令,只有一个操作数,即除数,而被除数则为 edx:eax 中的内容,64 位整数;操作结果分为两部分:商和余数,商送到 eax,余数送到 edx;语法格式如下:
	idiv <reg32>
	idiv <mem>
	example:
	idiv ebx
	idiv dword ptr [var]
and/or/xor 指令
  • 逻辑与、逻辑或、逻辑异或操作指令,用于操作数的位操作,操作结果放在第一个操作数中;语法格式如下,由于格式类似,只需将前面的指令改一下就可以,所以这里以 and 为例:
	and <reg>, <reg>
	and <reg>, <mem>
	and <reg>, <con>
	and <mem> ,<con>
	example:
	and eax, ofH    ;将 eax 中的前28 位全部置零,最后 4 位不变
	xor edx, edx    ;置 edx 中的内容为 
not 指令
  • 位翻转指令,将操作数的每一位翻转,即0⟶1,1⟶0;语法格式如下:
	not <reg>
	not <mem>
	example:
	not byte ptr [var]   ;将 var 值指示的内存地址的一字节的所有位翻转。
neg 指令
  • 取负指令,语法格式如下:
	neg <reg>
	neg <mem>
	example:
	neg eax
shl/shr 指令
  • 逻辑位移指令,shr 为逻辑右移,shl 表示逻辑左移,第一个操作数表示被操作数,第二个操作数指示移位的位数;语法格式如下:
	shl <reg>, <con8>
	shl <mem>, <con8>
	shl <reg>, <cl>
	shl <mem>, <cl> 
	; 上面的 shl 改成 shr 就是逻辑右移的格式
	example
	shl eax, 1    ;将 eax 的值左移 1 位,相当乘于 2
	shr ebx, cl   ;将 ebx 值右移 n 位,n 为 cl 中的值,相当于除于 2^n

3)控制流指令

  • X86 处理器维持这一个指示当前执行指令的指令指针(IP),当执行一条指令后,此指针自动指向下一条指令。IP 寄存器不能直接操作,但可以用控制流指令更新。通常用标签(label)指示程序中的指令地址,在 X86 汇编代码中,可在任何指令前加入标签,例如:
			mov esi, [edp+8]
	begin:         xor ecx, ecx
			mov eax, [esi]
  • 这样就用 begin 指示了第二条指令,控制流指令通过标签可以实现程序的跳转。
jmp 指令
  • 控制 IP 转移到 label 所指示的地址,从 label 中取出指令执行;语法格式如下:
	jmp <label>
	example:
	jmp begin
jcondition 指令
  • 条件转移指令,它依据处理机状态字中的一系列条件状态转移。处理机状态字包括指示最后一个算术运算结果是否为 0,运算结果是否为负数等;语法格式如下:
	je <label> (jump when equal)
	jne <label>(jump when not equal)
	jz <label>(jump when last result was zero)
	jg <label>(jump when greater than)
	jge <label>(jump when greater than or equal to)
	jl <label>(jump when less than)
	jle <label>(jump when less than or equal to)
	example:
	cmp eax, ebx
	jle done   ;如果 eax 的值小于等于 ebx 值,跳转到 done 所指示的指令执行,否则执行下一条指令
cmp 指令
  • 比较两个操作数的值,并根据比较结果设置处理机状态字中的条件码;语法格式如下:
	cmp <reg>,<reg>
	cmp <reg>, <mem>
	cmp <mem>, <reg>
	cmp <reg>, <con>
  • 通常与 jcondition 指令搭配使用:
	cmp dword ptr [var], 10
	jne loop   ;如果 var 指示的内存地址的 4 字节内容等于 10,则继续执行下一条指令;否则跳转到 loop 指示的指令执行。
call/ret 指令
  • 这两条指令实现子程序(过程、函数等)的调用及返回。call 指令首先将当前指令地址入栈,然后无条件转移到由标签指示的指令。与其他简单的跳转指令不同,call 指令保存调用之前的地址信息,当 call 指令结束后,返回调用之前的地址。ret 指令实现子程序的返回机制,ret 指令弹出栈中保存的指令地址,然后无条件转移到保存的指令地址执行。call 和 ret 是函数调用中最关键的两条指令,其语法格式如下:
	call <label>
	ret

上一篇
下一篇

发布了184 篇原创文章 · 获赞 24 · 访问量 2万+

猜你喜欢

转载自blog.csdn.net/qq_42896653/article/details/105016916