Reading Notes: 7-Dec-09

Comments
are in Italics and marked as red.
 
Multiplication
and registers
Why do we need two registers to store the result
of a multiplication? This is because each register or integer memory cell on
x86 PC can contain a number between -2147483648 and 2147483647.
 
We can think of EDX:EAX pair as two memory cells
joined together to hold the large multiplication result. (P.32)
 
At
first, I wrote a simple sample for examination.
 
int a, b;
__int64 c;
 
int main(int argc, char*
argv[])
{
           a = 5555555;
           b = 5555555;
           c = a * b;
 
           return
0;
}
 
I
was expecting the result of “c” to be 30864191358025 because I use __int64 to
hold the number. Instead, “c” is 556368969.
 
In
WinDbg, I set the breakpoint at the very beginning and checked the registers
values step by step.
 
0:000> p
eax=0054c563 ebx=00000000 ecx=00000000 edx=00000000 esi=0182f73a edi=0012ff68
eip=004113a7 esp=0012fe9c ebp=0012ff68
iopl=0         nv up ei pl nz na po nc
cs=001b 
ss=0023  ds=0023  es=0023 
fs=003b  gs=0000             efl=00000202
Test!main+0×37:
004113a7
imul    eax,dword ptr [Test!b
(00417140)]    ds:0023:00417140=0054c563
 
[a]
has been moved to eax (0×0054c563 = 5555555) and is going to multiply [b] in
the next step.
 
0:000> p
eax=21298449 ebx=00000000
ecx=00000000 edx=00000000
esi=0182f73a edi=0012ff68
eip=004113ae esp=0012fe9c ebp=0012ff68
iopl=0         ov up ei pl nz na po cy
cs=001b 
ss=0023  ds=0023  es=0023 
fs=003b  gs=0000             efl=00000a03
Test!main+0×3e:
004113ae cdq
 
The
large number should be divided into EDX:EAX to hold the large number but it’s
not. EAX = 0×21298449 = 556368969 which is exactly what I saw in Visual Studio
2005/2008.
 
After
several hours I found that I made an extremely stupid mistake. I didn’t cast
the int to __int64 immediately after multiplication. That’s why even I used __int64
to hold the number, it was still an integer. It ignored the High part of the
result and only kept the low part in eax.
 
So
here comes the second version.
 
int
a, b;
__int64
c;
 
int
main(int argc, char*
argv[])
{
           a
= 5555555;
           b
= 5555555;
           c
= (__int64)a * b;
 
           return 0;
}
 
After
multiplication, you can see the result is separated into 2 parts in WinDbg.
 
0:000> p
eax=21298449 ebx=7ffde000
ecx=0054c563
edx=00001c12 esi=00000000 edi=0012ff68
eip=004113eb esp=0012fe9c ebp=0012ff68
iopl=0         ov up ei pl zr na pe cy
cs=001b 
ss=0023  ds=0023  es=0023 
fs=003b  gs=0000             efl=00000a47
Mul!main+0×4b:
004113eb mov     dword ptr [Mul!c (00417148)],eax    

Leave a Reply