机器语言
每种类型的CPU都能理解它们自己的机器语言。机器语言里的指令是以字节形式在内存中储存的数字。每条指令有它唯一的数字码称为操作代码,或简称为操作码。80x86处理器的指令大小不同。操作码通常是在指令的开始处。许多指令还包含指令使用的数据(例如:常量或地址)。
机器语言很难直接进行编程。解译这些数字代码指令的意思对人类来说是沉闷的。例如:执行将EAX 和EBX 寄存器相加然后将结果送回到EAX的指令以十六进制码编译如下:
03 C3
这个很难理解。幸运的是,一个叫做汇编的程序可以为程序员做这个沉闷的工作。
汇编语言
一个汇编语言程序以文本格式储存(正如一个高级语言程序)。每条汇编指令代表确切的一条机器指令。例如:上面描述的加法指令在汇编语言中将描述成:
add eax, ebx
这里指令的意思比在机器代码表示得更清楚。代码add是加法指令的助记符。一条汇编指令的通常格式为:
mnemonic(助记符) operand(s)(操作数)
汇编程序是一个读包含汇编指令的文本文件和将汇编语言转换成机器代码的程序。编译器是为高级编程语言做同样转换的程序。一个汇编程序比一个编译器要简单。每条汇编语句接代表一个唯一的机器指令。高级语言更复杂而且可能要求更多的机器指令。
汇编和高级语言之间另一个更重要的区别是因为每种不同类型的CPU有它自己的机器代码,所以它同样有它自己的汇编语言。在不同的电脑构造中移植汇编语言比高级语言要困难得多。
本教程使用了Netwide Assembler,或简称为NASM 。它在Internet上是免费提供的。更普遍的汇编程序是Microsoft As-sembler(MASM) 或Borland Assembler (TASM)。MASM/TASM和NASM之间有一些汇编语法区别。
指令操作数
机器代码指令拥有个数和类型不同的操作数;然而,通常每个指令有几个固定的操作数(0到3个)。操作数可以有下面的类型:
寄存器: 这些操作数直接指向CPU寄存器里的内容。
内存: 这些操作数指向内存里的数据。数据的地址可能是硬编码到指令里的常量或可能直接使用寄存器的值计算得到。距离段的起始地址的偏移值即为此地址。
立即数: 这些操作数是指令本身列出的固定的值。它们储存在指令本身(在代码段),而不在数据段。
暗指的操作数: 这些操作数没有明确显示。例如:往寄存器或内存增加1的加法指令。1是暗指的。
基本指令
最基本指令是MOV 指令。它将数据从一个地方移到另一个地方(像高级语言里面的赋值操作一样)。它携带两个操作数:
mov dest (目的操作数), src(源操作数)
src指定的数据拷贝到了dest。一个指令的两个操作数不能同时是内存操作数。这就指出了一个汇编古怪的地方。通常,对于各种各样指令的使用都有某些强制性的规定。操作数必须是同样的大小。AX里的值就不能储存到BL 里去。
这儿有一个例子(分号表示注释的开始):