SIGFP - But no division by 0 or by big number | MASM/UASM

80 Views Asked by At

Performing a division by 10, I get a "floating point exception". when stepping through the code in GDB, I find that ax = 23 and bx = 10 when dividing.

.686                                    ;
                                        ;
BSS SEGMENT                             ;
    BUF DB 0                            ;
BSS ENDS                                ;
                                        ;
DATA SEGMENT                            ;
    ASSUME DS:BSS                       ;
                                        ;
PUBLIC _start                           ;
_start PROC                             ;
    MOV cx, 230                         ;
    CALL prN                            ;
                                        ;
...
_start ENDP                             ;
                                        ;
;---------------------------------------;
; prNum                                 ;
; TOFIX: numbers are printed backwards  ;
;---------------------------------------;
; CX = number to print                  ;
;---------------------------------------;
prN PROC                                ;
    MOV ax, cx                          ; prepare first loop
    MOV bx, 10                          ; !! BX = 10
@@loop:                                 ;
    ;- PROBLEMATIC LINE vvvvvvvvvvvvvvvv;
    DIV bx                              ; Get rightmost decimal digit
    ;- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^;
    ADD dl, '0'                         ; convert to ASCII-numeral
    MOV BYTE PTR [BUF], dl              ;
    PUSHA                               ; Not ideal, this is a playground
    ;- print byte buffer                ;
...
    ;--                                 ;
    POPA                                ;
    OR ax, ax                           ; Is cx = 0?
    JNZ @@loop                          ; NO: loop for the next decimal part
    RET                                 ; YES: leave loop
prN ENDP                                ;
DATA ENDS
END

Example runthrough of Loop (as I imagine it):

MOV ax, cx ; ax = 230
MOV bx, 10 ; bx = 10
           ;
(@@loop)   ;
DIX bx     ; ax = 23 - dx = 0
;- print   ; STDOUT = 0
OR ax, ax  ; ZF = 0
JNZ @@loop ; continue looping with AX = 23

DIV bx     ; AX = 2 - DX = 3 --> THIS is where the SIGFPE occurs
;- print   ; STDOUT = 03
OR ax, ax  ; ZF = 0
JNZ @@loop ; continue looping with AX = 2
           ;
DIX bx     ; AX = 0 - DX = 2
;- print   ; STOUD = 032 (230 but backwards)
OR ax, ax  ; ZF = 1
JNZ @@loop ; not looping
RET        ; all done, we are returning

Since I am dividing 23 by 10, I expect this operation to be problem-free. In particular:

  • No division by zero
  • No overflow
  • No underflow

I expect

AX = 2
DX = 3
BX = 10
1

There are 1 best solutions below

0
On

Oversight on my part. The 16-bit DIV operation takes in DX:AX.
With DX being 0x0030 in the first pass, the number I was dividing seemed not to be valid anymore:

DX = 0x0030 (48 in decimal)
AX = 0x0017 (23 in decimal)

0x00300017 divided by 10 is bigger than 0xFFFF.

if(Source == 0) Exception(DE); //divide error

if(OperandSize == 8) { //word/byte operation
  Temporary = AX / Source;
  if(Temporary > 0xFF) Exception(DE); //divide error
  else {
      AL = Temporary;
      AH = AX % Source;
  }
}
else if(OperandSize == 16) { //doubleword/word operation
  Temporary = DX:AX / Source;
  if(Temporary > 0xFFFF) Exception(DE); //divide error
  else {
      AX = Temporary;
      DX = DX:AX % Source;
  }
}
else { //quadword/doubleword operation
  Temporary = EDX:EAX / Source;
  if(Temporary > 0xFFFFFFFF) Exception(DE); //divide error
  else {
      EAX = Temporary;
      EDX = EDX:EAX % Source;
  }
}

https://c9x.me/x86/html/file_module_x86_id_72.html