Page 1 of 1

cdecl register preservation

Posted: Fri Dec 16, 2011 10:27 am
by evoex
Hello all,

I read somewhere that for an cdecl call the registers eax, ecx and edx do not need to be preserved by the called function. However, when testing the following code on gcc:

Code: Select all

#include <stdio.h>

void __attribute__((cdecl)) test()
{
	__asm__("movl $0, %eax");
}

int __attribute__((cdecl)) test1()
{
	int a;
	scanf("%d", &a);
	return a;
}

int main()
{
	int a = test1();
	test();
	printf("%d\n", a);
}
And optimizing with -O2, the printf would always show 0, probably meaning that eax DOES need to be preserved for void functions. Is this correct?
What about the other registers? They are not preserved, is that correct?

What about the syscall calling convention? Is the same true, there?

Also, how do I specify the calling convention to use in gcc? The above actually complains about it being ignored - but I believe cdecl is the default in gcc anyway (otherwise my complaint is even wrong). So how would I specify the syscall calling convention, for instance?
Edit: never mind this last question, I was accidentally compiling it on 64 bits, which is why cdecl was ignored. But the issue with eax was not fixed compiling it as 32 bits.

Thanks in advance

Re: cdecl register preservation

Posted: Fri Dec 16, 2011 1:33 pm
by gerryg400
The problem is probably that your inline asm

Code: Select all

 __asm__("movl $0, %eax");
is trashing the EAX register but GCC doesn't know. I'm guessing that if you put the proper constraints on that line of asm your problem will go away.

Re: cdecl register preservation

Posted: Fri Dec 16, 2011 2:26 pm
by evoex
gerryg400 wrote:The problem is probably that your inline asm

Code: Select all

 __asm__("movl $0, %eax");
is trashing the EAX register but GCC doesn't know. I'm guessing that if you put the proper constraints on that line of asm your problem will go away.
Ahh okay that makes sense. So basically I can safely change eax even in a void function, without having to worry about extremely complex bugs in the future? ;-)

Thanks for your answer!

Re: cdecl register preservation

Posted: Fri Dec 16, 2011 2:38 pm
by gerryg400
evoex wrote:... So basically I can safely change eax even in a void function, without having to worry about extremely complex bugs in the future? ;-)
No. The future is full of complex bugs.

Re: cdecl register preservation

Posted: Sun Dec 25, 2011 1:26 pm
by Tobba
What happens without -O2? GCC most likely tries to optimize the code, but doesnt know you're trashing the register, which makes it think eax is not trashed within the function and can be preserved until the printf call?

Re: cdecl register preservation

Posted: Mon Dec 26, 2011 10:11 am
by JamesM
Tobba wrote:What happens without -O2? GCC most likely tries to optimize the code, but doesnt know you're trashing the register, which makes it think eax is not trashed within the function and can be preserved until the printf call?
Hi,

I'd be highly surprised if the "test" function isn't being inlined. When it's out of line (needs to be CALLed), the compiler assumes that eax will be trashed (along with other caller save regs as per the ABI).

With -O2, it's likely test() has been inlined, so the compiler no longer has to adhere to the ABI and EAX gets corrupted. As a previous poster has said, changing the inline assembly statement so that the eax constraint is known will alleviate this:

Code: Select all

int dummy;
asm volatile("movl $0, %0" : "=a" (dummy));
Or just compile with -fno-inline.

Re: cdecl register preservation

Posted: Tue Dec 27, 2011 4:35 am
by evoex
Yeah; the C code wasn't actually part of any production code or so, it was only to test whether the EAX register could be changed or not. Because wikipedia said it couldn't (I already changed that), where other sources said it could. So I made this test and wondered about the results - but it is understandable GCC inlines it, causing this "bug".
So I'm not worried about it anymore, thanks for your help guys!