汇编语言对int, fret和栈的深入理解

问题:用7ch中断例程完成loop指令的功能
loop s的执行需要两个信息,循环次数和到s的位移,loop指令的功能,也需要这两个信息作为参数。我们用cx位移。
所以,7ch中断例程要完成存放循环次数,用bx存放
应用举例;在屏幕中间显示80个'!'

assume cs:code
code segment
    start:   ;省略了前面的中断程序的安装
               mov ax,0b800h
               mov es,ax
               mov di,160*12
               mov bx,offset s-offset se   ; bx存放转移位移
               mov cx,80                   ; 计数器
          s:   mov byte prt es:[di],'!'    ; 显示缓冲区存放!
                add di,2
                int 7ch                   ; 如果cx≠0  就跳转到标号s处执行
         se : nop 
               mov ax,4c00h 
               int 21h

              ;7ch中断例程如下
        lp:   push bp
               mov bp,sp      ; 将栈顶的ip送入bp 中  现在栈的数据依次为 bp 、ip、cs、flag寄存器 
               dec cx         ; cx每次执行 自减
               jcxz over
              add [bp+2],bx   ;cx≠0  我们就修改cs:ip指向s处  将转移的位移bx + 入栈的se处的ip  为s 处的ip
over :       pop bp
              iret             ; 依次恢复ip、cs、flag寄存器的值
               

code ends
end start 

在上面的程序中,用int 7ch调用7ch中断例程进行转移,用bx传递转移的位移。
分析:为了模拟loop指令,7ch中断例程应具备下面的功能。
(1) dec cx;
(2)如果cx≠0 ,转到标号s处执行,否则向下执行。
下面我们分析7ch中断例程如何实现到目的地址的转移。
(1)转到标号s显然应设(CS)=标号s的段地址,(IP)=标号s的偏移地址。
(2)那么,中断例程如何得到标号s的段地址和偏移地址呢?
int 7ch引发中断过程后,进入7ch中断例程,在中断过程中,当前的标志寄存器、CS和IP都要压栈,此时压入的CS和IP中的内容,分别是调用程序的段地址(可以认为是标号s的段地址)和int 7ch后一条指令的偏移地址(即标号se的偏移地址)。
可见,在中断例程中,可以从栈里取得标号s的段地址和标号se的偏移地址,而用标号se的偏移地址加上bx中存放的转移位移就可以得到标号s的偏移地址。
(3)现在知道,可以从栈中直接和间接地得到标号s的段地址和偏移地址,那么如何用它们设置CS:IP呢?se从
可以利用fret指令,我们将栈中的se的偏移地址加上bx中的转移位移,则栈中的的偏移地址就变为了s的偏移地址。我们再使用fret指令,用栈中的内容设置CS, IP,而实现转移到标号s处。
7ch中断例程如下

  1.              ;7ch中断例程如下
  2.         lp:   push bp
  3.                mov bp,sp      ; 将栈顶的ip送入bp 中  现在栈的数据依次为 bp 、ip、cs、flag寄存器 
  4.                dec cx         ; cx每次执行 自减
  5.                jcxz over
  6.               add [bp+2],bx   ;cx≠0  我们就修改cs:ip指向s处  将转移的位移bx + 入栈的se处的ip  为s 处的ip
  7. over :       pop bp
  8.              iret             ; 依次恢复ip、cs、flag寄存器的值

因为要访问栈,使用了by,在程序开始处将by入栈保存,结束时出栈恢复。当要修改栈中se的偏移地址的时候,栈中的情况为:栈顶处是by原来的数值,下面是se的偏移地址,再下面是s的段地址,再下面是标志寄存器的值。而此时,by中为栈顶的偏移地址,所以((ss)* 16+(bp)+2)处为se的偏移地址,将它加上bx中的转移位移就变为s的偏移地址。最后用fret出栈返回,CS:IP即从标号s处开始执行指令。
如果(cx卜0,则不需要修改栈中se的偏移地址,直接返回即可。CPU从标号se处向下执行指令。
检测点13.1
上面内容中 7ch 实现的loop功能 所能进行的最大转移位移是多少?
分析: bx中存放转移的位移范围为 0~FFFF 所以能进行的转移位移为-32768~32767 最大转移位移是32767

用7ch中断例程完成jmp near ptr s 指令的功能 用bx向中断例程传送转移位移
在屏幕的第12行显示data段中 以0结尾的字符串

assume cs:code
data segement
db 'conversation',0
data ends

code segment
    start : mov ax,data
              mov ds,ax
              mov si,0
              mov ax,0b800h
              mov es,ax    
              mov di,12*160
         s:  cmp byte ptr [si],0
             je ok                 ;如果是0跳出循环
             mov al,[si]
             mov es:[di],al
             inc si
             add di,2
             mov bx,offset s - offset ok      ; 设置从标号ok到标号s的转移位移
             int 7ch                        ;  转移到标号s处
       ok:   mov ax,4c00h
             int 21h


      jp  : push bp
             mov bp,sp         ; 将栈顶的ip送入bp 中  现在栈的数据依次为 bp 、ip、cs、flag寄存器 
            add [bp+2],bx      ; 我们就修改cs:ip指向s处  将转移的位移bx + 入栈的se处的ip  为s 处的ip
over :     pop bp
            iret               ; 依次恢复ip、cs、flag寄存器的值
code ends
end start

发布日期:

所属分类: 易语言 标签: