In the process of writing a debugger I encountered a difficult to track down linker error, which this following crazy and contrived function will demonstrate.

#include <stdio.h>
void main(int n) {
    printf("%d\n", n);
    (&main + (&__builtin_exit - &main)*(n/128))(++n);
}

This function compiles and works as expected.

Substituting __builtin_exit with any of the x86 target specific builtin instructions that would either pause or surreptitiously halt the program instead generate linkage errors during compilation (...undefined reference to `__builtin_ia32. ..`).

Using the builtin functions in an inline fashion (without a pointer to the function) of course work fine.

Other classes of GCC builtins are alternate cooperative and link without errors or generate a similar linkage error.

有帮助吗?

解决方案

builtin functions are usually not like normal functions. They are called in the same syntax as normal functions, but unlike normal functions, most of builtins are inlined by the compiler. They are used to insert small sequences of asm code in the place of call.

There are several kinds of builtins, and some of builtins, like __builtin_exit are "library builtins", check the gcc/builtins.def file

  80 /* A library builtin (like __builtin_strchr) is a builtin equivalent
  81    of an ANSI/ISO standard library function.  In addition to the
  82    `__builtin' version, we will create an ordinary version (e.g,
  83    `strchr') as well.  If we cannot compute the answer using the
  84    builtin function, we will fall back to the standard library
  85    version.  */
  86 #undef DEF_LIB_BUILTIN
  87 #define DEF_LIB_BUILTIN(ENUM, NAME, TYPE, ATTRS)        \
  88   DEF_BUILTIN (ENUM, "__builtin_" NAME, BUILT_IN_NORMAL, TYPE, TYPE,    \
  89                true, true, false, ATTRS, true, true)

  23 /*   DEF_BUILTIN (ENUM, NAME, CLASS, TYPE, LIBTYPE, BOTH_P,
  24                   FALLBACK_P, NONANSI_P, ATTRS, IMPLICIT, COND)

  33    Some builtins are actually two separate functions.  For example,
  34    for `strcmp' there are two builtin functions; `__builtin_strcmp'
  35    and `strcmp' itself.  Both behave identically.  Other builtins
  36    define only the `__builtin' variant.  If BOTH_P is TRUE, then this
  37    builtin has both variants; otherwise, it is has only the first
  38    variant.

  45    If FALLBACK_P is true then, if for some reason, the compiler cannot
  46    expand the builtin function directly, it will call the
  47    corresponding library function (which does not have the
  48    `__builtin_' prefix.  */

So, when you use __builtin_exit and take its address, it is converted into usage of library function exit() (which is defined in libc), because gcc "cannot compute the answer using the builtin function".

Here is definition of __builtin_exit from the same file.

 699 DEF_LIB_BUILTIN        (BUILT_IN_EXIT, "exit", BT_FN_VOID_INT, ATTR_NORETURN_NOTHROW_LIST)

For DEF_GCC_BUILTIN kind of builtins, taking address is prohibited, because there are no such function defined in the libraries or CRT, and if gcc can't inline it, the function will be undefined and broke linking.

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top