【问题标题】:How does the gettimeofday syscall wor‍k?gettimeofday 系统调用如何工作?
【发布时间】:2023-04-09 16:49:01
【问题描述】:

gettimeofday 是根据this page 对x86-86 的系统调用(只需在框中搜索gettimeofday):

int gettimeofday(struct timeval *tv, struct timezone *tz);

我认为反汇编应该很容易,只需准备两个指针并调用相关的syscall,但它的反汇编做得更多:

(gdb) disas gettimeofday
Dump of assembler code for function gettimeofday:
0x00000034f408c2d0 <gettimeofday+0>: sub    $0x8,%rsp
0x00000034f408c2d4 <gettimeofday+4>: mov    $0xffffffffff600000,%rax
0x00000034f408c2db <gettimeofday+11>: callq  *%rax
0x00000034f408c2dd <gettimeofday+13>: cmp    $0xfffff001,%eax
0x00000034f408c2e2 <gettimeofday+18>: jae    0x34f408c2e9 <gettimeofday+25>
0x00000034f408c2e4 <gettimeofday+20>: add    $0x8,%rsp
0x00000034f408c2e8 <gettimeofday+24>: retq   
0x00000034f408c2e9 <gettimeofday+25>: mov    0x2c4cb8(%rip),%rcx        # 0x34f4350fa8 <free+3356736>
0x00000034f408c2f0 <gettimeofday+32>: xor    %edx,%edx
0x00000034f408c2f2 <gettimeofday+34>: sub    %rax,%rdx
0x00000034f408c2f5 <gettimeofday+37>: mov    %edx,%fs:(%rcx)
0x00000034f408c2f8 <gettimeofday+40>: or     $0xffffffffffffffff,%rax
0x00000034f408c2fc <gettimeofday+44>: jmp    0x34f408c2e4 <gettimeofday+20>
End of assembler dump. 

我根本看不到syscall

谁能解释它是如何工作的?

【问题讨论】:

标签: linux assembly x86-64 system-calls vdso


【解决方案1】:

Linux 上的gettimeofday() 是所谓的vsyscall 和/或vdso。因此,您会看到两行:

0x00000034f408c2d4 : 移动 $0xffffffffff600000,%rax
0x00000034f408c2db : callq *%rax

在您的反汇编中。地址0xffffffffff600000 是 vsyscall 页面(在 x86_64 上)。

该机制将特定内核创建的代码页映射到用户内存中,因此可以进行一些“系统调用”而无需用户/内核上下文切换的开销,而是作为“普通”函数调用。实际实现是right here

【讨论】:

  • AFAIK 0xffffffffff600000是内核空间地址,用户空间如何直接调用内核空间?
  • 这就是 vsyscall 页面的全部意义——它是一个 kernel-created 页面(因此恰好在内核 VA 范围内),它是“exported"(即映射)在创建进程地址空间时进入用户空间。对于用户空间应用程序,它看起来就像另一个链接器预加载的共享对象(即使内核本身执行此“预加载”),因此vdso.so。内核设置权限,以便用户空间可以读取(但不能写入)它。
【解决方案2】:

系统调用通常会产生大量开销,并且考虑到大量的 gettimeofday() 调用,人们宁愿不使用系统调用。为此,Linux 内核可能会在每个程序中映射一个或两个特殊区域,称为 vdso 和 vsyscall。您的 gettimeofday() 实现似乎正在使用 vsyscall:

mov $0xffffffffff600000,%rax

这是vsyscall map的标准地址。尝试cat /proc/self/maps 以查看该映射。 vsyscall 背后的想法是内核提供了一些函数的快速用户空间实现,而 libc 只是调用它们。

阅读nice article了解更多详情。

【讨论】:

  • 哎呀,这里有某种超时 - 发布我的时没有看到你的答案......正确且正确。
猜你喜欢
  • 2014-03-26
  • 2011-09-08
  • 2020-08-28
  • 2015-04-15
  • 2014-11-17
  • 2015-02-23
  • 2017-04-19
  • 2014-07-25
相关资源
最近更新 更多