遵循简短的c程序:
void foo(int a, int b) {
printf("a = %p b = %p\n", &a, &b);
}
main() {
foo(1, 2);
}
好的,现在我用gdb来查看这个程序。我得到了输出:
a = 0x7fff5fbff9ac b = 0x7fff5fbff9a8
并在输出后停止执行(在foo()中)。现在我检查了0x7fff5fbff9ac,内容是:
1 ....正确
然后是0x7fff5fbff9a8和内容:
2 ...正确
现在我想查看函数的返回地址并检查(a + 4个字节):
x / g 0x7fff5fbff9b1(8字节!!地址,因此“g”(巨字))
及其内容为:
(gdb) x/g 0x7fff5fbff9b1
0x7fff5fbff9b1: 0xd700007fff5fbff9
但是这不是主要的回报!我的错在哪里?
答案 0 :(得分:3)
你的问题中有很多错误的假设。
您假设整数参数在返回地址上方的堆栈上传递(因为它们位于许多 - 不是所有 - x86 ABI下默认调用约定)。如果是这种情况,那么在调用之后,您的堆栈将如下所示:
// stack frame of main( )
// ...
value of b
value of a
return address <--- stack pointer
但是,您的假设不正确。您已将代码编译为64位可执行文件(由您正在打印的指针的大小证明)。根据OS X ABI,在64位Intel可执行文件中,前几个整数参数在寄存器中传递,而不是在堆栈中传递。因此,在调用之后,堆栈实际看起来像这样:
// stack frame of main( )
// ...
return address <--- stack pointer
由于你取a
和b
的地址,它们将在调用printf( )
之前的某个时刻写入堆栈(除非编译器真的< / em>聪明,并且意识到它实际上并不需要传递printf( )
有效指针,因为它不会使用指向的值,但是这将是非常邪恶的,因为优化会去),但你真的不喜欢知道它们相对于返回地址的位置;实际上,因为64位ABI提供了红色区域,所以您甚至不知道它们是在堆栈指针之上还是之下。因此,在您打印出a和b的地址时,您的堆栈如下所示:
// stack frame of main( )
// ...
return address |
// ... |
// a and b are somewhere down here | <-- stack pointer points somewhere in here
// ... |
一般来说,C语言标准没有说明堆栈布局,甚至根本不需要堆栈。您无法通过C代码以任何便携方式获得此类信息。
答案 1 :(得分:1)
首先,&a + 4
是0x7FFF5FBFF9B0
,所以你看起来偏离了你想象的一个字节。
其次,保存的帧指针位于a
和返回地址之间,这是您看到的值。
答案 2 :(得分:1)
你做错了是在给定平台上对堆栈框架的布局做出一堆不正确和随机的假设。你在哪里得到关于“a + 4
字节”位置据说持有返回地址的奇怪想法?
如果您真的想这样做,请获取您的平台的文档(或进行一些逆向工程),以找出存储返回地址的确切位置和方式。进行随机猜测然后询问其他人为什么你的随机猜测不能产生结果,你出于某种原因预期并不是一种富有成效的方法。