實驗8 分析一個奇怪的程序
題目:分析下面程序,在運行前思考:這個程序可以正確返回嗎?
運行后思考:為什么是這樣的結果?
通過這個程序加深對相關內容的理解.
代碼如下:
assume 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
程序分析:
1. 看懂程序從何處入口?有start標號的地方(當然是和end start匹配的)。
2. s:標號語句nop作用,在運行時在代碼段分配一個字節的空間。(機器碼90,在內存中就是90H),它的作用是方便在程序運行時代碼段分配空間,在此寫入代碼(實際是機器碼)。執行二次nop后,在cs段中分配了2個字節空間,內容都是90H。(這個空間目前是空的,CPU遇到這2個字節,就不執行,順序執行下面的機器碼了。)
3. mov di, offset s ;將s標號處的偏移地址賦值給di,di指向了s
mov si, offset s2 ;將s2標號處的偏移地址賦值給si,si指向了s2
mov ax, cs:[si] ;將cs:si指向的內存單元的內容賦值給ax(內容為機器碼)
mov cs:[di], ax ;將機器碼賦值給s標號處
這四條語句的作用是將s2處的機器碼賦值給s標號開始的2個連續空間中(也就是說將jmp short s1這個指令的機器碼這個內容賦值給了s標號后面2個字節)。在匯編語言層面上,我們不必去關心offset s和offset s2的值他們到底是多少,但我們要明白,他們代表了標號開始處的ip值,他們是偏移地址值(也就是指針)。
(這里我們要搞清楚賦值的是機器碼這個內容,而不是代碼:jmp short s1,千萬不要憑字面意思去生硬的將代碼搬到s標號處。)
jmp short s1機器碼到底是多少?(理解jmp指令偏移的是相對位移),它應該是從si標號偏移地址- jmp指令后的第一個字節偏移地址。我們所說的偏移地址就是ip。我們計算下。mov ax,0 ==3個字節; int 21H ==2個字節;mov ax,0 ==3個字節;jmp short s1==2字節,那么我們可以計算出此代碼位移的偏移量是10個字節,也就是說IP變化了10,由於s1處標號(IP值)-s2標號后的第一個字節地址(ip值)是-10,轉換成16進制(補碼方式存儲)00001010(源碼10)>> 11110101(取反)>>11110110(加一)==F6H;故這個機器代碼是:EBF6,(EB代表jmp指令,F6代表了自此偏移地址開始,向前偏移10個字節)。
那么在標號S處存儲的是EBF6這二個字節。它就代表了一個jmp指令,無條件向前移動10個字節的內存單元處,然后執行此處的代碼。
程序一直自頂向下執行着,直到遇到S0標號。
s0: jmp short s 程序運行到此處。表示跳轉到s標號處,此處有代碼是EBF6,執行它,向前偏移10個字節,正好是codesg segment(s標號占2個字節(此處也是jmp指令,占2個字節,jmp指令后面的第一個字節地址,也就是從這個地址開始偏移,偏移量是10,簡單畫圖);mov ax,0 ==3byte; int 21H==2byte; mov ax 4c00H==3byte)也就是程序從mov ax 4c00H開始執行了,直到int 21H正常結束程序。
測試程序:我們編譯連接后,測試這個程序。
-d cs:0 ;執行到最后時,看看代碼段內存的變化
0B65:0000 B8 00 4C CD 21 B8 00 00-EB F6 BF 08 00 BE 20 00 ..L.!........
0B65:0010 2E 8B 04 2E 89 05 EB F0-B8 00 00 CD 21 B8 00 00 ............!
0B65:0020 EB F6 90
總結:
1. jmp XXXX,我們在匯編語言中,你不必去考慮位移的問題,那是編譯器的事情,要不我們累死啦。它自動計算位移(偏移量)。
2. 如果涉及到了jmp指令的機器碼問題。我們必須考慮位移的問題。
3. jmp指令的位移的計算方式,在機器碼中,位移是按照補碼方式存儲的;也就是說向下移動EB代碼后面是正整數(正數,補碼是原碼);如果是向上移動EB代碼后面是負整數(原碼取反+1)。EB代碼后邊跟隨的數值,是jmp的偏移位移,這個位移是按照字節作為移動單位的。
4. 我們發現,標號s1及以后的匯編代碼,程序就沒有執行。為什么?使用jmp跳轉到前邊了。雖然沒有執行,但是在編譯過程中,它們的機器碼也被編譯並存儲在了代碼段了。
