gpt4 book ai didi

c - 为什么 va_arg() 在 x86_64 和 arm 上产生不同的效果?

转载 作者:太空宇宙 更新时间:2023-11-04 05:16:19 25 4
gpt4 key购买 nike

代码:

#include <stdio.h>
#include <stdarg.h>
#include <stdlib.h>

typedef unsigned int uint32_t;

float average(int n_values, ... )
{
va_list var_arg;
int count;
float sum = 0;

va_start(var_arg, n_values);

for (count = 0; count < n_values; count += 1) {
sum += va_arg(var_arg, signed long long int);
}

va_end(var_arg);

return sum / n_values;
}

int main(int argc, char *argv[])
{
(void)argc;
(void)argv;

printf("hello world!\n");

uint32_t t1 = 1;
uint32_t t2 = 4;
uint32_t t3 = 4;
printf("result:%f\n", average(3, t1, t2, t3));

return 0;
}

当我在 ubuntu (x86_64) 中运行时,没问题。

lix@lix-VirtualBox:~/test/c$ ./a.out 
hello world!
result:3.000000
lix@lix-VirtualBox:~/test/c$ uname -a
Linux lix-VirtualBox 4.4.0-116-generic #140-Ubuntu SMP Mon Feb 12 21:23:04 UTC 2018 x86_64 x86_64 x86_64 GNU/Linux
lix@lix-VirtualBox:~/test/c$

但是我在openwrt(ARM 32bit)中交叉编译运行时,就报错了。

[root@OneCloud_0723:/root/lx]#./helloworld 
hello world!
result:13952062464.000000
[root@OneCloud_0723:/root/lx]#uname -a
Linux OneCloud_0723 3.10.33 #1 SMP PREEMPT Thu Nov 2 19:55:17 CST 2017 armv7l GNU/Linux

我知道不要使用错误类型的参数调用 va_arg。但是为什么我们可以在 x86_64 中得到正确的结果而不是在 arm 中?

谢谢。

最佳答案

在 x86-64 Linux 上,每个 32 位 arg 都在一个单独的 64 位寄存器中传递(因为这是 x86-64 System V 调用约定所要求的)。

调用者恰好将 32 位 arg 零扩展到 64 位寄存器中。 (这不是必需的;您程序中的未定义行为可能会让您被另一个在参数传递寄存器中留下大量垃圾的调用者咬住。)

被调用者 ( average() ) 正在寻找三个 64 位参数,并在调用者放置它们的相同寄存器中查找,所以它恰好可以工作。


在 32 位 ARM 上,long long不适合单个寄存器,因此被调用者正在寻找 long long args 肯定在与调用者放置的位置不同的地方寻找 uint32_t参数。

被调用者看到的第一个 64 位 arg 可能是 ((long long)t1<<32) | t2 , 或相反。但是由于被调用者正在寻找 6x 32 位的 args,它会查看调用者根本不打算作为 args 的寄存器/内存。

(请注意,这可能会导致调用者在堆栈上的局部变量损坏,因为被调用者可以破坏堆栈参数。)


有关完整详细信息,请使用编译器 + 编译选项查看代码的 asm 输出,以查看源代码中的 C 未定义行为究竟导致了哪些行为。 objdump -d ./helloworld应该可以解决问题,或者直接查看编译器输出:How to remove "noise" from GCC/clang assembly output? .

关于c - 为什么 va_arg() 在 x86_64 和 arm 上产生不同的效果?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49041919/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com