1. 程式人生 > 實用技巧 >SpringCloud高階篇01

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 段前有自己設定的邏輯段,需要指明程式的入口,否則會將資料段內的內容當作程式碼來執行。
  • 瞭解到各暫存器都有其各自的功能,不可隨意將資料附入。