我可以改变clang中参数评估的顺序吗?

时间:2015-02-17 20:43:43

标签: clang

Clang从左到右评估其参数,从右到左评估gcc。 (根据C和C ++语言规范,两者都可以,参见g++ vs intel/clang argument passing order?)有没有办法改变clang中参数评估的顺序?如果没有通过编译指示或编译器开关,也许有人可以指出我在clang代码库中的正确位置?


一些背景信息:我有一个巨大的(第三方,没有那么好记录)代码库,我正试图从gcc移植到clang,我看到了奇怪的问题。根据以前的经验,我认为至少部分问题是参数订单评估。能够在两种模式之间来回切换而不混合两个完全不同的编译器(因此可能引入许多其他问题来源)对于将问题分成两部分非常有帮助。

2 个答案:

答案 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之下的堆栈中。