计算机组成原理学习笔记——常用X86 汇编指令
X86 架构的常用汇编指令
·
X86 汇编指令
1、相关寄存器
- X86 处理器中有 8 个 32 位的通用寄存器。
- 为了向后兼容,
EAX、EBX、ECX
和EDX
的高两位字节和低两位字节
可以独立使用,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
开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!
更多推荐
已为社区贡献9条内容
所有评论(0)