Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

GCC function name conflict

Tags:

c

gcc

I was having some problems with a sample code i was testing, since my abs function was not returning the correct result. abs(-2) was outputing -2 (this, by the way, is suposed to be the absolute value function, if that was unclear)

After getting a bit desperate, i eventually had the following code

#include <stdio.h>

unsigned int abs(int x) {
    return 1;
}

int main() {
    printf("%d\n", abs(-2));
    return 0;
}

This does nothing useful but it serves to show my problem. This was outputing -2, when it was expected to output 1.

if i change the function name to something else (abs2 for example), the result is now correct. Also, if i change it to receive two arguments instead of one, it also fixes the problem.

My obvious guess: a conflict with the standart abs function. But this still doesn't explain why the output is -2 (it should be 2, if using the standart abs function). I tried checking the assembly output of both versions (with the function named abs and abs2)

Here's the diff output for both assemblys:

23,25c23,25
< .globl abs
<   .type   abs, @function
< abs:
---
> .globl abs2
>   .type   abs2, @function
> abs2:
54c54
<   .size   abs, .-abs
---
>   .size   abs2, .-abs2
71c71,74
<   movl    -4(%rbp), %edx
---
>   movl    -4(%rbp), %eax
>   movl    %eax, %edi
>   call    abs2
>   movl    %eax, %edx

From what i understand, the first version (where the function is named abs) is simply discarding the function call, thus using the parameter x instead of abs(x)

So to sum up: why does this happen, especially since i couldn't find a way to get any sort of warning or error about this.

Tested on Debian Squeeze, ggc 4.4.5, and also on gcc 4.1.2

like image 439
Naps62 Avatar asked Apr 10 '12 11:04

Naps62


2 Answers

GCC is playing tricks on you due to the interplay of the following:

  • abs is a built-in function;
  • you're declaring abs to return unsigned int while the standard (and built-in) abs returns signed int.

Try compiling with gcc -fno-builtin; on my box, that gives the expected result of 1. Compiling without that option but with abs declared as returning signed int causes the program to print 2.

(The real solution to this problem is to not use library identifiers for your own functions. Also note that you shouldn't be printing an unsigned int with %d.)

like image 105
Fred Foo Avatar answered Oct 11 '22 23:10

Fred Foo


gcc optimizes the call to abs() to use its built-in abs(). So if you use the -fno-builtin option (or define your abs() as returning int), you'll notice you get the correct result. According to this (quoting):

GCC includes built-in versions of many of the functions in the standard C library. The versions prefixed with _builtin will always be treated as having the same meaning as the C library function even if you specify the -fno-builtin option. (see C Dialect Options) Many of these functions are only optimized in certain cases; if they are not optimized in a particular case, a call to the library function will be emitted.

Had you included stdlib.h, which declares abs() in the first place, you'd get an error at compile time.

like image 23
Michael Foukarakis Avatar answered Oct 11 '22 22:10

Michael Foukarakis