aleix's blog

32-bit and 64-bit return values in OS X

25 April 2013 2:01 AM (c | mac os x)

I've spent a couple of days with a silly compiler problem. I have to admit that it was my fault but, at least, I learned something in the process. To make a long story short: do not forget to include header files and enable all warnings (-Wall).

In C, you can use a function without including its header file. Then, depending on how you set the compiler flags, it might not complain as long as it can find the function at linking time.

Imagine you have this function (defined in foo.h and implemented in foo.c) :

unsigned long foo_add (void);

and you use it in another module bar.c without including the foo.h header:

//#include "foo.h"

unsigned long bar_add (void)
{
  return foo_add () + foo_add ();
}

Compile with: gcc -c -O2 bar.c (we just missed -Wall)

If we disassemble the code of bar.o we get:

$ otool -tV bar.o
bar.o:
(__TEXT,__text) section
_bar_add:
...
000000000000000b callq _foo_add
0000000000000010 movl  %eax, %ebx
...
0000000000000024 ret

Now, let's try to include the header foo.h and disassemble again:

$ otool -tV bar.o
bar.o:
(__TEXT,__text) section
_bar_add:
...
0000000000000009 callq _foo_add
000000000000000e movq  %rax, %rbx
...
000000000000001f ret

Note how the compiler uses two different instructions: movl (32-bit) in the first case, when it really doesn't know anything about the foo_add function, and movq (64-bit) when it knows that foo_add returns a 64-bit value.

This can lead to unexpected behavior as I have found in the code I was working on. And actually, I have only found this in OS X.

So, please do not forget to include header files and enable -Wall. It will save you from some headaches.

No responses

Leave a Reply