在寄存器中载入另一寄存器,或立即数的值:
mov reg32, (reg32 | imm8 | imm16 | imm32)
mov reg32, (reg16 | imm8 | imm16)
mov reg8, (reg8 | imm8)
例如,mov eax, 010h 表示,在 eax 中载入 00000010h。需要注意的是,如果你希望在寄存器中装入 0,则有一种更快的方法,在后面我们将提到。
交换寄存器的内容:
xchg reg32, reg32
xchg reg16, reg16
xchg reg8, reg8
例如,xchg ebx,ecx,则 ebx 与 ecx 的数值将被交换。由于系统提供了这个指令,因此,采用其他方法交换时,速度将会较慢,并需要占用更多
的存储空间,编程时要避免这种情况,即,尽量利用系统提供的指令,因为多数情况下,这意味着更小、更快的代码,同时也杜绝了错误(如果
说 Intel 的 CPU 在交换寄存器内容的时候也会出错,那么它就不用卖 CPU 了。而对于你来说,检查一行代码的正确性也显然比检查更多代码的正
确性要容易)刚才的习题的程序用下面的代码将更有效:
mov eax, 0a1234h
mov bx, ax
xchg ah, al
; 将 0a1234h 送入 eax
; 将 ax 内容送入 bx
; 交换 ah, al 的内容
递增或递减寄存器的值:
inc reg(8,16,32)
dec reg(8,16,32)
这两个指令往往用于循环中对指针的操作。需要说明的是,某些时候我们有更好的方法来处理循环,例如使用 loop 指令,或 rep 前缀。这些将在
后面的章节中介绍。
将寄存器的数值与另一寄存器,或立即数的值相加,并存回此寄存器:
add reg32, reg32 / imm(8,16,32)
add reg16, reg16 / imm(8,16)
add reg8, reg8 / imm(8)
例如,add eax, edx,将 eax+edx 的值存入 eax。减法指令和加法类似,只是将 add 换成 sub。
需要说明的是,与高级语言不同,汇编语言中,如果要计算两数之和(差、积、商,或一般地说,运算结果),那么必然有一个寄存器被用来保
存结果。在 PASCAL 中,我们可以用 nA := nB +nC 来让 nA 保存 nB+nC 的结果,然而,汇编语言并不提供这种方法。如果你希望保持寄存器中的结
果,需要用另外的指令。这也从另一个侧面反映了“寄存器”这个名字的意义。数据只是“寄存”在那里。如果你需要保存数据,那么需要将它
放到内存或其他地方。
类似的指令还有 and、or、xor(与,或,异或)等等。它们进行的是逻辑运算。
我们称 add、mov、sub、and 等称为为指令助记符(这么叫是因为它比机器语言容易记忆,而起作用就是方便人记忆,某些资料中也称为指令、操
作码、opcode[operationcode]等);后面的参数成为操作数,一个指令可以没有操作数,也可以有一两个操作数,通常有一个操作数的指令,这
个操作数就是它的操作对象;而两个参数的指令,前一个操作数一般是保存操作结果的地方,而后一个是附加的参数。
我不打算在这份教程中用大量的篇幅介绍指令——很多人做得比我更好,而且指令本身并不是重点,如果你学会了如何组织语句,那么只要稍加
学习就能轻易掌握其他指令。更多的指令可以参考 Intel 提供的资料。编写程序的时候,也可以参考一些在线参考手册。Tech!Help 和 HelpPC 2.10
尽管已经很旧,但足以应付绝大多数需要。
聪明的读者也许已经发现,使用 sub eax, eax,或者 xor eax, eax,可以得到与 mov eax,0 类似的效果。在高级语言中,你大概不会选择用 a=a-a
来给 a 赋值,因为测试会告诉你这么做更慢,简直就是在自找麻烦,然而在汇编语言中,你会得到相反的结论,多数情况下,以由快到慢的速度
排列,这三条指令将是 xor eax, eax、sub eax, eax 和 mov eax, 0。
为什么呢?处理器在执行指令时,需要经过几个不同的阶段:取指、译码、取数、执行。
我们反复强调,寄存器是 CPU 的一部分。从寄存器取数,其速度很显然要比从内存中取数快。那么,不难理解,xor eax, eax 要比 mov eax, 0
更快一些。
那么,为什么 a=a-a 通常要比 a=0 慢一些呢?这和编译器的优化有一定关系。多数编译器会把 a=a-a 翻译成类似下面的代码(通常,高级语言通过
ebp 和偏移量来访问局部变量;程序中,x 为 a 相对于本地堆的偏移量,在只包含一个 32-bit 整形变量的程序中,这个值通常是 4):