I wrote a snippet of x86-64 to get current time of day on a mac using a syscall. Everything worked fine. I got a time. Then I thought to add a little error checking.
To get an idea of what to do, I disassembled the "gettimeofday" wrapper. It uses a jae
instruction after the syscall to handle a successful result.
___gettimeofday:
4969: 48 c7 c2 00 00 00 00 movq $0x0, %rdx
4970: b8 74 00 00 02 movl $0x2000074, %eax
4975: 49 89 ca movq %rcx, %r10
4978: 0f 05 syscall
497a: 73 08 jae 0x4984
497c: 48 89 c7 movq %rax, %rdi
497f: e9 41 d8 ff ff jmp _cerror_nocancel
4984: 48 83 f8 00 cmpq $0x0, %rax
4988: 74 08 je 0x4992
498a: 48 89 07 movq %rax, (%rdi)
498d: 89 57 08 movl %edx, 0x8(%rdi)
4990: 31 c0 xorl %eax, %eax
4992: c3 retq
I think this is simply checking the carry flag. According to "Introduction to 64 Bit Assembly Programming for Linux and OS X" (Seyfarth, 2013) this is an alias for jnc
. So I figured I can use jc
as an error check. Jump to error if there is a carry flag set. Initially this seemed to work, but then weirdness ensued.
The second time I executed this syscall in my program, the carry flag was set, but the new time was also fetched. After messing around with it for a bit, I ended up with this bit of code demonstrating the issue:
# get current time
movq $0x2000074, %rax
leaq curtime(%rip), %rdi
syscall
jc error
# get current time again
movq $0x2000074, %rax
leaq curtime(%rip), %rdi
syscall
jc error
# add 5 seconds to the start time and stash in rdx
movq curtime(%rip), %rdx
addq $5, %rdx
movq $0x2000074, %rax
leaq curtime(%rip), %rdi
syscall
jc error
If I comment out the code that sets up %rdx with current time plus five seconds, then the jc error
instruction does not jump to the error label.
Thing is, if I have a look at what's happening to $curtime(%rip)
, it is getting updated every time in a way that makes it look like things are working. The values go up by a few seconds each time. When I check the carry flag (low rflags bit) after the failed system call, it is set. Also, rax contains 0xe(15).
What am I doing wrong? Why do the move and add instructions seem to be messing something up?