为啥在同一个 ARM64 Linux 上调用 select 时,不同大小的 struct timeval 都可以工作?

Posted

技术标签:

【中文标题】为啥在同一个 ARM64 Linux 上调用 select 时,不同大小的 struct timeval 都可以工作?【英文标题】:Why do both struct timeval with different sizes work when calling select on the same ARM64 Linux?为什么在同一个 ARM64 Linux 上调用 select 时,不同大小的 struct timeval 都可以工作? 【发布时间】:2020-11-20 00:14:30 【问题描述】:

我使用 ARMv7 和 ARMv8 工具链来编译相同的 .c 文件,如下所示。然后我使用 QEMU 在 ARM64 Linux 上运行了两个生成的程序(select32select64)。

#include <sys/select.h>
#include <stdio.h>

int main()

    struct timeval t = 10, 999999;

    printf("sizeof timeval is %d, sizeof(tv_sec) is %d, sizeof(tv_usec) is %d\nstart select()\n", 
           (int) sizeof(struct timeval), (int)sizeof(t.tv_sec), (int)sizeof(t.tv_usec));
    select(0,0,0,0, &t);
    printf("select() ends\n");

我发现两个程序在start select()select() ends之间都睡了大约10秒

/ # ./select64
sizeof timeval is 16, sizeof(tv_sec) is 8, sizeof(tv_usec) is 8
start select()
select() ends
/ # ./select32
sizeof timeval is 8, sizeof(tv_sec) is 4, sizeof(tv_usec) is 4
start select()
select() ends 

为什么 32 位应用程序也休眠了 10 秒,尽管(我认为)它通过了内核没有预料到的 struct timeval 形式?是内核中的某些代码,还是 C 库中的某些代码,发现了一些奇怪的东西然后转换了结构?

【问题讨论】:

【参考方案1】:

当你用 32 位工具链编译时,struct timeval 的成员是 32 位的,当你用 64 位工具链编译时,它们是 64 位的。这意味着您提供的值会被编译器自动转换为适当的类型,并且您传递给它的数据大小合适。

如果使用的类型较大(如long,这可能是所使用的,则在结构初始化程序中使用它们时,C 编译器会自动将您提供的 int 类型的值转换为适当的类型在引擎盖下)。

32 位和 64 位程序的系统调用不同,所以在这种情况下,当您调用 select 时,您实际上是在调用两个不同的系统调用,其中一个可能是 32 位 EABI,另一个可能是, 64 位。

【讨论】:

【参考方案2】:

内核区分 32 位和 64 位系统调用。 32 位 select 传递 old_timeval32compat_timeval 结构,而 64 位 select 传递 timeval 结构类型。由于Year 2038 problem,不推荐使用 32 位。

timespec类似:32位pselect传递timespec结构,而64位pselect传递timespec64结构。实现之间的名称不同,例如,compat_timespec 用于 32 位,timespec 用于 64 位。

这里有一些来自 Raspberry Pi OS 中使用的 linux 内核的代码:compat.c 中有明确的转换例程来在两种类型之间复制数据:

static int compat_put_timeval(struct compat_timeval __user *o,
        struct timeval *i)

    return (put_user(i->tv_sec, &o->tv_sec) ||
        put_user(i->tv_usec, &o->tv_usec)) ? -EFAULT : 0;

【讨论】:

以上是关于为啥在同一个 ARM64 Linux 上调用 select 时,不同大小的 struct timeval 都可以工作?的主要内容,如果未能解决你的问题,请参考以下文章

如果节点这样做,为啥 verdaccio 不支持 arm 处理器

linux arch/arm64 添加系统调用

arm64linux无法使用数据库

Linux-我可以在aarch64体系结构上运行arm64二进制文件吗?

为啥 x86-64 Linux 系统调用使用 6 个寄存器集?

ARM64的函数调用标准和栈布局