一、預備知識
ps:這一章我同樣不分開做知識點總結了,一個是因為覺得能力不夠,沒有那么多的發現,而且掌握也不算好,還有一點是現在時間不夠,每一次作業都要花好久的時間
(1)dw:字型數據;db:字節型數據
(2)如果代碼和數據放在一個段中,反匯編時,如果從0開始,會把數據當成指令機器碼反匯編,所以反匯編時注意sp的值
(3)8086CPU不允許將一個數值直接送入段寄存器中
(4)調試時,可以通過r命令修改ip的值或在t/g命令中指定執行的起始地址
(5)end 標號:表示程序到標號處開始,到此結束,后面的標號有時候可以省略
(6)使用assume僅僅表示將某個邏輯段和某個段寄存器關聯起來;真正當做特定的段使用,需要在代碼段中設置相應的段寄存器值
二、實驗任務
1、將下面的程序編譯、連接、,用debug加載、跟蹤,然后回答問題
assume cs:code,ds:data,ss:stack
data segment
dw 0123h,0456h,0789h,0abch,0defh,0fedh,0cbah,0987h
data ends
stack segment
dw 0,0,0,0,0,0,0,0
stack ends
code segment
start: mov ax,stack
mov ss,ax
mov sp,16
mov ax,data
mov ds,ax
push ds:[0]
push ds:[2]
pop ds:[2]
pop ds:[0]
mov ax,4c00h
int 21h
code ends
end start
先用r查看各寄存器的值,CX的值為42h,前面的數據一共用了20h,剩下的一共是22h,從0~21h
接着用g命令多步執行,到程序返回前停下,所以用g 001d,接着查看data段中的數據
(1)CPU執行程序,程序返回前,data段中的數據為多少?
0123h,0456h,0789h,0abch,0defh,0fedh,0cbah,0987h
(2)CPU執行程序,程序返回前,cs=0772h,ss=0771h,ds=0770h
(3)設程序加載后,code段的段地址為X,則data段的段地址為X-2,stack段的段地址為X-1
2、將下面的程序編譯、連接,用debug加載、跟蹤,然后回答問題
assume cs:code,ds:data,ss:stack
data segment
dw 0123h,0456h
data ends
stack segment
dw 0,0
stack ends
code segment
start: mov ax,stack
mov ss,ax
mov sp,16
mov ax,data
mov ds,ax
push ds:[0]
push ds:[2]
pop ds:[2]
pop ds:[0]
mov ax,4c00h
int 21h
code ends
end start
這個程序和上面的程序一樣的方法調試
(1)CPU執行程序,程序返回前,data段中的數據為多少?
0123h,0456h
(2)CPU執行程序,程序返回前,cs=0772h,ss=0771h,ds=0770h
(3)設程序加載后,code段的段地址為X,則data段的段地址為X-2,stack段的段地址為X-1
(4)對於如下定義的段:
name segment
……
name ends
如果段中的數據占N個字節,則程序加載后,該段實際占有的空間為((N+15)/16)* 16
ps:這道題我確實無從下手,不知道是該怎么處理,最后沒辦法,去查了一下
N分為被16整除和不被16整除。
當N被16整除時: 占有的空間為(N/16)*16
當N不被16整除時: 占有的空間為(N/16+1)*16,N/16得出的是可以整除的部分,還有一個余數,余數肯定小於16,加上一個16。
程序加載后分配空間是以16個字節為單位的,也就是說如果不足16個字節的也分配16個字節。
兩種情況總結成一個通用的公式:((N+15)/16)*16
3、將下面的程序編譯、連接,用debug加載、跟蹤,然后回答問題
assume cs:code,ds:data,ss:stack
code segment
start: mov ax,stack
mov ss,ax
mov sp,16
mov ax,data
mov ds,ax
push ds:[0]
push ds:[2]
pop ds:[2]
pop ds:[0]
mov ax,4c00h
int 21h
code ends
data segment
dw 0123h,0456h
data ends
stack segment
dw 0,0
stack ends
end start
這個程序和上面的程序一樣的方法調試
(1)CPU執行程序,程序返回前,data段中的數據為多少?
0123h,0456h
(2)CPU執行程序,程序返回前,cs=0772h,ss=0774h,ds=0773h
(3)設程序加載后,code段的段地址為X,則data段的段地址為X+3,stack段的段地址為X+4
4、如果將(1)、(2)、(3)題中的最后一條偽指令“end start”改為“end”(也就是說,不知名程序的入口),則哪個程序仍然可以正確執行?請說明原因
(3)可以,(1)、(2)的開始都是數據段,而(3)的開始是指令
(1)、(2)如果直接執行,機器會把數據當成指令才執行,而(3)指令的一開始偏移地址就是0,直接執行不會有問題
5、程序如下,編寫code段中的代碼,將a段和b段中的數據依次相加,將結果存到c段中
assume cs:code
a segment
db 1,2,3,4,5,6,7,8
a ends
b segment
db 1,2,3,4,5,6,7,8
b ends
c1 segment
db 0,0,0,0,0,0,0,0
c1 ends
code segment
start:
???
code ends
end start
源代碼:
接着,調試一下,看看能不能達到預期的效果
在實現數據相加前,邏輯段c中放的是原本的數據
很明顯,最后數據的確相加了,而且存在了c段中
但素,做這個可沒那么容易
中間出了各種各樣的問題,做了很久才做出來
這是我一開始的代碼,粗來的數據很奇怪,找了很久才找到錯誤
assume cs:code
a segment
db 1,2,3,4,5,6,7,8
a ends
b segment
db 1,2,3,4,5,6,7,8
b ends
c1 segment
db 0,0,0,0,0,0,0,0
c1 ends
code segment
start: mov ax,c1
mov es,ax
mov ax,b
mov ds,ax
mov ax,a
mov ss,bx //問題出在這里,不應該是ss,bx,而應該是ss,ax
mov bx,0
mov cx,8
s: mov al,ds:[bx]
add al,ss:[bx]
mov es:[bx],al
inc bx
loop s
mov ax,4c00h
int 21h
code ends
end start
我在調試的時候才發現這個程序的問題
前面都沒有什么問題,直到我用d命令查看寄存器的值的時候,很奇怪,為什么這個數據是這個樣子的
我看了一下到程序返回前各寄存器的值,一看,ss的值還是0,也就是說,數據段中的數據並沒有到棧段中去
而那些數據都是操作系統自己的數據
因此,我去看了一下程序,問題出在我上面標出來的那一行
改過來之后程序就沒有問題了
6、程序如下,編寫code段中的代碼,用push指令將a段中的前8個字型數據,逆序存儲到b段中
assume cs:code
a segment
dw 1,2,3,4,5,6,7,8,9,0ah,0bh,0ch,0dh,0dh,0fh,0ffh
a ends
b segment
dw 0,0,0,0,0,0,0,0
b ends
code segment
start:
???
code ends
end start
源代碼:
這個代碼是借鑒了書上P133頁的代碼
下面是調試過程:
這里是在push操作執行前,查看邏輯段b的8個子單元
在程序返回前,再次查看邏輯段b的8個子單元
最后實現了逆序存儲
總結:
(1)當提到逆序存儲的時候,可以利用棧的先進后出的特點來實現這個問題
(2)可以利用寄存器cx的值來進行精確反匯編,同時可以用反匯編得到的偏移地址的值進行多步執行
(3)當程序達不到自己想要的結果時,可以通過單步執行來尋找問題,也可以利用寄存器的值來尋找問題
(4)要看清楚給的數據是字型數據還是字節型數據,用相應的寄存器去實現題目的問題
(5)前面的幾個程序,由每個段寫的位置可見,代碼段,數據段和棧段的段地址之間存在一定的關系