1. 編寫程序的工作過程

assume cs:codesg
codesg segment
mov ax,0123H
mov bx,0456H
add,ax,bx
add ax,ax
mov ax,4c00h
int 21h
codesg ends
end
2. 匯編程序: 包含匯編指令和偽指令的文本
-
偽指令: 沒有對應(yīng)的機(jī)器碼的指令, 最終不被cpu 所執(zhí)行, 第1, 2, 9, 10 行代碼
- 偽指令是由編譯器來執(zhí)行的指令, 編譯器根據(jù)偽指令來進(jìn)行相關(guān)的編譯工作
匯編指令, 對應(yīng)有機(jī)器碼的指令, 可以被編譯為機(jī)器指令, 最終被cpu 執(zhí)行, 3~8 行
程序返回: 程序運(yùn)行結(jié)束后, 將cpu 的控制權(quán)交還給使它得以運(yùn)行的程序, 常為dos 系統(tǒng)
3. 三種偽指令
- 段定義:
- 一個(gè)匯編程序是由多個(gè)段組成的, 這些段被用來存放代碼, 數(shù)據(jù)或當(dāng)做??臻g來使用
- 一個(gè)有意義的匯編程序中至少有一個(gè)段, 這個(gè)段用來存放代碼
- 定義程序中的段: 每個(gè)段都需要有段名,
segment段開始,end段結(jié)束
- end: 匯編程序的結(jié)束標(biāo)記, 若程序結(jié)尾處不是end, 編譯器在編譯程序時(shí), 無法知道程序在何處結(jié)束
- assume: 含義是假設(shè)某一段寄存器和程序中的某一個(gè)用segment...ends 定義的段相關(guān)聯(lián). assume cs:codesg 指cs 寄存器與codesg 關(guān)聯(lián), 將定義的codesg 當(dāng)做程序的代碼段使用
源程序經(jīng)編譯連接后變?yōu)闄C(jī)器碼
適合編寫大程序, ;注釋符號(hào) 為注釋
4. 編寫程序的步驟
- 定義一個(gè)段
- 實(shí)現(xiàn)處理任務(wù)
- 支出程序在何處結(jié)束
- 段與寄存器關(guān)聯(lián)
- 加上程序返回的代碼
assume cs:abc
abc segment
mov ax,2
add ax,ax
add ax,ax
mov ax,4c00h
int 21h
abc ends
end
程序中可能出現(xiàn)的錯(cuò)誤
-
語法錯(cuò)誤
在編譯時(shí)被編譯器發(fā)現(xiàn)的錯(cuò)誤
-
邏輯錯(cuò)誤
在編譯時(shí)不能表現(xiàn)出來, 在運(yùn)行時(shí)發(fā)生的錯(cuò)誤
5. 源程序到程序運(yùn)行

assume cs:codesg
codesg segment
mov ax,0123H
mov bx,0456H
add ax,ax
add ax,ax
mov ax,4c00h
int 21h
codesg ends
end

- 目標(biāo)文件(*.obj) 是我們對一個(gè)源程序進(jìn)行編譯得到的最終結(jié)果
- 列表文件(*.lst) 是編譯器將源程序編譯為目標(biāo)文件過程中產(chǎn)生的中間結(jié)果
- 交叉引用文件(*.crf) 同列表文件一樣, 是編譯器將源程序編譯為目標(biāo)文件過程中產(chǎn)生的中間結(jié)果
- 對源程序的編譯結(jié)束, 編譯器輸出的最后兩行告訴我們這個(gè)源程序沒有警告錯(cuò)誤和必須要改正的錯(cuò)誤
- 命令后加上
;可以簡化流程

- 可執(zhí)行文件(.exe) 是我們對一個(gè)重新進(jìn)行連接得到的最終結(jié)果
- 印象文件(.map) 是連接程序?qū)⒛繕?biāo)文件連接為可執(zhí)行文件過程中產(chǎn)生的中間結(jié)果
- 庫文件(.lib) 里包含了一些可以調(diào)用的子程序, 如果我們的程序中調(diào)用了某一個(gè)庫文件中的子程序, 就需要在連接的時(shí)候, 將這個(gè)庫文件和我們的目標(biāo)文件連接到一起, 生成可執(zhí)行的文件
- no stack segment, 一個(gè)"沒有棧段" 的警告錯(cuò)誤, 可以不用理會(huì)
執(zhí)行過程, 源文件.asm -> 目標(biāo)文件.obj -> 可執(zhí)行文件.exe
使用debug 裝載程序


