как программа, созданная пользователем на Python, например, компилируется и знает, где делать системные вызовы?
Вы можете изучить некоторые из них самостоятельно.
Учитываяэта программа на Python: print("Hello")
, в системе UNIX можно догадаться, что системный вызов write(2)
будет в конечном счете вызван. Давайте посмотрим, правда ли это:
gdb -q --args python -c 'print("Hello")'
(gdb) catch syscall write
Catchpoint 1 (syscall 'write' [1])
(gdb) run
Starting program: /usr/bin/python -c print\(\"Hello\"\)
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".
Catchpoint 1 (call to syscall write), 0x00007ffff6f3cdd4 in __GI___libc_write (fd=1, buf=0x555555b2f9f0, nbytes=6) at ../sysdeps/unix/sysv/linux/write.c:26
26 ../sysdeps/unix/sysv/linux/write.c: No such file or directory.
(gdb) x/s $rsi
0x555555b2f9f0: "Hello\n"
(gdb) bt
#0 0x00007ffff6f3cdd4 in __GI___libc_write (fd=1, buf=0x555555b2f9f0, nbytes=6) at ../sysdeps/unix/sysv/linux/write.c:26
#1 0x00007ffff6ecdb9d in _IO_new_file_write (f=0x7ffff720d760 <_IO_2_1_stdout_>, data=0x555555b2f9f0, n=6) at fileops.c:1183
#2 0x00007ffff6eccf3f in new_do_write (fp=0x7ffff720d760 <_IO_2_1_stdout_>, data=0x555555b2f9f0 "Hello\n", to_do=to_do@entry=6) at libioP.h:839
#3 0x00007ffff6ecece9 in _IO_new_do_write (fp=<optimized out>, data=<optimized out>, to_do=6) at fileops.c:432
#4 0x00007ffff6ece26f in _IO_new_file_xsputn (f=0x7ffff720d760 <_IO_2_1_stdout_>, data=<optimized out>, n=1) at libioP.h:839
#5 0x00007ffff6ec2c3f in __GI__IO_fputs (str=0x55555580d74d "\n", fp=0x7ffff720d760 <_IO_2_1_stdout_>) at libioP.h:839
#6 0x00005555556966ac in PyFile_WriteString ()
#7 0x000055555564c42d in PyEval_EvalFrameEx ()
#8 0x000055555564610a in PyEval_EvalCodeEx ()
#9 0x0000555555645a29 in PyEval_EvalCode ()
#10 0x0000555555676c5f in ?? ()
#11 0x00005555556a4846 in PyRun_StringFlags ()
#12 0x00005555556a567c in PyRun_SimpleStringFlags ()
#13 0x000055555562005a in Py_Main ()
#14 0x00007ffff6e7652b in __libc_start_main (main=0x55555561fb30 <main>, argc=3, argv=0x7fffffffdc78, init=<optimized out>, fini=<optimized out>, rtld_fini=<optimized out>,
stack_end=0x7fffffffdc68) at ../csu/libc-start.c:308
#15 0x000055555561fa4a in _start ()
Что вы можете из этого сделать?
- Системный вызов
write
действительно вызывается с ожидаемыми символами в регистре $RSI
(в этом случае второй аргумент системных вызовов должен быть для этой конкретной платформы). - Системный вызов вызывается из подпрограммы
__GI___libc_write
, которая представляет собой системный вызов wrapper . libc
. - Python не вызывал
__libc_write
напрямую. Он называется __GI__IO_fputs
(который на самом деле является псевдонимом для fputs
. - Интерпретатор Python преобразовал
print
в вызов PyFile_WriteString
, и эта функция делегировала действительныйработать в libc.
Это не является чем-то необычным - на самом деле большинство программ уровня пользователя не выполняют системные вызовы напрямую. Вместо этого они вызывают libc
подпрограммы, такие как write
илиfputs
, и пусть libc беспокоится о том, как реализовать эти подпрограммы в терминах системных вызовов.
Таким образом, они могут абстрагировать детали конкретной машины и ОС; они ожидаютчтобы найти libc
на любом компьютере, и только libc
разработчикам приходится беспокоиться о реальных деталях системного вызова.