ITEEDU

(6)指针处理指令

指针的概念在前面的章节里已有所讲述,这个词诈听上去有些悬妙,其实要用最明确的话来说,指针就是数据在内存中的地址。这个地址可以是单纯的16位偏移地址,也可以是32位的"段:偏移"形式。

我们前面编制的许多程序中都应用了"OFFSET"这个分析运算符,实际上这个分析符起的作用就是用于取得指向数据块首的指针。但是使用"OFFSET"并非是唯一的方法,请看下面的程序所指出的另一条途径:

WWW.ASM
        data  segment
              assume    ds:data
         msg  db        World Wild Wed--Paradise and Tomb',0
        vram  dd        0b8000670h	;采用DD伪指令直接定义32位指针
        data  ends
			
        code  segment
              assume    cs:code
        main  proc      far
              push      ds	;初始化堆栈
              xor       ax,ax
              push      ax
              mov       ax,data	;初始化DS寄存器
              mov       ds,ax
			
              mov       ax,0003h	;设置字符显示模式3
              int       10h
			
              lea       si,msg	;将字符串MSG的有效地址送入SI寄存器
              les       di,vram	;将显示缓存的指针送入ES:DI
			
              mov       ah,2	;字符属性字节
      loop1:
              lodsb     ;取得一个字符
              cmp       al,0	;已经到字符串结尾了吗?
              jz        exit	;已到字符串结尾,转EXIT结束
			
              stosw     ;将字符及属性字节送入显示缓存中
              jmp       loop1	;转LOOP1继续显示下一个字符
       exit:
              mov       ah,0	;等待键盘输入
              int       16h
              ret       ;结束进程
        main  endp
        code  ends
              end       main

这个程序中引入了一些新的指令和伪指令,取代了"OFFSET"的指令就是"LEA":

助记符:LEA(Load Effective Address)
用 途:将数据的有效地址送入指定寄存器
格 式:LEA 寄存器,数据标号
执 行:标号对应的偏移地址送入指定的寄存器中

"有效地址"这个词听上去有些耳生,其实有效地址就是数据在内存某个段内的偏移地址。使用LEA指令时不能再用"OFFSET"分析运算符,否则反而有错误。这个指令执行的操作与指令"MOV 寄存器,OFFSET 数据标号"完全一致,但是它们之间有一些很微妙的差别。这个差别在应用DEBUG编制程序时就有体现,请看下面的例子:

 C:\ASM\>DEBUG[Enter] 
-a100[Enter]
0F6A:0100 mov ah,9
0F6A:0102 mov dx,109
0F6A:0105 int 21
0F6A:0107 int 20
0F6A:0109 db'This is a sample',0d,0a,24
0F6A:011C[Enter] 

-a100[Enter]
0F6A:0100 mov ah,9
0F6A:0102 lea dx,[10a]
0F6A:0106 int 21
0F6A:0108 int 20
0F6A:010A db'This is a sample',0d,0a,24
0F6A:011D [Enter] 

 这两个程序很简单,可以在屏幕上显示一个字符串。所不同的是第二个程序换用"LEA"指令完成取偏移地址的功能。"LEA"的应用格式是很特殊的,表面上看这个指令采用一个存储器直接寻址方式,取到DX寄存器中的数据应该是"T"与"h"的ASCII码6854H,实际上如果跟踪执行这个程序就会观察到取到DX寄存器中的数据并非是6854H,而正是010AH。可见这个指令与MOV指令并不相同,通常对"寻址方式"的理解并不适用于LEA指令。

由此看来指令"LEA BX,[SI]"也不是要把内存中[SI]地址处的两字节数据送进BX寄存器,而是送进SI的值。这一点可以说是这个指令最奇怪的地方,不过要是再细想一下这也正是将LEA称为"取有效地址指令"的原因。

特别值得一提的是Borland公司出品的Turbo Assembly编译程序(TASM.EXE)对LEA指令的处理方法很不寻常,它会不声不响地用指令"MOV 寄存器,OFFSET 标号"替换掉LEA。原因很简单,这样替换之后生成的可执行程序会短小一些。这一点从刚才我们用DEBUG编制的两个对比程序中也可以看出来。
另外新增的LES指令是用于处理32位指针的:

助记符:LES(Load ES with pointer)
用 途:将存于内存中的32位指针送入ES和指定的寄存器内
格 式:LES 寄存器,存储单元
执 行:32位指针中低16位作为偏移地址送入指定的寄存器中,高16位作为段地址送入ES寄存器中