使用gcc编译一个显示“未定义引用`abort'”的项目

时间:2013-06-19 11:05:35

标签: c linux printf variadic-functions

我写了一个使用va_list / va_arg / va_start / va_end / va_arg的printf myselef。

typedef char *va_list;
#define  _AUPBND                (sizeof (acpi_native_int) - 1)
#define  _ADNBND                (sizeof (acpi_native_int) - 1)
#define _bnd(X, bnd)            (((sizeof (X)) + (bnd)) & (~(bnd)))
#define va_arg(ap, T)           (*(T *)(((ap) += (_bnd (T, _AUPBND))) - (_bnd (T,_ADNBND))))
#define va_end(ap)              (void) 0
#define va_start(ap, A)         (void) ((ap) = (((char *) &(A)) + (_bnd (A,_AUPBND))))

首先,我从linux内核复制这些宏,printf可以打印32位整数正确,但不能打印64位整数,打印double / float可能会失败或崩溃。然后我检查代码,我猜va_ *可能有错误,所以我使用__builtin_va_ *而不是kernel的va _ *。

typedef __builtin_va_list va_list;
#define va_start(v,l)   __builtin_va_start(v,l)
#define va_end(v)       __builtin_va_end(v)
#define va_arg(v,l)     __builtin_va_arg(v,l)

但是gcc提示“未定义引用`abort'”,所以我写了一个空的abort()和myprintf正确地工作。 我的问题是:

  1. 为什么linux内核的va_list/va_arg/va_start/va_end/va_arg不能用于printf 64位整数和双/浮?
  2. 当我使用__builtin_va_start/__builtin_va_arg/__builtin_va_end/__builtin_va_list时,为什么gcc会提示“未定义引用abort'"? But I can not find the definition of __ builtin_va_ *`,这是他们的定义吗?

2 个答案:

答案 0 :(得分:3)

不要从Linux标题中剪切和粘贴内容。相反,将它放在源文件的顶部:

#include <stdarg.h>

这将为您提供使用va_listva_arg所需的一切。但是,不会拉入printf或任何标准I / O内容(位于<stdio.h>中)。

答案 1 :(得分:1)

gcc的__builtin_va_arg()显然会调用abort()(至少在某些平台或情况下),如果使用类型参数调用它,则无法在参数列表的...部分中传递一个函数调用。

例如,由于促销charfloat已通过,因此此参数将被提升为intdouble。以va_arg(ap,char)va_arg(ap,float)访问这些参数是未定义的行为,gcc可能在这种情况下调用abort() - 或者它可能会执行其他操作(我的MinGW编译器将执行无效指令以导致崩溃) )。

编译时可能会看到类似的内容:

In file included from D:\temp\test.c:2:0:
D:\temp\test.c: In function 'foo':
D:\temp\test.c:12:16: warning: 'char' is promoted to 'int' when passed through '...' [enabled by default]
  c = va_arg(ap,char);
                ^
D:\temp\test.c:12:16: note: (so you should pass 'int' not 'char' to 'va_arg')
D:\temp\test.c:12:16: note: if this code is reached, the program will abort

__builtin_va_*的'定义'被编译到编译器中(这就是为什么'builtin'是名称的一部分)。

对于varargs访问的Linux宏:虽然你从linux内核头文件中获取的定义确实存在于include / acpi / platform / acenv.h中,如果仔细查看有效的条件编译,你将会看看在构建linux内核时没有使用这些宏。我不确定这些宏何时生效,但它们不适用于x64 / x86-64 / amd64版本,因为该平台上的ABI不完全基于堆栈。有关详细信息,请参见“System V应用程序二进制接口 - AMD64架构处理器补充说明”的第3.5.6节。