gettimeofday是一个x86-86的系统调用,根据this page(只是在框中搜索gettimeofday
):
int gettimeofday(struct timeval *tv, struct timezone *tz);
我认为disas应该很容易,只需准备两个指针并调用相关的syscall
。
但它的disas做得更多:
(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
。
任何人都明白它是如何运作的?
答案 0 :(得分:8)
gettimeofday()
就是所谓的vsyscall
和/或vdso
。因此,您会看到两行:
0x00000034f408c2d4 : mov $0xffffffffff600000,%rax 0x00000034f408c2db : callq *%rax
在您的反汇编中。地址0xffffffffff600000
是vsyscall页面(在x86_64上)。
该机制将特定的内核创建的代码页映射到用户内存中,这样就可以在没有用户/内核上下文切换的开销的情况下制作一些“系统调用”,而是作为“普通”函数调用。实际实施是right here。
答案 1 :(得分:7)
Syscalls通常会产生大量开销,并且考虑到大量的gettimeofday()调用,人们宁愿不使用系统调用。为此,Linux内核可以将一个或两个特殊区域映射到每个程序中,称为vdso和vsyscall。你的gettimeofday()实现似乎是使用vsyscall:
mov $0xffffffffff600000,%rax
这是vsyscall地图的标准地址。尝试cat /proc/self/maps
查看该映射。 vsyscall背后的想法是内核提供了一些函数的快速用户空间实现,而libc只是调用它们。
阅读此nice article了解详情。