在學習王爽老師《匯編語言》的第6.2節時,在程序6.3代碼中,給出了如下的代碼:
1 assume cs:code 2 code segment 3 dw 0123h, 0456h, 0789h, 0abch, 0123h, 0456h, 0789h, 0abch 4 dw 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0 5 6 start: mov ax,cs 7 mov ss,ax 8 mov sp,30h 9 10 mov bx,0h 11 mov cx,8 12 s: push cs:[bx] 13 add bx,2 14 loop s 15 16 mov bx,0 17 mov cx,8 18 s0: pop cs:[bx] 19 add bx,2 20 loop s0 21 22 mov ax,4c00h 23 int 21h 24 code ends 25 end start
可以看到第4行中定義了16個dw 0,也就是16個字型數據(32個字節型),隨后將該32個字節內存空間當做棧來使用。初始棧頂為30h,結構圖如下:
從上圖可以看到,總共花費了48個字節,48轉換成16進制值為30H,而內存地址從0開始計數,因此這2個dw的內存起止地址為0~2F,上面的代碼將第二個dw段視作棧空間,初始棧為空,因此指向棧下面的內存空間,結構如下:
所以代碼的第8行將棧偏移地址寄存器SP設置為30h。
這里有一個問題,第一個dw段只定義了8個字型數據(16個字節),為了逆序反轉它,應該只需要8個字型大小的棧空間,但實際卻定義了16個字型數據(32個字節),多出來8個字型數據,似乎是多余的。更改代碼,將第二個dw段中定義的16個字型數據更改為8個,這樣棧偏移地址寄存器SP就應該設置為20h,然后調試程序看看,如下:
首先回憶書本第4章4.9節程序執行過程的跟蹤中的說明,一個程序的加載一定是先找到一段足夠空間的內存,該內存空間的地址段為SA,偏移地址為0,因此寄存器CS=SA,寄存器IP=0h。而該內存前面256個字節用來和程序通信,因此實際的指令段地址為CS=CS+10h。
上機查看加載到內存的代碼指令,可以看到IP寄存器的值的確為20h,因為前面32個字節是數據空間,第33個字節才是真正指令,因此IP指向20h(這是程序源碼中start標志告訴編譯器的)。另外,也可以看到第一個壓棧的循環在0B34:002D~0B34:0033處。
在執行循環壓棧數據之前,先查看代碼指令前20個字節的空間的值,也就是2個dw段中定義的數據。然后一次性執行完第一個循環,使用g命令,令其執行到0B34:0035處開始等待,然后再查看一次前20字節的數據空間,如下:
從上圖可以發現一個比較奇怪的地方,那就是棧空間的數據並沒有改變,第一個dw段的數據沒有壓棧。這不應該,為什么沒有正常工作?再次查看代碼指令,突然發現代碼指令被改寫了,如下圖:
由於指令被改寫,那自然上面的程序就沒發正常工作了。那為什么指令的內容會被改變呢?回想書本第3章最后一個問題,也就是實驗2中最后一個提問,為什么棧里的數據改變了?
最前面的程序使用16個dw字型數據做棧空間時,能夠正常工作,而使用8個字型數據時,則出現了問題,這原因是不是和上面圖中的提問的答案一樣?