13

gettimeofday is a syscall of x86-86 according to this page(just search gettimeofday in the box):

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

I thought the disassembly should be easy enough, just prepare the two pointers and call the related syscall, but its disassembly is doing much more:

(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. 

And I don't see syscall at all.

Can anyone explain how it works?

Jack G
  • 4,553
  • 2
  • 41
  • 50
asker
  • 2,159
  • 3
  • 22
  • 27
  • Did you see the last column in that syscall site? (btw great site) Definition - links to kernel/time.c:101 - http://lxr.free-electrons.com/source/kernel/time.c#L101 . Or were you looking for something else? – arunkumar Sep 01 '11 at 06:49
  • The last line is the implementation of OS, I don't need to know that.I just need to follow the calling side. – asker Sep 01 '11 at 06:55
  • Related: https://blog.packagecloud.io/eng/2016/04/05/the-definitive-guide-to-linux-system-calls/ – Peter Cordes Dec 05 '21 at 20:25

2 Answers2

15

gettimeofday() on Linux is what's called a vsyscall and/or vdso. Hence you see the two lines:

0x00000034f408c2d4 : mov    $0xffffffffff600000,%rax
0x00000034f408c2db : callq  *%rax

in your disassembly. The address 0xffffffffff600000 is the vsyscall page (on x86_64).

The mechanism maps a specific kernel-created code page into user memory, so that a few "syscalls" can be made without the overhead of a user/kernel context switch, but rather as "ordinary" function call. The actual implementation is right here.

FrankH.
  • 17,675
  • 3
  • 44
  • 63
  • AFAIK `0xffffffffff600000` is kernel space address, how can user space call kernel space directly? – asker Sep 02 '11 at 05:08
  • 4
    That's the whole point of the vsyscall page - it's a _kernel-created_ page (which therefore happens to be within the kernel VA range) that is "_exported_" (i.e. mapped) into userspace when the process address space is created. To the userspace app, it looks just like another linker-preloaded shared object (even though the kernel itself does this 'preload'), hence `vdso.so`. The kernel sets the permissions so that userspace can read (but not write) it. – FrankH. Sep 02 '11 at 13:25
10

Syscalls generally create a lot of overhead, and given the abundance of gettimeofday() calls, one would prefer not to use a syscall. To that end, Linux kernel may map one or two special areas into each program, called vdso and vsyscall. Your implementation of gettimeofday() seems to be using vsyscall:

mov $0xffffffffff600000,%rax

This is the standard address of vsyscall map. Try cat /proc/self/maps to see that mapping. The idea behind vsyscall is that kernel provides fast user-space implementations of some functions, and libc just calls them.

Read this nice article for more details.

dragonroot
  • 5,653
  • 3
  • 38
  • 63
  • oops, had some sort of timeout here - not seeing your answer while posting mine ... right & correct. – FrankH. Sep 01 '11 at 10:30