offset的值这里是用字节的形式表示的,但它事实上是32位的值,比如3A(这不是一个常见的offset的值,但如果不这样简写表格装不下),这也是一个32位的值:0000003Ah。只是为了节省空间,使用了一些不常见的低位offset。所有的值均为16进制。
看上表的offset 3A。那个offset的数据是25, 7A, 5E, 72, EF等。例如,要把这个位于3A的值用mov放入寄存器中:
mov eax, dword ptr[0000003Ah]
(h后缀表明这是一个十六进制值)
mov eax, dword ptr[0000003Ah]这条指令的意思是:把位于内存地址3A的DWORD大小的值放入eax寄存器。执行了这条指令后,eax包含了值725E7A25h。可能你注意到了这是在内存中时的反转结果:25 7A 5E 72。这是因为存储在内存中的值使用了little endian格式。这意味着越靠右的字节位数越高:字节顺序被反转了。我想一些例子可以使你把这个搞清楚。
十六进制dword(32位)值放在内存中时是这样:40, 30, 20, 10(每个值占一个字节(8位))
十六进制word(16位)值放在内存中时是这样:50, 40
回到前面的例子。你也可以对其他大小的值这么做:
mov cl, byte ptr [34h] ; cl得到值0Dh(参考上表)
mov dx, word ptr [3Eh] ; dx将得到值 7DEFh (看上表,记住反序)
大小有时不是必须的。
Mov eax,[00403045h]
因为eax是32位寄存器,编译器假定(也只能这么做)它应该从地址403045(十六进制)取个32位的值。
直接数值是允许的:
mov edx, 5006
这只是使得edx寄存器装有值5006,综括号[和]用来从括号间的内存地址处取值,没有括号就只是这个值。寄存器和内存地址也可以(他应该是32位程序中的32位寄存器):
mov eax,403045h;使eax装有值403045h(十六进制)
mov cx,[eax];把位于内存地址eax的word大小的值(403045)移入cx寄存器。
在mov cx, [eax]中,处理器会先查看eax装有什么值(=内存地址),然后在那个内存地址中有什么值,并把这个word(16位,因为目标-cx-是个16位寄存器)移入cx。
ADD, SUB, MUL, DIV
许多伪代码做计算工作。你可以猜出它们中的大多数的名字:add(加),sub(减),mul(乘),div(除)等。
Add伪代码有如下语法:
Add 目标,源
执行的运算是 目标=目标+源。下面的格式是允许的。
目标源例子
RegisterRegisteradd ecx, edx
RegisterMemoryadd ecx, dword ptr [104h] / add ecx, [edx]
RegisterImmediate valueadd eax, 102
MemoryImmediate valueadd dword ptr [401231h], 80
MemoryRegisteradd dword ptr [401231h], edx
这条指令非常简单。它只是把源值加到目标值中并把结果保存在目标中。其他的数学指令有:
sub 目标,源(目标=目标-源)
mul 目标,源(目标=目标×源)
div 源(eax=eax/源,edx=余数)
减法和加法一样做,乘法是目标=目标×源。除法有一点不同,因为寄存器是整数值(注意,绕回数不是浮点数)除法的结果被分为商和余数。例如:
28/6->商=4,余数=4
30/9->商=3,余数=3
97/10->商=9,余数=7
18/6->商=3,余数=0
现在,取决于源的大小,商(一部分)被存在eax中,余数(一部分)在edx:
源大小除法商存于… 余数存于…
BYTE (8-bits)ax / sourceALAH
WORD (16-bits)dx:ax* / sourceAXDX
DWORD (32-bits)edx:eax* / sourceEAXEDX
*:例如,如果dx=2030h,而ax=0040h,dx:ax=20300040h。dx:ax是一个双字值。其中高字代表dx,低字代表ax,Edx:eax是个四字值(64位)其高字是edx低字是eax。
Div伪代码的源可以是
·an 8-bit register (al, ah, cl,...)
·a 16-bit register (ax, dx, ...)
·a 32-bit register (eax, edx, ecx...)
·an 8-bit memory value (byte ptr [xxxx])
·a 16-bit memory value (word ptr [xxxx])
·a 32-bit memory value (dword ptr [xxxx])
源不可以是直接数值因为处理器不能决定源参数的大小。
位操作
这些指令都由源和目标,除了“NOT”指令。目标中的每位与源中的每位作比较,并看是那个指令,决定是0还是1放入目标位中。
指令ANDORXORNOT
源位00110011001101
目标位010101010101XX
输出位00010111011010
如果源和目标均为1,AND把输出位设为1。
如果源和目标中有一个为1,OR把输出位设为1。
如果源和目标位不一样,XOR把输出位设为1。
NOT反转源位
一个例子:
mov ax, 3406
mov dx, 13EAh
xor ax,dx
ax=3406(十六进制)是二进制的0000110101001110
dx=13EA(十六进制)是二进制的0001001111101010
对这些位进行xor操作:
源0001001111101010 (dx)
目标0000110101001110 (ax)
输出0001111010100100 (new ax)
新dx是0001111010100100 (十进制的7845, 十六进制的1EA4)
另一个例子:
mov ecx, FFFF0000h
not ecx
FFFF0000在二进制中是11111111111111110000000000000000(16个1,16个0)如果反转每位会得到
00000000000000001111111111111111(16个0,16个1)在十六进制中是0000FFFF。因而执行NOT操作后,ecx是0000FFFFh。
步增/减
有两个很简单的指令,DEC和INC。这些指令使内存地址和寄存器步增或步减,就是这样:
inc reg -> reg = reg + 1
dec reg -> reg = reg - 1
inc dword ptr [103405] -> 位于103405的值步增
dec dword ptr [103405] -> 位于103405的值步减
NOP
这条指令什么都不干。它仅仅占用空间和时间。它用作填充或给代码打补丁的目的。
位移(Bit Rotation 和 shifiting)
注意:下面的大部分例子使用8位数,但这只是为了使目的清楚。
Shifting函数
SHL 目标,计数(count)
SHR 目标,计数(count)
SHL和SHR在寄存器,内存地址中像左或向右移动一定数目(count)的位。
例如:
;这儿al=01011011(二进制)
shr al, 3
它的意思是:把al寄存器中的所有位向右移三个位置。因而al会变成为00001011。左边的字节用0填充,而右边的字节被移出。最后一个被移出的位保存在carry-flag中。Carry-flag是处理器标志寄存器的一位,它不是像eax或ecx一样的,你可以访问的寄存器(虽然有伪代码干这活),但它的值决定于该指令的结构。它(carry-flag)会在后面解释,你要记住的唯一一件事是carry是标志寄存器的一位且它可以被打开或者关闭。这个位等于最后一个移出的位。
Shl和shr一样,只不过是向左移。
;这儿bl=11100101(二进制)
shl bl, 2
执行了指令后bl是10010100(二进制)。最后的两个位是由0填充的,carry-flag是1,因为最后移出的位是1。
还有两个伪代码:
SAL 目标, 计数(算术左移)
SAR 目标, 计数(算术右移)
SAL和SHL一样,但SAR不完全和SHR一样。SAR不是用0来填充移出的位而是复制MSB(最高位)例如:
al = 10100110
sar al, 3
al = 11110100
sar al, 2
al = 11101001
bl = 00100110
sar bl, 3
bl = 00000100
Rotation(循环移动) 函数
Rol 目标,计数;循环左移
Ror 目标,计数;循环右移
Rcl 目标,计数;通过carry循环左移
Rcr 目标,计数;通过carry循环右移
循环移动(Rotation)看上去就像移(Shifting),只是移出的位又到了另一边。
例如:Ror(循环右移)
Bit 7Bit 6Bit 5Bit 4Bit 3Bit 2Bit 1 Bit 0
原来 10011011
循环移动,计数=3 100110 1 1 (移出)
结果 01110011
如你在上图所见,位循环了。注意,每个被推出的位又移到了另一边。和Shifting一样,carry位装有最后被移出的位。Rcl和Rcr实际上和Rol,Rcr一样。它们的名字暗示了它们用carry位来表明最后移出的位,但和Rol和Ror干同样的事情。它们没有什么不同。
交换
XCHG指令也非常简单。它同在两个寄存器和内存地址之间交换:
eax = 237h
ecx = 978h
xchg eax, ecx
eax = 978h
ecx = 237h