2015-02-17 67 views
2

Clang從左到右評估它的參數,gcc從右到左。 (根據C和C++語言規範,這兩種都可以,另請參閱g++ vs intel/clang argument passing order?)有沒有辦法改變clang中參數評估的順序?如果不通過編譯指示或編譯器開關,也許有人可以指引我在叮叮代碼庫中的正確位置?我可以在clang中更改參數評估的順序嗎?


一些背景信息:我有一個巨大的(第三方,沒有做到有據可查)代碼庫我試圖從端口GCC來鐺和我看到的奇怪問題。根據以往的經驗,我認爲問題的至少一部分是論證順序評估。在不混合兩種完全不同的編譯器(因此可能引入許多其他問題源)的情況下,能夠在兩種模式之間來回切換將有助於平分問題。

回答

2

在clang中沒有選項或編譯指令來顛倒函數參數評估的順序。但是現有的代碼支持MSVC ABI(似乎需要從右向左進行參數評估)。可以使用以下hack(針對當前叮噹svn主幹的補丁)來基於環境變量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++項目已在「科學怪人模式」的一大試驗檯:對象的一半CLANG_REVERSE_ARGS=1和半與CLANG_REVERSE_ARGS=0的對象。生成的二進制文件通過了項目的測試平臺。

0

我認爲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複製到堆棧

int add(int a, int b) { return a+b; }

當鐺之後編譯

`

+---------+ 
|high  | 
+---------+ 
|101  |<-arg2 
+---------+ 
|99  |<-arg1 
+---------+ 
|ret  | 
+---------+ 
|ebp  | 
+---------+ 
|99  |<-a 
+---------+ 
|101  |<-b 
+---------+ 
|low  | 
+---------+ 

`

當打印&一個或& b在gdb的,這似乎是ARG1比ARG2更高的地址。

acctully,a和b現在在ebp下面的堆棧中。

+0

堆棧中參數的順序由ABI定義,並且獨立於調用方中參數表達式的評估順序。問題是關於後者,而不是前者。 – CliffordVienna 2017-04-01 02:23:25

相關問題