.model 指令與記憶體模型
; Model 偽操作格式
.model memory_model, model_options
; memory_model 可選:
; tiny -> .COM 檔 (單段 64KB, CS=DS=ES=SS, ORG 100h)
; small -> .EXE 檔 (代碼段 64KB + 資料段 64KB, 近地址訪問) **最常用**
; medium -> 代碼 >64KB (遠呼叫), 資料 64KB
; compact-> 代碼 64KB, 資料 >64KB (遠資料指標)
; large -> 代碼/資料皆 >64KB
; huge -> 單一陣列 >64KB
; flat -> 32-bit 保護模式 (Win32), 4GB 線性位址
Small Model 完整範例:2.asm
.model small ; 生成 EXE 格式
.stack 100h ; 堆疊大小 256 bytes (預設 1024=400h)
.data ; 初始化資料段
mess db 'How, world!$' ; DOS 9h 功能需 '$' 結尾
.data? ; 未初始化資料段 (不佔檔案大小)
pp dw 200h dup(?) ; 必須用 '?' 佔位
.code ; 代碼段
.startup ; 偽指令:自動產生 DS/SS 初始化代碼
mov ah, 9
lea dx, mess
int 21h ; 顯示字串
mov pp, ax
.exit ; 偽指令:產生結束代碼 (mov ah,4Ch / int 21h)
end ; 因用 .startup,無需指定程式入口標籤
編譯連結與檔案大小
D:\Masm615>ml 2.asm
Microsoft (R) Macro Assembler Version 6.15.8803
Assembling: 2.asm
Microsoft (R) Segmented Executable Linker Version 5.60.339
Object Modules [.obj]: 2.obj
Run File [2.exe]: "2.exe"
List File [nul.map]: NUL
Libraries [.lib]:
Definitions File [nul.def]:
D:\Masm615>dir 2
2 ASM 711 02-15-03 10:48 2.asm
2 OBJ 207 02-15-03 10:50 2.obj
2 EXE 562 02-15-03 10:50 2.exe
DEBUG 實戰:剖析記憶體佈局與啟動代碼
-r
AX=0000 BX=0000 CX=0032 DX=0000 SP=0100 BP=0000 SI=0000 DI=0000
DS=128C ES=128C SS=12A0 CS=129C IP=0000
129C:0000 BA9E12 MOV DX,129E ; .startup 產生:載入資料段段位址
-u0 25
129C:0000 BA9E12 MOV DX,129E
129C:0003 8EDA MOV DS,DX ; 設定 DS = 資料段
129C:0005 8CD3 MOV BX,SS
129C:0007 2BDA SUB BX,DX
129C:0009 D1E3 SHL BX,1
129C:000B D1E3 SHL BX,1
129C:000D D1E3 SHL BX,1
129C:000F D1E3 SHL BX,1 ; 計算堆疊段相對位移 (段落單位 * 16 = 位元組)
129C:0011 FA CLI
129C:0012 8ED2 MOV SS,DX ; 重設 SS = 資料段 (Small Model DS=SS)
129C:0014 03E3 ADD SP,BX ; 調整 SP 指向堆疊頂
129C:0016 FB STI
129C:0017 B409 MOV AH,09 ; 使用者代碼開始
129C:0019 8D160600 LEA DX,[0006] ; mess 偏移 6 (WORD 對齊)
129C:001D CD21 INT 21
129C:001F A32001 MOV [0120],AX ; pp 變數位置 (程式碼+資料+堆疊後)
129C:0022 B44C MOV AH,4C
129C:0024 CD21 INT 21 ; 結束程式
資料區驗證
-d 129e:6 11
129E:0000 48 6F 77 2C 20 77 6F 72 6C 64 How, world
129E:0010 21 24 !$
記憶體佈局圖解 (Small Model EXE 載入後)
+-------------------------+ <-- CS:IP (程式碼段起始)
| PSP (Program Segment | 256 bytes (0000h-00FFh)
| Prefix) 環境參數/FCB... |
+-------------------------+
| 程式碼段 | <-- CS 基址
| (啟動代碼 + 使用者代碼) |
+-------------------------+
| 資料段 (初始化) | <-- DS/SS 基址 (Small Model DS=SS)
| mess, 其他變數 |
+-------------------------+
| 資料段 (未初始化 .data?)| 不佔 EXE 檔案空間,載入時由 OS 零初始化
| pp 陣列 |
+-------------------------+
| 堆疊區 | 向下增長,SP 初始指向此處頂端
| (100h bytes) |
+-------------------------+ <-- 記憶體結束
關鍵觀察點
- 原始堆疊 SS:SP = 12A0:0100,啟動代碼調整後 新堆疊 129E:0120,**物理位址相同** (12A00h = 129E0h + 120h)。驗證
.startup 正確重設堆疊於資料段之後。
.data? 區塊 (pp) 位於初始化資料之後,偏移 0120h (見 MOV [0120],AX),不佔 EXE 檔案大小 (562 bytes 含代碼+初始化資料+PSP 重定位資訊)。
LEA DX,[0006]:Small Model 近資料指標為 Word (16-bit),偏移量必須為偶數 (WORD 對齊),mess 因前有 PSP/對齊等因素落在 offset 6。
.startup/.exit 是 MASM 高層偽指令,簡化樣板代碼,但掩蓋了段暫存器初始化細節,學習階段建議手寫初始化代碼理解機制。
對比:.COM vs .EXE (Tiny vs Small)
| 特性 | .COM (Tiny) | .EXE (Small) |
| 最大大小 | 64KB (含 PSP) | 代碼 64KB + 資料 64KB + 堆疊 |
| 段暫存器 | CS=DS=ES=SS | CS!=DS, DS=SS (Small) |
| 載入位址 | 固定 Offset 100h | 動態段位址,需重定位 |
| 檔案結構 | 純二進位映像 | MZ Header + 重定位表 + 段資料 |
| 適用場景 | 極小工具、開機磁區 | 一般 DOS 應用程式 |