C x86_64 va_列表结构的格式是什么?
有人参考过x86_64 ABI(Linux上使用的)中的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
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
}