匯編語言(王爽第三版)檢測點10


檢測點10.1

補全程序,實現從內存1000:0000處開始執行指令

匯編源代碼check10-1.asm

assume cs:code

stack segment

    db 16 dup (0)

stack ends

code segment

start:  ;建棧

        mov ax,stack

        mov ss,ax

        mov sp,16

        ;壓棧

        mov ax,1000H

        push ax

        mov ax,0000H

        push ax

        retf

       

        mov ax,4c00H

        int 21H

code ends

end start

程序分析:

1. retf指令作用(CPU角度):從棧中彈出2個字單元,並修改CS(第二個字)和IP(第一個字);首先它彈出的是IP,其次是CS,故在壓棧時,CS的值首先入棧,IP再入棧。

    在匯編編程角度,retf實現了遠轉移。

講解:在匯編代碼這個層次,retf指令作用是修改CS和IP的值,進而使指令從修改后的地址處開始執行。由於它所依賴的是棧中存儲的內容,故在壓棧過程中要搞清楚入棧的順序、入棧的值。

2.熟悉ret指令和RETF指令執行的操作。

我們編譯鏈接后,debug跟蹤check10-1.exe

-d ss:0

0B66:0000  00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00   ................

在stack數據區中初始化了16個0,此時它未成為棧結構。直到初始化棧的結構。

執行代碼t t(二次)

AX=0B66  BX=0000  CX=0026  DX=0000  SP=0010  BP=0000  SI=0000  DI=0000

DS=0B56  ES=0B56  SS=0B66  CS=0B67  IP=0008   NV UP EI PL NZ NA PO NC

0B67:0008 B80010        MOV     AX,1000

-d ss:00

0B66:0000  00 00 00 00 00 00 66 0B-00 00 08 00 67 0B 68 05   ......f.....g.h.

初始化一個棧sp=0010H(16),棧地址:ss=0b66,這里我們發現一些不應該有的數據(不理會它,它是中斷的信息)

繼續執行代碼:

-d ss:0

0B66:0000  00 00 00 00 00 00 10 00-67 0B 68 05 00 00 00 10   ........g.h.....

發現從高位開始存儲10 00 00 00四個字節的數據,(體會棧是從高地址向低地址發展的,sp指針從10H減少到了0cH)

此時的CS=0B67  IP=0010

執行retf代碼:

我們發現:CS=1000  IP=0000,CS和IP的值改變了。

總結:ret和RETF依賴於棧的結構存儲一個程序執行點(IP或CS和IP),當執行這個代碼時,可以恢復到這個程序的執行點(將棧中的數據修改IP或CS和IP,使CPU指向新的CS:IP)

 

檢測點10.2

       下面的程序執行后,ax中的數值為多少?

內存地址:         機器碼                 匯編指令          

1000: 0           b8 00 00              mov ax,0

1000:3           e8 01 00              call s    

1000: 6           40                    inc ax

1000:7           58                  s:pop ax

程序分析:

1.熟悉call指令的操作過程。call指令在執行時,首先push ip(此時ip應為6 ,CPU將要執行的地址),然后jmp 標號,執行標號處的代碼,pop ax (彈棧寫入ax,(ax)= 6),我們發現inc ax沒有執行。

       此時使用的棧空間是系統自動創建的。

2.結論:(ax)= 6

 

檢測點10.3

內存地址          機器碼                 匯編指令                 執行后情況

1000:0             b8 00 00             mov ax,0                ax=0,ip指向1000:3

1000:3             9a 09 00 00 10       call far ptr s          push cs,push ip,ip指向1000:9

1000:8             40                   inc ax

1000:9             58                 s:pop ax                  ax=8h

                                        add ax,ax               ax=10h

                                        pop bx                  bx=1000h

                                        add ax,bx               ax=1010h

程序分析:

1.關鍵還要明白是什么段地址和偏移地址壓棧?遇到CALL指令,老樣子,首先將當前的CS和IP值壓棧,(cs)=1000H(由CALL的機器碼得知),此時IP指向了0008H。它們統統壓棧(cs先入棧,ip在棧頂)。(ax)=0

2.轉移到標號S處繼續執行代碼,pop ax出棧寫入到ax,(IP)先出棧(0008H),(ax)=0008H

3.add ax,ax   0008H+0008H=0010H

4.pop bx 將(cs)=1000H出棧,並寫入bx中,(bx)=1000H

