Reputation: 8235
Clang evaluates its arguments from left to right, gcc from right to left. (Both is ok according to the C and C++ language specs, see also g++ vs intel/clang argument passing order?) Is there a way to change the order of argument evaluation in clang? If not via a pragma or compiler switch, maybe someone can point me to the right place in the clang codebase?
Some background information: I'm having a huge (3rd party, not so well documented) codebase that I'm trying to port from gcc to clang and I'm seeing strange problems. From previous experiences I think that at least part of the problem is the argument order evaluation. Being able to switch back and forth between the two modes without mixing two entirely different compilers (and thus maybe introducing many other sources of problems) would be very helpful in bisecting the problem.
Upvotes: 5
Views: 1738
Reputation: 165
i think clang still eval the arguments from right to left.
Consider this code:
int add(int a, int b)
{
return a+b;
}
When compiled after 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)
let think about this decompiled code:
the mov copy the args to the stack
`
+---------+
|high |
+---------+
|101 |<-arg2
+---------+
|99 |<-arg1
+---------+
|ret |
+---------+
|ebp |
+---------+
|99 |<-a
+---------+
|101 |<-b
+---------+
|low |
+---------+
`
when print &a or &b in gdb, it seems like the arg1 has a higher address than arg2.
acctully, the a and b are now in the stack which below the ebp.
Upvotes: 0
Reputation: 8235
There is no option or pragma in clang to reverse the order of function argument evaluation. But there is existing code to support the MSVC ABI (which seem to require argument evaluation from right to left). The following hack (patch against current clang svn trunk) can be used to reverse the order of argument evaluation based on the value of the environment variable CLANG_REVERSE_ARGS
. A value of 1
reverses the order, a value of 0
keeps the order as it is.
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();
It even seems to work:
$ 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
I have built a large-ish C++ project that has a big test bench in "frankenstein mode": half of the objects with CLANG_REVERSE_ARGS=1
and half of the objects with CLANG_REVERSE_ARGS=0
. The resulting binary passed the testbench of the project.
Upvotes: 4