0

I'm trying to rewrite the 0h interrupt (Divide by zero) to a custom label I've made, which is supposed to print a custom message I've made instead of the normal exception which the emulator throws.

I haven't managed to find a good source which explains all this stuff in a good and understandable way, so my code obviously didn't work when I first made it. I've found this post: Is it possible to make a custom Interrupt in Assembly? But I'm still confused.

org 100h


jmp main


main:
    xor ax, ax
    mov es, ax    
    CLI
    mov bx, offset divideByZero
    mov es:[0h], bx 
    add bx, 2
    mov ax, cx
    mov es:[bx], ax 
    STI


    mov ax, 10
    mov bx, 0
    div bx

    mov ah, 0
    int 16h
    ret

divideByZero:
    push bp 
    mov bp, sp 

    PRINTN "Error: Divide By Zero Can Break The Universe" 

    pop bp
    iret

Can somebody explain to me how can I make my own interrupt like I tried to do, and how does it work?

1201ProgramAlarm
  • 32,384
  • 7
  • 42
  • 56
Kidsm
  • 308
  • 2
  • 14

1 Answers1

3

There are a few mistakes in your code where you set the interrupt vector. add bx,2 is completely unnecessary, mov ax,cx should be mov ax,cs, and mov es:[bx],ax should be mov es:[2],ax.

I'll also mention that while the original 8086 (and EMU8086) pushes the address of the instruction after the divide when a divide-by-zero (or overflow) occurs, on later chips the return address will be the same div instruction that just faulted. So on these later chips when you execute the iret you will go back to the div bx and trigger another division by zero. Then the handler will either need to abort the process (easy) or make appropriate changes to the saved registers and/or return address before executing the iret (difficult).

1201ProgramAlarm
  • 32,384
  • 7
  • 42
  • 56
  • [`mov r/m16, Sreg` is a valid encoding](https://www.felixcloutier.com/x86/mov); there's no need for AX here. Just `mov es:[2], cs`. But well spotted that CX was a typo for CS; I assumed it was just some nonsense related to their confusion with storing *to* the function address in BX. (There's also no need for `bx`; `mov r/m16, imm16` is also a valid encoding. It does take 2 instructions to zero a segment register, though.) – Peter Cordes Dec 08 '19 at 22:25
  • Are you sure emu8086 doesn't emulate a real 8086 and take `#DE` exceptions with the address of the instruction *after* `div`? Only later x86 changed that. [Why do call and jump instruction use a displacement relative to the next instruction, not current?](//stackoverflow.com/q/58720936) points out that original 8086 probably doesn't even keep track of the real instruction start address (even if you exclude multiple prefixes, which it unfortunately does for resuming from `rep movs`) – Peter Cordes Dec 08 '19 at 22:42
  • 1
    @PeterCordes : EMU8086 does in fact emulate the behaviour of an 8086 in this regard. EMU8086 will return to the next instruction after the DIV – Michael Petch Dec 09 '19 at 21:10
  • 1
    @PeterCordes I've rephrased things to account for the different 8086 behavior with exceptions, but have left the explanation of the behavior for later chips. – 1201ProgramAlarm Dec 10 '19 at 15:21
  • @MichaelPetch Thanks for that confirmation. I haven't had much time available to look into details like that. – 1201ProgramAlarm Dec 10 '19 at 15:21