今天在看雪看到一个帖:
引用
#include <iostream>
using namespace std;
int main()
{
cout<<"hello world!"<<endl;
__asm jmp main
return 0;
}
这个函数为啥不是死循环?怎么执行一会就结束?
按理说这应该是一个死循环,但编译后运行了一下却一会儿就退出了
小小改动一下,加入一个计数用的变量,再运行一下
#include <iostream>
using namespace std;
int a=0;
int main()
{
a++;
cout<<a<<endl;
__asm jmp main
return 0;
}
在debug编译方式下运行到退出的时候,a的值是12918,而在release编译方式的情况下,则是19889.
这问题太诡异了!
但真的诡异吗?
转到汇编语言下看看下(本来用VC++6就可以看了,但用着怎么都不顺手,于是就换成od)
main函数的开头如下:
debug方式:
引用
00401560 > > \55 push ebp
00401561 . 8BEC mov ebp, esp
00401563 . 83EC 40 sub esp, 40
00401566 . 53 push ebx
00401567 . 56 push esi
00401568 . 57 push edi
release方式:
引用
00401000 $ 55 push ebp
00401001 . 8BEC mov ebp, esp
00401003 . 83EC 24 sub esp, 24
00401006 . 53 push ebx
00401007 . 56 push esi
00401008 . 57 push edi
这两段代码可以说是熟悉得不能再熟悉的了函数开头的保存寄存器以及开辟临时变量的代码。而在函数结束的时候保存在栈中的值会弹出来。
于是上面那个死循环的问题就出现了:每个循环都往栈中压几次,但却又得不到释放,而栈空间不是无限大的,于是乎,程序就只好退出了。而用od运行后得到的终止代码是C0000005,这正是访问了无效的内存的错误代码。
为了再验证一下,再做一个小学的数学题:
在debug方式下,每次循环将80个字节压到栈中,而在循环12918次后,总共填了1033440个字节到栈中;
在release方式下,每次循环将52个字节压到栈中,而在循环19889次后,总共填了1034228个字节到栈中。
而这两个数值正好接近了1mb,这正是VC++6中默认的栈大小!
然后,再改动一下代码
#include <iostream>
using namespace std;
int a=0;
int main()
{
for(;;)
{
a++;
cout<<a<<endl;
__asm push eax
}
return 0;
}
同样是运行了一会儿就退出了,而由于每次循环都只是往栈中压进了4个字节,所以两种编译方式得到的结果差别不大,均为250000左右。