Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/c/61.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C x86_64 va_列表结构的格式是什么?_C_Linux_X86 64_Variadic Functions_Abi - Fatal编程技术网

C x86_64 va_列表结构的格式是什么?

C x86_64 va_列表结构的格式是什么?,c,linux,x86-64,variadic-functions,abi,C,Linux,X86 64,Variadic Functions,Abi,有人参考过x86_64 ABI(Linux上使用的)中的va_列表的表示形式吗?我正试图调试一些堆栈或参数似乎已损坏的代码,这将真正有助于理解我应该看到的内容…我将我的评论变成了答案 。这是一个参考,尽管重量很轻(编辑:原始链接已失效;替换了Wayback机器保留的链接) 变量参数列表参考从第50页开始,然后继续,第52-53页文档va_列表: va_列表类型 va_列表类型是一个数组 包含一个元素中的单个元素 结构包含必要的 实施va_参数的信息 宏。va_列表的定义 类型如图3.34所示 v

有人参考过x86_64 ABI(Linux上使用的)中的
va_列表的表示形式吗?我正试图调试一些堆栈或参数似乎已损坏的代码,这将真正有助于理解我应该看到的内容…

我将我的评论变成了答案

。这是一个参考,尽管重量很轻(编辑:原始链接已失效;替换了Wayback机器保留的链接)

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

va_列表类型

va_列表类型是一个数组 包含一个元素中的单个元素 结构包含必要的 实施va_参数的信息 宏。va_列表的定义 类型如图3.34所示

va_开始宏

va_start宏初始化 结构如下:

reg\u save\u区域
元素指向 寄存器保存区域的开始

过流arg\u区域
使用此指针 获取在上传递的参数 堆栈它是用 传递的第一个参数的地址 堆栈(如果有),然后始终 已更新为指向 堆栈上的下一个参数

gp_offset
元素保存偏移量 以字节为单位,从reg_save_区域到 下一个可用的将军所在的地方 保存目的参数寄存器。在里面 案例所有参数寄存器都已被删除 耗尽后,将其设置为值48 (6 ∗ 8)

fp_offset
元素保存偏移量 以字节为单位,从reg_save_区域到 放置下一层可用涂层的位置 保存点参数寄存器。在里面 案例所有参数寄存器都已被删除 耗尽后,将其设置为值304 (6 ∗ 8 + 16 ∗ 16)


原来问题在于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
是数组类型和它不是数组类型的可能性。

在i386体系结构中,va_list是指针类型。但是,在AMD64体系结构中,它是一种数组类型。有什么区别?实际上,如果对指针类型应用&操作,将获得该指针变量的地址。但无论对数组类型应用多少次&operation,该值都是相同的,并且等于该数组的地址

那么,在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
}

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

@caf:
foo
有一个固定的签名,我无法更改。即使不是这样,
v*
函数总是采用
va_列表
参数,而不是
va_列表*
参数。这是标准约定,违反此约定会让函数用户感到恼火。@bdonlan:
bar
foo
多次调用,每次调用
bar
都必须看到上一次调用的效果。如果您通过
va_列表
,则这是明确的UB(根据ISO C);对于这种用法,您需要传递一个指向
va_list
的指针。@Christoph:回头看,我明白您的意思,但我认为这不是问题。
va_copy
的明显预期用途是在作为参数获得的
va_列表中使用它。如果您是通过
va_start
获得的,您可以再次调用
va_start
获取副本,而无需
va_copy
@polymonent_donut:您链接到的博客文章是假的,如顶部更新中所述。将收到的
va_列表
作为参数传递给另一个使用
va_列表
的函数总是可以的(只要在此之后不使用它,除了
va_end
)。也可以将指针传递到
va_列表
。。。。。。。问题是,在声明对象
va_list ap
为您提供类型为
va_list
的对象,以便
&ap
具有指向-
va_list
的类型指针,接收声明的参数
va_list ap
不一定意味着
ap
具有类型
va_list
。如果
va_list
是数组类型,则函数参数的数组衰减规则适用,然后
ap
的类型指针指向-
\uuu typeof__(*ap)
,这既不兼容类型,也不是传递给期望指针指向-
va_list
的函数的正确值(这是额外的间接级别)
va_copy
to temp是解决此问题的唯一方法。我很确定这些“浮点”寄存器实际上是SSE寄存器,并且只有8个。@DaveAbrahams x86_64有16个常规和SSE寄存器。这并不能回答问题。
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
}