系统调用:用户进程如何向内核传递数据/从内核接收数据?

系统调用:用户进程如何向内核传递数据/从内核接收数据?

用户和内核虚拟地址的关系在之前的几个问题中已经讨论过(下面链接),但是据我了解,用户进程不能读取或写入内核地址。

所以,如何用户进程是否共享和接收来自内核的数据?

是通过记忆吗?如果是这样,内存布局在哪里?也许CPU寄存器?

相关问题:

内存布局

答案1

让我们考虑一个例子:一个简单的 x86你好世界Linux 程序,打印一条消息stdout并退出。它需要将几个数据项传递给内核:

  • 要输出的文本字符串,
  • 退出代码。

这是汇编代码(用 FASM 编译):

format ELF executable
segment readable executable

; system call numbers
SYS_EXIT=1
SYS_WRITE=4
; file descriptors
STDOUT=1

entry $
start:
    mov eax, SYS_WRITE
    mov ebx, STDOUT
    mov ecx, message
    mov edx, messageLength
    int 0x80

    mov eax, SYS_EXIT
    xor ebx, ebx ; exit code 0
    int 0x80

message:
    db "Hello, world!",0xa
messageLength=$-message

该程序为实现其主要目标(消息输出)所做的所有工作是

  • sys_write将适当的 CPU 寄存器设置为表示系统调用号(对于syscall)、文件描述符 ( stdout)、消息地址和消息长度的值
  • 执行系统调用,在本例中通过软件中断 0x80

类似的顺序是退出:将寄存器设置为系统调用号和退出代码,然后执行系统调用。

哪些寄存器要设置哪些值由系统调用定义调用约定

内核开始执行系统调用处理程序后,该处理程序从应用程序的上下文中读取寄存器的值,并根据调用约定解释它们。特别是,当它看到系统调用是 时sys_write,它会获取消息的长度和地址,并使用它们从用户空间内存中读取。然后这些数据(以及文件描述符)被传递给将执行实际工作的驱动程序。

答案2

用户进程无法读取或写入内核地址

不,但是内核可以根据需要读取和写入用户地址。 Linux 系统调用传递系统调用号和 CPU 寄存器中的参数。 (查找诸如“Linux 系统调用调用约定”之类的内容。)

其中一些参数可能是指针,在这种情况下,内核知道在用户地址空间中的指向位置中查找数据。据我了解,内核实际上在使用数据之前将其复制到内核空间。 (否则另一个用户空间线程可能会在系统调用期间修改数据。)但数据的位置可以根据程序的要求位于用户地址空间中的任何位置。

相关内容