c - 指向 GCC 目标内置函数的函数指针(有时)会产生链接错误

标签 c gcc linker-errors ld

在编写调试器的过程中,我遇到了一个难以追踪的链接器错误,下面这个疯狂而人为的函数将证明这一点。

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

此函数按预期编译和工作。

__builtin_exit 替换为任何 x86 目标特定的内置指令,这些指令将暂停或暗中停止程序,而不是在编译期间生成链接错误(... undefined reference `__builtin_ia32. . .`).

以内联方式使用内置函数(没有指向函数的指针)当然可以正常工作。

其他类的 GCC 内置函数是交替协作的,并且没有错误地链接或产生类似的链接错误。

最佳答案

内置函数通常不像普通函数。它们的调用语法与普通函数相同,但与普通函数不同的是,大多数内置函数都由编译器内联。它们用于在调用位置插入一小段 asm 代码。

有几种内建函数,其中一些内建函数,如__builtin_exit 是“库内建函数”,查看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.  */

因此,当您使用 __builtin_exit 并获取其地址时,它会转换为库函数 exit() 的用法(在 libc 中定义),因为 gcc "无法使用内置函数计算答案”。

这是来自同一文件的 __builtin_exit 的定义。

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

对于 DEF_GCC_BUILTIN 类的内置函数,禁止取地址,因为在库或 CRT 中没有定义这样的函数,如果 gcc 不能内联它,函数将是未定义的并被破坏链接。

关于c - 指向 GCC 目标内置函数的函数指针(有时)会产生链接错误,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/22888741/

相关文章:

c 在堆上创建一个字符串

c++ - strcmp() 和 strcoll() 有什么区别?

c - 未初始化的堆分配误解(代码有效——需要更正以消除 Valgrind 错误)

c - 为什么在一个字节中分配一个大数字在 C 中有效?

ios - 知道编译 iOS 应用程序时 "dyld: Symbol not found: ___gcc_personality_sj0"是什么吗?

二进制协议(protocol)的 C 和内存对齐

c++ - OS X Yosemite gcc 无法识别的命令行选项 'mdll' 在 brew install gcc 之后

visual-studio-2010 - 指定的文件是无法识别或不受支持的二进制格式

ios - 将 Xcode 升级到 4.5.2 并将 OpenCV 升级到 2.4.3 后出现链接器错误

objective-c - 切换到 Xcode7 时出现链接器问题,未定义架构 armv7 的符号 : _objc_readClassPair