直接寻址很少用于数组处理,因为,用常数偏移量来寻址多个数组元素时,直接寻址不实用。反之,会用寄存器作为指针(称为间接寻址)并控制该寄存器的值。如果一个操作数使用的是间接寻址,就称之为间接操作数。
任何一个 32 位通用寄存器(EAX、EBX、ECX、EDX、ESI、EDI、EBP 和 ESP)加上括号就能构成一个间接操作数。
寄存器中存放的是数据的地址。示例如下,ESI 存放的是 byteVal 的偏移量,MOV 指令使用间接操作数作为源操作数,解析 ESI 中的偏移量,并将一个字节送入 AL:
.data byteVal BYTE 10h .code mov esi,OFFSET byteVal mov al,[esi] ; AL = 10h
如果目的操作数也是间接操作数,那么新值将存入由寄存器提供地址的内存位置。在下面的例子中,BL 寄存器的内容复制到 ESI 寻址的内存地址中:
mov [esi],bl
一个操作数的大小可能无法从指令中直接看出来。下面的指令会导致汇编器产生“operand must have size(操作数必须有大小)”的错误信息:
inc [esi] ;错误:operand must have size
汇编器不知道 ESI 指针的类型是字节、字、双字,还是其他的类型。而 PTR 运算符则可以确定操作数的大小类型:
inc BYTE PTR [esi]
间接操作数是步进遍历数组的理想工具。下例中,arrayB 有 3 个字节,随着 ESI 不断加 1,它就能顺序指向每一个字节:
.data arrayB BYTE 10h,20h,30h .code mov esi,OFFSET arrayB mov alz [esi] ;AL = lOh inc esi mov al, [esi] ;AL = 20h inc esi mov al, [esi] ;AL = 30h
如果数组是 16 位整数类型,则 ESI 加 2 就可以顺序寻址每个数组元素:
.data arrayW WORD 1000h,2000h,3000h .code mov esi,OFFSET arrayW mov ax,[esi] ; AX = 1000h add esi, 2 mov ax,[esi] ; AX = 2000h add esi, 2 mov axz [esi] ; AX = 3000h
假设 arrayW 的偏移量为 10200h,下图展示的是 ESI 初始值相对数组数据的位置。