1. 程式人生 > 其它 >彙編課程實驗二 多個邏輯段的彙編源程式編寫與除錯

彙編課程實驗二 多個邏輯段的彙編源程式編寫與除錯

一、實驗目的

  1. 理解和掌握8086多個邏輯段的彙編源程式
  2. 理解和熟練應用靈活的定址方式
  3. 通過彙編指令loop的使用理解程式語言中迴圈的本質,掌握其在巢狀迴圈中的正確使用
  4. 掌握使用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. 在實驗1的實驗任務3中,做過達到同樣效果的實驗。但當時是通過debug的f命令實現填充的。這一次,要求程式設計實現。
在debug中,使用f命令,向記憶體單元批量填寫資料。
-f b800:0f00 0f9f 03 04
把記憶體單元區間b800:0f00 ~ b800:0f9f連續160個位元組,依次重複填充十六進位制資料03 04。
  1. 程式設計實現時,注意進位制問題、位元組順序問題。編寫後,執行程式,如果與實驗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

實驗結果: