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
相关产品推荐
相关产品推荐

