-84- | PC机汇编语言实战精解 | ![]() |
|||||||||||||||||||
continue: change code |
sub mov inc loop pop ret endp ends end |
al,20h [bx],al bx chloop bp 2 main |
;将小写字母转换成大写 ;将大写字母重新存入字符串 ;字符串指针加1 ;处理下一个字符 ;恢复BP寄存器的原值 ;返回主过程,并清空堆栈 |
||||||||||||||||||
这个程序演示了如何将小写字母转换为大写字母。在主过程中使用了"PUSH DX"指令将DX寄存器中存储的字符串首地址压入堆栈,然后调用CHANGE子过程。那么CHANGE子过程又是如何得到字符串地址的呢? 首先可以肯定地说直接用"POP"指令不可能从堆栈中取得正确的字符串首地址,这是因为执行"CALL"指令时堆栈中存入了主过程的返回地址。习惯上我们常用"基指针寄存器" --BP来取得数据。 BP(BASS POINT)寄存器是一个十六位寄存器,它和BX寄存器一样可用于完成间接寻址,不过BP寄存器无法分成两个八位寄存器来使,而且它和BX寄存器也不完全一样。当我们使用BX做间接寻址时,如果不指定段寄存器,则CPU将默认DS寄存器的值为段地址,而使用BP做此工作时,CPU会默认SS的值为段地址,即BP寄存器常用于在堆栈中取得数据时应用。不难想象BP寄存器为我们灵活处理堆栈中的数据提供了便利,这使我们可以不必顾及堆栈数据"后入先出"的规矩,也不必冒险修改SP寄存器。 需要说明的是BP也可以做其它的工作,比如暂存数据,或在其它段中完成间接寻址,只需注意明确给出段寄存器即可。一般来讲BP寄存器更多地用于取得参数,特别是当我们用汇编语言为一些高级语言编制子模块的时候,这几乎是唯一的方法。因为高级语言在调用子过程时几乎都用堆栈传递数据。 子过程中的"RET"指令有些不同寻常,它带了一个立即数。由于我们在调用子过程之前将一个数据压入了堆栈,显然子过程返回后这个数已经没有用了,所以我们要调整堆栈指针寄存器SP的值,以恢复堆栈的原始状态。 采用带常数的RET指令是个比较简单的方法,CPU在执行这样的RET指令时会在返回主过程后自动地将SP寄存器减掉这个常数值,堆栈中的参数也就算自动出栈了。不难想到这个常数在数值上应该等于"参数个数×2"。 下面是用DEBUG根踪这个程序的过程,请注意观察BP寄存器的应用和堆栈的变化: |
|||||||||||||||||||||
-g=0 c[Enter] | |||||||||||||||||||||
welcome to pc world | ← 程序显示出的字符串 | ||||||||||||||||||||
AX=0924 | BX=0000 | CX=004E | DX=0000 | SP=0000 | BP=0000 | SI=0000 | DI=0000 | ||||||||||||||
DS=1031 | ES=1021 | SS=1031 | CS=1033 | IP=000C | NV UP EI PL NZ NA PO NC | ||||||||||||||||
1033:000C | 52 | PUSH DX | |||||||||||||||||||
Copyright © 2004-2015 Reanimator | www.cookmoon.org |