【问题标题】:How to force cdecl on variadic function如何在可变参数函数上强制 cdecl
【发布时间】:2012-03-26 17:07:37
【问题描述】:

我正在使用 g++ 编写一个 64 位操作系统,并且我有一个可变参数函数,例如:

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

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

在 cdecl 中使用旧的 stdarg.h 宏 va_start、va_arg 等非常容易,因为 va_arg 只是获取堆栈中的下一个元素。但是现在这些宏在第 7 个参数之前根本不起作用。

唯一可能的解决方案是(恕我直言):

  • 强制 g++ 创建 cdecl 函数。这似乎是不可能的,因为 __attribute__((cdecl)) 被故意清晰地突出显示为忽略
  • 拥有一组新的宏,可以使用新的参数传递方式。

(我实际上正在开发 Win,所以我没有 glibc 标头来检查它们的实现)。

谁有解决方案?提前致谢。

【问题讨论】:

    标签: c variadic-functions cdecl


    【解决方案1】:

    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 使用的调用约定。

    【讨论】:

    • 另请注意,用于实现stdarg.h 的旧方法(伪指针算法)在现代 GCC 版本上不起作用,即使在 x86(32 位)上也是如此。如果编译器选择内联函数,参数将根本不存在于堆栈上,即使不存在,也有其他方法可以破坏它。不幸的是,__builtin 函数确实是必需的。
    猜你喜欢
    • 2020-07-14
    • 1970-01-01
    • 2022-01-01
    • 1970-01-01
    • 2020-05-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多