【发布时间】:2015-07-09 18:12:22
【问题描述】:
关于 C 调用约定和 64/32 位编译之间可能未定义的行为,我有一些奇怪的问题。 首先是我的代码:
int f() { return 0; }
int main()
{
int x = 42;
return f(x);
}
如您所见,我使用参数调用 f 而 f 不带参数。 我的第一个问题是这个参数在调用它时是否真的被赋予了 f。
神秘的线条
经过一点 objdump 我得到了奇怪的结果。 将 x 作为 f 的参数传递时:
00000000004004b6 <f>:
4004b6: 55 push %rbp
4004b7: 48 89 e5 mov %rsp,%rbp
4004ba: b8 00 00 00 00 mov $0x0,%eax
4004bf: 5d pop %rbp
4004c0: c3 retq
00000000004004c1 <main>:
4004c1: 55 push %rbp
4004c2: 48 89 e5 mov %rsp,%rbp
4004c5: 48 83 ec 10 sub $0x10,%rsp
4004c9: c7 45 fc 2a 00 00 00 movl $0x2a,-0x4(%rbp)
4004d0: 8b 45 fc mov -0x4(%rbp),%eax
4004d3: 89 c7 mov %eax,%edi
4004d5: b8 00 00 00 00 mov $0x0,%eax
4004da: e8 d7 ff ff ff callq 4004b6 <f>
4004df: c9 leaveq
4004e0: c3 retq
4004e1: 66 2e 0f 1f 84 00 00 nopw %cs:0x0(%rax,%rax,1)
4004e8: 00 00 00
4004eb: 0f 1f 44 00 00 nopl 0x0(%rax,%rax,1)
不传递 x 作为参数:
00000000004004b6 <f>:
4004b6: 55 push %rbp
4004b7: 48 89 e5 mov %rsp,%rbp
4004ba: b8 00 00 00 00 mov $0x0,%eax
4004bf: 5d pop %rbp
4004c0: c3 retq
00000000004004c1 <main>:
4004c1: 55 push %rbp
4004c2: 48 89 e5 mov %rsp,%rbp
4004c5: 48 83 ec 10 sub $0x10,%rsp
4004c9: c7 45 fc 2a 00 00 00 movl $0x2a,-0x4(%rbp)
4004d0: b8 00 00 00 00 mov $0x0,%eax
4004d5: e8 dc ff ff ff callq 4004b6 <f>
4004da: c9 leaveq
4004db: c3 retq
4004dc: 0f 1f 40 00 nopl 0x0(%rax)
如我们所见:
4004d0: 8b 45 fc mov -0x4(%rbp),%eax
4004d3: 89 c7 mov %eax,%edi
当我用 x 调用 f 时会发生这种情况,但因为我在汇编方面不是很好,所以我不太了解这些行。
64/32 位悖论
否则我尝试了其他方法并开始打印我的程序堆栈。
将 x 赋予 f 的堆栈(以 64 位编译):
Address of x: ffcf115c
ffcf1128: 0 0
ffcf1130: -3206820 0
ffcf1138: -3206808 134513826
ffcf1140: 42 -3206820
ffcf1148: -145495616 134513915
ffcf1150: 1 -3206636
ffcf1158: -3206628 42
ffcf1160: -143903780 -3206784
没有给 f 的 x 堆栈(以 64 位编译):
Address of x: 3c19183c
3c191818: 0 0
3c191820: 1008277568 32766
3c191828: 4195766 0
3c191830: 1008277792 32766
3c191838: 0 42
3c191840: 4195776 0
由于某种原因,32 位 x 似乎被压入堆栈。
将 x 赋予 f 的堆栈(以 32 位编译):
Address of x: ffdc8eac
ffdc8e78: 0 0
ffdc8e80: -2322772 0
ffdc8e88: -2322760 134513826
ffdc8e90: 42 -2322772
ffdc8e98: -145086016 134513915
ffdc8ea0: 1 -2322588
ffdc8ea8: -2322580 42
ffdc8eb0: -143494180 -2322736
为什么 x 出现在 32 而不是 64 ???
打印代码:http://paste.awesom.eu/yayg/QYw6&ln
我为什么要问这么愚蠢的问题?
- 首先是因为我没有找到任何标准来回答我的问题
- 其次,考虑在 C 中调用可变参数函数而不给出参数计数。
- 最后但同样重要的是,我认为未定义的行为很有趣。
感谢您花时间阅读到这里,并帮助我理解某些东西或让我意识到我的问题毫无意义。
【问题讨论】:
-
这不是讨论论坛。调用 UB 根本没有任何价值。
-
@yayg 编译器应该发出诊断消息,因为它看到了函数原型。
-
@Olaf 其实我也不知道这是不是UB
-
@VladfromMoscow 使用 -Wall -Wextra gcc 不会引发任何错误或警告
-
“我认为未定义的行为很有趣。” - 不是当你在调试别人的代码时,它看似无休止地调用它的赏金;相信我。
标签: c 32bit-64bit stack-trace undefined-behavior calling-convention