x86_64 va_list结构的格式是什么?

时间:2011-02-10 14:34:19

标签: c linux x86-64 variadic-functions abi

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

3 个答案:

答案 0 :(得分:28)

我对答案做了评论。

This may help。这是一个参考,尽管是轻量级的(编辑:原始链接已死;替换了Wayback Machine保留的链接)。

变量参数列表参考从第50页开始,然后继续,第52-53页文档va_list

  

va_list类型

     

va_list类型是一个数组   包含一个元素   结构包含必要的   实现va_arg的信息   宏。 va_list的定义   类型在图3.34中给出

// Figure 3.34
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到。的字节数   下一个可用的将军的地方   目的参数寄存器已保存。在   case所有参数寄存器都是   用尽,它被设置为值48   (6 * 8)。

     

fp_offset元素保留偏移量   从reg_save_area到。的字节数   下一个可用浮动的地方   点参数寄存器已保存。在   case所有参数寄存器都是   耗尽,将其设置为值304   (6 * 8 + 16 * 16)。

答案 1 :(得分:14)

事实证明问题是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是数组类型的可能性以及它不是的可能性。

答案 2 :(得分: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
}

就可以了!而且您不必担心有多少论点。