5.add ax,bx   0010H+1000H =1010H

6.(ax)=1010H;代碼:inc ax沒有執行

 

檢測點 10.4

下面的程序執行后,ax中的數值為多少?

內存地址      機器碼           匯編指令            執行后情況

1000:0           b8 06 00        mov ax,6               (ax)=6,ip指向1000:3

1000:3                  ff d0            call ax                  push ip(此時IP值為5),ip轉移指向1000:6

1000:5           40                      inc ax

1000:6           58                 mov bp,sp                    (bp)=(sp)=fffeh

                                         add ax,[bp]                  (ax)=6+(ss:bp)=6+5=0bh

程序分析:

1. 遇到CALL指令,老樣子,(ip)(此時是5),壓棧;這里我們可以不管sp是多少(我的debug是0000H),目前我們確定的就是IP的值是5(壓棧的數據)。此時棧中有一個字就是0005H。(sp)=(sp)-2 =>>0000H-2=fffeH

2.由於是CALL ax,(ax)=0006H,直接轉移到1000:0006處執行,將sp的值賦值給bp。

3.由於bp默認隸屬於ss段寄存器,故[bp]指向ss段的物理內存,也就是棧結構的空間,此時棧中就一個字0005H,那么(ss:[bp])=0005H(讀取ss棧中的內容)。

4.add ax,[bp]    ,0006H+0005H=000BH

5.結果:ax的值是000BH。inc ax指令依然沒有執行。

 

檢測點10.5

(1)下面的程序執行后,ax中的數值為多少?

assume cs:code

stack segment

     dw 8 dup (0)

stack ends

code segment

start:  mov ax,stack

        mov ss,ax

        mov sp,16

        mov ds,ax

        mov ax,0

        call word ptr ds:[0eh]

        inc ax

        inc ax

        inc ax

 

         mov ax,4c00h

        int 21h

code ends

end start

程序分析:

1. 在棧段初始化並定義了8個字,16個字節的空間。是dw指令。

2. 初始化棧,將棧段地址也賦值給了ds;(ss)=(ds),數據段和棧段是同一個內存空間段。

3. 遇到了call,老樣子,將(cs)壓棧(這個值肯定是call指令后面的那個指令的cs和ip我們可以不關心它,依據你的debug程序)、將(ip)壓棧,此時的ip值應該是第一個inc ax的偏移地址。然后jmp到ds:[0eh]內存單元內容作為偏移地址的點執行代碼。由於ds和ss都是同一個段,call的是一個字單元,故ds:[0eh]內存單元是指向的一個字(ds:[0eh]~ds:[0fh]內存單元),此單元正好是棧空間棧頂的存儲單元,存儲着最后壓入的ip的值,這個值就是代碼inc ax的偏移地址,那么開始執行inc ax

4.執行3次inc ax后, (ax)=3。

5.總結:這個考察了我們對於CALL 內存空間這個指令的熟悉程度,也考察了棧段和數據段在同一段地址下,怎樣讀出棧空間單元內容。

       為什么不讓使用debug來逐步調試?因為在執行到CALL指令時,顯示ds:[0eh]=065D(在我的環境中debug后),ds:【oeh】中的內容是中斷的信息,並不是我們程序所希望的0011H,它一下就jmp到065D的地址去了,而不是cs:11地址執行。

       stack段初始的時候定義的全是0,怎么初始化棧段后有數據了?因為中斷信息。

(2)下面的程序執行后,ax和bx中的數值為多少?

assume cs:codesg

stack segment

    dw 8 dup(0)                       ;初始化8個雙字,16個字的內存作為棧空間

stack ends

codesg segment

start:

    mov ax,stack

    mov ss,ax

    mov sp,10h                        ;初始化棧頂

    mov word ptr ss:[0],offset s      ;(ss:[0])=001ah

    mov ss:[2],cs                     ;(ss:[2])=cs

    call dword ptr ss:[0]             ;cs入棧,ip=19h入棧,轉到cs:1ah處執行指令

                                        ;(ss:[4])=cs,(ss:[6])=ip

    nop

s:  mov ax,offset s                   ;ax=1ah

    sub ax,ss:[0ch]                     ;ax=1ah-(ss:[0ch])=1ah-19h=1

    mov bx,cs                         ;bx=cs=0c5bh

    sub bx,ss:[0eh]                   ;bx=cs-cs=0

 

    mov ax,4c00h

    int 21h

codesg ends

end start

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM