Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why doesn't time() from time.h have a syscall to sys_time?

I wrote a very simple program with calls time() to illustrate the use ofstrace, but I'm having a problem; the time() call doesn't seem to actually produce a syscall!

I ended up stepping into the time() function in GDB and now I'm more confused than ever. From the disassembly of the time() function:

0x7ffff7ffad90 <time>:  push   rbp
0x7ffff7ffad91 <time+1>:    test   rdi,rdi
0x7ffff7ffad94 <time+4>:    mov    rax,QWORD PTR [rip+0xffffffffffffd30d]        # 0x7ffff7ff80a8
0x7ffff7ffad9b <time+11>:   mov    rbp,rsp
0x7ffff7ffad9e <time+14>:   je     0x7ffff7ffada3 <time+19>
0x7ffff7ffada0 <time+16>:   mov    QWORD PTR [rdi],rax
0x7ffff7ffada3 <time+19>:   pop    rbp
0x7ffff7ffada4 <time+20>:   ret 

How is this function actually getting the current time if it does not call the kernel? Its flow is:

  • Prologue
  • Get some value from (0x7ffff7ffad94 + 0xffffffffffffd30d) (0x7ffff7ff80a8) and put it in rax (to be returned)
  • Check if rdi (first argument) was null
  • If not put the value in rax (return value) there also
  • Epilogue

This makes sense with the functionality of time(); if the argument is null, it just returns the value, but if not it also puts it in the argument. The question I have is, where is it getting the time value? What's so magical about address 0x7ffff7ff80a8, and how does it do this without a syscall?

I'm using GCC 6.3.0 and Ubuntu GLIBC 2.24-9ubuntu2.2.

like image 278
Leonora Tindall Avatar asked Jan 14 '18 17:01

Leonora Tindall


1 Answers

Read time(7). Probably your call to time(2) uses the vdso(7) (maybe via clock_gettime(2) or via __vdso_time). If vdso(7) is used,

When tracing systems calls with strace(1), symbols (system calls) that are exported by the vDSO will not appear in the trace output.

Details could be kernel and libc specific (and of course architecture specific).

For similar vDSO reasons, strace date don't show any time-related syscalls.

And vDSO is a really handy feature (subject to ASLR). Thanks to it, timing calls (e.g. clock_gettime(2)...) go really quick (about 40 nanoseconds on my i5-4690S). AFAIU, no context switch (or user to kernel mode transition) is happening.

So your 0x7ffff7ff80a8 is probably sitting in the vDSO (and the kernel ensures it contains the current time). You might check by using proc(5) (e.g. reading and showing /proc/self/maps from your program), or perhaps using ldd(1) and pmap(1)

like image 134
Basile Starynkevitch Avatar answered Dec 01 '22 23:12

Basile Starynkevitch