多個邏輯段的匯編源程序編寫與調試
實驗任務1
-
任務1-1
對程序task1_1.asm進行匯編、連接,用debug加載、跟蹤調試,基於結果,回答問題。
assume ds:data, cs:code, ss:stack data segment db 16 dup(0) data ends stack segment db 16 dup(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
問題1:
查看寄存器值
使用U命令查看反匯編代碼,找到mov ah,4ch這一代碼的內存地址,並使用G命令快速執行到這條命令之前。
(DS)=076C
(SS)=076D
(CS)=076E
問題2:
假設程序加載后,CODE段地址為X,則data段地址為X-2,stack段地址為X-1
由於程序占用的內存空間是連續的,又由於段大小占16字節的整數倍,所以如果按照task1-1.ASM的代碼,data緊挨着程序段前綴,stack緊挨着data,code緊挨着stack。 -
任務1-2
對程序task1_2.asm進行匯編、連接,用debug加載、跟蹤調試,基於結果,回答問題。assume ds:data, cs:code, ss:stack data segment db 4 dup(0) data ends stack segment db 8 dup(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
問題1:
重復task1-1的問題1的操作,查看寄存器值
(DS)=076C
(SS)=076D
(CS)=076E
問題2:
假設程序加載后,CODE段地址為X,則data段地址為X-2,stack段地址為X-1
由於程序占用的內存空間是連續的,又由於段大小占16字節的整數倍,所以如果按照task1-2.ASM的代碼,data緊挨着程序段前綴,stack緊挨着data,code緊挨着stack。 -
任務1-3
對程序task1_3.asm進行匯編、連接,用debug加載、跟蹤調試,基於結果,回答問題。assume ds:data, cs:code, ss:stack data segment db 20 dup(0) data ends stack segment db 20 dup(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
問題1:
重復task1-1和task1-2的操作,結果如下
(DS)=076C
(SS)=076E
(CS)=0770
問題2:
假設程序加載后,CODE段地址為X,則data段地址為X-4,stack段地址為X-2
由於程序占用的內存空間是連續的,又由於段大小占16字節的整數倍,所以如果按照task1-3.ASM的代碼,data緊挨着程序段前綴,stack緊挨着data,code緊挨着stack。 -
任務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
問題1:
重復操作,查看寄存器值
(DS)=076E
(SS)=0770
(CS)=076C
問題2:
假設程序加載后,CODE段地址為X,則data段地址為X+2,stack段地址為X+4
由於程序占用的內存空間是連續的,又由於段大小占16字節的整數倍,所以如果按照task1-4.ASM的代碼,code緊挨着程序段前綴,data緊挨着code,stack緊挨着data。
這里的情況很特殊,一般的段空間,由於8086尋址的特性,都是16的整數倍,但是這里的stack段,由於stack下面沒有其他段,猜測當時為了節省內存空間,沒有分配16的整數倍空間,而是要多少分配多少。具體實踐如下圖- 查看最后段的段空間分配情況
- 查看task1-1,task1-2,task1-3 code段后的內存分配情況
可以看到並非為0
- 查看最后段的段空間分配情況
-
任務1-5
基於上述四個實驗任務的實踐、觀察,總結並回答:
問題1:
對於如下定義的段,程序加載后,實際分配給該段的內存空間大小是
當本段不是程序的最后一段時: \(\lceil \frac{N}{16} \rceil \times 16\)。
當本段是程序的最后一段時: \(N\)xxx segment db N dup(0) xxx ends
問題2:
如果將程序task1_1.asm, task1_2.asm, task1_3.asm, task1_4.asm中,偽指令end start
改成end
, 哪一個程序仍然可以正確執行?結合實踐觀察得到的結論,分析、說明原因。
注意:本處正常執行指的是從start標號處開始執行,沒從start標號處執行均視為不能正常執行- 程序task1-1.ASM
不能正常執行 - 程序task1-2.ASM
不能正常執行 - 程序task1-3.ASM
不能正常執行 - 程序task1-4.ASM
可以正常執行 - 分析
匯編器在處理匯編源程序的時候會先處理偽指令。start
偽指令表示程序段從此處開始,會將code segment
給CS段寄存器。由於start
和end start
需要成對出現,匯編器找到start
后,卻沒找到end start
,所以start
無效,因此從程序段前綴之后開始執行程序,由於1,2,3個子任務的程序段前綴之后都是數據段,因為在8086匯編環境下,數據和指令處於同等地位,所以CPU無法辨別內存中的是指令還是數據,所以1,2,3個子任務不能正確完成期望的代碼的執行。
- 程序task1-1.ASM
實驗任務2
編寫一個匯編源程序,實現向內存單元
b800:0f00
~b800:0f9f
連續160字節,依次重復填充十六進制數據03 04
。
代碼如下:
assume cs:code
code segment
start:
mov ax,0b800h
mov ds,ax
mov bx,0f00h
mov cx,80
p:
mov ds:[bx],0403h
inc bx
inc bx
loop p
mov ah,4ch
int 21h
code ends
end start
運行結果如下:
注意事項:
數字要以數字開頭,所以b800h要寫成0b800h,f00h同理,要寫成0f00h
03 04 也需要注意,03是低位,04是高位,所以應該存0403h。
實驗任務3
已知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:
; ×××
code ends
end start
要求:
① 編程實現把邏輯段data1和邏輯段data2的數據依次相加,結果保存到邏輯段data3中。
② 在debug中加載、反匯編、調試。在數據項依次相加前,和相加后,分別查看三個邏輯段data1,
data2, data3對應的內存空間,確認逐一相加后,結果的確保存在了邏輯段data3中。
問題1:
源代碼如下:
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
問題2:
運行結果如下,相加成功
實驗任務4
代碼如下:
assume cs:code
data1 segment
dw 2, 0, 4, 9, 2, 0, 1, 9
data1 ends
data2 segment
dw 8 dup(?)
data2 ends
stack segment
db 16 dup(0)
stack 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]
inc bx
inc bx
loop s1
mov bx,16
mov cx,8
s2:
pop ds:[bx]
inc bx
inc bx
loop s2
mov ah, 4ch
int 21h
code ends
end start
運行結果如下
分析:
使用棧先進后出的特性,完成逆序存放。因為棧每次放入一個字,數據也是一個字,非常完美的配合起來了。
實驗任務5
-
問題1運行結果
-
問題2測試結果(line 25 line 27之前)
-
代碼line19的作用是將所有字母轉換為大寫字母
將0dfh
轉換為二進制可得
11011111
大寫字母ASCII碼
0100 0001
~0101 1010
小寫字母ASCII碼
0110 0001
~0111 1010
可以觀察得出,相差的位數就是第三位(從高到低,從1開始數)。
所以只需要將第三位置零,其他位保持不變即可。
所以只需要與上11011111
即可,因為任意位數與上0
得0
,任意數字與上1
不變。 -
問題4測試結果
分析以及猜測:
顯示一個字符占一個字,低位字節表示是什么字母(ASCII碼),第二個字節表示字符的顯示參數,高四位表示字符的底色,低四位表示字符得顏色。
實驗任務6
-
程序源代碼
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
-
運行結果
分析:使用二重循環,dx用來暫存cx的值。此處也可以用棧來保存,但是由於只需要保存cx,所以可以暫時不用棧
實驗任務7
assume cs:code, ds:data, es:table
data segment
db '1975', '1976', '1977', '1978', '1979' ;一個數字占4個字節,0起步,每次偏移量為4
dw 16, 22, 382, 1356, 2390 ;一個數字占一個字,20起步,每次偏移2
dw 3, 7, 9, 13, 28 ;一個數字占一個字,30起步,每次偏移2
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 cx,5
mov bx,0
mov si,0
s:
mov ax,[bx+2]
mov es:[di+2],ax
mov ax,[bx]
mov es:[di],ax
mov ax,[si+20]
mov es:[di+5],0
mov es:[di+7],ax
mov ax,[si+30]
mov es:[di+11],ax
mov es:[di+9],0
mov ax,es:[di+7]
div byte ptr es:[di+11]
mov byte ptr es:[di+13],0
mov es:[di+14],al
add bx,4
add si,2
add di,16
loop s
mov ah, 4ch
int 21h
code ends
end start
程序運行截圖
原始數據截圖