assume cs:code, ds:data
data segment
db 'welcome to asm', 0
data ends
code segment
start:
mov ax, data
mov ds, ax
mov si, 0
mov dh, 10 ; 行號
mov dl, 3 ; 列號
mov cl, 42h ; 顏色屬性
call str_show
mov ax, 4c00h
int 21h
; 入口參數:dh=行, dl=列, cl=顏色, ds:si=字符串首址
str_show:
push ax, bx, cx, dx, si, es
mov ax, 0B800h
mov es, ax
sub dh, 1
sub dl, 1
mov al, 160
mul dh
push ax
mov al, 2
mul dl
pop bx
add bx, ax
s:
push cx
mov ch, 0
mov cl, [si]
jcxz ok
mov es:[bx], cl
pop cx
mov es:[bx+1], cl
add bx, 2
inc si
jmp short s
ok:
pop es, si, dx, cx, bx, ax
ret
code ends
end start
mov cl, [si] / jcxz ok 依賴字符串以 0 結尾(代碼中定義了 `db '...', 0`),這部分邏輯正確。mul dh 後結果在 AX,但隨後 push ax / mul dl / pop bx / add bx, ax 這段邏輯計算 `bx = dh*160 + dl*2` 是正確的(80列×2字節/列=160)。mov es:[bx+1], cl 將 CL (42h) 寫入屬性字節,正確。正如最佳回答所強調:**「代碼功能歸根結底不是別人幫自己看或講解出來的;而是被自己靜下心來花足夠長的時間和精力親自動手單步或設斷點分析出來的。」**
DH, DL:輸入坐標是否正確傳遞BX:視頻內存偏移量計算是否正確 (應指向 B800:xxxx)SI:字符串指針遞增情況CL:字符值與屬性值ES:[BX]:視頻內存實際寫入內容 (可在 Dump 窗口查看 B800:0)| 現象 | 可能原因 | 調試重點 |
|---|---|---|
| 無任何輸出 | 坐標計算錯誤、視頻模式不匹配、字符串首地址錯 | 檢查 BX 計算結果、DS:SI 指向、當前視頻模式 (int 10h, ah=0fh) |
| 顯示亂碼 | 字符屬性錯誤、字符串未以 0 結尾、SI 未正確遞增 | 查看 ES:[BX] 寫入的字符碼與屬性碼、CL 值變化 |
| 程序崩潰/重啟 | 棧不平衡、段寄存器錯誤、越界寫入關鍵內存區 | 檢查 push/pop 配對、ES 段值、BX 是否超出 B800:FFFF |
| 只顯示第一個字符 | 循環條件判斷錯誤 (jcxz 邏輯) | 單步跟蹤循環體,觀察 SI, CL, ZF |
; 增加邊界檢查:防止超出屏幕範圍
str_show:
; ... 保存寄存器 ...
; 計算起始偏移 ...
s:
push cx
mov ch, 0
mov cl, [si]
jcxz ok
; 新增:檢查 BX 是否超出 1999 (25行*80列*2 - 2)
cmp bx, 1999
ja ok ; 超出則退出
mov es:[bx], cl
pop cx
mov es:[bx+1], cl
add bx, 2
inc si
jmp short s
ok:
; ... 恢復寄存器返回 ...
「單步調試和設斷點調試是程序員必須掌握的技能之一。再牛×的老師也無法代替學生自己領悟和上廁所!」