在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
的對象。生成的二進制文件通過了項目的測試平臺。
堆棧中參數的順序由ABI定義,並且獨立於調用方中參數表達式的評估順序。問題是關於後者,而不是前者。 – CliffordVienna 2017-04-01 02:23:25