2012-03-26 103 views
1

我用G ++编写64位操作系统的cdecl,和我有一个可变参数函数,如:如何迫使可变参数函数

void DbgPrint(const char *fmt, ...); 

其行为应该挺喜欢的printf。 这里的问题是g ++遵循System V ABI,因此它传递RDI,RSI,RDX,RCX,R8,R9中的第一个参数,然后将剩余的(如果有的话)压入堆栈。

将旧的stdarg.h宏va_start,va_arg等与cdecl一起使用,非常简单,因为va_arg只是将下一个元素放在堆栈中。但是现在这些宏直到第七个参数才会工作。

唯一不可能性的解决方案是(IMHO):

  • 强制克++创建一个的cdecl功能。这似乎是不可能的,因为__ 属性 __((cdecl))被故意明确突出显示为忽略
  • 有一组新的宏,这些宏使用传递参数的新方法。

(我实际上在Win上工作,所以我没有glibc头文件来检查它们的实现)。

任何人都有解决方案吗?提前致谢。

回答

2

stdarg.h不是libc的一部分,它是编译器本身的一部分。所以如果你使用的是g ++,它应该有一个stdarg.h来处理它 - 它通常被安装在gcc的私有包含目录中,该目录在系统包含之前被自动搜索。

如果您在GCC的STDARG.H看,你看到va_宏都被定义映射到__builtin编译器神奇知道如何处理功能:

typedef __builtin_va_list __gnuc_va_list; 
typedef __gnuc_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) 

和那些建宏都明白调用目标ABI使用的约定。

+0

另请注意,即使在x86(32位)上,用于实现'stdarg.h' **的旧方法(伪指针算术)在现代GCC版本上不起作用。在编译器选择内联函数的情况下,参数在堆栈中根本不存在,即使不是,也有其他方式可以被破坏。不幸的是'__builtin'函数真的很有必要。 – 2012-03-26 17:40:07

+0

谢谢你,你一直很有用:) – 2012-03-26 17:48:44