x86汇编单步中断处理器问题:无法识别打印mov byte ptr [bx]及BX寄存器
x86汇编单步中断处理器修复方案
问题描述
基于x86架构编写单步中断处理器时,无法识别并打印mov byte ptr [bx]指令及BX寄存器的值,期望输出格式为:
0000:0128 C60723 mov byte ptr [bx], 23h ; bx= 0001, [bx]=12
原代码如下:
.model small .stack 100h .data senasIP dw ? senasCS dw ? regAX dw ? regBX dw ? regCX dw ? regDX dw ? regSP dw ? regBP dw ? regSI dw ? regDI dw ? baitas1 db ? baitas2 db ? baitas3 db ? baitas4 db ? baitas5 db ? baitas6 db ? zingsn_pranesimas db "Zingsninis pertraukimas: $" mov_bx_kabl db "MOV bx, $" bx_lygu db "bx=$" enteris db 13,10,"$" .code mov ax, @data mov ds, ax mov ax, 0 mov es, ax ;Extra segmentas prasides ten pat kur vektoriu lentele ;To reikia, kad galetume prieiti prie vektoriu lenteles baitu reiksmiu mov ax, es:[4] mov bx, es:[6] mov senasCS, bx mov senasIP, ax ;neisikeliam tiesiai, nes nera perdavimo is atminties i atminti (butina panaudoti registrus, isimtis eilutines komandos, bet jas panaudoti butu sudetingiau) ;===================PERIMAME PERTRAUKIMA========================== mov ax, cs mov bx, offset pertraukimas mov es:[4], bx mov es:[6], ax ;=================AKTYVUOJAME ZINGSNINI REZIMA=================== pushf ;PUSH SF pop ax or ax, 100h ;0000 0001 0000 0000 (TF=1, kiti lieka kokie buvo) push ax popf ;POP SF ;>Zingsninis rezimas ijungiamas po sios komandos ivykdymo - ivykdzius kiekviena sekancia komanda ivyks zingsninis pertraukimas ;==================BELEKOKIOS KOMANDOS==================== mov byte ptr [bx],23h mov bx,001h ;==================ISJUNGIAME ZINGSNINI REZIMA====================== pushf pop ax and ax, 0FEFFh ;1111 1110 1111 1111 (nuliukas priekyj F, nes skaiciai privalo prasideti skaitmeniu, ne raide) - TF=0, visi kiti liks nepakeisti push ax popf ; mov ax, senasIP mov bx, senasCS mov es:[4], ax mov es:[6], bx uzdaryti_programa: mov ah, 4Ch int 21h ;================================================================== ;Pertraukimo apdorojimo procedura ;================================================================== pertraukimas: ; Save register values mov regAX, ax mov regBX, bx mov regCX, cx mov regDX, dx mov regSP, sp mov regBP, bp mov regSI, si mov regDI, di ; Retrieve instruction bytes at CS:IP pop si ; Get IP value pop di ; Get CS value push di ; Restore CS push si ; Restore IP ; Copy bytes into local storage mov al, cs:[si] ; First byte of instruction mov ah, cs:[si+1] ; Second byte of instruction mov baitas1, al mov baitas2, ah cmp al, 0C6h ; Check for opcode `C6` jne grizti_is_pertraukimo cmp ah, 07h ; Check for ModRM byte `07` (BX addressing mode) jne grizti_is_pertraukimo ; Print the recognized instruction mov ah, 9 mov dx, offset zingsn_pranesimas int 21h ; Print CS:IP mov ax, di call printAX mov ah, 2 mov dl, ":" int 21h mov ax, si call printAX call printSpace ; Print machine code bytes mov ah, baitas1 call printAL mov al, baitas2 call printAL mov al, cs:[si+2] ; Immediate byte call printAL call printSpace call printSpace ; Print assembly mnemonic mov ah, 9 mov dx, offset mov_bx_kabl ; Text: `MOV bx,` int 21h mov al, cs:[si+2] ; Immediate value call printAL mov ah, 2 mov dl, "h" ; Append `h` for hexadecimal notation int 21h call printSpace call printSpace ; Print the value of BX register before execution mov ah, 9 mov dx, offset bx_lygu ; Text: `bx=` int 21h mov ax, regBX call printAX ; Print newline mov ah, 9 mov dx, offset enteris int 21h grizti_is_pertraukimo: mov ax, regAX mov bx, regBX mov cx, regCX mov dx, regDX mov sp, regSP mov bp, regBP mov si, regSI mov di, regDI IRET ; Return from interrupt handler ;===================PAGALBINES pertraukime naudojamos proceduros================ ;>>>Spausdinti AX reiksme printAX: push ax mov al, ah call printAL pop ax call printAL RET ;>>>>Spausdink tarpa printSpace: push ax push dx mov ah, 2 mov dl, " " int 21h pop dx pop ax RET ;>>>Spausdinti AL reiksme printAL: push ax push cx push ax mov cl, 4 shr al, cl call printHexSkaitmuo pop ax call printHexSkaitmuo pop cx pop ax RET ;>>>Spausdina hex skaitmeni pagal AL jaunesniji pusbaiti (4 jaunesnieji bitai - > AL=72, tai 0010) printHexSkaitmuo: push ax push dx and al, 0Fh ;nunulinam vyresniji pusbaiti AND al, 00001111b cmp al, 9 jbe PrintHexSkaitmuo_0_9 jmp PrintHexSkaitmuo_A_F PrintHexSkaitmuo_A_F: sub al, 10 ;10-15 ===> 0-5 add al, 41h mov dl, al mov ah, 2; spausdiname simboli (A-F) is DL'o int 21h jmp PrintHexSkaitmuo_grizti PrintHexSkaitmuo_0_9: ;0-9 mov dl, al add dl, 30h mov ah, 2 ;spausdiname simboli (0-9) is DL'o int 21h jmp printHexSkaitmuo_grizti printHexSkaitmuo_grizti: pop dx pop ax RET END
核心问题及修复步骤
1. 栈帧访问错误
单步中断触发时,CPU会依次压入FLAGS、CS、IP到栈中。原代码直接pop si/pop di获取IP/CS,会破坏栈的原始结构,导致IRET无法正确恢复执行环境。
修复方式:通过BP寄存器访问栈中的CS和IP,避免修改栈结构:
pertraukimas: ; 先保存所有寄存器到栈中(而非数据段变量,更可靠) push ax push bx push cx push dx push si push di push bp push sp mov bp, sp ; 栈结构:SP, BP, DI, SI, DX, CX, BX, AX, FLAGS, CS, IP mov si, [bp+14] ; 取出IP值 mov di, [bp+12] ; 取出CS值
2. 寄存器保存时机错误
原代码在中断处理开头直接将BX存入regBX,但此时BX已被之前的中断向量设置代码修改,无法获取指令执行前的BX值。
修复方式:在触发单步中断前,确保BX指向合法内存,且通过栈保存的寄存器值来获取指令执行前的BX:
; 在主程序中先设置BX指向数据段变量 .data some_var db 12h ; 初始值12h,对应期望输出的[bx]=12 .code ;==================BELEKOKIOS KOMANDOS==================== mov bx, offset some_var ; 设置BX指向数据段变量 mov byte ptr [bx],23h ; 待跟踪的指令 mov bx,001h
3. 字符串常量错误
原代码中mov_bx_kabl定义为"MOV bx, $",与期望输出的mov byte ptr [bx],不符,导致打印错误。
修复方式:修改字符串定义:
.data mov_byte_bx db "mov byte ptr [bx], $" semicolon_str db " ; $" bracket_bx db "[bx]=$"
4. 缺失[bx]值打印逻辑
原代码未实现读取并打印BX指向内存值的功能,无法满足期望输出。
修复方式:添加打印[bx]值的代码:
; 打印分号和空格 mov ah, 9 mov dx, offset semicolon_str int 21h ; 打印BX值 mov ah, 9 mov dx, offset bx_lygu int 21h mov ax, [bp+8] ; 从栈中取出指令执行前的BX值 call printAX ; 打印[bx]值 mov ah, 2 mov dl, "," int 21h call printSpace mov ah, 9 mov dx, offset bracket_bx int 21h mov bx, [bp+8] mov al, [bx] call printAL mov ah, 2 mov dl, "h" int 21h
5. 单步中断触发时机注意
TF标志位会让CPU在每条指令执行完毕后触发INT1,因此要打印指令执行前的寄存器值,需确保获取的是中断触发前的寄存器状态(通过栈保存的值)。
修改后的完整代码
.model small .stack 100h .data senasIP dw ? senasCS dw ? zingsn_pranesimas db "Zingsninis pertraukimas: $" mov_byte_bx db "mov byte ptr [bx], $" semicolon_str db " ; $" bx_lygu db "bx=$" bracket_bx db "[bx]=$" enteris db 13,10,"$" some_var db 12h ; 用于测试[bx]的初始值 .code mov ax, @data mov ds, ax ; 保存原INT1中断向量 mov ax, 0 mov es, ax mov ax, es:[4] mov senasIP, ax mov ax, es:[6] mov senasCS, ax ; 设置自定义INT1中断向量 mov ax, cs mov bx, offset pertraukimas mov es:[4], bx mov es:[6], ax ; 开启单步模式 pushf pop ax or ax, 100h push ax popf ; 测试指令 mov bx, offset some_var mov byte ptr [bx],23h mov bx,001h ; 关闭单步模式 pushf pop ax and ax, 0FEFFh push ax popf ; 恢复原INT1中断向量 mov ax, senasIP mov bx, senasCS mov es:[4], ax mov es:[6], bx uzdaryti_programa: mov ah, 4Ch int 21h ;================================================================== ; 单步中断处理程序 ;================================================================== pertraukimas: ; 保存所有寄存器到栈中 push ax push bx push cx push dx push si push di push bp push sp mov bp, sp ; 从栈中获取IP和CS(指令执行前的地址) mov si, [bp+14] mov di, [bp+12] ; 读取指令字节 mov al, cs:[si] mov ah, cs:[si+1] ; 判断是否为mov byte ptr [bx], imm8指令(opcode C6, ModRM 07) cmp al, 0C6h jne grizti_is_pertraukimo cmp ah, 07h jne grizti_is_pertraukimo ; 打印中断提示 mov ah, 9 mov dx, offset zingsn_pranesimas int 21h ; 打印CS:IP mov ax, di call printAX mov ah, 2 mov dl, ":" int 21h mov ax, si call printAX call printSpace ; 打印机器码 mov ah, al call printAL mov al, ah call printAL mov al, cs:[si+2] call printAL call printSpace call printSpace ; 打印汇编助记符 mov ah, 9 mov dx, offset mov_byte_bx int 21h mov al, cs:[si+2] call printAL mov ah, 2 mov dl, "h" int 21h ; 打印寄存器和内存值 mov ah, 9 mov dx, offset semicolon_str int 21h mov ah, 9 mov dx, offset bx_lygu int 21h mov ax, [bp+8] ; 取出指令执行前的BX值 call printAX mov ah, 2 mov dl, "," int 21h call printSpace mov ah, 9 mov dx, offset bracket_bx int 21h mov bx, [bp+8] mov al, [bx] call printAL mov ah, 2 mov dl, "h" int 21h ; 打印换行 mov ah, 9 mov dx, offset enteris int 21h grizti_is_pertraukimo: ; 恢复所有寄存器 pop sp pop bp pop di pop si pop dx pop cx pop bx pop ax IRET ;=================== 辅助打印函数 ==================== ; 打印AX的16进制值 printAX: push ax mov al, ah call printAL pop ax call printAL RET ; 打印空格 printSpace: push ax push dx mov ah, 2 mov dl, " " int 21h pop dx pop ax RET ; 打印AL的8进制值(两位16进制) printAL: push ax push cx push ax mov cl, 4 shr al, cl call printHexSkaitmuo pop ax call printHexSkaitmuo pop cx pop ax RET ; 打印单个16进制字符 printHexSkaitmuo: push ax push dx
相关产品推荐
相关产品推荐

