Reputation: 39
Hi i have redirected divide overflow interrupt to point at my custom created interrupt which prints 'hello man here i am' on the screen, instead it print weird ascii characters. Can someone tell me why? here is the code
[ORG 100h]
jmp start
message: dw 'hello man here i am'
prntstr: push ax
push bx
push cx
push dx
push si
push di
push bp
push ds
push es
push cs
pop ds
mov ah, 0x13
mov al, 1
mov bh, 0
mov bl, 7
mov dx,0x0a03
mov cx,11
push cs
push es
mov bp,message
int 0x10
pop es
pop ds
pop bp
pop di
pop si
pop dx
pop cx
pop bx
pop ax
ret
tsr: mov ah, 0
int 0x16
call prntstr
iret
;mov ah,4ch
;mov al, 6
;int 0x21
;iret
divs: mov ax,0x8569
mov dl,2
div dl
ret
start: xor ax,ax
mov es,ax
mov word[es:0*4], tsr
mov [es:0*4+2],cs
call divs
mov ax,0x4c00
int 0x21
one more thing i do not understand about the code is where i set offset at es:0*4 -- i assument that 00 is the location of the divide overflow interrupt? what is the 0*4 for coz anything multiplied by zero would mean the same, so why the 4 ? thanks in advance
Upvotes: 0
Views: 1390
Reputation: 881263
As to you weird character problems, I think:
push cs
push es
should be:
push cs
pop es
Otherwise:
es
segment register is not set up for es:bp
to point to the message correctly. It will print whatever is at offset message
in the segment es
was pointing to when your interrupt fired rather than in the code segment where your actual message is.For the 0*4
issue, I'm not sure. It's been a while since I did x86 but I know you can scale indirect addressing modes such as with:
mov eax, dwarray[edx*4]
to ensure the correct memory locations are accessed. This scaled edx
up to the correct value before adding to the dwarray
base address.
I don't think that was needed for immediate offsets though, so I suspect it was just boilerplate code for being able to change any interrupt by just replacing the 0
with the relevant interrupt number.
And, as an aside, you probably don't want to be changing interrupt vectors without ensuring that interrupts are disabled during the process. If an interrupt fires after you've written the offset of tsr
, but before you've written the segment, the results will not be pretty.
Upvotes: 1
Reputation: 62048
You have multiple issues in your code. See the comments:
[ORG 100h]
jmp start
message: db 'hello man here i am' ; chars are 8-bit, hence db, not dw
msglen equ $ - message ; calculate message length
prntstr: push ax
push bx
push cx
push dx
push si
push di
push bp
push ds
push es
;push cs ; not really needed here
;pop ds
mov ah, 0x13
mov al, 1
mov bh, 0
mov bl, 7
mov dx,0x0a03
mov cx,msglen ; use proper message length
push cs
pop es ; not "push es" - copy'n'paste bug !!!
mov bp,message
int 0x10
pop es
pop ds
pop bp
pop di
pop si
pop dx
pop cx
pop bx
pop ax
ret
tsr:
call prntstr
; skip DIV (by advancing IP) to avoid infinite loop on DIV
push bp
mov bp, sp
add word [bp+1*2], divend-divstart; IP (location of divstart) on the stack
pop bp
push ax ; save AX because int 0x16 will change it
mov ah, 0
int 0x16
pop ax ; restore AX
iret
divs: mov ax,0x8569
mov dl,2
divstart:
div dl
divend:
ret
start:
mov ax, 3
int 0x10 ; clear screen by setting mode 3
xor ax,ax
mov es,ax
cli ; update ISR address w/ ints disabled
push word[es:0*4+2] ; preserve ISR address
push word[es:0*4]
mov word[es:0*4], tsr
mov [es:0*4+2],cs
sti
call divs
cli ; update ISR address w/ ints disabled
pop word[es:0*4] ; restore ISR address
pop word[es:0*4+2]
sti
mov ax,0x4c00
int 0x21
4 is a far pointer size (2 bytes for offset and 2 bytes for segment selector). So, for int 0
the address in the interrupt vector table will be 0*4
, for int 1
it will be 1*4
, for int n
it will be n*4
. In this particular case the multiplication is unnecessary, but it won't affect code generation anyway since the assembler will calculate and substitute 0
for 0*4
and 2
for 0*4+2
.
Upvotes: 0