echarts玩轉圖表之矩形樹圖
一、實驗目的
1.理解和掌握將資料、程式碼、棧放入不同邏輯段的程式的編寫和除錯2.理解具有多個段的彙編源程式對應的目標程式執行時,記憶體分配方式3.掌握大小寫字元的轉換方法、數字字元和數值之間的轉換方法
4.理解並掌握各種定址方式的靈活應用
5.掌握彙編指令loop, and, or,div, mul的用法
二、實驗準備
複習教材chapter 6-8章。
chapter 6包含多個段的程式
chapter 7更靈活的定位記憶體地址的方法
chapter 8資料處理的兩個基本問題
三、實驗內容與結論
1.實驗任務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], alinc si add di, 2 loop s mov ah, 4ch int 21h code ends end start
使用masm、link對task1.asm進行彙編、連結,得到可執行檔案task1.exe,執行並觀察結果。
使用debug工具對程式進行除錯,執行到程式返回前,即line27之前,觀察結果。 修改line4裡5個位元組單元的值,重新彙編、連結、執行,觀察結果。
輸出結果:
通過閱讀程式原始碼以及逐步除錯可以看出,15-25行的loop從資料段中讀出字資料(字元的ascii碼值),向視訊記憶體指定位置輸出。
資料段中db 5 dup(2)表示定義5個重複位元組,資料值都為十進位制2,在loop中使用mov al, [5+si]讀出並且輸出,用於設定顯示顏色。
2.實驗任務2
已知資料段data中定義位元組資料如下:
data segments db 23, 50, 66, 71, 35 data ends
注意這裡位元組資料為十進位制,在d命令檢視記憶體時顯示十六進位制的資料
task2程式碼
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 ax, 0b800H mov es, ax mov cx, 5 mov si, 0 mov di, 0f00h s: mov al, [si] mov dx,0 mov ah,0 mov bx,10 div bx add al,48 add dl,48 mov es:[di], al mov al,dl mov es:[di+2], al inc si add di, 6 loop s mov ah, 4ch int 21h code ends end start
task2程式碼基於task1程式碼進行理解修改得出
思路:
迴圈之前先把資料段地址存放到ds,輸出的視訊記憶體地址存放到
迴圈時先讀出資料,資料在資料段中db存放,是單位元組資料,所以將存放資料的暫存器高位設定為0。
被除數存放在ax,除數存放在bx,利用除法指令div,商存放在ax中,餘數存放在dx中,計算出十位和個位上的數值。
利用數值和數字字元之間ascII碼的關係,把各位上的數值加上48,十六進位制0030h,得出相應字元
利用系統功能呼叫int 21h中的2號子功能,輸出單個字元,視訊記憶體位置自增6位元組(兩個資料,一個空格),資料段迴圈偏移量自增1個位元組。
輸出效果:
需要注意的是,dx初始為0,第一次運算後有垃圾資料殘餘,為了防止程式出錯每次迴圈後dx需要賦值為0。
參考:https://stackoverflow.com/questions/13028561/assembly-division
3.實驗任務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
課本填空:
程式返回前,data段中的資料:
程式返回前,cs、ss和ds的值:
程式載入後,code段地址為X,data段地址為X-32,stack段地址為X-16。
4.實驗任務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
程式返回前,data段中資料:
程式返回前,cs、ss和ds的值:
程式載入後,code段地址為X,data段地址為X-32,stack段地址為X-16。
對於如下定義的段
name segment
...
name ends
如果段中資料佔N個位元組,程式載入後,該段實際佔有的空間為N/16+16位元組,即能容納資料的最小16位元組的整數倍。
5.實驗任務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
程式返回前,data段中資料:
程式返回前,cs、ss和ds的值:
程式載入後,code段地址為X,data段地址為X+48,stack段地址為X+64。
6.實驗任務6
(1)(2)均無法正常執行
(3)不受影響
說明原因:
如果程式末尾為end start,CPU知道程式從start:處開始執行;如果程式末尾end,將從頭執行。
參考:王爽教材P126
由於實驗(1)task3和實驗(2)task4的資料段在code segment之前,將資料段中的資料作為指令讀出執行肯定是不正確的。實驗(3)task5中從code segment正確執行退出,從而不會進入到code segment一下的資料段中。
7.實驗任務7
教材「實驗5編寫、除錯具有多個段的程式」(5)程式原始碼見task7.asm。
注*:如果在整合軟體環境下編寫、彙編這個實驗任務,請將段名為c的邏輯段,名稱改為c1或別的標識 符。由於早期一些指令集中使用c指代暫存器,如不更正,有些彙編器在彙編時會報錯。
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 c segment db 8 dup(0) c ends code segment start: mov si,0 mov cx,8 s: mov ax,a mov ds,ax mov dl,[si] mov ax,b mov ds,ax add dl,[si] mov ax,c mov ds,ax mov [si],dl mov dx,0 add si,1 loop s mov ah, 4ch int 21h code ends end start
由於知道的暫存器太少,這裡實現使用了笨辦法,每次從一個數據段中讀出資料後,將ds賦值為另一個數據段的其實地址。
這裡使用了dl儲存資料進行計算,是因為資料段中定義的資料是db單位元組資料。然而這裡使用dx作為儲存資料,一次寫入兩個byte資料,由於這裡資料不存在加法溢位的顧慮,也能達到同樣的效果。
執行task7後資料段c中的資料:
8.實驗任務8教材
「實驗5編寫、除錯具有多個段的程式」(6)
程式原始碼: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,a mov ds,ax mov ax,b mov ss,ax mov sp,16 mov cx,8 mov si,0 s: push ds:[si] add si,2 loop s mov ah, 4ch int 21h code ends end start
資料段a有16個雙位元組字資料,佔了32byte,該程式題沒有設定棧段,所以顯然不是用棧段作為中間容器實現逆序。經過思考,棧低為高址,每次push棧頂向低址移動,也可以實現逆序存放,所以將資料段b的末尾設定為棧低ss:sp。用loop重複讀取資料壓棧操作。
執行結果:
資料段a:076A:0000 ~ 076A:001f
資料段b:076A:0020 ~ 076A:002f
可以看出實現了逆序儲存
四、實驗總結
1、看清資料段是dw資料還是db資料,以及題目要求是什麼大小的資料。
2、實驗2困惑了很久,起初頭腦不清醒,找不到資料段中的資料。後來發現.asm原始碼中資料段是十進位制資料,在debug中-d命令時顯示十六進位制。
3、dx初始為0,第一次運算後有垃圾資料殘餘。除法運算為了防止程式出錯,每次迴圈後dx需要重新賦值為0。
4、關於彩色文字模式一般在B800h段,單色文字在B000h段;圖形模式在A000h段。task1設定es為0b800h。在文字16色模式下,字元的屬性儲存在bl中,bl為一個位元組大小,共八位。b7控制字元是否閃爍,b6-b4為背景色,b3-b0為前景色。