【问题标题】:Nasm x86_64: Why can't I write and read from the same file?Nasm x86_64:为什么我不能从同一个文件中读写?
【发布时间】:2020-01-10 03:54:27
【问题描述】:

我在 Nasm x86_64 中处理文件时遇到问题。 我已经正确打开了文件,我可以写入或读取它,但是如果我在写入文件后尝试从文件中读取一些东西,我什么也得不到。 所以我从文件中读取或写入。 奇怪的是,如果我第一次读写我没有任何问题并且一切正常,所以问题只是当我第一次写然后读时。 有人可以帮我解决这个问题并找出原因吗?

这是打开文件的代码:

    mov     rax, SYS_OPEN
    mov     rdi, filename
    mov     rsi, O_CREAT+O_RDWR+O_APPEND
    mov     rdx, 0744o
    syscall
    push    rax

关闭文件的代码:

    mov     rax, SYS_CLOSE
    mov     rdi, r11
    syscall

打印字符串的代码:

    mov rdx, rax
    mov rax, SYS_WRITE
    mov rdi, STDOUT
    mov rsi, temp
    syscall

getLength的代码(参数是我要获取长度的字符串):

%macro getLength 1
    mov     r10, %1
    mov     r11, r10

    %%begin:
        cmp     byte [r11], 10
        je      %%end
        inc     r11
        jmp     %%begin

    %%end:
        sub     r11, r10
%endmacro

要写的代码:

    getLength msg
    mov     rax, SYS_WRITE
    mov     rdi, [rsp]
    mov     rsi, msg
    mov     rdx, r11
    syscall

阅读代码:

    mov     rax, SYS_READ
    mov     rdi, [rsp]
    mov     rsi, temp    ;buffer to store the string read
    mov     rdx, 10
    syscall

要读取的代码和要编写的代码都可以完美地单独工作,问题是当我在编写代码之后使用代码读取时。

所以这段代码有效。

    %include "./standardlib.inc"

section .data
    filename db "./file.txt", 0
    msg     db "hello", 10

section .bss
    temp    resb 10

section .text
    global _start:

    _start:
    mov     rax, SYS_OPEN
    mov     rdi, filename
    mov     rsi, O_CREAT+O_RDWR+O_APPEND
    mov     rdx, 0744o
    syscall
    push    rax

    mov     rax, SYS_READ
    mov     rdi, [rsp]
    mov     rsi, temp
    mov     rdx, 10
    syscall

    mov rdx, rax
    mov rax, SYS_WRITE
    mov rdi, STDOUT
    mov rsi, temp
    syscall

    getLength msg

    mov     rax, SYS_WRITE
    mov     rdi, [rsp]
    mov     rsi, msg
    mov     rdx, r11
    syscall

    mov     rax, SYS_CLOSE
    mov     rdi, r11
    syscall

    exit

这个 coe 不起作用:

    %include "./standardlib.inc"

section .data
    filename db "./file.txt", 0
    msg     db "hello", 10

section .bss
    temp    resb 10

section .text
    global _start:

    _start:
    mov     rax, SYS_OPEN
    mov     rdi, filename
    mov     rsi, O_CREAT+O_RDWR+O_APPEND
    mov     rdx, 0744o
    syscall
    push    rax

    getLength msg

    mov     rax, SYS_WRITE
    mov     rdi, [rsp]
    mov     rsi, msg
    mov     rdx, r11
    syscall

    mov     rax, SYS_READ
    mov     rdi, [rsp]
    mov     rsi, temp
    mov     rdx, 10
    syscall

    mov rdx, rax
    mov rax, SYS_WRITE
    mov rdi, STDOUT
    mov rsi, temp
    syscall

    mov     rax, SYS_CLOSE
    mov     rdi, r11
    syscall

    exit

所以我明白我必须使用 lseek 返回到文件的开头。 这是对 sys_lseek 的良好调用吗?

    mov rax, 8        ;sys_lseek syscall ID
    mov rdi, [rsp]    ;file descriptor
    mov rsi, 0        ;The offset
    mov rdx, 0        ;I imagine the value of SEEK_SET

sys_lseek

我猜是偏移值不对,应该用 ftell 找到,但是不知道怎么调用。

ftell

【问题讨论】:

  • 您没有向我们展示./standardlib.inc 的内容,尤其是getlength 的定义方式(我假设是一个宏)。不确定它是否返回 r11 中的值?那里似乎有些可疑。你能告诉我们getlength是如何出现在那个.inc文件中的吗?
  • 为什么要以追加模式打开文件?附加到文件后,您希望从文件中读取什么?如果您不知道附加模式的作用,请先阅读 open(2) 的手册页。
  • 阅读 write 的文档,我们看到:写入发生在当前文件偏移量处,文件偏移量增加实际写入的字节数。由于您正在对文件末尾进行写入(由于 O_APPEND),因此写入后的文件位置也将是文件的末尾。没有什么要读的了,因为,嗯,它在文件的末尾。也许你需要的是lseek
  • @MichaelPetch 我没有放标准库的代码,因为我知道 getLength 工作正常,因为我在各种情况下使用它从来没有给我带来问题,如果它有问题也可能执行之前未写入文件的单次读取文件会引发问题。
  • @LeonardoDeFaveri 使用SEEK_CUR 和偏移量0 执行lseek。然后观察返回值。

标签: linux assembly x86-64 nasm system-calls


【解决方案1】:

由于文件是按顺序读取的,在追加模式下调用 sys_read 后,光标会移动到文件的末尾,因此如果您尝试从该位置读取,您将不会读取任何内容。

要解决这个问题,您必须将光标重新定位在文件的开头。

为此,您可以使用 lseek 系统调用。

    mov     rax, 8        ;system call Id for sys_lseek
    mov     rdi, [rsp]    ;file descriptor
    mov     rsi, 0        ;offset value, so number of characters to move the cursor
    mov     rdx, 0        ;It indicates the initial position from which move the cursor, in this case the value 0 indicates that the initial position is the beginning of the file
    syscall

调用此系统调用后,光标位置将位于文件的开头,您将能够从中读取。

【讨论】:

  • 另外请注意,如果您知道要从哪个位置读取,您可以简单地使用pread()(位置读取)系统调用而不是lseek + readpread 不会移动 fd 的文件位置。但是,如果您想为可能的多个reads 倒带文件位置,那么是的,您想使用lseek
猜你喜欢
  • 2021-11-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-08-01
  • 2012-05-18
  • 1970-01-01
  • 2020-08-31
相关资源
最近更新 更多