sys_read(即调用号为0read系统调用)是 Linux 中的一个基本系统调用,用于从文件描述符中读取数据,并存储在一段指定的内存区域中,返回值为读取到的字节数。

  • sys_read

    • 函数原型

      1
      ssize_t read(int fd, void *buf, size_t count);
    • 参数

      • fd: 文件描述符,即指定读取的“源”之所在
      • buf: 缓冲区指针,数据将被读取到这里
      • count: 要读取的最大字节数
    • 返回值

      • 成功时返回实际读取的字节数
      • 返回0表示已到达文件末尾(EOF)
      • 失败时返回-errno(如EINTR, EBADF
  • 用例

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    	.section .data
    buffer:
    .space 128

    .section .text
    .globl _start

    _start:
    # 调用 sys_read 读取数据
    mov $0, %rax # 系统调用号 (0 = sys_read)
    mov $0, %rdi # 文件描述符 (0 = stdin)
    lea buffer(%rip), %rsi # 使得 void * buf = &buffer
    mov $128, %rdx # count = 128 (前面定义 buffer 的长度)
    syscall # 执行系统调用

    # 数据读取完毕,存储在 buffer 中
    # 返回值 %rax 为读取的字节长度
    mov %rax, %r12 # 备份 %rax 至 %r12

    # 调用 sys_write 将刚刚输入的数据打印出来
    mov $1, %rax # 系统调用号 (1 = sys_write)
    mov $1, %rdi # 文件描述符 (1 = stdout)
    lea buffer(%rip), %rsi # 使得void * buf = &buffer
    mov %r12, %rdx # 使得 sys_write 输出的长度为前面读取的字节长度
    syscall

    # 退出程序
    mov $60, %rax # 系统调用号 (60 = sys_exit)
    xor %rdi, %rdi # return 0
    syscall

    分析

    上述代码演示了如何使用 sys_read系统调用从标准输入(stdin,文件描述符0)读取数据。

    程序首先定义了一个128字节的buffer作为存储读取数据的缓冲区。在_start标签处,程序将系统调用号0sys_read)存入 %rax寄存器,将文件描述符0stdin)存入%rdi,将buffer的地址加载到%rsi,并设置要读取的最大字节数为128。此即为以下代码所指的调用:

    1
    read(0, &buffer, 128);

    执行syscall指令后,系统调用会从标准输入读取用户输入的数据,并将实际读取的字节数存储在%rax中。

    随后,程序将返回值(读取的字节数)备份到%r12寄存器,然后准备调用sys_write(系统调用号为1)将读取的数据输出到标准输出(stdout,文件描述符1)。最后,程序调用sys_exit(系统调用号为60)退出,返回值为0表示成功执行。