x86_64 va_list 结构的格式是什么?

发布于 2024-10-16 17:01:31 字数 119 浏览 1 评论 0原文

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

Anyone have a reference for the representation of va_list in 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 supposed to be seeing...

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

南烟 2024-10-23 17:01:31

x86-64 System V ABi 文档可能会有所帮助< /a>.尽管很轻,但它是一个参考。

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

va_list 类型

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

图 3.34:va_list 类型声明

typedef 结构 {
   无符号整型 gp_offset;
   无符号整型 fp_offset;
   无效*overflow_arg_area;
   无效*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)。

The x86-64 System V ABi doc may help. It's a reference, albeit lightweight.

The Variable Argument List reference starts on page 54, then it goes on, page 56-57 documents 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 definition of va_list type is given in figure 3.34.

Figure 3.34: va_list Type Declaration

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_area The element points to the start of the register save area.

overflow_arg_area This pointer is used to fetch arguments passed on the stack. It is initialized with the address of the first argument passed on the stack, if any, and then always updated to point to the start of the next argument on the stack.

gp_offset The 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_offset The element holds the offset in bytes from reg_save_area to the place where the next available floating point argument register is saved. In case all argument registers have been exhausted, it is set to the value 304 (6 * 8 + 16 * 16).

清秋悲枫 2024-10-23 17:01:31

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

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

void foo(va_list ap);

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

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_list is an array type and the possibility that it's not.

你在看孤独的风景 2024-10-23 17:01:31

在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
}

它确实有效!而且你不需要担心你有多少争论。

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.

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.

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.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文