Author Topic: Why do MUL and IMUL give the same output?  (Read 5804 times)

Offline ben321

  • Full Member
  • **
  • Posts: 182
Why do MUL and IMUL give the same output?
« on: October 13, 2019, 04:17:03 AM »
Ok, so I made a simple Win32 program, and then observed the output of this program via OllyDbg.

If I do this with unsigned multiplying:
Code: [Select]
mov ax,0x4000
mov cx,0x0002
mul cx
AX receives the value 0x8000 (as I'd expect, as it is a valid value).

However if I change it to signed multiplying:
Code: [Select]
mov ax,0x4000
mov cx,0x0002
imul cx
I still get the same output value of 0x8000 stored in AX. However, this is invalid, since both inputs are positive, and therefore the output is clearly also positive, but positive 0x8000 is an INVALID value for a 16bit signed integer. Why does the CPU actually complete this calculation, instead of throwing an error (which then would need to be handled by SEH, structured exception handling, in the program)?

It seems that with the CPU ignoring this error condition, MUL and IMUL operators are actually identical.

Offline fredericopissarra

  • Full Member
  • **
  • Posts: 368
  • Country: br
Re: Why do MUL and IMUL give the same output?
« Reply #1 on: October 13, 2019, 10:58:53 AM »
I still get the same output value of 0x8000 stored in AX. However, this is invalid, since both inputs are positive, and therefore the output is clearly also positive, but positive 0x8000 is an INVALID value for a 16bit signed integer. Why does the CPU actually complete this calculation, instead of throwing an error (which then would need to be handled by SEH, structured exception handling, in the program)?

It seems that with the CPU ignoring this error condition, MUL and IMUL operators are actually identical.
You are forgetting that MUL/IMUL results, in this case, are 32 bits values stored in DX:AX.
Using IMUL, 0x4000 times 2 is 0x00008000 (32 bits).

MUL/IMUL doesn't raise exceptions, they affect the flags (CF and OF - they have the same meaning: flagging overflow condition). Here's a simple test:
Code: [Select]
; mul.asm
bits  64

section .text

; int testmul( int *carry );
  global testmul
testmul:
  mov ecx,0x40000000
  mov eax,2
  imul ecx
  mov ecx,0
  setc cl
  mov [rdi],ecx
  ret
Code: [Select]
/* test.c */
#include <stdio.h>

extern int testmul( int * );

int main( void )
{
  int r, c;

  r = testmul(&c);

  printf( "result=%#x, carry=%d\n", r, c );
}
This will result in:
Code: [Select]
result=0x80000000, carry=1As it should!
« Last Edit: October 13, 2019, 11:40:19 AM by fredericopissarra »

Offline ben321

  • Full Member
  • **
  • Posts: 182
Re: Why do MUL and IMUL give the same output?
« Reply #2 on: October 14, 2019, 02:19:45 AM »
You are forgetting that MUL/IMUL results, in this case, are 32 bits values stored in DX:AX.
Using IMUL, 0x4000 times 2 is 0x00008000 (32 bits).!

Good point, but one error. The output may occupy 32bits, but I think the range of possible output values is still the range allowed for 16bit signed integers. Therefore, your statement that the output of IMUL for 0x4000 and 2, would actually be 0xFFFF8000 (not 0x00008000 like you said). That is, it outputs a 32bit signed value which represents the corresponding 16bit signed output of the IMUL operation. In order to do this, if the value represented by 16bits is negative, the 32bit value is simply sign-extends the top bit of the 16bit value to the upper 16bits of the 32bit value. This must happen with signed 16bit value 0x8000, because positive 0x8000 is not a valid 16bit signed integer, and therefore clearly is represents a negative number. And when generating negative 16bit signed integer 0x8000 from positive numbers 0x4000 and 2, there must clearly be an overflow happening.

Ok, just tested my theory and IMUL did NOT output 0xFFFF8000 as I thought it would. Seems strange.
However, it DID trigger the overflow and carry flags.
« Last Edit: October 14, 2019, 02:28:41 AM by ben321 »

Offline fredericopissarra

  • Full Member
  • **
  • Posts: 368
  • Country: br
Re: Why do MUL and IMUL give the same output?
« Reply #3 on: October 14, 2019, 03:18:24 AM »
Ok, just tested my theory and IMUL did NOT output 0xFFFF8000 as I thought it would. Seems strange.
However, it DID trigger the overflow and carry flags.
Consider IMUL with 2 "positive" maximum values: 0x7fff * 0x7fff. This will result in 0x3fff0001, still a "positive" 32 bits value.