首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 更多程式語言 >> 程式設計綜合問答

汇编语言子程序調試指南:顯示字符程序錯誤分析與單步調試技巧

     編輯:程式設計綜合問答

問題代碼回顧

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

潛在問題分析

  1. 字符串結束判斷邏輯:mov cl, [si] / jcxz ok 依賴字符串以 0 結尾(代碼中定義了 `db '...', 0`),這部分邏輯正確。
  2. 屏幕坐標計算:mul dh 後結果在 AX,但隨後 push ax / mul dl / pop bx / add bx, ax 這段邏輯計算 `bx = dh*160 + dl*2` 是正確的(80列×2字節/列=160)。
  3. 寄存器保護:入口保存了所有用到的寄存器,出口恢復順序正確。
  4. 顏色屬性寫入:mov es:[bx+1], cl 將 CL (42h) 寫入屬性字節,正確。
  5. 潛在風險:若字符串過長超過行尾,會繼續寫入下一行甚至越界;未檢查邊界。

調試方法論:單步調試是核心技能

正如最佳回答所強調:**「代碼功能歸根結底不是別人幫自己看或講解出來的;而是被自己靜下心來花足夠長的時間和精力親自動手單步或設斷點分析出來的。」**

使用 Turbo Debugger (TD) / DOSBox 調試步驟

  1. 加載程序:`td yourprog.exe`
  2. 設置斷點:在 `call str_show` 處按 F2 設置斷點,運行到此處 (F9)。
  3. 單步執行 (F8):進入 `str_show` 子程序,觀察關鍵寄存器變化:
    • DH, DL:輸入坐標是否正確傳遞
    • BX:視頻內存偏移量計算是否正確 (應指向 B800:xxxx)
    • SI:字符串指針遞增情況
    • CL:字符值與屬性值
    • ES:[BX]:視頻內存實際寫入內容 (可在 Dump 窗口查看 B800:0)
  4. 設置內存斷點:監視視頻內存區域 `B800:0` 變化,定位寫入異常指令。
  5. 檢查標誌寄存器:關注 `ZF` (Zero Flag) 在 `jcxz` 後的狀態,確認循環退出條件。

常見錯誤現象與排查方向

現象可能原因調試重點
無任何輸出坐標計算錯誤、視頻模式不匹配、字符串首地址錯檢查 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:
    ; ... 恢復寄存器返回 ...

給初學者的建議

「單步調試和設斷點調試是程序員必須掌握的技能之一。再牛×的老師也無法代替學生自己領悟和上廁所!」

  • 養成「預測→執行→觀察→驗證」的單步循環習慣。
  • 學會使用調試器的寄存器窗口、內存窗口、堆棧窗口、標誌寄存器。
  • 遇到問題先縮小範圍:註釋掉一半代碼,二分法定位故障指令。
  • 閱讀《PC 汇编语言》、《橙皮書》等經典資料,理解 8086 實模式內存與視頻顯示機制。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved