一、8086匯編定義數據
要處理結構化數據,必須先定義數據。8086匯編作為一門編程語言,定義數據的方式比起復雜的高級語言要簡單不少。
匯編語言貼近機器底層,所處理的數據邏輯上都可以視為二進制數據,按照對不同大小內存單元的處理,分為三種:db、dw、dd。
1.db
db 即define byte,定義一個字節變量。例如 db 1h,代表着db指令后的值占用一個字節的內存空間 1h=>01h。
特別的,使用db可以比較簡單的定義字符串數據,例如db "ABC",代表着定義A、B、C三個連續的字符。
2.dw
db 即define word,定義一個字變量。例如 dw 1h,代表着dw指令后的值占用一個字/兩個字節的內存空間 1h=>0001h。
3.dd
dd 即define doubleword,定義一個雙字變量。例如 dd 1h,代表着dw指令后的值占用兩個字/四個字節的內存空間 1h=>0000 0001h。
在連續定義數據時,可以通過逗號進行縮寫。例如 db 1h,2h,3h等價與db 1h;db 2h;db 3h。
同時上述三種方式都可以與dup關鍵字(duplicate)使用。例如,定義3個值為1h的字形數據,可以寫為dw 3 dup(1h),其等價於dw 1h,1h,1h。在定義復數個相同的數據時,可以簡化程序,增強可讀性。
db、dw、dd、dup都屬於8086匯編的偽指令,由匯編器在編譯時進行處理,並沒有對應的機器指令。
二、8086匯編處理結構化數據
之前介紹了8086各種不同方式的內存尋址方式,下面介紹8086如何利用這些多樣的尋址方式來處理結構化的數據。
舉一個簡單的例子,假設存在一個結構化的數據(公司),擁有五個屬性。
公司屬性:
公司名稱: BLZ
總裁名稱: Deckard Cain
公司排名: 15
年收入(億元): 50
產品: WOW
需求是,在內存中定義該數據並且對其中的部分屬性進行修改,將公司排名修改為10,年收入修改為80,產品名稱修改為OWO。
整理思路后的偽代碼:
1. 先按照順序在內存中存放對應的數據結構
2. 找到公司排名所在的內存地址,將其修改(偏移地址 0Fh)
3. 找到年收入所在的內存地址,將其修改(偏移地址 11h)
4. 找到產品所在的內存地址(14h),並將產品名稱字符串中的字符逐一修改
令P=0h
修改13h+P處的字符
P=P+1h
修改13h+P處的字符
P=P+1h
修改13h+P處的字符
根據上述偽代碼,寫出對應匯編程序:
assume cs:codesg,ds:data data segment db "BLZ","Deckard Cain"; 定義公司名稱、總裁名稱 dw 15h,50h; 定義排名、年收入 db "WOW"; 定義產品名稱 data ends codesg segment start: mov ax,data; mov ds,ax; 設置段基址為data mov bx,0h; 設置數據在段中的起始位置為0h mov word ptr [bx+0Fh],10h; 修改排名所在的字數據為10 mov word ptr [bx+11h],80h; 修改收入所在的子數據為80 mov si,0; 引入si變量,遍歷產品名稱 mov byte ptr [bx+13h+si],'O'; 第一個字符設置為0 inc si; si自增1,bx+idata+si 指向下一個字符 mov byte ptr [bx+13h+si],'M'; 第二個字符設置為M inc si; si自增1,bx+idata+si 指向下一個字符 mov byte ptr [bx+13h+si],'O'; 第三個字符設置為0 mov ax,4c00H; int 21H; codesg ends end start
如果用C這種較高級的語言來實現,則簡單很多。
用C語言的結構體表示為:
struct company{ char cname[3]; char hname[12]; int rank; int income; char product[3]; }
用C語言實現需求:
{ struct company blz={"BLZ","Deckard Cain",15,50,"WOW"} // 定義數據 int i; blz.rank=10; // 修改排名 blz.income=80; // 修改收入 i=0; blz.product[i] = 'O'; // 修改產品名稱 i++; blz.product[i] = 'M'; i++; blz.product[i] = 'O'; }
通過對比,可以清楚看到,C語言的實現比起匯編要來的輕松和簡潔許多。8086匯編提供了指定偏移地址的語法糖,使得尋址時的程序更像高級語言,可讀性更高。
將上述的匯編程序以類似C語言的風格進行部分重構:
assume cs:codesg,ds:data data segment db "BLZ","Deckard Cain"; dw 15h,50h; db "WOW"; data ends codesg segment start: mov ax,data; mov ds,ax; 設置段基址為data mov bx,0h; 設置數據在段中的起始位置為0h mov word ptr [bx].0fh,10h; 修改排名所在的字數據為10 mov word ptr [bx].11h,80h; 修改收入所在的子數據為80 mov si,0; 引入si變量,遍歷產品字段 mov byte ptr [bx].13h[si],'O'; 第一個字符設置為0 inc si; si自增1,bx+idata+si 指向下一個字符 mov byte ptr [bx].13h[si],'M'; 第二個字符設置為M inc si; si自增1,bx+idata+si 指向下一個字符 mov byte ptr [bx].13h[si],'O'; 第三個字符設置為0 mov ax,4c00H; int 21H; codesg ends end start
主要是對數據內存尋址的方式進行了重構。這里的ds:[bx]相當於C程序中的變量blz,[bx].0fh相當於blz的屬性rank,而[bx].11h則相當於blz的屬性income。
[bx].14h相當於blz的屬性product,[bx].14h[si]相當於product字符數組中的某一字符項。
使用類似高級語言語法的尋址方式優化過后的匯編程序,比標准化的尋址方式更易理解,減少了程序出錯的可能性。