王爽《匯編語言》(第三版)實驗8解析(超詳細)


題目

分析程序,在運行前思考:這個程序是否能夠正確返回?
運行之后再思考:為什么是這種結果?
通過這個程序加深對相關內容的理解。

貼入代碼如下:

assueme cs:codesg
codesg segment
        mov ax,4c00h
        int 21h
start:  mov ax,0
    s:  nop
        nop

        mov di,offset s
        mov si,offset s2
        mov ax,cs:[si]
        mov cs:[di],ax

    s0: jmp short s

    s1: mov ax,0
        int 21h
        mov ax,0

    s2: jmp short s1
        nop
codesg ends
end start

分析

由我們之前學到的知識,我們知道這個程序從start標號的字段開始執行。

我們先來看一下程序的執行流程:

 1. start: mov ax,0
 2.   s:  nop  ; nop標號語句,在運行時在代碼段中分配一個字節的空間,
 3.       nop  ; 這個字節(空間)的值為90h。
        
        ; 操作符 `offset` 的功能是取得標號的偏移地址。
 4.       mov di,offset s   ; 將 s 的偏移地址存到 di 寄存器中
 5.       mov si,offset s2  ; 將 s2 的偏移地址存到 si 寄存器中
 6.       mov ax,cs:[si]   ; 此行是將cs:[si]內存中的機器碼存到ax寄存器中,
                           ; 這個機器碼是由編譯器將 s2 標號字段中的指令編譯而成。
 7.       mov cs:[di],ax  ; 將 ax 中的 s2 標號字段的機器碼存放到 s 標號字段中。

 8.   s0: jmp short s  ; 跳轉到 s 標號字段處執行代碼。

 9.   s:  jmp short s1 ; 根據我們之前的分析, 指令是用相對偏移來表示的
    ; 因此執行的操作並不是真的跳轉到 s1 這個標號, 
    ; 而是跳轉編譯時確定的 該指令到 s1 標號的偏移量。
    ; 所以我們要分析接下來程序的流程的話 , 就必須先編譯程序 , 
    ; 通過查看這條指令的機器代碼,才知道偏移量是多少。
    ; 然后再根據這個偏移量確定程序下一步應該執行哪里的指令。
    ; 根據下圖的編譯結果 , 可以發現 , 
    ; jmp short s1 在編譯后得到的指令是 : EB F6
    ; 由上可知,偏移量是 :F6 
    ; 偏移量是由 補碼 來表示的,由書中 附注二 ,
    ; 我們可以算出 F6對應的有符號十進制數為 -10。
    ; 從這里,我們可以知道,這條指令是將 ip 的值加上 -10。
    ; 那么,我們再看看 ip - 10 指向的地址是哪里呢 ? 
    ; 由下圖的編譯結果,我們可以知道,
    ; 它指向的剛好就是 code segment 開始的位置.

 10.   mov ax,4c00h
 11.   int 21h      ;看到這兩句,大家就知道,程序是可以正常返回了

反編譯

注意這里使用 debug 的 u 命令進行反匯編的時候要指定代碼段的偏移地址為 0 ,否則 debug 會自動從 start 標號的地方開始反匯編

不完整的反編譯代碼

有時候單純從 u 0 命令無法查看到jmp short s1這條代碼。因為有的命令行工具可能不能夠顯示過多的代碼。 我們可以從上圖中找一個參照點,再次運用 u 命令,就可以看到這行代碼了。從下圖中,我們可以看到,jmp short s1對應的機器代碼,正是 EB F6

完整的反編譯代碼

  • jmp short s1的跳轉原理分析:
1. codesg segment
        mov ax,4c00h     ; 3字節
        int 21h          ; 2字節
2. start:  mov ax,0         ; 3字節
3.    s:  jmp short s1     ; 2字節   
    ; 上述4條指令總共加起來是10字節,即 10 個單位的偏移量!
    ; 由於 nop 只占一個字節 , 因此
    ; 原來 s 中的兩個 nop 被jmp short s1完全替代。
    ; CPU首先讀取這條指令到指令緩存器里
    ; 此時的ip為8(由上圖可以知道)
    ; 【文末的參考文章中的len(EB F6)解釋錯誤,應為2,此處已更正】
    ; 接下來 , (ip) = (ip) + len(EB F6) = (ip) + 2 = 10 
    ; 然后執行這條指令 , 即為 (ip) = (ip) - 10 = 0
    ; 這樣 ip 就回到了 code segment 的起始處
    ; 這樣繼續執行
4. mov ax,4c00h
5. int 21h
    ; 這樣,程序就這樣神奇的執行成功啦!!!

總結

運用王爽老師在P179頁的話,CPU在執行jmp指令的時候並不需要轉移的目的地址,而包含的是轉移的位移。這個位移,是編譯器根據匯編指令中的“標號”計算出來的。

本博參考了他的文章:
鏈接:https://www.jianshu.com/p/7e5dfea72b65


免責聲明!

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



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