Clang 我可以更改参数计算的顺序吗?

Clang 我可以更改参数计算的顺序吗?,clang,Clang,Clang从左到右评估其参数,gcc从右到左评估其参数。(根据C和C++语言规范都可以),有没有办法改变CLAN中的参数评估顺序?如果不是通过pragma或编译器开关,也许有人可以给我指出代码库中正确的位置 一些背景信息:我有一个巨大的(第三方,没有那么好的文档)代码库,我试图从gcc移植到clang,我发现了一些奇怪的问题。根据以前的经验,我认为问题的一部分是论证顺序的评估。能够在两种模式之间来回切换而不混合两个完全不同的编译器(因此可能会引入许多其他问题源)将非常有助于将问题一分为二。没有

Clang从左到右评估其参数,gcc从右到左评估其参数。(根据C和C++语言规范都可以),有没有办法改变CLAN中的参数评估顺序?如果不是通过pragma或编译器开关,也许有人可以给我指出代码库中正确的位置



一些背景信息:我有一个巨大的(第三方,没有那么好的文档)代码库,我试图从gcc移植到clang,我发现了一些奇怪的问题。根据以前的经验,我认为问题的一部分是论证顺序的评估。能够在两种模式之间来回切换而不混合两个完全不同的编译器(因此可能会引入许多其他问题源)将非常有助于将问题一分为二。

没有任何选项或术语来颠倒函数参数求值的顺序。但是现有的代码支持MSVC ABI(它似乎需要从右到左的参数求值)。下面的hack(针对当前clang svn trunk的补丁)可用于根据环境变量
clang\u reverse\u 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();
索引:lib/CodeGen/CGCall.cpp
===================================================================
---lib/CodeGen/CGCall.cpp(修订版229661)
+++lib/CodeGen/CGCall.cpp(工作副本)
@@ -2676,9 +2676,20 @@
CallExpr::const_arg_迭代器ArgEnd,
常量函数decl*被调用的函数decl,
无符号参数(跳过){
+布尔力反向搜索=假;
+const char*p=getenv(“铿锵的声音”);
+如果(p!=nullptr){
+如果(!strcmp(p,“1”))
+ForceReverseArgs=真;
+否则如果(strcmp(p,“0”)){
+fprintf(stderr,“预期$CLANG_REVERSE_ARGS为'0'或'1'!\n”);
+出口(1);
+    }
+  }
+
//我们*在MS C++ +ABI中评估从右到左的参数,
//因为参数在被调用方中从左到右被销毁。
-if(CGM.getTarget().getCXXABI().AreaRGSDRestoroyedLeftToRightInCallee()){
+if(CGM.getTarget().getCXXABI().AreaRGSDRestoroyedLeftToRightInCallee()| | ForceReverseArgs){
//如果需要任何inalloca参数,请插入堆栈保存。
bool HasInAllocaArgs=假;
对于(ArrayRef::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

$cat>demo.c我认为clang仍然从右向左评估参数

考虑以下代码:

intadd(inta,intb)
{
返回a+b;
}

在叮当声后编译时:

080483c0:
80483c0:55推力%ebp
80483c1:89 e5 mov%esp,%ebp
80483c3:83 ec 08子$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添加-0x8(%ebp),%eax
80483d8:83 c4 08添加$0x8,%esp
80483db:5d pop%ebp
80483dc:c3 ret
80483dd:0f 1f 00 nopl(%eax)

让我们考虑一下这段反编译代码:

mov将参数复制到堆栈中

`

+---------+
|高|
+---------+

|101 |堆栈上的参数顺序由ABI定义,与参数表达式的计算顺序无关​ 问题是关于后者,而不是前者。
+---------+
|high     |
+---------+
|101      |<-arg2
+---------+
|99       |<-arg1
+---------+
|ret      |
+---------+
|ebp      |
+---------+
|99       |<-a
+---------+
|101      |<-b
+---------+
|low      |
+---------+