王爽《汇编语言》附注4用栈传递数据分析

我们给子程序传递参数时,可以用栈,如下列程序
备注:下面的程序,我们假设初始的sp=10,ss=0001
mov ax,1
push ax       ;(sp)=(sp-2)=10-2=E,  (ss:[sp])=(ss:[E])=1
mov ax,2
push ax       ;(sp)=(sp-2)=E-2=C,   (ss:[sp])=(ss:[C])=2
mov ax,3
push ax       ;(sp)=(sp-2)=C-2=A,   (ss:[sp])=(ss:[A])=3
call addsub   ;(sp)=(sp-2)=A-2=8,   (ss:[sp])=(ss:[8])=(下一个指令的ip)
add sp,6      ;(sp)=(A+6)=10    还原为初始值

addsub:
       mov ax,ss:[sp+2]    ;(ax)=(ss:[sp+2])=(ss:[8+2])=(ss:[A])=3
       add ax,ss:[sp+4]    ;(ax)=3+(ss:[sp+2])=3+(ss:[8+4])=3+(ss:[C])=5
       add ax,ss:[sp+6]    ;(ax)=5+(ss:[sp+2])=5+(ss:[8+6])=5+(ss:[E])=6
       ret                 ;(ip)=(栈顶的值),(sp)=(sp+2)=A
上面还原 sp 的方法为 外平栈,下面这种方法用到 ret n ,即 内平栈
mov ax,1
push ax       ;(sp)=(sp-2)=10-2=E,  (ss:[sp])=(ss:[E])=1
mov ax,2
push ax       ;(sp)=(sp-2)=E-2=C,   (ss:[sp])=(ss:[C])=2
mov ax,3
push ax       ;(sp)=(sp-2)=C-2=A,   (ss:[sp])=(ss:[A])=3
call addsub   ;(sp)=(sp-2)=A-2=8,   (ss:[sp])=(ss:[8])=(下一个指令的ip)


addsub:
       mov ax,ss:[sp+2]    ;(ax)=(ss:[sp+2])=(ss:[8+2])=(ss:[A])=3
       add ax,ss:[sp+4]    ;(ax)=3+(ss:[sp+2])=3+(ss:[8+4])=3+(ss:[C])=5
       add ax,ss:[sp+6]    ;(ax)=5+(ss:[sp+2])=5+(ss:[8+6])=5+(ss:[E])=6
       ret 6               ;(ip)=(栈顶的值),(sp)=(sp+2)=A,(sp)=(sp+6)=10  还原为初始值
但实际程序中,往往需要暂存寄存器,所以用sp定位方式也得变化,如下: 
       mov ax,1
       push ax       ;(sp)=(sp-2)=10-2=E,  (ss:[sp])=(ss:[E])=1
       mov ax,2
       push ax       ;(sp)=(sp-2)=E-2=C,   (ss:[sp])=(ss:[C])=2
       mov ax,3
       push ax       ;(sp)=(sp-2)=C-2=A,   (ss:[sp])=(ss:[A])=3
       call addsub   ;(sp)=(sp-2)=A-2=8,   (ss:[sp])=(ss:[8])=(下一个指令的ip)
       add sp,6      ;(sp)=(A+6)=10    还原为初始值

addsub:              ;这里我们假设子程序中还有其他指令,所以要暂存相关寄存器
       push bx       ;(sp)=(sp-2)=8-2=6,   (ss:[sp])=(ss:[6])=(bx)
       push cx       ;(sp)=(sp-2)=6-2=4,   (ss:[sp])=(ss:[4])=(cx)
       push dx       ;(sp)=(sp-2)=4-2=2,   (ss:[sp])=(ss:[2])=(dx)

       ;....假设省略了其他指令,注意下面用sp定位之前传递入栈的参数方式变化                 
       mov ax,ss:[sp+6+2]    ;(ax)=(ss:[sp+8])=(ss:[2+8])=(ss:[A])=3
       add ax,ss:[sp+6+4]    ;(ax)=3+(ss:[sp+2])=3+(ss:[2+A])=3+(ss:[C])=5
       add ax,ss:[sp+6+6]    ;(ax)=5+(ss:[sp+2])=5+(ss:[2+C])=5+(ss:[E])=6
       
       pop dx                ;(sp)=(sp+2)=2+2=4
       pop cx                ;(sp)=(sp+2)=4+2=6
       pop bx                ;(sp)=(sp+2)=6+2=8
       ret                   ;(ip)=(栈顶的值),(sp)=(sp+2)=8+2=A

那么上述用sp定位方法很不方便,因为每次都有数据需要进栈暂存,解决方法如下:

 ;这里为了方便我们假设初始的 SS=0,SP=20H
       mov ax,1
       push ax       ;(sp)=(sp-2)=20-2=1E,    (ss:[sp])=(ss:[1E])=1
       mov ax,2 
       push ax       ;(sp)=(sp-2)=1E-2=1C,    (ss:[sp])=(ss:[1C])=2
       mov ax,3
       push ax       ;(sp)=(sp-2)=1C-2=1A,    (ss:[sp])=(ss:[1A])=3
       call addsub   ;(sp)=(sp-2)=1A-2=18h,   (ss:[sp])=(ss:[18h])=(下一个指令的ip)
       add sp,6      ;(sp)=(1A+6)=20h    还原为初始值

addsub:              ;下面是用bp来定位栈中数据的方法      
       push bp       ;(sp)=(sp-2)=18-2=16h,   (ss:[sp])=(ss:[16h])=(bp)
       mov bp,sp     ;(bp)=(sp)=16h
       sub sp,10h    ;(sp)=16-10=6h, 这里可以随便减去一个值

                     ;这里我们假设子程序中还有其他指令,所以要暂存相关寄存器
       push bx       ;(sp)=(sp-2)=6-2=4,   (ss:[sp])=(ss:[6])=(bx)
       push cx       ;(sp)=(sp-2)=4-2=2,   (ss:[sp])=(ss:[4])=(cx)
       push dx       ;(sp)=(sp-2)=2-2=0,   (ss:[sp])=(ss:[2])=(dx)

                           ;下面用bp定位栈中数据,bp永远从+4开始,与上面入栈多少数据无关              
       mov ax,ss:[bp+4]    ;(ax)=(ss:[bp+4])=(ss:[16h+4])=(ss:[1A])=3
       add ax,ss:[bp+6]    ;(ax)=3+(ss:[bp+4])=3+(ss:[16+6])=3+(ss:[1C])=5
       add ax,ss:[bp+8]    ;(ax)=5+(ss:[bp+8])=5+(ss:[16+8])=5+(ss:[1E])=6
       
       pop dx                ;(sp)=(sp+2)=0+2=2
       pop cx                ;(sp)=(sp+2)=2+2=4
       pop bx                ;(sp)=(sp+2)=4+2=6

       mov sp,bp             ;等价于add sp,10h, 目的是还原sp,(sp)=16h
       pop bp                ;(sp)=(sp+2)=18h  
       ret                   ;(ip)=(栈顶的值),(sp)=(sp+2)=18+2=1A

在这个基础上,再去理解附注4就很简单了:


附注4最后那个C程序转换的汇编程序中:

mov sp,bp  为的就是还原sp,避免万一子程序中有栈操作改变了sp,所以最后必须还原,相当于清除自身临时变量。否则没有这句话保护可能导致整个程序崩溃。

至于 add sp,6 为的是平衡栈,因为之前sp减了6,将栈还原到初始状态

inc word ptr [bp-2] 对应 C++

猜你喜欢

转载自blog.csdn.net/weixin_41944412/article/details/80955327