有没有谁注意到这个问题,请帮我分析下?
5 个解决方案
#1
gcc版本 4.1.2
#2
你怎么看的地址分配? 反汇编看看
#3
分析了下好像是这样的:如果某变量有取地址操作,则将此变量尽量放在栈顶(相对于没有取地址操作的变量)
比如变量:int a,b,c,d,e,f;
如果 a,c,f 有取地址操作,则栈分配应该是这样的:
b
d
e
a
c
f
上图栈顶的方向是向下的。
这是我的C代码
objdump的main函数如下:
比如变量:int a,b,c,d,e,f;
如果 a,c,f 有取地址操作,则栈分配应该是这样的:
b
d
e
a
c
f
上图栈顶的方向是向下的。
这是我的C代码
#include <stdio.h>
void test(int x,int y)
{
printf("x:%d\n",x);
printf("y:%d\n",y);
}
int main()
{
int a = 0;
int b = 0;
int c = 0;
char x = 0;
char y = 0;
char z = 0;
test(a,b);
printf("a:%p\n",&a);
/* printf("b:%p\n",&b);
printf("c:%p\n",&c);
printf("x:%p\n",&z);
printf("y:%p\n",&y);
printf("z:%p\n",&z);
*/
return 0;
}
objdump的main函数如下:
int main()
{
804846a: 55 push %ebp
804846b: 89 e5 mov %esp,%ebp
804846d: 83 e4 f0 and $0xfffffff0,%esp
8048470: 83 ec 20 sub $0x20,%esp
int a = 0;
8048473: c7 44 24 10 00 00 00 movl $0x0,0x10(%esp)
804847a: 00
int b = 0;
804847b: c7 44 24 1c 00 00 00 movl $0x0,0x1c(%esp)
8048482: 00
int c = 0;
8048483: c7 44 24 18 00 00 00 movl $0x0,0x18(%esp)
804848a: 00
char x = 0;
804848b: c6 44 24 17 00 movb $0x0,0x17(%esp)
char y = 0;
8048490: c6 44 24 16 00 movb $0x0,0x16(%esp)
char z = 0;
8048495: c6 44 24 15 00 movb $0x0,0x15(%esp)
test(a,b);
804849a: 8b 44 24 10 mov 0x10(%esp),%eax
804849e: 8b 54 24 1c mov 0x1c(%esp),%edx
80484a2: 89 54 24 04 mov %edx,0x4(%esp)
80484a6: 89 04 24 mov %eax,(%esp)
80484a9: e8 8e ff ff ff call 804843c <test>
printf("a:%p\n",&a);
80484ae: 8d 44 24 10 lea 0x10(%esp),%eax
80484b2: 89 44 24 04 mov %eax,0x4(%esp)
80484b6: c7 04 24 6c 85 04 08 movl $0x804856c,(%esp)
80484bd: e8 4e fe ff ff call 8048310 <printf@plt>
printf("c:%p\n",&c);
printf("x:%p\n",&z);
printf("y:%p\n",&y);
printf("z:%p\n",&z);
*/
return 0;
80484c2: b8 00 00 00 00 mov $0x0,%eax
}
#4
这个好像没什么规律啊。
楼上的嗲吗我试验了两个系统,结果如下,没有对取地址的变量特殊处理吧。
只是看起来,不同版本的gcc对局部变量的内存分配顺序策略有所不同。
FreeBSD8.1下gcc 4.2.1
Linux 2.6.32-131.0.15.el6.x86_64 x86_64, gcc version 4.4.5 20110214 (Red Hat 4.4.5-6) (GCC)
楼上的嗲吗我试验了两个系统,结果如下,没有对取地址的变量特殊处理吧。
只是看起来,不同版本的gcc对局部变量的内存分配顺序策略有所不同。
FreeBSD8.1下gcc 4.2.1
08048450 <main>:
int main()
{
8048450: 8d 4c 24 04 lea 0x4(%esp),%ecx
8048454: 83 e4 f0 and $0xfffffff0,%esp
8048457: ff 71 fc pushl 0xfffffffc(%ecx)
804845a: 55 push %ebp
804845b: 89 e5 mov %esp,%ebp
804845d: 51 push %ecx
804845e: 83 ec 24 sub $0x24,%esp
int a = 0;
8048461: c7 45 ec 00 00 00 00 movl $0x0,0xffffffec(%ebp)
int b = 0;
8048468: c7 45 f0 00 00 00 00 movl $0x0,0xfffffff0(%ebp)
int c = 0;
804846f: c7 45 f4 00 00 00 00 movl $0x0,0xfffffff4(%ebp)
char x = 0;
8048476: c6 45 f9 00 movb $0x0,0xfffffff9(%ebp)
char y = 0;
804847a: c6 45 fa 00 movb $0x0,0xfffffffa(%ebp)
char z = 0;
804847e: c6 45 fb 00 movb $0x0,0xfffffffb(%ebp)
test(a,b);
8048482: 8b 55 ec mov 0xffffffec(%ebp),%edx
8048485: 8b 45 f0 mov 0xfffffff0(%ebp),%eax
8048488: 89 44 24 04 mov %eax,0x4(%esp)
804848c: 89 14 24 mov %edx,(%esp)
804848f: e8 8c ff ff ff call 8048420 <test>
printf("a:%p\n",&a);
8048494: 8d 45 ec lea 0xffffffec(%ebp),%eax
8048497: 89 44 24 04 mov %eax,0x4(%esp)
804849b: c7 04 24 5d 85 04 08 movl $0x804855d,(%esp)
80484a2: e8 25 fe ff ff call 80482cc <_init+0x34>
/*
printf("b:%p\n",&b);
printf("c:%p\n",&c);
printf("x:%p\n",&z);
printf("y:%p\n",&y);
printf("z:%p\n",&z);
*/
return 0;
80484a7: b8 00 00 00 00 mov $0x0,%eax
}
Linux 2.6.32-131.0.15.el6.x86_64 x86_64, gcc version 4.4.5 20110214 (Red Hat 4.4.5-6) (GCC)
0000000000400502 <main>:
int main()
{
400502: 55 push %rbp
400503: 48 89 e5 mov %rsp,%rbp
400506: 48 83 ec 10 sub $0x10,%rsp
int a = 0;
40050a: c7 45 f0 00 00 00 00 movl $0x0,-0x10(%rbp)
int b = 0;
400511: c7 45 f4 00 00 00 00 movl $0x0,-0xc(%rbp)
int c = 0;
400518: c7 45 f8 00 00 00 00 movl $0x0,-0x8(%rbp)
char x = 0;
40051f: c6 45 fd 00 movb $0x0,-0x3(%rbp)
char y = 0;
400523: c6 45 fe 00 movb $0x0,-0x2(%rbp)
char z = 0;
400527: c6 45 ff 00 movb $0x0,-0x1(%rbp)
test(a,b);
40052b: 8b 45 f0 mov -0x10(%rbp),%eax
40052e: 8b 55 f4 mov -0xc(%rbp),%edx
400531: 89 d6 mov %edx,%esi
400533: 89 c7 mov %eax,%edi
400535: e8 8a ff ff ff callq 4004c4 <test>
printf("a:%p\n",&a);
40053a: b8 64 06 40 00 mov $0x400664,%eax
40053f: 48 8d 55 f0 lea -0x10(%rbp),%rdx
400543: 48 89 d6 mov %rdx,%rsi
400546: 48 89 c7 mov %rax,%rdi
400549: b8 00 00 00 00 mov $0x0,%eax
40054e: e8 65 fe ff ff callq 4003b8 <printf@plt>
printf("c:%p\n",&c);
printf("x:%p\n",&z);
printf("y:%p\n",&y);
printf("z:%p\n",&z);
*/
return 0;
400553: b8 00 00 00 00 mov $0x0,%eax
}
#5
感谢mymtom的帮助!
你的第二个系统好像就对取地址的变量有了特殊操作,局部变量分配顺序是从栈顶到栈底,不管怎么说b应该是在变量队列的中间,现在却在栈顶。
这个是不是有的GCC版本会有这样的操作,但是其中的原因却有些觉历不明啊,我胡乱猜测下原因,不知道对不对,这样做可能是想把有取地址操作的变量放在一块,系统在做取地址操作的时候,一次也把附近的变量也做取地址操作,避免重复的劳作。
int a = 0;
40050a: c7 45 f0 00 00 00 00 movl $0x0,-0x10(%rbp)
int b = 0;
400511: c7 45 f4 00 00 00 00 movl $0x0,-0xc(%rbp)
int c = 0;
400518: c7 45 f8 00 00 00 00 movl $0x0,-0x8(%rbp)
char x = 0;
#1
gcc版本 4.1.2
#2
你怎么看的地址分配? 反汇编看看
#3
分析了下好像是这样的:如果某变量有取地址操作,则将此变量尽量放在栈顶(相对于没有取地址操作的变量)
比如变量:int a,b,c,d,e,f;
如果 a,c,f 有取地址操作,则栈分配应该是这样的:
b
d
e
a
c
f
上图栈顶的方向是向下的。
这是我的C代码
objdump的main函数如下:
比如变量:int a,b,c,d,e,f;
如果 a,c,f 有取地址操作,则栈分配应该是这样的:
b
d
e
a
c
f
上图栈顶的方向是向下的。
这是我的C代码
#include <stdio.h>
void test(int x,int y)
{
printf("x:%d\n",x);
printf("y:%d\n",y);
}
int main()
{
int a = 0;
int b = 0;
int c = 0;
char x = 0;
char y = 0;
char z = 0;
test(a,b);
printf("a:%p\n",&a);
/* printf("b:%p\n",&b);
printf("c:%p\n",&c);
printf("x:%p\n",&z);
printf("y:%p\n",&y);
printf("z:%p\n",&z);
*/
return 0;
}
objdump的main函数如下:
int main()
{
804846a: 55 push %ebp
804846b: 89 e5 mov %esp,%ebp
804846d: 83 e4 f0 and $0xfffffff0,%esp
8048470: 83 ec 20 sub $0x20,%esp
int a = 0;
8048473: c7 44 24 10 00 00 00 movl $0x0,0x10(%esp)
804847a: 00
int b = 0;
804847b: c7 44 24 1c 00 00 00 movl $0x0,0x1c(%esp)
8048482: 00
int c = 0;
8048483: c7 44 24 18 00 00 00 movl $0x0,0x18(%esp)
804848a: 00
char x = 0;
804848b: c6 44 24 17 00 movb $0x0,0x17(%esp)
char y = 0;
8048490: c6 44 24 16 00 movb $0x0,0x16(%esp)
char z = 0;
8048495: c6 44 24 15 00 movb $0x0,0x15(%esp)
test(a,b);
804849a: 8b 44 24 10 mov 0x10(%esp),%eax
804849e: 8b 54 24 1c mov 0x1c(%esp),%edx
80484a2: 89 54 24 04 mov %edx,0x4(%esp)
80484a6: 89 04 24 mov %eax,(%esp)
80484a9: e8 8e ff ff ff call 804843c <test>
printf("a:%p\n",&a);
80484ae: 8d 44 24 10 lea 0x10(%esp),%eax
80484b2: 89 44 24 04 mov %eax,0x4(%esp)
80484b6: c7 04 24 6c 85 04 08 movl $0x804856c,(%esp)
80484bd: e8 4e fe ff ff call 8048310 <printf@plt>
printf("c:%p\n",&c);
printf("x:%p\n",&z);
printf("y:%p\n",&y);
printf("z:%p\n",&z);
*/
return 0;
80484c2: b8 00 00 00 00 mov $0x0,%eax
}
#4
这个好像没什么规律啊。
楼上的嗲吗我试验了两个系统,结果如下,没有对取地址的变量特殊处理吧。
只是看起来,不同版本的gcc对局部变量的内存分配顺序策略有所不同。
FreeBSD8.1下gcc 4.2.1
Linux 2.6.32-131.0.15.el6.x86_64 x86_64, gcc version 4.4.5 20110214 (Red Hat 4.4.5-6) (GCC)
楼上的嗲吗我试验了两个系统,结果如下,没有对取地址的变量特殊处理吧。
只是看起来,不同版本的gcc对局部变量的内存分配顺序策略有所不同。
FreeBSD8.1下gcc 4.2.1
08048450 <main>:
int main()
{
8048450: 8d 4c 24 04 lea 0x4(%esp),%ecx
8048454: 83 e4 f0 and $0xfffffff0,%esp
8048457: ff 71 fc pushl 0xfffffffc(%ecx)
804845a: 55 push %ebp
804845b: 89 e5 mov %esp,%ebp
804845d: 51 push %ecx
804845e: 83 ec 24 sub $0x24,%esp
int a = 0;
8048461: c7 45 ec 00 00 00 00 movl $0x0,0xffffffec(%ebp)
int b = 0;
8048468: c7 45 f0 00 00 00 00 movl $0x0,0xfffffff0(%ebp)
int c = 0;
804846f: c7 45 f4 00 00 00 00 movl $0x0,0xfffffff4(%ebp)
char x = 0;
8048476: c6 45 f9 00 movb $0x0,0xfffffff9(%ebp)
char y = 0;
804847a: c6 45 fa 00 movb $0x0,0xfffffffa(%ebp)
char z = 0;
804847e: c6 45 fb 00 movb $0x0,0xfffffffb(%ebp)
test(a,b);
8048482: 8b 55 ec mov 0xffffffec(%ebp),%edx
8048485: 8b 45 f0 mov 0xfffffff0(%ebp),%eax
8048488: 89 44 24 04 mov %eax,0x4(%esp)
804848c: 89 14 24 mov %edx,(%esp)
804848f: e8 8c ff ff ff call 8048420 <test>
printf("a:%p\n",&a);
8048494: 8d 45 ec lea 0xffffffec(%ebp),%eax
8048497: 89 44 24 04 mov %eax,0x4(%esp)
804849b: c7 04 24 5d 85 04 08 movl $0x804855d,(%esp)
80484a2: e8 25 fe ff ff call 80482cc <_init+0x34>
/*
printf("b:%p\n",&b);
printf("c:%p\n",&c);
printf("x:%p\n",&z);
printf("y:%p\n",&y);
printf("z:%p\n",&z);
*/
return 0;
80484a7: b8 00 00 00 00 mov $0x0,%eax
}
Linux 2.6.32-131.0.15.el6.x86_64 x86_64, gcc version 4.4.5 20110214 (Red Hat 4.4.5-6) (GCC)
0000000000400502 <main>:
int main()
{
400502: 55 push %rbp
400503: 48 89 e5 mov %rsp,%rbp
400506: 48 83 ec 10 sub $0x10,%rsp
int a = 0;
40050a: c7 45 f0 00 00 00 00 movl $0x0,-0x10(%rbp)
int b = 0;
400511: c7 45 f4 00 00 00 00 movl $0x0,-0xc(%rbp)
int c = 0;
400518: c7 45 f8 00 00 00 00 movl $0x0,-0x8(%rbp)
char x = 0;
40051f: c6 45 fd 00 movb $0x0,-0x3(%rbp)
char y = 0;
400523: c6 45 fe 00 movb $0x0,-0x2(%rbp)
char z = 0;
400527: c6 45 ff 00 movb $0x0,-0x1(%rbp)
test(a,b);
40052b: 8b 45 f0 mov -0x10(%rbp),%eax
40052e: 8b 55 f4 mov -0xc(%rbp),%edx
400531: 89 d6 mov %edx,%esi
400533: 89 c7 mov %eax,%edi
400535: e8 8a ff ff ff callq 4004c4 <test>
printf("a:%p\n",&a);
40053a: b8 64 06 40 00 mov $0x400664,%eax
40053f: 48 8d 55 f0 lea -0x10(%rbp),%rdx
400543: 48 89 d6 mov %rdx,%rsi
400546: 48 89 c7 mov %rax,%rdi
400549: b8 00 00 00 00 mov $0x0,%eax
40054e: e8 65 fe ff ff callq 4003b8 <printf@plt>
printf("c:%p\n",&c);
printf("x:%p\n",&z);
printf("y:%p\n",&y);
printf("z:%p\n",&z);
*/
return 0;
400553: b8 00 00 00 00 mov $0x0,%eax
}
#5
感谢mymtom的帮助!
你的第二个系统好像就对取地址的变量有了特殊操作,局部变量分配顺序是从栈顶到栈底,不管怎么说b应该是在变量队列的中间,现在却在栈顶。
这个是不是有的GCC版本会有这样的操作,但是其中的原因却有些觉历不明啊,我胡乱猜测下原因,不知道对不对,这样做可能是想把有取地址操作的变量放在一块,系统在做取地址操作的时候,一次也把附近的变量也做取地址操作,避免重复的劳作。
int a = 0;
40050a: c7 45 f0 00 00 00 00 movl $0x0,-0x10(%rbp)
int b = 0;
400511: c7 45 f4 00 00 00 00 movl $0x0,-0xc(%rbp)
int c = 0;
400518: c7 45 f8 00 00 00 00 movl $0x0,-0x8(%rbp)
char x = 0;