- 论坛徽章:
- 0
|
本帖最后由 BJSH 于 2010-11-22 22:16 编辑
虽然我很清楚不能像1里面那样使用,但我奇怪的是编译器出于什么样一种优化决策,1里面的自动变量 ...
donotblock 发表于 2010-11-22 09:48 ![]()
这和优化没关系, 只是你的测试代码 还没有更改那块栈空间而已
getint:
pushl %ebp
movl %esp, %ebp
subl $16, %esp
movl $10, -4(%ebp)
movl 8(%ebp), %eax
leal -4(%ebp), %edx
movl %edx, (%eax)
movl $0, %eax
leave
ret
c 调用函数最开始会让EBP指向栈底, 然后ESP会在最开始就偏移一定的空间, 取决于该函数的局部变量和需要调用的函数的参数以及字节对齐的问题
局部变量会在栈底分配, 比如getint的局部变量 i 的空间就是 -4(%ebp), EBP下的四字节空间
调用函数的参数 会在栈顶算偏移写入栈中
看看main函数调用printf的过程
.LC1:
.string "%d\n"
....
movl $.LC1, %eax
movl %edx, 4(%esp) ;printf的第二个参数
movl %eax, (%esp) ;printf的第一个参数 %d\n
call printf
我要说的是, 栈底和栈顶还有一段空间,
void * p = NULL;
getint(&p);
printf("%d\n", *(int *)p);
不要认为调用printf后, getint中的栈空间就完全被覆盖掉了。 正是因为这段空间, getint中的局部变量 i 才没有被覆盖。 这不是编译器的什么优化
假如:
void * p = NULL;
void * p1 = NULL;
getint(&p);
getstring(&p1);
printf("%d\n", *(int *)p);
printf("%s\n", (char *)p1);
在getint后 调用一下其它的函数, 然后再打印, 你看看 还是不是10,
甚至你还可以精心构造去改变那块栈空间
比如:
int getint(void **p){
int i = 10;
(*p) = &i;
return 0;
}
int getstring2(void **p){
char s[] = {0x12,0x34,0x56,0x78};
(*p) = s;
return 0;
}
int main(int argc, char * argv[])
{
void * p = NULL;
void * p1 = NULL;
getint(&p);
getstring2(&p1);
printf("%X\n", *(int *)p);
printf("%s\n", (char *)p1);
return 0;
}
在getstring2中讲那四字节空间改为 0x12, 0x34, 0x56, 0x78
输出结果不是10 而是 : %x : 78563412
================================
或者这么说, 在你调用printf之前, 给printf的参数已经被复制到了 栈底的上方, 调用printf后确实会把getint的栈空间覆盖掉, 但是执行过程中用到的是EBP上方的参数, 而不再是原来的位置
比如:
nt main(int argc, char * argv[])
{
void * p = NULL;
getint(&p);
printf("%d\n", *(int *)p);
printf("%d\n", *(int *)p);
return 0;
}
连续打印两次, 第一次是10, 第二次就不再是了。 |
|