views:

258

answers:

3

I am working on x86_64 machine. My linux kernel is also 64 bit kernel. As there are different ways to implement a system call (int 80, syscall, sysenter), i wanted to know what type of system call my machine is using. I am newbie to linux. I have written a demo program.

#include <stdio.h>
int main()
{
  getpid();
  return 0;
}

getpid() does one system call. Can anybody give me a method to find which type of system call will be used by my machine for this program.. Thank you....

+1  A: 

Under linux, you can use strace to record which system calls are made by a particular process.

Justin Ethier
+1 too fast :=)
f4
That doesn't answer the question. `strace` will show what system call was made (in this case `getpid`) but won't tell the user the specific mechanism.
R Samuel Klatchko
Can you please explain?
Justin Ethier
The OP is asking for how to determine the specific sys call mechanism (int 80, syscall, sysenter). strace just tells you the name of the syscall being made.
R Samuel Klatchko
+5  A: 
victory:~ # gcc getpid.c -o getpid -g
victory:~ # gdb getpid
<snip>
(gdb) break main
Breakpoint 1 at 0x400540: file getpid.c, line 4.
(gdb) run
Starting program: /root/getpid 

Breakpoint 1, main () at getpid.c:4
4     getpid();
(gdb) disassemble
Dump of assembler code for function main:
0x000000000040053c <main+0>:    push   %rbp
0x000000000040053d <main+1>:    mov    %rsp,%rbp
0x0000000000400540 <main+4>:    mov    $0x0,%eax
0x0000000000400545 <main+9>:    callq  0x400440 <getpid@plt>
0x000000000040054a <main+14>:   mov    $0x0,%eax
0x000000000040054f <main+19>:   leaveq 
0x0000000000400550 <main+20>:   retq   
End of assembler dump.

Looks like our call to getpid() is actually a library call. Let's set a breakpoint there and continue.

(gdb) break getpid
Breakpoint 2 at 0x7ffff7b29c00
(gdb) cont
Continuing.

Breakpoint 2, 0x00007ffff7b29c00 in getpid () from /lib64/libc.so.6
(gdb) disassemble
Dump of assembler code for function getpid:
0x00007ffff7b29c00 <getpid+0>:  mov    %fs:0x94,%edx
0x00007ffff7b29c08 <getpid+8>:  cmp    $0x0,%edx
0x00007ffff7b29c0b <getpid+11>: mov    %edx,%eax
0x00007ffff7b29c0d <getpid+13>: jle    0x7ffff7b29c11 <getpid+17>
0x00007ffff7b29c0f <getpid+15>: repz retq 
0x00007ffff7b29c11 <getpid+17>: jne    0x7ffff7b29c1f <getpid+31>
0x00007ffff7b29c13 <getpid+19>: mov    %fs:0x90,%eax
0x00007ffff7b29c1b <getpid+27>: test   %eax,%eax
0x00007ffff7b29c1d <getpid+29>: jne    0x7ffff7b29c0f <getpid+15>
0x00007ffff7b29c1f <getpid+31>: mov    $0x27,%eax
0x00007ffff7b29c24 <getpid+36>: syscall 
0x00007ffff7b29c26 <getpid+38>: test   %edx,%edx
0x00007ffff7b29c28 <getpid+40>: mov    %rax,%rsi
0x00007ffff7b29c2b <getpid+43>: jne    0x7ffff7b29c0f <getpid+15>
0x00007ffff7b29c2d <getpid+45>: mov    %esi,%fs:0x90
0x00007ffff7b29c35 <getpid+53>: mov    %esi,%eax
0x00007ffff7b29c37 <getpid+55>: retq   
End of assembler dump.

Buried in the getpid() library is the syscall assembler instruction. This is an AMD64 instruction that supports a fast context switch to ring0 for the purpose of system calls.

MikeyB
Some more implementation details can be found here: http://www.win.tue.nl/~aeb/linux/lk/lk-4.html
MikeyB
I'm slightly confused: you say `sysenter` but the disassembly says `syscall`.
Eric Seppanen
I meant syscall, fixed.
MikeyB
Awesome.... thank you very much
A: 

One way is to use the gdb to step through the machine code (using stepi) until you get to the instruction that initiates the system call. Because different machines put the instruction in different places (sometimes in the system call wrapper itself and sometimes in a function called by the system call wrapper), I can't predict where exactly the instruction will be.

For example, on one old machine, getpid itself did a int 0x80 while in a newer machine, getpid does a call *gs:0x10 which brings it to __kernel_vsyscall which does a sysenter

R Samuel Klatchko
Your backticks have gone awry.
Eric Seppanen
In amd64 it doesn't do call *gs:0x10 it just does callq. It does have a vdso page mapped on the process space. But --kernel_vsyscall is not called. You can see from Mikey's answer that it directly calls syscall without going through the __kernel_vsyscall.... why is it so???
@bala1486 - different builds of libc. MikeyB did a good job at showing how he figured out the specific mechanism for his version of libc/OS. But you should follow his technique to see if your version of libc does the same thing. Also, assuming you like his answer, you should accept it it.
R Samuel Klatchko
Accepted it.. Thank you....