一、實驗目的
- 理解和掌握8086多個邏輯段的匯編源程序
- 理解和熟練應用靈活的尋址方式
- 通過匯編指令loop的使用理解編程語言中循環的本質,掌握其在嵌套循環中的正確使用
- 掌握使用debug調試8086匯編程序的方法
二、實驗准備
復習王爽《匯編語言》5-8章:
- 包含多個邏輯段的匯編源程序結構
- 尋址方式
- 匯編指令loop, div用法
三、實驗內容
實驗任務1
此實驗任務中,包含4個子任務。逐一實踐,結合實踐觀察、驗證,回答問題。
- 1.1
對程序task1_1.asm進行匯編、連接,用debug加載、跟蹤調試,基於結果,回答問題。
assume ds:data, cs:code, ss:stack
data segment
db 16 dup(0) ; 預留16個字節單元,初始值均為0
data ends
stack segment
db 16 dup(0) ;預留16個字節單元,初始值均為0
stack ends
code segment
start:
mov ax, data
mov ds, ax
mov ax, stack
mov ss, ax
mov sp, 16 ; 設置棧頂
mov ah, 4ch
int 21h
code ends
end start
① 在debug中將執行到line17結束、line19之前,記錄此時:寄存器(DS) =076a, 寄存器(SS) =076B, 寄存器(CS) =076C
② 假設程序加載后,code段的段地址是X,則,data段的段地址是 X-2, stack的段地址是 X-1。
內存按照代碼中數據、代碼段書寫順序自上而下分配,故先分配data段再分配stack段最后分配code段,一個段地址長度為16字節,故兩個數據段各分配1個段地址長度,為X-2和X-1。以下子任務類似。
- 1.2
對程序task1_2.asm進行匯編、連接,用debug加載、跟蹤調試,基於結果,回答問題。
assume ds:data, cs:code, ss:stack
data segment
db 4 dup(0) ; 預留4個字節單元,初始值均為0
data ends
stack segment
db 8 dup(0) ; 預留8個字節單元,初始值均為0
stack ends
code segment
start:
mov ax, data
mov ds, ax
mov ax, stack
mov ss, ax
mov sp, 8 ; 設置棧頂
mov ah, 4ch
int 21h
code ends
end start
① 在debug中將執行到line17結束、line19之前,記錄此時:寄存器(DS) =076a, 寄存器(SS) =076B, 寄存器(CS) =076C
② 假設程序加載后,code段的段地址是X,則,data段的段地址是 X-2, stack的段地址是 X-1。
數據段不足16字節也分配滿16字節。8086內存分配一般以16字節為單位。
- 1.3
對程序task1_3.asm進行匯編、連接,用debug加載、跟蹤調試,基於結果,回答問題
assume ds:data, cs:code, ss:stack
data segment
db 20 dup(0) ; 預留20個字節單元,初始值均為0
data ends
stack segment
db 20 dup(0) ; 預留20個字節單元,初始值均為0
stack ends
code segment
start:
mov ax, data
mov ds, ax
mov ax, stack
mov ss, ax
mov sp, 20 ; 設置初始棧頂
mov ah, 4ch
int 21h
code ends
end start
① 在debug中將執行到line17結束、line19之前,記錄此時:寄存器(DS) =076a, 寄存器(SS) =076C, 寄存器(CS) =076E
② 假設程序加載后,code段的段地址是X,則,data段的段地址是 X-4, stack的段地址是 X-2。
- 1.4
對程序task1_4.asm進行匯編、連接,用debug加載、跟蹤調試,基於結果,回答問題。
assume ds:data, cs:code, ss:stack
code segment
start:
mov ax, data
mov ds, ax
mov ax, stack
mov ss, ax
mov sp, 20
mov ah, 4ch
int 21h
code ends
data segment
db 20 dup(0)
data ends
stack segment
db 20 dup(0)
stack ends
end start
① 在debug中將執行到line17結束、line19之前,記錄此時:寄存器(DS) =076C, 寄存器(SS) =076E, 寄存器(CS) =076A
② 假設程序加載后,code段的段地址是X,則,data段的段地址是 X+2, stack的段地址是 X+4。
該任務code段位於開頭故data段和stack段地址在后。
- 1.5
基於上述四個實驗任務的實踐、觀察,總結並回答:
① 對於如下定義的段,程序加載后,實際分配給該段的內存空間大小是[N/16]*16 (中括號是向上取整)
xxx segment
db N dup(0)
xxx ends
② 如果將程序task1_1.asm, task1_2.asm, task1_3.asm, task1_4.asm中,偽指令 end start
改成end
, 哪一個程序仍然可以正確執行?結合實踐觀察得到的結論,分析、說明原因。
第四個任務依舊能夠成功運行。其他三個任務再更改末尾的end start后,start偽指令失效,程序從段前綴起始依次向后執行,根據分配次序前三個任務有數據段打頭,程序無法識別代碼類別產生錯誤,第四個任務代碼段最先分配規避了沖突的產生。
實驗任務二
編寫一個匯編源程序,實現向內存單元b800:0f00 ~ b800:0f9f連續160字節,依次重復填充十六進制數據03 04。
Tips:
- 在實驗1的實驗任務3中,做過達到同樣效果的實驗。但當時是通過debug的f命令實現填充的。這一次,要求編程實現。
在debug中,使用f命令,向內存單元批量填寫數據。
-f b800:0f00 0f9f 03 04
把內存單元區間b800:0f00 ~ b800:0f9f連續160個字節,依次重復填充十六進制數據03 04。
- 編程實現時,注意進制問題、字節順序問題。編寫后,運行程序,如果與實驗1的實驗任務3結果不一致,說明程序編寫有錯誤。
程序代碼:
assume cs:code
code segment
start:
mov ax,0b800h
mov ds,ax
mov bx,0f00h
mov cx,80
p:
mov ds:[bx],0403h
add bx,2
loop p
mov ah,4ch
int 21h
code ends
end start
結果如圖
實驗任務三
已知8086匯編源程序task3.asm代碼片段如下
assume cs:code
data1 segment
db 50, 48, 50, 50, 0, 48, 49, 0, 48, 49 ; ten numbers
data1 ends
data2 segment
db 0, 0, 0, 0, 47, 0, 0, 47, 0, 0 ; ten numbers
data2 ends
data3 segment
db 16 dup(0)
data3 ends
code segment
start:
; ×××
mov ah, 4ch
int 21h
code ends
end start
要求:
① 編程實現把邏輯段data1和邏輯段data2的數據依次相加,結果保存到邏輯段data3中。
② 在debug中加載、反匯編、調試。在數據項依次相加前,和相加后,分別查看三個邏輯段data1,data2, data3對應的內存空間,確認逐一相加后,結果的確保存在了邏輯段data3中。
補全后的代碼
assume cs:code
data1 segment
db 50, 48, 50, 50, 0, 48, 49, 0, 48, 49 ; ten numbers
data1 ends
data2 segment
db 0, 0, 0, 0, 47, 0, 0, 47, 0, 0 ; ten numbers
data2 ends
data3 segment
db 16 dup(0)
data3 ends
code segment
start:
mov ax,data1
mov ds,ax
mov cx,16
mov bx,0
s:
mov al,ds:[bx]
add al,ds:[bx+16]
mov ds:[bx+32],al
inc bx
loop s
mov ah, 4ch
int 21h
code ends
end start
data1和data2各存有10個10進制數,為其分配16字節空間,所以data1數據段對應data2數據段的位置為data1+16,對應data3的位置為data1+32。據此寫出此三步代碼
mov al,ds:[bx]
add al,ds:[bx+16]
mov ds:[bx+32],al
完成對應位置數相加后的保存。
實驗結果:
實驗任務四
已知8086匯編源程序task4.asm代碼片段如下
assume cs:code
data1 segment
dw 2, 0, 4, 9, 2, 0, 1, 9
data1 ends
data2 segment
dw 8 dup(?)
data2 ends
code segment
start:
; ×××
mov ah, 4ch
int 21h
code ends
end start
要求:
① 補全程序,實現把邏輯段data1中的8個字數據逆序存儲到邏輯段b中。
② 匯編、連接后,在debug中加載程序,運行到line15程序退出前,使用d命令查看數據段data2對應的內存空間,確認是否實現題目要求。
補全后代碼:
assume cs:code
data1 segment
dw 2, 0, 4, 9, 2, 0, 1, 9
data1 ends
data2 segment
dw 8 dup(?)
data2 ends
code segment
start:
` mov ax,data1
mov ds,ax
mov ax,stack
mov ss,ax
mov sp,16
mov bx,0
mov cx,8
s1:
push ds:[bx]
add bx,2
loop s1
mov bx,16
mov cx,8
s2:
pop ds:[bx]
add bx,2
loop s2
mov ah, 4ch
int 21h
code ends
end start
利用棧依次壓入8個數再依次彈出到data2對應位置,注意彈出時bx值的設置。
實驗結果:
實驗任務五
使用任意文本編輯器,錄入匯編源程序task5.asm
assume cs:code, ds:data
data segment
db 'Nuist'
db 2, 3, 4, 5, 6
data ends
code segment
start:
mov ax, data
mov ds, ax
mov ax, 0b800H
mov es, ax
mov cx, 5
mov si, 0
mov di, 0f00h
s: mov al, [si]
and al, 0dfh
mov es:[di], al
mov al, [5+si]
mov es:[di+1], al
inc si
add di, 2
loop s
mov ah, 4ch
int 21h
code ends
end start
閱讀源程序,從理論上分析源代碼的功能,尤其是line15-25,循環實現的功能是什么,逐行理解每條指令的功能。
- 對程序進行匯編、鏈接,得到可執行文件,運行並觀察結果。
- 使用debug工具對程序進行調試,執行到程序返回前,即line25執行之后、line27執行之前,觀察結果。
- 源代碼中line19的作用是?
- 修改line4里5個字節單元的值,重新匯編、鏈接、運行,觀察結果。
db 2,3,4,5,6
--> 改成:
db 5 dup(2) 或 db 5 dup(5)
基於觀察,分析、猜測這里的數值作用是什么。
1.運行結果
2.運行結果
3.line19的作用是將小寫字母轉換為大寫字母,實現方式基於英文大小寫字母ASCII碼的特性,小寫字母比對應大寫字母高32,可以利用二進制數相與改變對應位的數值,相與的二進制數在想要賦0的位置填充0,其余位填充1,可以達到一種“二進制掩碼”的效果。
4.運行結果
5個數值依次對應5個字母的字體顏色。
實驗任務六
已知8086匯編源程序task6.asm代碼片段如下
assume cs:code, ds:data
data segment
db 'Pink Floyd ' ; 16字節
db 'JOAN Baez ' ; 16字節
db 'NEIL Young ' ; 16字節
db 'Joan Lennon ' ; 16字節
data ends
code segment
start:
; ×××
mov ah, 4ch
int 21h
code ends
end start
要求:
① 補全程序,將data段中的每行第一個單詞從大寫->小寫。
② 在debug中加載程序,反匯編,執行到line13退出前,用d命令查看data段對應的內存空間,確認每行第一個單詞已經由大寫->小寫。
補全后的程序:
assume cs:code, ds:data
data segment
db 'Pink Floyd '
db 'JOAN Baez '
db 'NEIL Young '
db 'Joan Lennon '
data ends
code segment
start:
mov ax,data
mov ds,ax
mov cx,4
mov bx,0
s:
mov dx,cx
mov cx,4
mov si,0
p:
mov al,ds:[bx+si]
or al,00100000B
mov ds:[bx+si],al
inc si
loop p
add bx,16
mov cx,dx
loop s
mov ah, 4ch
int 21h
code ends
end start
實驗結果:
外層循環遍歷4行單詞,內存循環遍歷首單詞的每個字母,利用dx暫存cx值。通過or指令將單詞數據與00100000B相或得到ASCII更大的小寫字母。
實驗任務七
問題場景描述:
Power idea公司1975年-1979年的基本情況如下:
程序task7.asm的邏輯段data中(line4-6),已經定義好了這些數據。
assume cs:code, ds:data, es:table
data segment
db '1975', '1976', '1977', '1978', '1979'
dw 16, 22, 382, 1356, 2390
dw 3, 7, 9, 13, 28
data ends
table segment
db 5 dup( 16 dup(' ') ) ;
table ends
code segment
start:
mov ah, 4ch
int 21h
code ends
end start
要求:
① 補全程序,實現題目要求,把年份、收入、雇員人數、人均收入,以結構化方式寫入table段中。
表格中,每行數據,在邏輯段table中占16個字節,各項數據占據字節大小分配如下。期中,數據之間用空格間隔。
② 匯編、連接后,在debug中加載、調試程序。靈活、合理使用u命令、g命令、d命令,顯示剛開始邏輯段table的數據信息,以及,結構化存入數據后,數據段table的數據信息,確認實現題目要求。
補全后的程序:
assume cs:code, ds:data, es:table
data segment
db '1975', '1976', '1977', '1978', '1979'
dw 16, 22, 382, 1356, 2390
dw 3, 7, 9, 13, 28
data ends
table segment
db 5 dup( 16 dup(' ') ) ;
table ends
code segment
start:
mov ax,data
mov ds,ax
mov ax,table
mov es,ax
mov si,0
mov di,0
mov bx,0
mov cx,5
mov sp,0
s: mov ax,[si]
mov es:[di],ax
mov ax,[si+2]
mov es:[di+2],ax
mov ax,[bx+20]
mov es:[di+5],ax
mov dx,0
mov es:[di+7],dx
push cx
mov cx,[20+10+bx]
mov es:[di+10],cx
div cx
pop cx
mov es:[di+0dh],ax
add si,4
add di,16
add bx,2
loop s
mov ah, 4ch
int 21h
code ends
end start
實驗結果: