整数乘法指令 Integer Multiplication
对于有符号数的乘法有特殊的规则, 因此无符号数乘法和有符号数乘法对应着不同的指令mul和imul. 乘法会产生两倍尺寸的数值结果, 即两个n-bit数相乘会产生2n-bit的数. 两个8bit数相乘会产生16bit的数. 对于乘法指令有许多变种, 例如对于带符号乘法, 一些指令能将结果裁剪至和源数值一样的尺寸.
无符号的乘法 Unsigned Multiplication
通常这种乘法的格式为
mulmul mul mul mul mul word [wVvar]mul almul dword [dVar]mul qword [qVar]
src运算数必须是寄存器或内存地址, 不能为立即数. 对于这样的单运算数乘法指令, 在执行时, 会使用A寄存器中对应尺寸的数值(al/ax/eax/rax). 分别对应8bit, 16bit, 32bit, 64bit尺寸的运算数. 乘法的结果会被放置在A寄存器以及D寄存器中. 下面的表格显示了不同尺寸下的无符号乘法及其结果
Byte: ax = al * <src>Word: dx:ax = ax * <src>Double: edx:eax = eax * <src>Quad: rdx:rax = rax * <src>这样的结果位置组合, 是由于要向下兼容早先的版本, 会让人有些困惑.代码例子bNumA db 42bNumB db 73wAns dw 0wAns1 dw 0wNumA dw 4321wNumB dw 1234dAns2 dd 0dNumA dd 42000dNumB dd 73000qAns3 dq 0qNumA dq 420000qNumB dq 730000dqAns4 ddq 0; wAns = bNumA^2 or bNumA squaredmov al, byte [bNumA] mul al ; result in axmov word [wAns], ax; wAns1 = bNumA * bNumBmov al, byte [bNumA]mul byte [bNumB] ; result in axmov word [wAns1], ax ; dAns1 = wNumA * wNumBmov ax, word [wNumA]mul word [wNumB] ; result in dx:axmov word [dAns1], axmov word [dAns1+2], dx; qAns3 = dNumA * dNumBmov eax, dword [dNumA]mul dword [dNumB] ; result in edx:eaxmov dword [qAns3], eax mov dword [qAns3+4], edx; dqAns4 = qNumA * qNumBmov rax, qword [qNumA]mul qword [qNumB] ; result in rdx:raxmov qword [dqAns4], raxmov qword [dqAns4+8], rdx
带符号数乘法 Signed Multiplication
带符号数的乘法允许更大范围的运算数和尺寸. 通常的格式为
imulimul , imul , , imul imul imul imul imul , imul , imul , imul , , imul , , imul , , imul ax, 17imul alimul ebx, dword [dVar]imul rbx, dword [dVar], 791imul rcx, qword [qVar]imul qword [qVar]
所有的格式中, dest运算数都必须是寄存器, 并且所有的运算数都不能为byte. 当使用单个运算数时, imul的格式和mul是一致的. 当使用两个运算数时, 相乘的是src和dest运算数, 并且结果会存放在desc运算数, 覆盖原值. 立即数的尺寸受src运算数的限制, 可以是double word(32bit), 甚至quadword(64bit), 运算结果被裁剪为dest的尺寸后存放在desc. desc不支持8bit的运算数.
代码例子wNumA dw 1200wNumB dw 2000wAns1 dw 0wAns2 dw 0dNumA dd 42000dNumB dd 13000dAns1 dd 0dAns2 dd 0qNumA dq 120000qNumB dq 230000qAns1 dq 0qAns2 dq 0; wAns1 = wNumA * 13mov ax, word [wNumA]imul ax, 13 ; result in axmov word [wAns1], ax; wAns2 = wNumA * wNumBmov ax, word [wNumA]imul ax, word [wNumB] ; result in axmov word [wAns2], ax; dAns1 = dNumA * 113mov eax, dword [dNumA]imul eax, 113 ; result in eaxmov dword [dAns1], eax; dAns2 = dNumA * dNumBmov eax, dword [dNumA]imul eax, dword [dNumB] ; result in eaxmov dword [dAns2], eax; qAns1 = qNumA * 7096mov rax, qword [qNumA]imul rax, 7096 ; result in raxmov qword [qAns1], rax; qAns2 = qNumA * qNumBmov rax, qword [qNumA]imul rax, qword [qNumB] ; result in raxmov qword [qAns2], rax; 计算 qAns1 = qNumA * 7096 的另一种方式是:; qAns1 = qNumA * 7096mov rcx, qword [qNumA]imul rbx, rcx, 7096 ; result in raxmov qword [qAns1], rax
.
整数除法指令 Integer Division
对有符号数和无符号数, 也有不同的除法指令div和idiv. 指令格式
divdiv div div div div word [wVvar]div bldiv dword [dVar]div qword [qVar]idiv idiv idiv idiv idiv idiv word [wVvar]idiv blidiv dword [dVar]idiv qword [qVar]
因为 dividend / divisor = quotient, 除法要求被除数的尺寸大于除数. 例如要除以8bit除数, 被除数必须为16bit. 和乘法一样, 运算中需要结合使用A和D寄存器, 这也是为了与旧的架构相兼容. 除法中A和D寄存器的组合如下:
Byte Divide: ax for 16-bitsWord Divide: dx:ax for 32-bitsDouble-word divide: edx:eax for 64-bitsQuadword Divide: rdx:rax for 128-bitsByte: al = ax / <src> , rem in ah
Word: ax = dx:ax / <src>, rem in dxDouble: eax = eax / <src>, rem in edxQuad: rax = rax / <src>, rem in rdx正确地设置被除数是问题的关键, 对于word, double word, quadword类型的被除数, 都需要用到A和D寄存器. 如果之前刚刚进行过乘法运算, 那么A和D就正好已经被赋值. 否则当前数值就需要升级成较大尺寸并将上半部分放到D寄存器. 对于无符号数, 高地址部分总是全为零, 而对于有符号数, 则需要根据之前的说明对高地址部分进行扩展.出书可以是一个内存地址或寄存器, 但是不能为立即数. 另外, 结果将被放置在A寄存器(al/ax/eax/rax), 余数部分会被放置在ah, dx, edx, 或者rdx 寄存器. 对更大尺寸的被除数的使用与乘法指令一样, 对于简单的除法, 要使用合适的转换保证数值被正确的初始化, 对于无符号数相除, 要将高地址部分置零, 对于有符号数相除, 要根据实际情况置零或置一. 零作为除数参与除法运算将会导致程序崩溃, 要避免零除数.代码例子bNumA db 63bNumB db 17bNumC db 5bAns1 db 0bAns2 db 0bRem2 db 0bAns3 db 0wNumA dw 4321wNumB dw 1234wNumC dw 167wAns1 dw 0wAns2 dw 0wRem2 dw 0wAns3 dw 0dNumA dd 42000dNumB dd 3157dNumC dd 293dAns1 dd 0dAns2 dd 0dRem2 dd 0dAns3 dd 0qNumA dq 730000qNumB dq 13456qNumC dq 1279qAns1 dq 0qAns2 dq 0qRem2 dq 0qAns3 dq 0; ----; example byte operations, unsigned; bAns1 = bNumA / 3 (unsigned)mov al, byte [bNumA]mov ah, 0mov bl, 3div bl ; al = ax / 3mov byte [bAns1], al; bAns2 = bNumA / bNumB (unsigned)mov ax, 0mov al, byte [bNumA]div byte [bNumB] ; al = ax / bNumBmov byte [bAns2], almov byte [bRem2], ah ; ah = ax % bNumB; bAns3 = (bNumA * bNumC) / bNumB (unsigned)mov al, byte [bNumA]mul byte [bNumC] ; result in aldiv byte [bNumB] ; al = ax / bNumBmov byte [bAns3], al; ----; example word operations, unsigned; wAns1 = wNumA / 5 (unsigned)mov ax, word [wNumA]mov dx, 0mov bx, 5div bx ; ax = dx:ax / 5mov word [wAns1], ax; wAns2 = wNumA / wNumB (unsigned)mov dx, 0mov ax, word [wNumA]div word [wNumB] ; ax = dx:ax / wNumBmov word [wAns2], axmov word [wRem2], dx; wAns3 = (wNumA * wNumC) / wNumB (unsigned)mov ax, word [wNumA]mul word [wNumC] ; result in dx:axdiv word [wNumB] ; ax = dx:ax / wNumBmov word [wAns3], ax; ----; example doubleword operations, signed; dAns1 = dNumA / 7 (signed)mov eax, dword [dNumA]cdq ; eax → edx:eaxmov ebx, 7idiv ebx ; eax = edx:eax / 7mov dword [dAns1], eax; dAns2 = dNumA / dNumB (signed)mov eax, dword [dNumA]cdq ; eax → edx:eaxidiv dword [dNumB] ; eax = edx:eax/dNumBmov dword [dAns2], eaxmov dword [dRem2], edx ; edx = edx:eax%dNumB; dAns3 = (dNumA * dNumC) / dNumB (signed)mov eax, dword [dNumA]imul dword [dNumC] ; result in edx:eaxidiv dword [dNumB] ; eax = edx:eax/dNumBmov dword [dAns3], eax; ----; example quadword operations, signed; qAns1 = qNumA / 9 (signed)mov rax, qword [qNumA]cqo ; rax → rdx:raxmov rbx, 9idiv rbx ; eax = edx:eax / 9mov qword [qAns1], rax; qAns2 = qNumA / qNumB (signed)mov rax, qword [qNumA]cqo ; rax → rdx:raxidiv qword [qNumB] ; rax = rdx:rax/qNumBmov qword [qAns2], raxmov qword [qRem2], rdx ; rdx = rdx:rax%qNumB; qAns3 = (qNumA * qNumC) / qNumB (signed)mov rax, qword [qNumA]imul qword [qNumC] ; result in rdx:raxidiv qword [qNumB] ; rax = rdx:rax/qNumBmov qword [qAns3], rax
逻辑指令 Logical Instructions
基础逻辑指令
与操作and, and ax, bxand rcx, rdxand eax, dword [dNum]and qword [qNum], rdx或操作or , or ax, bxor rcx, rdxor eax, dword [dNum]or qword [qNum], rdx或非操作xor , xor ax, bxxor rcx, rdxxor eax, dword [dNum]xor qword [qNum], rdx非操作not not bxnot rdxnot dword [dNum]not qword [qNum]
移位操作
逻辑左移, 从右边补零. <imm>和cl 取值必须在1~64之间, <dest>不能是立即数
shl, shl , clshl ax, 8shl rcx, 32shl eax, clshl qword [qNum], cl
逻辑右移, 从左边补零. <imm>和cl 取值必须在1~64之间, <dest>不能是立即数
shr, shr , clshr ax, 8shr rcx, 32shr eax, clshr qword [qNum], cl
算术移位将运算数作为一个有符号数进行处理并保留符号. 但是算数移位使用的是四舍五入而标准除法使用的是裁剪, 所以不能用算术移位代替除法指令
算术左移
sal, sal , clsal ax, 8sal rcx, 32sal eax, clsal qword [qNum], cl
算术右移
sar, sar , clsar ax, 8sar rcx, 32sar eax, clsar qword [qNum], cl
循环移位指令只是移位方向不同,它们移出的位不仅要进入CF,而且还要填补空出的位
循环左移
rol, rol , clrol ax, 8rol rcx, 32rol eax, clrol qword [qNum], cl
循环右移
ror, ror , clror ax, 8ror rcx, 32ror eax, clror qword [qNum], cl
控制指令 Control Instructions
.
.