Yesterday came across a very strange problem, first look at this code:
1#include <stdio.h>2 intMainintargcChar*argv[])3 {4 LongNUM1 =203879;5 Long Longnum2 =203879;6 7 Long LongRes1 = NUM1 *NUM1;8 Long LongRes2 = num2 *num2;9 Tenprintf"res1 =%lld\n", res1); Oneprintf"res2 =%lld\n", res2); A - return 0; -}
The running results of the program are as follows:
It feels strange here that 203879 is not more than 4 bytes in range, but it's squared over, so I put its results in a 8-byte number, why the end result still shows overflow?
And then I wrote a program that took the assembly code out and analyzed it? The procedure is as follows:
1 intMainintargcChar*argv[])2 {3 LongMuln =203879;4 Long LongMULNL =203879;5 6 Long LongNUM1 =203879*203879;7 Long Longnum2 = Muln *Muln;8 Long LongNUM3 = MULNL *MULNL;9 Ten return 0; One}
Here I am divided into three kinds of situations, one is a direct integer when the multiplier, one is a long integer when the multiplier, there is a long long integer as a multiplier, and then calculate their square, I use GDB debugging results are as follows:
One of the first two cases overflowed, and only the third was normal. And then we'll look at their assembly code, which is the assembler code I disassembled with Objdump:
1 intMainintArgc,char *argv[])2 {3 8048394: - Push%EBP4 8048395: theE5mov%ESP,%EBP5 8048397: theE4 F8 and$0xfffffff8,%esp6804839a: theEc - Sub$0x30,%esp7Long Muln =203879;8804839d: C7 - - 0c the1cGenevamovl $0x31c67,0xc (%ESP)980483A4:xx TenLong Long MULNL =203879; One80483a5: C7 - - Ten the1cGenevamovl $0x31c67,0x10 (%ESP) A80483ac:xx -80483ad: C7 - - - xx xx xxmovl $0x0,0x14 (%ESP) -80483b4:xx the -Long Long NUM1 =203879*203879; -80483b5: C7 - - - inB1 -movl $0xad90b171,0x18 (%ESP) -80483BC: Ad +80483bd: C7 - -1c FF FF FF MOVL $0xffffffff,0x1c (%ESP) -80483C4: FF +Long Long num2 = Muln * MULN; A80483c5: 8b - - 0c mov0xc (%ESP),%eax at80483c9:0fAf - - 0c Imul0xc (%ESP),%eax -80483ce: theC2mov%eax,%edx -80483d0: C1 FA 1fSAR$0x1f,%edx -80483d3: the - - - mov%eax,0x20 (%ESP) -80483d7: the Wu - - mov%edx,0x24 (%ESP) -Long Long num3 = MULNL * MULNL; in80483db: 8b - - - mov0x14 (%ESP),%eax -80483DF: theC1mov%eax,%ecx to80483e1:0fAF 4c - Ten Imul0x10 (%ESP),%ecx +80483e6: 8b - - - mov0x14 (%ESP),%eax -80483ea:0fAf - - Ten Imul0x10 (%ESP),%eax the80483ef: onC1Add%eax,%ecx *80483f1: 8b - - Ten mov0x10 (%ESP),%eax $80483f5: F7 - - TenMull 0x10 (%ESP)Panax Notoginseng80483f9: onD1Add%edx,%ecx -80483FB: theCamov%ecx,%edx the80483FD: the - - - mov%eax,0x28 (%ESP) + 8048401: the Wu -2cmov%edx,0x2c (%ESP) A 8048405: the - - - mov%eax,0x28 (%ESP) the 8048409: the Wu -2cmov%edx,0x2c (%ESP) + -Return0; $804840d: B8xx xx xx xx mov$0x0,%eax $}
First of all, NUM1 code (16~20 line), 203879 (31c67h) squared 41566646641 (9ad90b171h), the compiler directly calculated this result, and then take out the results of 4 bytes, stored in the NUM1, Then use the sign bit to populate the high 4 bytes.
Next we look at the code of NUM2 (21~27 line), first it put 203879 into the eax inside, and then the square result of the multiplication into the eax inside, because the EAX is 32 bits, so when the storage of the high 4-bit, only storage low 4 bytes. The next thing to do is to determine what the sign bit of this number is, and then use the shift operation to get 32 1 stored in edx, and then deposit this edx value into the high four bytes of the num2.
OK, through the above assembly code analysis, we will again from the concept of C language to analyze the code:
Long Long num2 = Muln * MULN;
First Muln is a 4-byte integer, and then Muln * Muln The result is also a four-byte integer (where overflow is generated), and then convert the result to a 8-byte integer, stored in the num2. So the result we get is also an overflow result.
After the analysis, I found that this is to get into the far ah, now also do not know how, encountered something like disassembly out to see ...
From a multiplication to analyze C language