27

va_list有人对 x86_64 ABI(Linux 上使用的那个)的表示有参考吗?我正在尝试调试一些堆栈或参数似乎已损坏的代码,这真的有助于理解我应该看到的内容......

4

3 回答 3

35

x86-64 System V ABi 文档可能会有所帮助。这是一个参考,虽然很轻。

变量参数列表参考从第 54 页开始,然后继续,第 56-57 页文档va_list

va_list类型_

va_list类型是一个数组,其中包含一个结构的单个元素,其中包含实现va_arg宏所需的信息。va_list图 3.34 给出了类型的 C 定义。

图 3.34:va_list类型声明

typedef struct {
   unsigned int gp_offset;
   unsigned int fp_offset;
   void *overflow_arg_area;
   void *reg_save_area;
} va_list[1];

va_start宏观_

va_start宏初始化结构如下:

reg_save_area该元素指向寄存器保存区域的开始。

overflow_arg_area此指针用于获取堆栈上传递的参数。它使用堆栈上传递的第一个参数的地址进行初始化,如果有的话,然后总是更新以指向堆栈上下一个参数的开始。

gp_offset该元素保存从reg_save_area到保存下一个可用通用参数寄存器的位置的偏移量(以字节为单位)。如果所有参数寄存器都已用尽,则将其设置为值 48 (6 * 8)。

fp_offset该元素保存从reg_save_area到保存下一个可用浮点参数寄存器的位置的偏移量(以字节为单位)。如果所有参数寄存器都已用尽,则将其设置为值 304 (6 * 8 + 16 * 16)。

于 2011-02-10T14:46:15.747 回答
19

事实证明,问题在于 gcc 制作va_list了一个数组类型。我的功能是签名:

void foo(va_list ap);

我想传递一个指向ap另一个函数的指针,所以我做了:

void foo(va_list ap)
{
    bar(&ap);
}

不幸的是,数组类型衰减为函数参数列表中的指针类型,因此我没有将指针传递给原始结构,而是将指针传递给指针。

为了解决这个问题,我将代码更改为:

void foo(va_list ap)
{
    va_list ap2;
    va_copy(ap2, ap);
    bar(&ap2);
    va_end(ap2);
}

这是我能想出的唯一可移植解决方案,它既可以解释va_list为数组类型的可能性,也可以解释不是数组类型的可能性。

于 2011-02-10T15:40:57.123 回答
0

在 i386 架构中,va_list 是指针类型。但是,在 AMD64 架构中,它是一个数组类型。有什么不同?实际上,如果你对一个指针类型应用 & 操作,你会得到这个指针变量的地址。但是无论你对一个数组类型应用&操作多少次,其值都是一样的,并且等于这个数组的地址。

那么,在 AMD64 中应该怎么做呢?在函数中传递 va_list 变量的最简单方法是不带 * 或 & 运算符传递它。

例如:

void foo(const char *fmt, ...) {
    va_list ap;
    int cnt;
    va_start(ap, fmt);
    bar(fmt, ap);
    va_end(ap);
    return cnt;
}
void bar(const char *fmt, va_list ap) {
    va_arg(ap, int);
    //do something
    test(ap);
}
void test(va_list ap) {
    va_arg(ap, int);
    //do something
}

它只是工作!而且您不必担心您有多少参数。

于 2018-09-16T16:35:35.307 回答