- ds 中存放程序所在區(qū)的段地址, 這個(gè)內(nèi)存的偏移地址為0, 則乘車所在的內(nèi)存區(qū)的地址為
ds:0 - 這個(gè)內(nèi)存區(qū)的前256 字節(jié)存PSP, dos 用來和程序進(jìn)行通信
- 從256 字節(jié)后的空間存放的是程序, cs 的值為ds+10h
- 程序加載后, cx 中存放代碼長度
6. [...] 的規(guī)定與(...) 的約定
- [...] 匯編語法的規(guī)定, 表示一個(gè)內(nèi)存單元
| 指令 | 段地址 | 偏移地址 | 操作單位 |
|---|---|---|---|
| mov ax,[0] | DS 中 | 在[0] 中 | 字 |
| mov al,[0] | DS 中 | 在[0] 中 | 字節(jié) |
| mov ax,[bx] | DS 中 | 在[bx] 中 | 字 |
| mov al,[bx] | DS 中 | 在[bx] 中 | 字節(jié) |
- (...) 方便學(xué)習(xí)做出的約定, 表示一個(gè)內(nèi)存單元或寄存器中的內(nèi)容
| 描述對象 | 描述方法 | 描述對象 | 描述方法 |
|---|---|---|---|
| ax中的內(nèi)容為0010h | (ax)=0010h | 2000:1000處的內(nèi)容為0010h | (21000h)=0010h |
| mov ax,[2]的功能 | (ax)=((ds)*16+2) | mov [2],ax的功能 | ((ds)*16+2)=(ax) |
| add ax,2 的功能 | (ax)=(ax)+2 | add ax,bx 的功能 | (ax)=(ax)+(bx) |
| push ax 的功能 | (sp)=(sp)-2; ((ss)*16 + (sp))=(ax) | pop ax 的功能 | (ax)=((ss*16)+(sp)); (sp)=(sp)+2 |
符號(hào)idata 表示常量
mov ax,[idata] 表示, mov ax,[1]
mov bx,idata 表示, mov bx,2
7. Loop 指令
功能: 實(shí)現(xiàn)循環(huán), 計(jì)數(shù)型循環(huán)
指令格式loop 標(biāo)號(hào)
cpu 執(zhí)行l(wèi)oop 指令時(shí)要進(jìn)行的操作
- (cx)=(cx)-1
- 判斷cx 中的值, 不為0 則跳轉(zhuǎn)至標(biāo)號(hào)處執(zhí)行, 為0 則向下執(zhí)行
注意點(diǎn):
- cx 存放循環(huán)次數(shù)
- 定義一個(gè)標(biāo)號(hào), 在標(biāo)號(hào)和loop 指令中間寫循環(huán)執(zhí)行的代碼段
實(shí)現(xiàn)
; loop 指令程序
assume cs:code
code segment
mov ax,2
mov cx,3
s: add ax,ax
loop s
mov ax,4c00h
int 21h
code ends
end
8. 段前綴的使用
現(xiàn)象
assume cs:code
code segment
mov ax,2000h
mov ds,ax
mov al,[0]
mov bl,[1]
mov cl,[2]
mov dl,[3]
mov ax,4c00h
int 21h
code ends
end

對策
在[idata] 前顯示寫上段寄存器
mov al,ds:[bx]
mov al,ds:[0]
這些出現(xiàn)在訪問內(nèi)存單元的指令中, 用于顯示的指明內(nèi)存單元段地址的"ds:", "cs:", "ss:", "es", 在匯編語言中稱為段前綴
; 使用附加段寄存器
assume cs:code
code segment
mov ax,0ffffh
mov ds,ax
mov ax,0020h
mov es,ax
mov bx,0
mov cx,12
s: mov dl,[bx]
mov es:[bx],dl
inc bx
loop s
mov ax,4c00h
int 21h
code ends
end
但是以上代碼有問題, 是危險(xiǎn)的
不可以直接寫地址, 這段地址中可能存放其他代碼或者數(shù)據(jù)
應(yīng)該為:
- 在程序的段中存放數(shù)據(jù), 運(yùn)行時(shí)由操作系統(tǒng)分配空間
- 段的類別, 數(shù)據(jù)段, 代碼段, 棧段
- 各種段中均可以有數(shù)據(jù)
- 可以在單個(gè)段中安置, 也可以將數(shù)據(jù), 代碼, 棧放入不同的段中
assume cs:code
code segment
dw 0123H,0456h,0789h,0abch
mov bx,0
mov ax,0
mov cx,4
s: add ax,cs:[bx]
add bx,2
loop s
mov ax,4c00h
int 21h
code ends
end
執(zhí)行debug 查看

代碼混亂, ip 是從0000 開始執(zhí)行, 但是, 段中開始存放的為數(shù)據(jù), 因此需要從0008 開始
改進(jìn)代碼
assume cs:code
code segment
dw 0123H,0456h,0789h,0abch
start: mov bx,0
mov ax,0
mov cx,4
s: add ax,cs:[bx]
add bx,2
loop s
mov ax,4c00h
int 21h
code ends
end start

9. 代碼中使用棧
方案一
問題, 將定義的數(shù)據(jù)逆序存放
思路:
- 定義的數(shù)據(jù)存在cs:0~cs:f 單元總, 共8 個(gè)字單元
- 一次將這8 個(gè)字單元中的數(shù)據(jù)入棧, 然后再一次出棧到8 個(gè)字單元中, 從而實(shí)現(xiàn)數(shù)據(jù)的逆序存放
- 棧需要的內(nèi)存空間, 在程序中通過定義空數(shù)據(jù)來取得
assume cs:code
code segment
dw 0123h,0456h,0789h,0abch,0defh,0fedh,0cbah,0987h
dw 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
start: mov ax,cs
mov ss,ax
mov sp,30h
mov bx,0 ; 入棧
mov cx,8
s: push cs:[bx]
add bx,2
loop s
mov bx,0 ; 出棧
mov cx,8
s0: pop cs:[bx]
add bx,2
loop s0
mov ax,4c00h
int 21h
code ends
end start


這種方案數(shù)據(jù)段, 棧, 代碼都在同一個(gè)段中
- 程序顯得混亂, 編程和閱讀時(shí)都要注意何處是數(shù)據(jù), 何處是棧, 何處是代碼
- 只應(yīng)用于處理數(shù)據(jù)很少, 用到的??臻g小, 沒多少代碼的情況
我們應(yīng)該將數(shù)據(jù), 棧, 代碼放在不同段中
方案二
修改為:
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,0,0,0,0,0,0,0,0
stack ends
code segment
start: mov ax,stack
mov ss,ax
mov sp,20h
mov ax,data
mov ds,ax
mov bx,0
mov cx,8
s: push [bx]
add bx,2
loop s
mov bx,0
mov cx,8
s0: pop [bx]
add bx,2
loop s0
mov ax,4c00h
int 21h
code ends
end start

