32位系统,eax,ecx,edx,ebx这些寄存器都是32位的,而要使用一个64位的变量,需要用到2个寄存器,或者一个寄存器用到2次,往往在某些地方就会出现意想不到的问题。
今天参加了CSDN的英雄会,有幸见了些名人,回到家上CSDN,看到个帖子
http://topic.csdn.net/u/20080905/16/3823c75d-c33b-4ea0-83b1-8386d03e6c6c.html
具体内容:
题目:
1、不能用库函数,要求达到效率o(1);
2、将符号'@'插入字符串ptr的首位,字符串ptr原内容按照原来的顺序排在'@'之后.
![None.gif](http://www.cppblog.com/Images/OutliningIndicators/None.gif)
![ExpandedBlockStart.gif](http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockStart.gif)
![ContractedBlock.gif](http://www.cppblog.com/Images/OutliningIndicators/ContractedBlock.gif)
![dot.gif](http://www.cppblog.com/Images/dot.gif)
![InBlock.gif](http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif)
![ExpandedBlockEnd.gif](http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockEnd.gif)
![None.gif](http://www.cppblog.com/Images/OutliningIndicators/None.gif)
![ExpandedBlockStart.gif](http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockStart.gif)
![ContractedBlock.gif](http://www.cppblog.com/Images/OutliningIndicators/ContractedBlock.gif)
![dot.gif](http://www.cppblog.com/Images/dot.gif)
![InBlock.gif](http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif)
![InBlock.gif](http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif)
![InBlock.gif](http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif)
![InBlock.gif](http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif)
![ExpandedBlockEnd.gif](http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockEnd.gif)
![None.gif](http://www.cppblog.com/Images/OutliningIndicators/None.gif)
我很容易想到
![None.gif](http://www.cppblog.com/Images/OutliningIndicators/None.gif)
![ExpandedBlockStart.gif](http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockStart.gif)
![ContractedBlock.gif](http://www.cppblog.com/Images/OutliningIndicators/ContractedBlock.gif)
![dot.gif](http://www.cppblog.com/Images/dot.gif)
![InBlock.gif](http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif)
![InBlock.gif](http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif)
![ExpandedBlockEnd.gif](http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockEnd.gif)
可是结果却很令人惊讶,输出@abcddfg,有一个字节不对。仔细一想,应该是把64位变量放到2个寄存器中了。
用OD反一下,看下主函数里的关键地方,OH,前面分配栈的一句是sub esp,18
1
00401030
/
$ A1 DCB64000 mov eax, dword ptr [40B6DC]
2
00401035
|?
8945
EC mov dword ptr [ebp
-
14
], eax
3
00401038
|?
8B0D E0B64000 mov ecx, dword ptr [40B6E0]
4
0040103E
|?
894D F0 mov dword ptr [ebp
-
10
], ecx
5
00401041
|?
33D2 xor edx, edx ; namespac.0040E2B8
6
00401043
|?
8955
F4 mov dword ptr [ebp
-
C], edx
7
00401046
|?
8955
F8 mov dword ptr [ebp
-
8
], edx
8
00401049
|?
C645 EB
40
mov
byte
ptr [ebp
-
15
],
40
9
0040104D
|?
0FB645 EB movzx eax,
byte
ptr [ebp
-
15
]
10
00401051
|
.
50
push eax
11
00401052
|?
8D4D EC lea ecx, dword ptr [ebp
-
14
]
12
00401055
|?
51
push ecx
13
00401056
|
. E8 A5FFFFFF call
00401000
14
0040105B
|?
83C4
08
add esp,
8
第一行,0x04B6DC就是常量字符串"abcdefg"的地址,把分2次每次4个送入栈,完成char ptr[16]的初始化,第8 9行是把
'@'放入eax,第10行把最后一个参数入栈,也就是@,11行把ebp
-
14也就是ptr传给ecx,12行把ptr入栈,也就是倒数第二个参数,然后调用下面的函数。
![None.gif](http://www.cppblog.com/Images/OutliningIndicators/None.gif)
2
![None.gif](http://www.cppblog.com/Images/OutliningIndicators/None.gif)
3
![None.gif](http://www.cppblog.com/Images/OutliningIndicators/None.gif)
4
![None.gif](http://www.cppblog.com/Images/OutliningIndicators/None.gif)
5
![None.gif](http://www.cppblog.com/Images/OutliningIndicators/None.gif)
6
![None.gif](http://www.cppblog.com/Images/OutliningIndicators/None.gif)
7
![None.gif](http://www.cppblog.com/Images/OutliningIndicators/None.gif)
8
![None.gif](http://www.cppblog.com/Images/OutliningIndicators/None.gif)
9
![None.gif](http://www.cppblog.com/Images/OutliningIndicators/None.gif)
10
![None.gif](http://www.cppblog.com/Images/OutliningIndicators/None.gif)
11
![None.gif](http://www.cppblog.com/Images/OutliningIndicators/None.gif)
12
![None.gif](http://www.cppblog.com/Images/OutliningIndicators/None.gif)
13
![None.gif](http://www.cppblog.com/Images/OutliningIndicators/None.gif)
14
![None.gif](http://www.cppblog.com/Images/OutliningIndicators/None.gif)
1
00401000
/
$
55
push ebp
2
00401001
|
. 8BEC mov ebp, esp
3
00401003
|
. 8B45
08
mov eax, dword ptr [ebp
+
8
]
4
00401006
|
. 8B4D
08
mov ecx, dword ptr [ebp
+
8
]
5
00401009
|?
8B11 mov edx, dword ptr [ecx]
6
0040100B
|
.
8950
01
mov dword ptr [eax
+
1
], edx
7
0040100E
|?
8B49
04
mov ecx, dword ptr [ecx
+
4
]
8
00401011
|?
8948
05
mov dword ptr [eax
+
5
], ecx
9
00401014
|?
8B55
08
mov edx, dword ptr [ebp
+
8
]
10
00401017
|
. 8A45 0C mov al,
byte
ptr [ebp
+
C]
11
0040101A
|
.
8802
mov
byte
ptr [edx], al
12
0040101C
|?
5D pop ebp
13
0040101D
|
. C3 retn
3 4行把刚才入栈的ptr指针存入eax,ecx
![None.gif](http://www.cppblog.com/Images/OutliningIndicators/None.gif)
2
![None.gif](http://www.cppblog.com/Images/OutliningIndicators/None.gif)
3
![None.gif](http://www.cppblog.com/Images/OutliningIndicators/None.gif)
4
![None.gif](http://www.cppblog.com/Images/OutliningIndicators/None.gif)
5
![None.gif](http://www.cppblog.com/Images/OutliningIndicators/None.gif)
6
![None.gif](http://www.cppblog.com/Images/OutliningIndicators/None.gif)
7
![None.gif](http://www.cppblog.com/Images/OutliningIndicators/None.gif)
8
![None.gif](http://www.cppblog.com/Images/OutliningIndicators/None.gif)
9
![None.gif](http://www.cppblog.com/Images/OutliningIndicators/None.gif)
10
![None.gif](http://www.cppblog.com/Images/OutliningIndicators/None.gif)
11
![None.gif](http://www.cppblog.com/Images/OutliningIndicators/None.gif)
12
![None.gif](http://www.cppblog.com/Images/OutliningIndicators/None.gif)
13
![None.gif](http://www.cppblog.com/Images/OutliningIndicators/None.gif)
第5行把char ptr[16]的前4个字节abcd存入edx,也就是0x64636261,注意高低位
然后把edx里的4个字节的数,写入ptr+1的位置,可见问题就出现在这里,一下写入4个字节,在ptr+1到ptr+4的位置,由于*(ptr+4)里的内容并未保存,所以被覆盖了,导致后面第2次读取的数据不正确,最后的结果也不会输出正确
看了下边网友的回帖,比较好的方法就是用移位,本来是数,移位肯定不会出问题,使用的是shld双精度左移指令(为什么是左移不是右移?同样注意高低位),保证数据不会丢失
![None.gif](http://www.cppblog.com/Images/OutliningIndicators/None.gif)
![ExpandedBlockStart.gif](http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockStart.gif)
![ContractedBlock.gif](http://www.cppblog.com/Images/OutliningIndicators/ContractedBlock.gif)
![dot.gif](http://www.cppblog.com/Images/dot.gif)
![InBlock.gif](http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif)
![InBlock.gif](http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif)
![ExpandedBlockEnd.gif](http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockEnd.gif)
可以看出,在32位系统使用64位变量需要很注意,尤其是在赋值的时候,比如我上边的例子。往往在一个大工程里,出现这样的问题,很难查出原因来,因此,需要格外注意。还有在多线程的时候,一个读一个写,由于使用2个寄存器,就有可能在一个写线程操作到一个64位数的32位的时候,线程正好切换到读线程,导致产生一些奇怪的数据,而且这种奇怪的情况并不是每次运行都能体现出来,造成的损失可想而知。所以对跨线程使用64位变量必须严格进行同步。
by greatws