0xa2 is the syscall number. The kernel uses it to decide what actual function to perform, since the syscall
instruction itself does not contain any information.
As for rax
, it does get used. To continue the tradition started in old days, the eax
is an alias to the low 32 bits of rax
. However, there is one not very well-known quirk of x64 architecture: whenever you modify that low 32-bit part, the top 32-bits get zeroed. So, in fact mov eax, 0xa2
is equivalent to mov rax, 0xa2
, except its encoding is shorter. NASM, or as -O2
, will even do that optimization for you.
The last three instructions perform the error handling. In case %rax
is between -1 and -4095, it means the syscall returned an error, for any Linux system call. Here's how it looks in the original source:
cmpq $-4095, %rax /* Check %rax for error. */
jae __syscall_error /* Branch forward if it failed. */
ret /* Return to caller. */
You see wrong target for the jae
because you're disassembling a relocatable object, and the relocatable fields have been set to 0 since they will be patched at the final link time.
To see the relocation targets, add -r
switch to objdump
command line:
0000000000000000 <sync>:
0: b8 a2 00 00 00 mov $0xa2,%eax
5: 0f 05 syscall
7: 48 3d 01 f0 ff ff cmp $0xfffffffffffff001,%rax
d: 0f 83 00 00 00 00 jae 13 <sync+0x13>
f: R_X86_64_PC32 __syscall_error-0x4
13: c3 retq
You can see that the bytes at offset f
will be patched so that jump goes to __syscall_error
.
Read https://cs.lmu.edu/~ray/notes/syscalls/ for more info on syscalls.
Also The Definitive Guide to Linux System Calls blog article.