Linux x86_64 va_list 结构的格式是什么?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/4958384/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-05 02:47:37  来源:igfitidea点击:

What is the format of the x86_64 va_list structure?

clinuxx86-64variadic-functionsabi

提问by R.. GitHub STOP HELPING ICE

Anyone have a reference for the representation of va_listin the x86_64 ABI (the one used on Linux)? I'm trying to debug some code where the stack or arguments seem corrupt and it would really help to understand what I'm supposedto be seeing...

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

采纳答案by Skurmedel

I made my comment into an answer.

我把我的评论变成了一个答案。

This may help. It's a reference, albeit lightweight (EDIT: original link dead; replaced Wayback Machine-preserved link).

这可能会有所帮助。这是一个参考,虽然很轻量级(编辑:原始链接已失效;替换了 Wayback Machine 保留的链接)。

The Variable Argument List reference starts on page 50, then it goes on, page 52-53 documents va_list:

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

The va_list Type

The va_list type is an array containing a single element of one structure containing the necessary information to implement the va_arg macro. The C de?nition of va_list type is given in ?gure 3.34

va_list 类型

va_list 类型是一个数组,其中包含一个结构的单个元素,该结构包含实现 va_arg 宏所需的信息。va_list 类型的 C 定义在图 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];

The va_start Macro

The va_start macro initializes the structure as follows:

reg_save_areaThe element points to the start of the register save area.

over?ow_arg_areaThis pointer is used to fetch arguments passed on the stack. It is initialized with the address of the ?rst argument passed on the stack, if any, and then always updated to point to the start of the next argument on the stack.

gp_offsetThe element holds the offset in bytes from reg_save_area to the place where the next available general purpose argument register is saved. In case all argument registers have been exhausted, it is set to the value 48 (6 ? 8).

fp_offsetThe element holds the offset in bytes from reg_save_area to the place where the next available ?oating point argument register is saved. In case all argument registers have been exhausted, it is set to the value 304 (6 ? 8 + 16 ? 16).

va_start 宏

va_start 宏初始化结构如下:

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

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

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

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

回答by R.. GitHub STOP HELPING ICE

It turns out the problem was gcc's making va_listan array type. My function was of the signature:

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

void foo(va_list ap);

and I wanted to pass a pointer to apto another function, so I did:

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

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

Unfortunately, array types decay to pointer types in function argument lists, so rather than passing a pointer to the original structure, I was passing a pointer to a pointer.

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

To work around the problem, I changed the code to:

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

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

This is the only portable solution I could come up with, that accounts for both the possibility that va_listis an array type and the possibility that it's not.

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

回答by Maple

In i386 architecture, the va_list is a pointer type. However, in AMD64 architecture, it is an array type. What is the difference? Actually, if you apply an & operation to a pointer type, you will get the address of this pointer variable. But no matter how many times you apply & operation to an array type, the value is the same, and is equal to the address of this array.

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

So, what should you do in AMD64? The easiest way to pass variable of va_list in a function is just passing it with no * or & operator.

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

For example:

例如:

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
}

It just works! And you don't need to worry about how many arguments you have got.

它只是有效!而且您无需担心您有多少参数。