I am writing a step-mode interrupt handler in x86 architecture assembler and can’t figure out how to find and print out mov byte ptr [bx]
and bx
registers.
So far i have this and in theory it should work but it doesn’t. The output should look something like this: 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 byte ptr [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
3
mov ax, cs mov bx, offset pertraukimas mov es:[4], bx mov es:[6], ax
It is always better if you modify an interrupt vector with interrupts disabled. This will avoid any risk of using an incomplete vector. That’s why I wrote:
cli
mov word [es:4], pertraukimas
mov [es:6], cs
sti
popf mov byte ptr [bx],23h mov bx,001h
Once your popf
instruction has set the single-step flag TF, the CPU will automatically generate an exception after the execution of following instructions. It is important to note that the exception is not generated for the instruction that actually sets TF. So, directly after your popf
there’s no invokation of your special handler, but there is after the execution of mov byte ptr [bx],23h
. In my program I solved it with an inserted nop
:
popf ; This sets TF=1
nop
; Here happens the very first trap and CS:IP point at
mov byte [bx], 23h ; ... this instruction
mov bx, 0001h
The CS:IP value that the processor places on the stack does not represent the address of the instruction that just ran, but rather the one that follows.
The demo program that I wrote is a .COM executable where all of the segment registers start off equal to each other. The single-step handler works as indicated in the question. I tested it in the DOSBox 0.74 environment.
The output I got is close to what you have showed:
Zingsninis pertraukimas: 0192:012A C60723 MOV bx, 23h bx=0070
ORG 256
xor ax, ax
mov es, ax
mov ax, [es:4]
mov bx, [es:6]
mov [senasIP], ax
mov [senasCS], bx
cli
mov word [es:4], pertraukimas
mov [es:6], cs
sti
pushf : pop ax : or ax, 0100h : push ax : popf
;===============================================
nop
mov byte [bx], 23h
mov bx, 0001h
;=================================================
pushf : pop ax : and ax, 0FEFFh : push ax : popf
cli
mov ax, [senasIP]
mov [es:4], ax
mov ax, [senasCS]
mov [es:6], ax
sti
mov ax, 4C00h
int 21h
;==================================================================
;Pertraukimo apdorojimo procedura
;==================================================================
pertraukimas:
push es ax bx cx dx si di bp
mov bp, sp
les si, [bp+16]
mov ax, [es:si]
cmp ax, 07C6h ; Check for opcode `C6` and ModRM byte `07` (BX addressing mode)
jne grizti_is_pertraukimo
mov ah, 9
mov dx, zingsn_pranesimas
int 21h
mov ax, es
call printAX
mov ah, 2
mov dl, ":"
int 21h
mov ax, si
call printAX
call printSpace
mov al, 0C7h
call printAL
mov al, 07h
call printAL
mov al, [es:si+2] ; Immediate byte
call printAL
call printSpace
call printSpace
mov ah, 9
mov dx, mov_bx_kabl ; Text: `MOV byte ptr [BX],`
int 21h
mov al, [es: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, bx_lygu ; Text: `bx=`
int 21h
mov ax, [bp+10] ; Pushed BX
call printAX
mov ah, 9
mov dx, enteris
int 21h
grizti_is_pertraukimo:
pop bp di si dx cx bx ax es
iret
;===================PAGALBINES pertraukime naudojamos proceduros================
printSpace:
push ax dx
mov ah, 2
mov dl, " "
int 21h
pop dx ax
ret
printAX:
push ax
mov al, ah
call printAL
pop ax
printAL:
push ax cx
push ax
mov cl, 4
shr al, cl
call printHexSkaitmuo
pop ax
call printHexSkaitmuo
pop cx ax
ret
printHexSkaitmuo:
push ax dx
and al, 15
cmp al, 10
jb .num
add al, 65-10-48
.num:
add al, 48
mov dl, al
mov ah, 2
int 21h
pop dx ax
ret
; ------------------------------------
senasIP: dw ?
senasCS: dw ?
zingsn_pranesimas: db "Zingsninis pertraukimas: $"
mov_bx_kabl: db "MOV bx, $"
bx_lygu: db "bx=$"
enteris: db 13,10,"$"
I used a private assembler (similar to FASM) for this. Do modify anything that your assembler might not allow.