SpringCloud高階篇01
實驗
實驗任務 1
錄入 task1.asm
assume cs:code, ds:data data segment db 'Nuist' db 5 dup(2) 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
lined15-25 的功能為將 Nuist 字串全部改為大寫,寫入視訊記憶體並附上顏色。
逐行解釋:
mov cx, 5 做五次迴圈 mov si, 0 初始化 si mov di, 0f00h 初始化 di s: mov al, [si] 取資料段內對應字元 and al, 0dfh 改為大寫 mov es:[di], al 寫入視訊記憶體 mov al, [5+si] 為 al 賦資料段內的值 mov es:[di+1], al 為先前寫入字元的字的高位賦值,以此附以字元顏色 inc si si + 1,移向資料段下一字元 add di, 2 di + 2,移向視訊記憶體下一個字 loop s 迴圈
使用 masm、link 對 task1.asm 進行彙編、連結,得到可執行檔案 task1.exe,執行並觀察結果:
使用 debug 工具進行除錯、反彙編,並使用 g 命令執行到程式返回前:
修改 line4 裡 5 個位元組單元的值:
db 5 dup(2)
--> 改成:
db 2,3,4,5,6
重新彙編、連結、執行,結果為:
由先前分析以及實驗可知:
db 2, 3, 4, 5, 6
在此程式中的作用為,設定字元在視訊記憶體中的顏色。
實驗任務 2
編寫 task2.asm
assume cs:code, ds:data data segment db 23,50,66,71,35 data ends code segment start: mov ax, data mov ds, ax mov cx, 5 mov bx, 0 s: mov al, byte ptr ds:[bx] mov ah, 0 mov dl, 0AH div dl mov byte ptr ds:[bx+10], ah mov ah, 2 mov dl, al add dl, 30h int 21h mov ah, 2 mov dl, byte ptr ds:[bx+10] add dl, 30h int 21h mov ah, 2 mov dl, " " int 21h add bx, 1 loop s mov ah, 4ch int 21h code ends end start
使用 masm、link 對 task2.asm 進行彙編、連結,得到可執行檔案 task2.exe,執行並觀察結果:
實驗任務 3
task3.asm:
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
問題 1:程式返回前,data 段中的資料為:
23 01 56 04 89 07 bc 0a ef 0d ed 0f ba 0c 87 09
反彙編以 076A:0 開始 16 個字的內容,可以觀察到與推斷一致。
問題 2:程式返回前,cs、ss、ds 的值為
cs = 076C ss = 076B ds = 076A
由最先的反彙編可知程式在 001D 返回,使用 g 命令執行到此之前,觀察到 cs ss ds 的值與推斷一致。
問題 3:設程式載入後,code 段的段地址為 X, 則 data 段的段地址為 X - 1,stack 段的段地址為 X - 2。
實驗任務 4
task4.asm
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:程式返回前,data 段中的資料為:
23 01 56 04 00 00 00 00 00 00 00 00 00 00 00 00
問題 2:程式返回前,cs、ss、ds 的值為
cs = 076C ss = 076B ds = 076A
由圖可知與預測一致
問題 3:設程式載入後,code 段的段地址為 X, 則 data 段的段地址為 X - 1,stack 段的段地址為 X - 2。
問題 4:對如下定義的段:
name segment
···
name ends
如果段中的資料佔 N 個位元組,則程式載入後,該段實際佔用的空間為
floor((N + 15) / 16)
由觀察可知,程式以 16 個字為單位分段
實驗任務 5
task5.asm
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:程式返回前,data 段中的資料為:
23 01 56 04 00 00 00 00 00 00 00 00 00 00 00 00
問題 2:程式返回前,cs、ss、ds 的值為
cs = 076A ss = 076E ds = 076D
由圖可得與推測一致:
問題 3:設程式載入後,code 段的段地址為 X, 則 data 段的段地址為 X + 4,stack 段的段地址為 X + 5。
實驗任務 6
只有實驗任務 5 的程式能夠正常執行。若將 end start 改為 end,即不指明函式的入口,由於實驗任務 3,4 的 data 段和 stack 段都處於 code 段之前,若不指明入口,會預設從 076A:0 開始執行,即將資料段與棧段的資料當作程式執行,會出錯;實驗任務 5 的 data 段與 stack 段處於 code 之後,預設執行的起點就是 code 段的內容,所以可以正確執行。
實驗任務 7
task7.asm
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 8 dup(0)
c1 ends
code segment
start: mov ax, c1
mov ds, ax
mov cx,8
mov bx, 0
mov ax, a
mov es, ax
s: mov al, byte ptr es:[bx]
mov byte ptr ds:[bx], al
add bx, 1
loop s
mov bx, 0;
mov cx, 8
mov ax, b
mov es, ax
s1: mov al, byte ptr es:[bx]
add byte ptr ds:[bx], al
add bx, 1
loop s1
mov ax,4c00h
int 21h
code ends
end start
反彙編後得知程式在 002F 處返回,使用 g 命令:
在程式中我將 c1 段的段地址賦予 ds,使用 d 命令檢視可發現程式正確執行。
實驗任務 8
task8.asm
assume cs:code
a segment
dw 1,2,3,4,5,6,7,8,9,0ah,0bh,0ch,0dh,0eh,0fh,0ffh
a ends
b segment
dw 8 dup(0)
b ends
code segment
start: mov ax, b;
mov ss, ax
mov sp, 10h
mov ax, a
mov ds, ax
mov bx, 0
mov cx, 8
s: push ds:[bx]
add bx, 2
loop s
mov ax,4c00h
int 21h
code ends
end start
反彙編後得知程式在 001A 處返回,使用 g 命令:
d 段的段地址為 076C,由圖可得成功地使用 push 指令將 a 段中地前 8 個字型資料儲存到了 b 段。
實驗總結
在本次實驗中,以多個段地的彙編源程式編寫與調式為中心,進行了多次實驗。
在此次實驗我瞭解到:
- 使用偽指令 segment 和 ends 定義邏輯段後,究竟是用作程式碼段、資料段還是棧,由程式設計師指定。
- 段名代表的是段地址,是常數。不能使用 mov 直接送入段暫存器。
- 使用 assume 僅僅表示將某個邏輯段和某個段暫存器關聯起來;真正當作特定的段使用,需要在程式碼段中設定相應的段暫存器值,如 ds, ss。
- 各邏輯段在記憶體空間中依序排列,並以 16 個字為一個單元進行分配
- 若 code 段前有自己設定的邏輯段,需要指明程式的入口,否則會將資料段內的內容當作程式碼來執行。
- 瞭解到各暫存器都有其各自的功能,不可隨意將資料附入。