今天把彙編16位部分學完了,隨着學習的深入,似乎找到了我學習彙編想知道的答案,但還並不完整.
基礎的指令,DOS調用,BIOS中斷就不多說了,我的BLOG中有一篇響應的中斷一覽表,大家有需要可以去參考.
PSP 駐留程序也不多說了,高級彙編語言技術也並不難接受,只要大家有一點高級語言的基礎,看明白還是不難的,我想說說模塊化程序設計部分的段的定義,簡單的說一下供C調用的過程(彙編編寫)!
段的定義分爲完整定義和簡化定義,完整定義通過你定義段時指定的參數來實現
段名 | SEGMENT [對齊類型] [組合類型] [類別] |
… | |
段名 | ENDS |
程序中的段名可以是唯一的,也可以與其它段同名。在同一模塊中,如果有二個段同名,則後者被認爲是前段的後續,這樣,它們就屬同一段。
段對齊類型PARA是一個適用於所有段類型的對齊類型,它也是缺省的對齊類型。對齊類型BYTE和WORD通常用於數據段的定位,對齊類型DWORD通常用於80386及其以後CPU代碼段的定位。
表6.1 段對齊類型與段起始地址之間的對應關係
對齊類型 | 起始地址(二進制) | 功能說明 | 最多的空閒字節數 |
BYTE | xxxx xxxx xxxx xxxx xxxx |
下一個字節地址 |
0 |
WORD | xxxx xxxx xxxx xxxx xxx0 |
下一個字地址 |
1 |
DWORD | xxxx xxxx xxxx xxxx xx00 |
下一個雙字地址 |
3 |
PARA | xxxx xxxx xxxx xxxx 0000 |
下一個節地址 |
15 |
PAGE | xxxx xxxx xxxx 0000 0000 |
下一個頁地址 |
127 |
組合類型(COMBINE)
組合類型是告訴連接程序如何把不同模塊中段名相同的段合併在一起。具體的組合類型如下:
NONE |
表示當前段在邏輯上獨立於其它模塊,並有其自己的基地址。NONE是缺省的組合類型。 |
|
PUBLIC | 表示當前段與其它模塊中同段名的PUBLIC類型段組合成一個段。組合的先後次序取決於LINK程序中目標模塊排列的次序。在組合時,後續段的起始地址要按其對齊類型進行定位,所以,同名段之間可能有間隔。 | |
COMMON | 表示當前段與其它模塊中同名段重疊,也就是說,它們的起始地址相同。最終段的長度是同名段的最大長度。由於段覆蓋,所以,前一同名段中的初始化數據被後續段的初始數據覆蓋掉。 | |
STACK | 組合類型STACK表示當前段是堆棧棧,其組合情況與PUBLIC相同。 | |
AT 數值表達式 | 該數值表達式是當前段所指定的絕對起始地址的段地址。 |
類別(CLASS)
類別是一個由程序員指定的用單引號括起來的字符串。如果一個段沒有給出類別,那麼,這個段的類別就爲空。類別是用於段的分類,連接程序利用該類別來調整同名、同類別的段,並使它們相鄰。典型的類別是"Data"和"Code"。如果指定某段的類別是"Code",那麼,該段最好是代碼段,這樣,有的調試程序(如:CodeView)就可以順序工作。
例如: |
||
DATA1 | SEGMENT WORD PUBLIC "Data" | |
… | ||
DATA1 | ENDS |
上述段定義說明了該段的起始地址是下一個字地址、組合類型爲PUBLIC、段類別是"Data"。
段組(GROUP)
段組僞指令GROUP是用於把源程序模塊中若干個段結合成一個組,並對該段組定義一個段組名。段組僞指令的格式如下:
段組名 GROUP 段名[, 段名, ……]
其中:段名之間要用逗號間隔,段名也可以用表達式“SEG 變量”或“SEG 標號”。
下面舉例說明段組僞指令的使用方法和作用。
例6.12 段組的作用 | ||||
方法1:用一個段寄存器對應二個數據段 |
||||
DATA1 | SEGMENT | ;第一個數據段 | ||
b1 | DB 10h | |||
DATA1 | ENDS | |||
DATA2 | SEGMENT | ;第二個數據段 | ||
b2 | DB 23h | |||
DATA2 | ENDS | |||
CODE1 | SEGMENT | |||
ASSUME CS:CODE1, DS:DATA1 | ;(1) | |||
START: | MOV | AX, DATA1 | ||
MOV | DS, AX | ;(2)把數據段DATA1的段值賦給段寄存器DS | ||
… | ||||
MOV | BL, b1 | ;(3)引用DS來訪問DATA1中的變量b1 | ||
… | ||||
ASSUME DS:DATA2 | ;(4) | |||
MOV | AX, DATA2 | |||
MOV | DS, AX | ;(5)把數據段DATA2的段值賦給段寄存器DS | ||
… | ||||
MOV | AL, b2 | ;(6)引用DS來訪問DATA2中的變量b2 | ||
… | ||||
CODE1 | ENDS | |||
END | START |
在上例中,語句(1)說明DS與DATA1建立聯繫,語句(2)對DS賦值,語句(3)用DS來訪問DATA1段的變量名。語句(4)說明DS與DATA2建立聯繫,語句(5)對DS賦值,語句(6)用DS來訪問DATA2段的變量名。
在該例子中,因爲只使用一個段寄存器DS來對應二個數據段,所以,需要切換DS的對應關係(如:語句(4))。但我們也可以用段寄存器DS和ES來分別對應段DATA1和DATA2,這樣,方法1就可變成方法2。
方法2:用二個段寄存器對應二個數據段 |
||||
DATA1 | SEGMENT | |||
b1 | DB 10h | |||
DATA1 | ENDS | |||
DATA2 | SEGMENT | |||
b2 | DB 23h | |||
DATA2 | ENDS | |||
CODE1 | SEGMENT | |||
ASSUME CS:CODE1, DS:DATA1, ES:DATA2 | ||||
START: | MOV | AX, DATA1 | ||
MOV | DS, AX | ;把數據段DATA1的段值賦給段寄存器DS | ||
MOV | AX, DATA2 | |||
MOV | ES, AX | ;把數據段DATA2的段值賦給段寄存器ES | ||
… | ||||
MOV | BL, b1 | ;引用DS來訪問DATA1中的變量b1 | ||
… | ||||
MOV | AL, b2 | ;引用ES來訪問DATA2中的變量b2 | ||
… | ||||
CODE1 | ENDS | |||
END | START |
我們還可以用段組來簡化段寄存器的使用,把段DATA1和DATA2組成一個數據段。所以,把方法2再改寫成方法3的形式。
方法3:用一個段組組成二個數據段 |
||||
GSEG | GROUP | DATA1, DATA2 | ;把段DATA1和DATA2定義成一個段組 | |
DATA1 | SEGMENT | |||
b1 | DB 10h | |||
DATA1 | ENDS | |||
DATA2 | SEGMENT | |||
b2 | DB 23h | |||
DATA2 | ENDS | |||
CODE1 | SEGMENT | |||
ASSUME CS:CODE1, DS:GSEG | ||||
START: | MOV | AX, GSEG | ||
MOV | DS, AX | ;把段組GSEG的段值賦給段寄存器DS | ||
… | ||||
MOV | BL, b1 | ;引用DS來訪問DATA1中的變量b1 | ||
… | ||||
MOV | AL, b2 | ;引用DS來訪問DATA2中的變量b2 | ||
… | ||||
CODE1 | ENDS | |||
END | START |
定義段組後,段組內各段所定義的標號和變量,除了與定義它們的段起始點相關外,還與段組的起始點相關。規定如下:
如果在ASSUME僞指令中說明段組與段寄存器相對應,那麼,有關標號或變量的偏移量就相對於段組起點計算;
如果在ASSUME僞指令中說明段組內的某各段與段寄存器相對應,那麼,有關標號或變量的偏移量就相對於該段的起點。
簡化的段定義
在使用簡化的段定義方式之前,必須使用存儲模式說明僞指令來描述源程序所採用的存儲模式。該僞指令說程序所使用的存儲模式,彙編程序將用該存儲模式生成相應的ASSUME和GROUP語句,同時也爲其它的簡化段創建等價的預定義。
程序存儲模式說明僞指令的格式如下:
.MODEL 存儲模式[,語言類型] [,操作系統類型] [,堆棧類型]
隱含的動作還有
DEGROUP GROUP DATA,CONST,BSS,STACK
ASSUME CS:_TEXT,DS:DGROUP,SS:DGROUP
這樣所有除代碼的段都在DEGROUP段組裏,同過同一寄存器來實現存取
、SMALL
所有的數據變量必須在一個數據段之內,所有的代碼也必須在一個代碼段之內。在這種模型下,數據段寄存器的內容保持不變,所有轉移也都是段內轉移。
該存儲類型是獨立彙編語言源程序常用的存儲模型。
、MEDIUM
所有的數據變量必須在一個數據段之內,但代碼段可以有多個。在這種模型下,數據段寄存器的內容保持不變,轉移可以是段間轉移。
、COMPACT
數據段可以有多個,但代碼段只能有一。
、LARGE
數據段和代碼段都可以有多個,但一個數組的字節數不能超過64KB。
、HUGE
數據段和代碼段都可以有多個,一個數組的字節數也可以超過64KB。
簡化段定義僞指令
簡化段定義僞指令在說明一個新段即將開始的同時,也說明了上一個段的結束。在本段定義結束時,也不必用僞指令“ENDS”來標識。
具體的僞指令說明形式及其功能描述如下:
1、代碼段定義
.CODE
作用:說明其下面的內容是代碼段中內容。
2、堆棧段定義
.STACK [堆棧字節數]
其中,“堆棧字節數”可以不寫,其缺省值爲1024B。
3、數據段定義
.DATA / .DATA? / .CONST
作用:說明其下面的內容是數據段中的變量定義。
在一個源程序中,可以有多個僞指令.DATA定義的數據段,這就好象在源程序中定義多個同段名的數據段一樣。
僞指令.DATA?說明下面是一個未初始化數據段的開始,僞指令.CONST說明下面是一個常數數據段的開始。這二條僞指令很少使用,除非在與高級語言編寫的程序相結合時,爲了遵守高級語言的某些約定,而需要特殊說明時才使用。
彙編程序在處理簡化的堆棧段和數據段定義時,它會自動地把僞指令.STACK、.DATA、.DATA?和.CONST所定義的段組合成一個段組。如果想定義一個獨立的、不與其它段組合在一起的數據段的話,那麼,就可選用下面的數據段定義方式。
4、遠程數據段定義
.FARDATA [段名] / .FARDATA? [段名]
其中:“段名”是可選項,如果不指定的話,則該段名就取其缺省段名。
作用:說明一個獨立的數據段。
僞指令.FARDATA?說明下面是一個未初始化的、獨立數據段的開始。通常情況下,很少使用該僞指令。
簡化段段名的引用
當使用簡化的段定義時,一般情況下,程序員可以不知道這些段的段名、段地址堆齊類型和組合類型等。但當把簡化定義的段和標準定義的段混合使用時,就需要知道簡化定義段的基本屬性。表6.3是在小模式下段的基本屬性對應表。
表6.3 小模式下簡化段定義的缺省屬性表
僞指令 |
缺省段名 |
對齊類型 |
組合類型 |
類別 |
段組名 |
.CODE |
_TEXT |
WORD |
PUBLIC |
'CODE' |
|
.FARDATA |
FAR_DATA |
PARA |
NONE |
'FAR_DATA' |
|
.FARDATA? |
FAR_BSS |
PARA |
NONE |
'FAR_BSS' |
|
.STACK |
STACK |
PARA |
STACK |
'STACK' |
DGROUP |
.DATA |
DATA |
WORD |
PUBLIC |
'DATA' |
DGROUP |
.DATA? |
BSS |
WORD |
PUBLIC |
'BSS' |
DGROUP |
.CONST |
CONST |
WORD |
PUBLIC |
'CONST' |
DGROUP |
在其它存儲模型下,由僞指令".CODE"說明的代碼段段名在"_TEXT"之前還要加上其模塊名(源程序名)。假設,某模塊名爲ABC,則其缺省的代碼段段名就爲ABC_TEXT。因此,在這種情況下,程序的模塊名或源程序名不要以數字開頭。
供C調用的過程:主要大家記住幾個要點,C語言把函數和外部變量和靜態變量在生成的彙編代碼中以_開頭,內存模式要匹配,通過堆棧,BP壓棧,BP=SP,返回要看C的彙編,一般爲累加AX,記得保護積存器