Как узнать, какой тип системного вызова используется программой

Я работаю на машине x86_64. Мое ядро ​​​​Linux также является 64-битным ядром. Поскольку существуют разные способы реализации системного вызова (int 80, syscall, sysenter), я хотел знать, какой тип системного вызова использует моя машина. Я новичок в линуксе. Я написал демонстрационную программу.

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

getpid() выполняет один системный вызов. Может ли кто-нибудь дать мне способ определить, какой тип системного вызова будет использоваться моей машиной для этой программы. Спасибо....


person bala1486    schedule 30.04.2010    source источник


Ответы (4)


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.

Похоже, наш вызов getpid() на самом деле является библиотечным вызовом. Ставим там точку останова и продолжаем.

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

В библиотеке getpid() скрыта инструкция ассемблера системных вызовов. Это инструкция AMD64, которая поддерживает быстрое переключение контекста на ring0 для системных вызовов.

person MikeyB    schedule 30.04.2010
comment
Дополнительные сведения о реализации можно найти здесь: win.tue. nl/~aeb/linux/lk/lk-4.html - person MikeyB; 01.05.2010
comment
Я немного запутался: вы говорите sysenter, а на разборке написано syscall. - person Eric Seppanen; 01.05.2010

В Linux вы можете использовать strace для записи того, какие системные вызовы выполняются конкретным процессом. .

person Justin Ethier    schedule 30.04.2010
comment
Это не отвечает на вопрос. strace покажет, какой системный вызов был выполнен (в данном случае getpid), но не сообщит пользователю конкретный механизм. - person R Samuel Klatchko; 30.04.2010
comment
ОП спрашивает, как определить конкретный механизм системного вызова (int 80, syscall, sysenter). strace просто сообщает вам имя выполняемого системного вызова. - person R Samuel Klatchko; 01.05.2010

Один из способов — использовать gdb для пошагового выполнения машинного кода (используя stepi), пока вы не дойдете до инструкции, которая инициирует системный вызов. Поскольку разные машины помещают инструкцию в разные места (иногда в саму оболочку системного вызова, а иногда в функцию, вызываемую оболочкой системного вызова), я не могу предсказать, где именно будет находиться инструкция.

Например, на одной старой машине getpid сам выполнил int 0x80, а на более новой машине getpid выполнил call *gs:0x10, что приводит к __kernel_vsyscall, что делает sysenter.

person R Samuel Klatchko    schedule 30.04.2010
comment
Ваши обратные кавычки пошли наперекосяк. - person Eric Seppanen; 01.05.2010
comment
В amd64 он не вызывает *gs:0x10, он просто вызывает callq. У него есть страница vdso, сопоставленная с пространством процесса. Но --kernel_vsyscall не вызывается. Из ответа Майки видно, что он напрямую вызывает системный вызов, минуя __kernel_vsyscall.... почему так??? - person bala1486; 01.05.2010
comment
@bala1486 - разные сборки libc. MikeyB хорошо показал, как он разобрался с конкретным механизмом для своей версии libc/OS. Но вы должны следовать его методике, чтобы убедиться, что ваша версия libc делает то же самое. Кроме того, если вам нравится его ответ, вы должны принять его. - person R Samuel Klatchko; 01.05.2010

Для этого я создал простой инструмент на основе strace. Он выполняет именно то, что вы просили:

ubuntu@pc:~$ ./syscalls whoami
ubuntu
The following syscalls were called:
access
arch_prctl
brk
close
connect
execve
exit_group
fstat
geteuid
lseek
mmap
mprotect
munmap
open
read
socket
write
The syscalls were saved to /home/ubuntu/syscalls.txt

https://github.com/avilum/syscalls

person avilum    schedule 24.08.2018
comment
Хотя этот код может ответить на вопрос, предоставление дополнительного контекста относительно того, почему и/или как этот код отвечает на вопрос, повышает его ценность в долгосрочной перспективе. - person Alex Riabov; 24.08.2018