0

Any assembler pros here? Been going through this for hours.. Can't figure out why do I get overflow and stuff. Any ideas why this is collapsing?

My variables:

a DB 2
b DB 1
c DW 4
x DB -1, 2, 3
y DW kiek dup(0AAh)

And my function

f3:
MOV bx, c
MOV ax, 2   ; ax = 2
IMUL bx      ; ax = 2c
JO kl1      ; mul too big to store 
MOV dx,ax   ; dx = 2c  
MOV al, a   ; al = a
CBW
SUB dx, ax  ; dx = 2c - a
MOV bx,dx   ; bx = 2c - a
MOV cl, x[si]
CBW
MOV al,a    ; al = a
IMUL cx  ; al = a*x
CBW
JO kl1      ; mul too big to store
MOV dx, c   ; dx = c  
ADD ax,dx   ; ax = a*x+c
MOV cx,ax   ; cx = a*x+c
MOV dx,bx   ; ax = 2c-a
MOV bx, cx
CMP bx, 0
JE kl2  ; divided by 0
MOV ax, dx     
IDIV bx
JMP re

Sorry if it's some dumb error, just can't handle it anymore, thanks!

everything goes fine, i get 6 in register A, 2 in register B, and when it tries to IDIV, it says: divide error - overflow. to manually process this error, change address of INT 0 in interrupt vector table.

and it shows me this line ( i don't even have it on my code):

 BIOS DI
 INT 00h
 IRET ; this is where i get the error 
  • 5
    Where is the overflow happening? Have you tried stepping through the code with a debugger? You should be able to watch the values of each register and the flags change in real-time. That makes short work of problems like this. – Cody Gray - on strike Dec 18 '16 at 12:59
  • 1
    The sizes seem inconsistent, eg `mov ax, 2` followed by `cbw` (useless), followed by `imul dword ptr [c]` (but the high word of `eax` can be whatever) – harold Dec 18 '16 at 13:01
  • I think that `imul c` may compile as `imul word ptr [c]` in masm, as `c dw 2`, but it's better to write the size modifier directly in code to avoid any ambiguity. Anyway, run it through debugger, the code looks to be a bit weird in some cases (doing `cbw` after `imul byte ptr x[si]` and checking overflow... why? You process 16b value later, so if (a*x) "overflows" to 16b, it can be processed anyway as is?) ... Anyway, we are just guessing, as OP didn't specify the assembler used (`dup` hints on MASM/TASM). – Ped7g Dec 18 '16 at 13:55
  • @Ped7g i updated the post, seems something really unexplainable – Lukas Baranauskas Dec 18 '16 at 16:38
  • With respect to your update, that's the BIOS divide-by-zero interrupt vector. It isn't part of your code, it gets triggered when the CPU takes a divide-by-zero exception. You're executing `IDIV BX`, which divides `AX` by the operand—in this case, `BX`. So clearly `BX` is 0 at that time. To confirm, place a breakpoint on the line that contains the `IDIV` instruction, and check what the value of `BX` is. – Cody Gray - on strike Dec 18 '16 at 16:49
  • Your current version is easy to explain. Just read details about `IDIV` instruction. @CodyGray I think the `dx` is the culprit, not `bx`. :) – Ped7g Dec 18 '16 at 16:49
  • AX is 0006 and BX is 0002 – Lukas Baranauskas Dec 18 '16 at 16:50
  • *"IDIV r/m16 Signed divide DX:AX by r/m16, with result stored in AX = Quotient, DX = Remainder."* Which means that you are dividing 0x00060006 / 0x0002 => overflows 16bit. – Ped7g Dec 18 '16 at 16:51
  • Your old version btw did `CWD`, so there were other problems, because `CWD` did sign-extend `ax` into `dx`. In case of `ax = 6` id did effectively `dx = 0`, then `IDIV` would work. If you are asking on SO, make sure the code base is already somewhat stable, and that you post current one (to the problem described). (BTW, at the moment you do also `MOV cl, x[si]`, but then you use `cx` in `IMUL`, without setting value of `ch` first). If there was something left over in `ch`, you will get unexpected results. .. and `CBW` ahead of `al` set... and I'm not going to read it further. – Ped7g Dec 18 '16 at 17:00
  • What do you mean by *"multiply by zero"*? What result do you want to get? (it's not clear from the question, there're some comments over code, but it's not clear what is the final goal). Nor is it [mcve]. – Ped7g Dec 18 '16 at 17:12
  • All i want is to divide the to registers, that's the thing that keeps me from finishing this school work. You said "you are dividing 0x00060006 / 0x0002 ", so how should I divide it to make the result not 0x – Lukas Baranauskas Dec 18 '16 at 17:16
  • 2
    Thinking how to help you... hm.. hard to say, maybe calm down a bit, you have to be absolutely precise and accurate with Assembly. doing `mov al,4` `cbw` in other order means something different, this version does `ax=4`, other order may end with `ax=0xFF04` when `al` was >= 0x80 before. ... about `IDIV bx`. This takes 32 bit value, composed of `dx` (upper 16b) and `ax` (lower 16b). So `mov ax,dx` `idiv bx` with `ax=6, bx=2` means that also `dx=6`. So the 32b dividend is 0x00060006 in hexadecimal. The 16b divisor is 2. Quotient is then 0x30003, and that value requires at least 18 bits. – Ped7g Dec 18 '16 at 17:17
  • `0xSomething` means "hexadecimal" number, from C/C++, sorry if you are not familiar with this. I use hexa, because in hexa it's easy to see particular byte value. I know dx=ax=6 forms 32b value 60006h, but I have no idea what it is in decimal (without using calculator) (it's `393222` or also `6*65536+6`). Ahead of `IDIV bx` your registers must be `dx = 0, ax = 6, bx = 2` to get 6/2 result. – Ped7g Dec 18 '16 at 17:19
  • Since you're asking why IDIV faults with those inputs, it's a duplicate of the usual forgot-to-set-DX question. Use CWD before 16-bit IDIV unless you know you want to use a 32-bit dividend in DX:AX. – Peter Cordes Dec 18 '16 at 20:18

0 Answers0