; THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX ; SOFTWARE CORPORATION ("PARALLAX"). PARALLAX, IN DISTRIBUTING THE CODE TO ; END-USERS, AND SUBJECT TO ALL OF THE TERMS AND CONDITIONS HEREIN, GRANTS A ; ROYALTY-FREE, PERPETUAL LICENSE TO SUCH END-USERS FOR USE BY SUCH END-USERS ; IN USING, DISPLAYING, AND CREATING DERIVATIVE WORKS THEREOF, SO LONG AS ; SUCH USE, DISPLAY OR CREATION IS FOR NON-COMMERCIAL, ROYALTY OR REVENUE ; FREE PURPOSES. IN NO EVENT SHALL THE END-USER USE THE COMPUTER CODE ; CONTAINED HEREIN FOR REVENUE-BEARING PURPOSES. THE END-USER UNDERSTANDS ; AND AGREES TO THE TERMS HEREIN AND ACCEPTS THE SAME BY USE OF THIS FILE. ; COPYRIGHT 1993-1999 PARALLAX SOFTWARE CORPORATION. ALL RIGHTS RESERVED. ; DIV0.ASM - Provides routines to capture divide overflow exceptions. ; See DIV0.H for calling parameters. .386 _DATA SEGMENT BYTE PUBLIC USE32 'DATA' MAX_SIZE EQU 100 Old_Ex_Sel dw ? ; Old Selector Old_Ex_Off dd ? ; Old offset Already_Init dd 0 ; Equal to 1 when installed DefaultMode dd 0 ; What to do when not in list. ; Callback List CB_Size dw 0 CB_Source dd MAX_SIZE DUP (0) CB_Dest dd MAX_SIZE DUP (0) ; Saturation List SAT_Size dw 0 SAT_Source dd MAX_SIZE DUP (0) PUBLIC _div0_num_handled_by_cblist PUBLIC _div0_num_handled_by_satlist PUBLIC _div0_num_saturated _div0_num_handled_by_cblist dd 0 _div0_num_handled_by_satlist dd 0 _div0_num_saturated dd 0 _DATA ENDS DGROUP GROUP _DATA _TEXT SEGMENT BYTE PUBLIC USE32 'CODE' ASSUME DS:_DATA ASSUME CS:_TEXT DivideByZeroException: PREFIX_ADRSIZ EQU 01100111b PREFIX_OPSIZE EQU 01100110b PREFIX_LOCK EQU 11110000b PREFIX_CS EQU 00101110b PREFIX_DS EQU 00111110b PREFIX_ES EQU 00100110b PREFIX_FS EQU 01100100b PREFIX_GS EQU 01100101b PREFIX_SS EQU 00110110b OPCODE_NOP EQU 10010000b OVERFLOW_8BIT_UNSIGNED EQU 0FFh OVERFLOW_16BIT_UNSIGNED EQU 0FFFFh OVERFLOW_32BIT_UNSIGNED EQU 0FFFFFFFFh OVERFLOW_8BIT_NEGATIVE EQU -128 OVERFLOW_16BIT_NEGATIVE EQU -32768 OVERFLOW_32BIT_NEGATIVE EQU -2147483648 OVERFLOW_8BIT_POSITIVE EQU 127 OVERFLOW_16BIT_POSITIVE EQU 32767 OVERFLOW_32BIT_POSITIVE EQU 2147483647 SAVED_REGS EQU 32 SAVED_EAX EQU DWORD PTR SS:[ESP+0] ; 4 SAVED_AL EQU BYTE PTR SS:[ESP+0] SAVED_AH EQU BYTE PTR SS:[ESP+1] SAVED_AX EQU WORD PTR SS:[ESP+0] SAVED_EBX EQU DWORD PTR SS:[ESP+4] ; 4 SAVED_BL EQU BYTE PTR SS:[ESP+4] SAVED_BH EQU BYTE PTR SS:[ESP+5] SAVED_BX EQU WORD PTR SS:[ESP+4] SAVED_ECX EQU DWORD PTR SS:[ESP+8] ; 4 SAVED_CL EQU BYTE PTR SS:[ESP+8] SAVED_CH EQU BYTE PTR SS:[ESP+9] SAVED_CX EQU WORD PTR SS:[ESP+8] SAVED_EDX EQU DWORD PTR SS:[ESP+12] ; 4 SAVED_DL EQU BYTE PTR SS:[ESP+12] SAVED_DH EQU BYTE PTR SS:[ESP+13] SAVED_DX EQU WORD PTR SS:[ESP+12] SAVED_ESI EQU DWORD PTR SS:[ESP+16] ; 4 SAVED_SI EQU WORD PTR SS:[ESP+16] SAVED_EDI EQU DWORD PTR SS:[ESP+20] ; 4 SAVED_DI EQU WORD PTR SS:[ESP+20] SAVED_ES EQU WORD PTR SS:[ESP+24] ; 4 SAVED_DS EQU WORD PTR SS:[ESP+28] ; 4 BAD_EIP EQU DWORD PTR SS:[ESP+0Ch+SAVED_REGS] BAD_CS EQU WORD PTR SS:[ESP+10h+SAVED_REGS] SAVED_ESP EQU DWORD PTR SS:[ESP+18h+SAVED_REGS] SAVED_SP EQU WORD PTR SS:[ESP+18h+SAVED_REGS] SAVED_SS EQU WORD PTR SS:[ESP+1Ch+SAVED_REGS] ;int 3 ; Bypass by typing: /eip++ push ds push es push edi push esi push edx push ecx push ebx push eax mov ax, DGROUP mov ds, ax mov eax, BAD_EIP xor ecx, ecx NextCB: cmp cx, CB_Size je CheckSatList cmp CB_Source[ecx*4], eax jne NotIt ; Found the right Call Back item inc _div0_num_handled_by_cblist mov ecx, CB_Dest[ecx*4] mov BAD_EIP, ecx jmp NormalReturn NotIt: inc cx jmp NextCB CheckSatList: xor ecx, ecx NextSAT: cmp cx, SAT_Size je UseDefaultAction cmp SAT_Source[ecx*4], eax jne NotIt1 ; Found the right Saturation item inc _div0_num_handled_by_satlist jmp SaturateIt NotIt1: inc cx jmp NextCB UseDefaultAction: cmp DefaultMode, 1 je DefaultSaturate ;====== Return Error Code. ============= ;int 3 ; Pop into debugger if active call div0_close_ jmp NormalReturn DefaultSaturate: ; This is hit when mode=DM_SATURATE and the instruction ; isn't in any callback or saturate lists. For your handy debugging ; information, the instruction that caused this exception is at ; BX:EAX. inc _div0_num_saturated mov eax, BAD_EIP mov bx, BAD_CS int 3 SaturateIt: xor ebx, ebx xor ecx, ecx xor esi, esi xor edi, edi mov es, SAVED_DS mov eax, BAD_EIP ; EAX = Pointer to Div instruction ; BH = temp byte holder ; BL = temp byte holder ; CH = Bits 0=8bit, 1=16bit, 2=32bit, 3=DIV ; CL = Temp bit shifter ; EDX = temp 32-bit holder PrefixCheck: mov bl, BYTE PTR CS:[eax] cmp bl, PREFIX_OPSIZE je OperandSize cmp bl, PREFIX_ADRSIZ je OverPrefix cmp bl, PREFIX_LOCK je OverPrefix cmp bl, PREFIX_CS je PrefixCS cmp bl, PREFIX_DS je PrefixDS cmp bl, PREFIX_ES je PrefixES cmp bl, PREFIX_FS je PrefixFS cmp bl, PREFIX_GS je PrefixGS cmp bl, PREFIX_SS je PrefixSS jmp DoneWithPrefixes OverPrefix: inc eax jmp PrefixCheck PrefixCS: mov es, BAD_CS jmp OverPrefix PrefixDS: push ds pop es jmp OverPrefix PrefixES: mov es, SAVED_ES PrefixFS: push fs pop es jmp OverPrefix PrefixGS: push gs pop es jmp OverPrefix PrefixSS: mov es, SAVED_SS jmp OverPrefix OperandSize: or ch, 10b ; Flag 16-bit jmp OverPrefix DoneWithPrefixes: ; Check for the divide opcode. cmp bl, 0F7h je OP32OR16BIT cmp bl, 0F6h je OP8BIT ; Something is wrong!!!!! This should never be reached!!! pop eax pop ebx pop ecx pop edx pop esi pop edi pop es pop ds int 3 retf OP32OR16BIT: test ch, 10b jnz OP16BIT OP32BIT: or ch, 100b ; Flag 32-bit jmp GotOpSize OP8BIT: or ch, 1b ; Flag 8-bit jmp GotOpSize OP16BIT: GotOpSize: inc eax ; We should be pointing to the mod,111,r/m byte mov bl, BYTE PTR CS:[eax] inc eax mov bh, bl shr bh, 6 ; BH = mod bits test bl, 001000b ; 110 = Div ; 111 = iDiv jz IsDIV ; This is a signed division or ch, 1000b ; Flag Signed IsDIV: and bl, 111b ; BL = r/m bits cmp bh, 11b je MOD_11 DoRMbits: cmp bl, 000b je RM_000 cmp bl, 001b je RM_001 cmp bl, 010b je RM_010 cmp bl, 011b je RM_011 cmp bl, 100b je RM_100 cmp bl, 101b je RM_101 cmp bl, 110b je RM_110 jmp RM_111 RM_000: add esi, SAVED_EAX jmp doneRM RM_001: add esi, SAVED_ECX jmp doneRM RM_010: add esi, SAVED_EDX jmp doneRM RM_011: add esi, SAVED_EBX jmp doneRM RM_100: jmp RM_SIB RM_101: cmp bh, 00b je DSdisp32 add esi, ebp mov es, SAVED_SS jmp doneRM DSdisp32: mov bh, 10b jmp doneRM RM_110: add esi, SAVED_ESI jmp doneRM RM_111: add esi, SAVED_EDI jmp doneRM RM_SIB: mov bl, BYTE PTR CS:[eax] ; BL = s-i-b byte mov cl, bl shl cl, 6 shl bl, 3 and bl, 111b cmp bl, 000b je INDEX_EAX cmp bl, 001b je INDEX_ECX cmp bl, 010b je INDEX_EDX cmp bl, 011b je INDEX_EBX cmp bl, 100b je doneSIB1 cmp bl, 101b je INDEX_EBP cmp bl, 110b je INDEX_ESI jmp INDEX_EDI INDEX_EAX: mov edx, SAVED_EAX jmp doneSIB INDEX_ECX: mov edx, SAVED_ECX jmp doneSIB INDEX_EDX: mov edx, SAVED_EDX jmp doneSIB INDEX_EBX: mov edx, SAVED_EBX jmp doneSIB INDEX_EBP: mov edx, ebp jmp doneSIB INDEX_ESI: mov edx, SAVED_ESI jmp doneSIB INDEX_EDI: mov edx, SAVED_EDI jmp doneSIB doneSIB: shl edx, cl add esi, edx doneSIB1: mov bl, BYTE PTR CS:[eax] ; BL = s-i-b byte inc eax mov bh, bl shl bh, 6 and bl, 111b jmp DoRMbits doneRM: ;BH = mod cmp bh, 00b je MOD_00 cmp bh, 01b je MOD_01 cmp bh, 10b je MOD_10 jmp MOD_11 MOD_00: ; No displacement jmp doneMOD MOD_01: ; disp8 movsx edx, BYTE PTR CS:[eax] add eax, 1 add esi, edx jmp doneMOD MOD_10: mov edx, DWORD PTR CS:[eax] add eax, 4 add esi, edx jmp doneMOD MOD_11: cmp bl, 000b je REG_000 cmp bl, 001b je REG_001 cmp bl, 010b je REG_010 cmp bl, 011b je REG_011 cmp bl, 100b je REG_100 cmp bl, 101b je REG_101 cmp bl, 110b je REG_110 jmp REG_111 REG_000: test ch, 1b ; Check if 8-bit jz @f ; Skip if not movsx edx, SAVED_AL @@: test ch, 10b ; Check if 16-bit jz @f ; Skip if not movsx edx, SAVED_AX @@: test ch, 100b ; Check if 32-bit jz GotValue ; skip if not mov edx, SAVED_EAX jmp GotValue REG_001: test ch, 1b ; Check if 8-bit jz @f ; Skip if not movsx edx, SAVED_CL @@: test ch, 10b ; Check if 16-bit jz @f ; Skip if not movsx edx, SAVED_CX @@: test ch, 100b ; Check if 32-bit jz GotValue ; skip if not mov edx, SAVED_ECX jmp GotValue REG_010: test ch, 1b ; Check if 8-bit jz @f ; Skip if not movsx edx, SAVED_DL @@: test ch, 10b ; Check if 16-bit jz @f ; Skip if not movsx edx, SAVED_DX @@: test ch, 100b ; Check if 32-bit jz GotValue ; skip if not mov edx, SAVED_EDX jmp GotValue REG_011: test ch, 1b ; Check if 8-bit jz @f ; Skip if not movsx edx, SAVED_BL @@: test ch, 10b ; Check if 16-bit jz @f ; Skip if not movsx edx, SAVED_BX @@: test ch, 100b ; Check if 32-bit jz GotValue ; skip if not mov edx, SAVED_EDX jmp GotValue REG_100: test ch, 1b ; Check if 8-bit jz @f ; Skip if not movsx edx, SAVED_AH @@: test ch, 10b ; Check if 16-bit jz @f ; Skip if not movsx edx, SAVED_SP @@: test ch, 100b ; Check if 32-bit jz GotValue ; skip if not mov edx, SAVED_ESP jmp GotValue REG_101: test ch, 1b ; Check if 8-bit jz @f ; Skip if not movsx edx, SAVED_CH @@: test ch, 10b ; Check if 16-bit jz @f ; Skip if not movsx edx, bp @@: test ch, 100b ; Check if 32-bit jz GotValue ; skip if not mov edx, ebp jmp GotValue REG_110: test ch, 1b ; Check if 8-bit jz @f ; Skip if not movsx edx, SAVED_DH @@: test ch, 10b ; Check if 16-bit jz @f ; Skip if not movsx edx, SAVED_SI @@: test ch, 100b ; Check if 32-bit jz GotValue ; skip if not mov edx, SAVED_ESI jmp GotValue REG_111: test ch, 1b ; Check if 8-bit jz @f ; Skip if not movsx edx, SAVED_BH @@: test ch, 10b ; Check if 16-bit jz @f ; Skip if not movsx edx, SAVED_DI @@: test ch, 100b ; Check if 32-bit jz GotValue ; skip if not mov edx, SAVED_EDI jmp GotValue doneMOD: test ch, 1b ; Check if 8-bit jz @f ; Skip if not movsx edx, BYTE PTR ES:[esi] @@: test ch, 10b ; Check if 16-bit jz @f ; Skip if not movsx edx, WORD PTR ES:[esi] @@: test ch, 100b ; Check if 32-bit jz GotValue ; skip if not mov edx, DWORD PTR ES:[esi] GotValue: ; EAX = Pointer to instruction right after DIV ; CH = Bits 0=8bit, 1=16bit, 2=32bit, 3=DIV ; EDX = 32-bit sign extended divisor (source operand) mov BAD_EIP, eax ; Point EIP to next instruction ; if size=8 then AL=1..., AH=1... ; if size=16 then AX=1..., DX=1... ; if size=32 then EAX=1..., EDX=1... ; ; resultsign = - (Assume negative or unsigned) ; ; If signed then ; if size=8 then resultsign = sign(ah:al) * sign(edx) ; if size=16 then resultsign = sign(dx:ax) * sign(edx) ; if size=32 then resultsign = sign(dx:ax) * sign(edx) ; ; if resultsign == + then ; if size=8 then AL = 01... ; if size=16 then AX = 01... ; if size=32 then EAX = 01... ; test ch, 1000b jz UnSigned shr edx, 31 ; Signed return test ch, 1b ; Check if 8-bit jnz Get8Sign test ch, 10b ; Check if 16-bit jnz Get16Sign jmp Get32Sign ; Else is 32-bit Get8Sign: mov ah, SAVED_AH shr ah, 7 ; AH = sign of divisor xor ah, dl jnz Neg8Return jmp Pos8Return Get16Sign: mov ah, SAVED_DH shr ah, 7 ; AH = sign of divisor xor ah, dl jnz Neg16Return jmp Pos16Return Get32Sign: mov eax, SAVED_EDX shr eax, 31 ; AL = sign of divisor xor al, dl jnz Neg32Return jmp Pos32Return UnSigned: ; We need to find the sign ; Unsigned div return test ch, 1b ; Check if 8-bit jnz Unsigned8Return test ch, 10b ; Check if 16-bit jnz Unsigned16Return jmp Unsigned32Return ; Else is 32-bit NormalReturn: pop eax pop ebx pop ecx pop edx pop esi pop edi pop es pop ds retf Neg8Return: pop eax mov al, OVERFLOW_8BIT_NEGATIVE mov ah, 0 ; Remainder = 0 pop ebx pop ecx pop edx pop esi pop edi pop es pop ds retf Neg16Return: pop eax mov ax, OVERFLOW_16BIT_NEGATIVE pop ebx pop ecx pop edx mov dx, 0 ; Remainder = 0 pop esi pop edi pop es pop ds retf Neg32Return: pop eax mov eax, OVERFLOW_32BIT_NEGATIVE pop ebx pop ecx pop edx mov edx, 0 ; Remainder = 0 pop esi pop edi pop es pop ds retf Pos8Return: pop eax mov al, OVERFLOW_8BIT_POSITIVE mov ah, 0 ; Remainder = 0 pop ebx pop ecx pop edx pop esi pop edi pop es pop ds retf Pos16Return: pop eax mov ax, OVERFLOW_16BIT_POSITIVE pop ebx pop ecx pop edx mov dx, 0 ; Remainder = 0 pop esi pop edi pop es pop ds retf Pos32Return: pop eax mov eax, OVERFLOW_32BIT_POSITIVE pop ebx pop ecx pop edx mov edx, 0 ; Remainder = 0 pop esi pop edi pop es pop ds retf Unsigned8Return: pop eax mov al, OVERFLOW_8BIT_UNSIGNED mov ah, 0 ; Remainder = 0 pop ebx pop ecx pop edx pop esi pop edi pop es pop ds retf Unsigned16Return: pop eax mov ax, OVERFLOW_16BIT_UNSIGNED pop ebx pop ecx pop edx mov dx, 0 ; Remainder = 0 pop esi pop edi pop es pop ds retf Unsigned32Return: pop eax mov eax, OVERFLOW_32BIT_UNSIGNED pop ebx pop ecx pop edx mov edx, 0 ; Remainder = 0 pop esi pop edi pop es pop ds retf PUBLIC div0_close_ div0_close_: push eax push ecx push edx mov Already_Init, 0 mov eax, 0203h mov bl, 0 mov cx, Old_Ex_Sel mov edx, Old_Ex_Off int 31h pop edx pop ecx pop eax ret PUBLIC div0_set_saturate_ div0_set_saturate_: ; EAX = div_addr push ecx xor ecx, ecx mov cx, SAT_Size inc cx cmp cx, MAX_SIZE jae TooMany1 mov SAT_Size, cx dec ecx mov SAT_Source[ecx*4], eax mov eax, 1 pop ecx ret TooMany1: mov eax, 0 pop ecx ret PUBLIC div0_set_handler_ div0_set_handler_: ; EAX = div_addr ; EDX = handler_addr push ecx xor ecx, ecx mov cx, CB_Size inc cx cmp cx, MAX_SIZE jae TooMany mov CB_Size, cx dec ecx mov CB_Source[ecx*4], eax mov CB_Dest[ecx*4], edx mov eax, 1 pop ecx ret TooMany: mov eax, 0 pop ecx ret PUBLIC div0_set_mode_ div0_set_mode_: and eax, 1 mov DefaultMode, eax ret PUBLIC div0_init_ div0_init_: push ds push ebx push ecx push edx cmp Already_Init, 1 je AlreadyInstalled mov Already_Init, 1 mov _div0_num_handled_by_cblist, 0 mov _div0_num_handled_by_satlist, 0 mov _div0_num_saturated, 0 and eax, 1 mov DefaultMode, eax mov SAT_Size, 0 mov CB_Size, 0 mov eax, 0202h mov bl, 0 int 31h jc ToBadSoSadItFailed mov Old_Ex_Sel,cx mov Old_Ex_Off,edx mov eax, 0203h mov bl, 0 mov cx, cs mov edx, offset DivideByZeroException int 31h jc ToBadSoSadItFailed AlreadyInstalled: mov eax, 1 pop edx pop ecx pop ebx pop ds ret ToBadSoSadItFailed: mov eax, 0 pop edx pop ebx pop ds ret _TEXT ENDS END