所以我明白系统调用的用途和作用。 几乎任何需要计算机资源的东西都会在某个时候调用系统调用。我的问题是,例如,用户在Python中创建的程序如何编译并知道在哪里进行系统调用?如果我编写一个"Hello World"程序,编译器(在这种情况下为解释器(是否知道将 Python 中的 print(( 函数与其主机操作系统中的特定系统调用相关联?在用编程语言编写用户程序并将其转换为 1 和 0 的过程中,系统调用在哪里发挥作用?谢谢。
用户在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: "Hellon"
(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 "Hellon", 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
例程调用的,例程是libc
提供的系统调用包装器。 - Python没有直接调用
__libc_write
。它称为__GI__IO_fputs
(实际上是fputs
的别名。 - Python解释器将
print
转换为对PyFile_WriteString
的调用,该函数将实际工作委托给libc。
这并不罕见 - 事实上,大多数用户级程序并不直接执行系统调用。相反,它们调用libc
例程,例如write
或fputs
,并让 libc 担心如何在系统调用方面实现这些例程。
通过这样做,他们可以抽象出特定机器和操作系统的细节;他们希望在任何机器上找到一些libc
,只有libc
开发人员才需要担心实际的系统调用细节。