王爽《彙編語言》附註4用棧傳遞數據分析

通過下面幾個程序來一步步理解附註4用棧傳遞數據的思想:

備註:下面的程序,我們假設初始的sp=10H,ss=0001H
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++

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章