linux - 从 x86 中的特定位置读取文件

标签 linux assembly file-io x86-64 nasm

是否可以从特定行或字节开始读取文件。目前我使用这段代码读取一个文件的 4 个字节:

section .data
    filename db "file.txt", 0

section .bss
    read_data resb 4

section .text
    global _start

_start:
  mov rax, SYS_OPEN
  mov rdi, filename
  mov rsi, O_RDONLY
  mov rdx, 0
  syscall

  push rax
  mov rdi, rax
  mov rax, SYS_READ
  mov rsi, read_data
  mov rdx, 4
  syscall

  mov rax, SYS_CLOSE
  pop rdi
  syscall

此代码始终读取前 4 个字节,但我想从文件的其他部分开始读取,例如中间部分。我需要添加或更改什么?

最佳答案

一个新打开的文件描述符从 position = 0 开始。如果你在一个循环中继续从同一个 fd 读取,你会得到连续的 block 。 (使用更大的缓冲区,如 8kiB,并在用户空间中循环双字,使用 read 返回的值作为上限!系统调用在 CPU 时间上非常昂贵。)

Is it possible to start reading a file from a specific line or byte.

  • 字节:是
  • 线路:没有。在 Unix/Linux 中,内核没有行起始字节偏移量索引或任何其他面向行的 API。例如,stdio fgets 中的行处理纯粹是在用户空间中完成的。有一些历史操作系统使用基于记录的文件,但 Unix 文件是平面字​​节数组。 (它们可能有漏洞、未写入的范围和扩展属性……但主要文件内容的内核 API 仅使用字节偏移量进行操作)。

如果你想换行,读取一个大块并向前循环,直到你看到一些换行符。如果您还没有,请阅读另一个街区;重复直到找到所需行号的开始和结束,或者您点击 EOF。 x86-64 可以使用 pcmpeqb/pmovmskb/popcnt 一次高效地搜索 16 个字节(popcnt 需要 SSE4.2 或特定的 popcnt 功能位).

或者仅使用 SSE2,或者在针对大块进行优化时,使用 pcmpeqb/psadbw(针对全零)将 hsum 字节转换为 qwords/padd。然后用一些标量代码检查你经常去多少行。或者保持简单并在 SIMD 向量中找到第一个换行符。

显然,缓慢而简单的选项是一个每次一个字节的循环,它计算 '\n' 个字符 - 如果您知道如何使用 SSE2 执行 strchr,那么向量化应该很简单使用上述建议进行搜索。


但如果您只想要一些特定的字节位置,您有两个主要选择:

  • read(2) 之前使用 lseek(2) 进行搜索(参见@Nicolae Natea 的回答)

  • 使用 POSIX/Linux pread(2)从指定的偏移量读取,而不移动 fd 的文件偏移量以供将来的 read 调用使用。 Linux 系统调用名称为 pread64(__NR_pread64 equ 17 来自 asm/unistd_64.h)

    ssize_t pread(int fd, void *buf, size_t count, off_t offset);read的唯一区别是偏移量arg,第4个arg因此传入R10(不像用户空间函数调用约定那样的 RCX)。 off_t 是一个 64 位类型,只是在 64 位代码中传入一个寄存器。

除了 .h 中的 pread64 名称外,asm 接口(interface)与 C 接口(interface)相比没有什么特别之处,它遵循标准的系统调用约定。 (自 Linux 2.1.60 以来就存在;在 glibc 的包装器使用 lseek 模拟它之前。)


您还可以执行其他操作,例如 mmappreadv 系统调用,但如果您的位置已知,pread 正是您要查找的内容你想阅读。

关于linux - 从 x86 中的特定位置读取文件,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/60687591/

相关文章:

linux - 将 Linux 内核 .config 文件复制到不同版本是否安全?

c++ - GDB 自动激活并具有 100% 的 CPU 事件

assembly - 在不同 CPU 上表现不同的 X64 指令

c - 关于 lea 指令的问题,IA32

java - 在 Java 中传递命令行参数来复制文件名

c - Pthread 条件等待和信号

c - fsync 和 syncfs 有什么区别?

assembly - JS 在 Assembly x86 中做什么?

c# - 使用多种分隔符类型将文本文件解析为字段

c++ - 使 C 代码能够作为 C++ 代码运行