You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

x86_64汇编逐字符读文件打印的EOF检测问题求助

x86_64汇编逐字符读取文件问题排查与修复

问题背景

我需要编写一个x86_64汇编程序,实现逐字符读取指定文本文件并打印,直到文件结束。目前遇到两个问题:

  • 用rax检测EOF(文件结束)的方法失效;
  • 逐字符读取时输出字符间会出现多余的点,一次性读取多个字符时无此问题。补全read_char的ret指令后,仅剩EOF检测问题。

测试发现执行以下代码时输出全为点:

mov     r15b, byte [input_buffer]
mov rsi, r15            ; Aktuelle Zeile

完整代码

%define STDOUT      1
%define STDIN       0
%define READONLY        0
%define SYS_READ        0
%define SYS_WRITE   1
%define SYS_OPEN    2
%define SYS_CLOSE       3
%define SYS_EXIT    60

section .data
newline:
    db 0x0a
space:
        db 0x20
tab:
        db 0x09


invalid_argument_text:
        db "No Path given"

section .bss
input_buffer:
    resb 1

section .text
    global _start

;;;================= Read/Write Functions =============================
write_invalid_arg:
    ;; save registers that are used in the code
    push    rax
    push    rdi
    push    rdx
    mov rax, SYS_WRITE
    mov rdi, STDOUT
    mov rsi, invalid_argument_text
    mov rdx, 13
    call    make_syscall
    pop rdx
    pop rdi
    pop rax
    jmp finish
    
write_newline:
    ;; save registers that are used in the code
    push    rax
    push    rdi
    push    rsi
    push    rdx
    ;; prepare arguments for write syscall
    mov rax, SYS_WRITE  ; write syscall
    mov rdi, STDOUT ; fd = 1 (stdout)
    mov rsi, newline    ; string
    mov rdx, 1      ; length

        call make_syscall

    ;; restore registers (in opposite order)
    pop rdx
    pop rsi
    pop rdi
    pop rax
    ret

write_char:
    push    rsi         ; speicher rsi
    mov rax, SYS_WRITE      ; Syscall Typ
    mov rdi, STDOUT     ; Out
    mov rsi, input_buffer   ; Aktuelle Zeile
    mov rdx, 1          ; Laenge der Zeile
    call    make_syscall        ; syscall
    pop rsi         ; Hol rsi zurueck
    ret

open_file:
        push    rdi
    push    rsi
    push    rdx
        mov     rax, SYS_OPEN      ; Datei oeffnen
        mov     rdi, rsi           ; Pfad zur Datei
        mov     rsi, READONLY      ; Nur lesen
        call    make_syscall
        mov     r11, rax
        pop     rdx
    pop     rsi
    pop     rdi
    ret

read_char:
        push    rdi
        push    rsi
        push    rdx
        mov     rdi, r11          ; Geoeffnete Datei
        mov     rax, SYS_READ
        mov     rsi, input_buffer
        mov     rdx, 1
        call    make_syscall
        pop     rdx
        pop     rsi
        pop     rdi
        ret

make_syscall:
        push    rcx     ; clobbered by syscall
    push    r11     ; clobbered by syscall
    syscall         ; system call
        pop r11
    pop rcx
    ret
; ======================================================


count_text:
        mov     r8, 0       ; Zeichen
        mov     r9, 0       ; Worte
        mov     r10, 0      ; Zeilen
        call    open_file
next_char:
        call    read_char
    
        cmp     r8, 10
        je      text_finished
    
        ;cmp        rax, 0
        ;jne        text_finished
        ;call    write_invalid_arg

        call    write_char
    
        inc     r8
    
        jmp     next_char
text_finished:
        ; Text schliessen
        mov     rax, SYS_CLOSE
        mov     rdi, r11
        call    make_syscall
        ret



;========================
_start:
    pop rbx         ; argc (>= 1 guaranteed) Anzahl Args
    
    dec rbx         ; remove command
    jz  write_invalid_arg   ; when no arg after command
    pop rsi         ; remove letters of command
    
    pop rsi         ; Pfad
    
    call   count_text
finish:
    call    write_newline
    ;; exit program via syscall exit (necessary!)
    mov rax, SYS_EXIT   ; exit syscall
    mov rdi, 0      ; exit code 0 (= "ok")
    syscall         ; kernel interrupt: system call

问题分析与修复

1. EOF检测失效问题

Linux的read系统调用返回值规则:

  • 返回大于0:成功读取的字节数;
  • 返回0:到达文件末尾(EOF);
  • 返回-1:读取错误(此时rax会被设置为负数错误码)。

你注释掉了EOF检测逻辑,需恢复并修正判断逻辑。在next_char标签后、调用read_char之后,添加正确的检测代码:

call    read_char

; 检测EOF:read返回0表示到达文件末尾
cmp     rax, 0
je      text_finished

; 可选:检测读取错误,返回值小于0则终止流程
cmp     rax, 0
jl      text_finished

注意:read_char函数调用make_syscall后,rax的返回值会被保留,因此可以直接用rax做判断。

2. 输出乱码(全为点)的问题

测试代码中的错误在于:write系统调用要求rsi传递内存地址,但你直接把字符值赋值给rsi,导致系统调用读取无效内存区域的内容,出现乱码。正确写法应传递缓冲区地址:

mov rsi, input_buffer

逐字符读取时的多余点问题,大概率是之前read_char缺少ret指令导致栈混乱,补全ret后该问题应已解决。

修正后的count_text核心逻辑

count_text:
        mov     r8, 0       ; Zeichen
        mov     r9, 0       ; Worte
        mov     r10, 0      ; Zeilen
        call    open_file
        ; 检查文件是否打开成功
        cmp     rax, 0
        jl      write_invalid_arg
next_char:
        call    read_char
    
        ; 检测EOF与读取错误
        cmp     rax, 0
        jle     text_finished

        call    write_char
    
        inc     r8
    
        jmp     next_char
text_finished:
        ; 关闭文件
        mov     rax, SYS_CLOSE
        mov     rdi, r11
        call    make_syscall
        ret

内容的提问来源于stack exchange,提问作者burprinz

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.03 15:21:05