Clang从左到右评估其参数,从右到左评估gcc。 (根据C和C ++语言规范,两者都可以,参见g++ vs intel/clang argument passing order?)有没有办法改变clang中参数评估的顺序?如果没有通过编译指示或编译器开关,也许有人可以指出我在clang代码库中的正确位置?
一些背景信息:我有一个巨大的(第三方,没有那么好记录)代码库,我正试图从gcc移植到clang,我看到了奇怪的问题。根据以前的经验,我认为至少部分问题是参数订单评估。能够在两种模式之间来回切换而不混合两个完全不同的编译器(因此可能引入许多其他问题来源)对于将问题分成两部分非常有帮助。
答案 0 :(得分:2)
clang中没有选项或编译指示来反转函数参数求值的顺序。但是现有的代码支持MSVC ABI(似乎需要从右到左进行参数评估)。以下hack(针对当前clang svn trunk的补丁)可用于根据环境变量CLANG_REVERSE_ARGS
的值反转参数评估的顺序。值1
会反转订单,值0
会保持订单不变。
Index: lib/CodeGen/CGCall.cpp
===================================================================
--- lib/CodeGen/CGCall.cpp (revision 229661)
+++ lib/CodeGen/CGCall.cpp (working copy)
@@ -2676,9 +2676,20 @@
CallExpr::const_arg_iterator ArgEnd,
const FunctionDecl *CalleeDecl,
unsigned ParamsToSkip) {
+ bool ForceReverseArgs = false;
+ const char *p = getenv("CLANG_REVERSE_ARGS");
+ if (p != nullptr) {
+ if (!strcmp(p, "1"))
+ ForceReverseArgs = true;
+ else if (strcmp(p, "0")) {
+ fprintf(stderr, "Expected $CLANG_REVERSE_ARGS to be '0' or '1'!\n");
+ exit(1);
+ }
+ }
+
// We *have* to evaluate arguments from right to left in the MS C++ ABI,
// because arguments are destroyed left to right in the callee.
- if (CGM.getTarget().getCXXABI().areArgsDestroyedLeftToRightInCallee()) {
+ if (CGM.getTarget().getCXXABI().areArgsDestroyedLeftToRightInCallee() || ForceReverseArgs) {
// Insert a stack save if we're going to need any inalloca args.
bool HasInAllocaArgs = false;
for (ArrayRef<QualType>::iterator I = ArgTypes.begin(), E = ArgTypes.end();
它甚至似乎有效:
$ cat > demo.c << EOT
#include <stdio.h>
int a() {
printf("a\n");
return 1;
}
int b() {
printf("b\n");
return 2;
}
int main() {
printf("%d%d\n", a(), b());
return 0;
}
EOT
$ CLANG_REVERSE_ARGS=0 Debug+Asserts/bin/clang demo.c && ./a.out
a
b
12
$ CLANG_REVERSE_ARGS=1 Debug+Asserts/bin/clang demo.c && ./a.out
b
a
12
我已经构建了一个大型的C ++项目,该项目在&#34; frankenstein模式下有一个很大的测试平台&#34;:一半的对象有CLANG_REVERSE_ARGS=1
,一半的对象有CLANG_REVERSE_ARGS=0
。生成的二进制文件通过了项目的测试平台。
答案 1 :(得分:0)
我认为clang仍然从右到左评估论点。
考虑以下代码:
int add(int a, int b)
{
return a+b;
}
在clang之后编译:
080483c0 <add>:
80483c0: 55 push %ebp
80483c1: 89 e5 mov %esp,%ebp
80483c3: 83 ec 08 sub $0x8,%esp
80483c6: 8b 45 0c mov 0xc(%ebp),%eax
80483c9: 8b 4d 08 mov 0x8(%ebp),%ecx
80483cc: 89 4d fc mov %ecx,-0x4(%ebp)
80483cf: 89 45 f8 mov %eax,-0x8(%ebp)
80483d2: 8b 45 fc mov -0x4(%ebp),%eax
80483d5: 03 45 f8 add -0x8(%ebp),%eax
80483d8: 83 c4 08 add $0x8,%esp
80483db: 5d pop %ebp
80483dc: c3 ret
80483dd: 0f 1f 00 nopl (%eax)
让我们考虑一下这个反编译的代码:
mov将args复制到堆栈
`
+---------+
|high |
+---------+
|101 |<-arg2
+---------+
|99 |<-arg1
+---------+
|ret |
+---------+
|ebp |
+---------+
|99 |<-a
+---------+
|101 |<-b
+---------+
|low |
+---------+
`
在gdb中打印&amp; a或&amp; b时,似乎arg1的地址高于arg2。
acctully,a和b现在位于ebp之下的堆栈中。