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?

3
  • offset divideByZero isn't the full linear address of your function. You need to store cs to linear address 2 (i.e. es:[2]), not to divideByZero+2 Commented Dec 8, 2019 at 17:18
  • I afraid that I didn't understand you. What do I need to do? and why? Commented Dec 8, 2019 at 17:21
  • @PeterCordes forgot to mention, sorry Commented Dec 8, 2019 at 17:39

1 Answer 1

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).

Sign up to request clarification or add additional context in comments.

5 Comments

mov r/m16, Sreg is a valid encoding; 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.)
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? 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)
@PeterCordes : EMU8086 does in fact emulate the behaviour of an 8086 in this regard. EMU8086 will return to the next instruction after the DIV
@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.
@MichaelPetch Thanks for that confirmation. I haven't had much time available to look into details like that.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.