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

Linux下NASM汇编程序文件打开失败问题求助

NASM汇编程序无法打开文件问题排查

错误输出

Error: Could not open file.
O5

程序预期功能

  • 检查是否通过命令行参数提供文件名
  • 未指定文件时,打印错误信息并退出
  • 尝试以只读方式打开指定文件
  • 文件打开成功后,读取内容、定位第二行并输出到标准输出
  • 无法打开或读取文件时,打印对应错误信息及错误码

问题详情

即使目标文件存在于程序同目录且具备读写权限,程序仍无法打开文件并输出上述错误。怀疑问题出在文件名传递/解析逻辑,或是sys_open系统调用的实现错误。完整代码如下:

section .data
    error_no_arg db "Error: File not specified.", 10, 0
    error_open db "Error: Could not open file.", 10, 0
    error_open_code db "Open failed with error code: ", 0
    error_read db "Error: Failed to read file.", 10, 0
    newline db 10

section .bss
    buffer resb 1024
    error_code resb 4

section .text
    global _start

_start:
    ; Check if a file name is provided
    mov eax, [esp + 4]              ; argc
    cmp eax, 2                      ; argc >= 2
    jae open_file                   ; Proceed to open file if true

    ; Error: File not specified
    mov eax, 4                      ; sys_write
    mov ebx, 1                      ; stdout
    mov ecx, error_no_arg           ; Error message
    mov edx, 26                     ; Length of the message
    int 0x80
    jmp exit_program

open_file:
    ; Debug: Print the file name (argv[1])
    lea ebx, [esp + 8]              ; Load address of argv[1]
    mov eax, 4                      ; sys_write
    mov ecx, ebx                    ; Pointer to file name
    mov edx, 100                    ; Limit length
    int 0x80

    ; Attempt to open file
    mov eax, 5                      ; sys_open
    lea ebx, [esp + 8]              ; Load address of argv[1]
    mov ecx, 0                      ; O_RDONLY
    int 0x80

    ; Check if the file was opened successfully
    cmp eax, 0                      ; File descriptor should be >= 0
    jl file_open_error              ; If error, handle it

    ; Save the file descriptor
    mov ebx, eax

    ; Debug: Print confirmation of file opening
    mov eax, 4                      ; sys_write
    mov ebx, 1                      ; stdout
    lea ecx, [esp + 8]              ; Pointer to file name
    mov edx, 100                    ; Limit length
    int 0x80

read_file:
    mov eax, 3                      ; sys_read
    mov ecx, buffer                 ; Buffer pointer
    mov edx, 1024                   ; Bytes to read
    int 0x80
    cmp eax, 0                      ; EOF reached?
    jle file_read_error             ; If error, handle it

    ; Look for the second line
    mov esi, buffer                 ; esi points to the buffer
    xor ecx, ecx                    ; Line counter

find_second_line:
    mov al, byte [esi]              ; Read a byte from the buffer
    cmp al, 0                       ; End of data?
    je end_of_buffer
    cmp al, [newline]               ; Check for newline
    jne skip_char

    inc ecx                         ; Increment line counter
    cmp ecx, 2                      ; Found the second line?
    je print_second_line

skip_char:
    inc esi                         ; Next character
    jmp find_second_line

print_second_line:
    ; Print the second line
    mov edx, 0                      ; Line length counter
find_line_end:
    mov al, byte [esi + edx]
    cmp al, 0                       ; End of data?
    je do_write
    cmp al, [newline]               ; End of line?
    je do_write
    inc edx                         ; Increment line length
    jmp find_line_end

do_write:
    mov eax, 4                      ; sys_write
    mov ebx, 1                      ; stdout
    lea ecx, [esi]                  ; Pointer to second line
    int 0x80
    jmp close_file

end_of_buffer:
close_file:
    ; Close the file
    mov eax, 6                      ; sys_close
    mov ebx, [esp + 4]              ; File descriptor in ebx
    int 0x80
    jmp exit_program

file_open_error:
    ; Error: Could not open file
    mov eax, 4                      ; sys_write
    mov ebx, 1                      ; stdout
    mov ecx, error_open             ; Error message
    mov edx, 30                     ; Length of the message
    int 0x80

    ; Print error code
    mov eax, 5                      ; sys_open returns the error code in eax
    lea ebx, [error_code]           ; Pointer to error code variable
    mov [error_code], eax           ; Store the error code
    mov eax, [error_code]           ; Load the error code
    ; Convert error code to string and print
    call print_error_code

    jmp exit_program

file_read_error:
    ; Error: Failed to read file
    mov eax, 4                      ; sys_write
    mov ebx, 1                      ; stdout
    mov ecx, error_read             ; Error message
    mov edx, 29                     ; Length of the message
    int 0x80

exit_program:
    ; Exit the program
    mov eax, 1                      ; sys_exit
    xor ebx, ebx                    ; Exit code: 0
    int 0x80

print_error_code:
    ; Print error code as a string
    add eax, '0'                    ; Convert error code to character
    mov [error_code], al            ; Write character to buffer
    mov eax, 4                      ; sys_write
    mov ebx, 1                      ; stdout
    lea ecx, [error_code]           ; Pointer to buffer
    mov edx, 1                      ; Output size
    int 0x80
    ret

问题分析与修复

1. 核心错误:文件名指针传递错误

open_file段中,lea ebx, [esp + 8]获取的是argv[1]在栈中的存储地址(即指针的指针),但sys_open系统调用要求ebx直接指向文件名字符串的首地址。正确写法是取出栈中存储的指针值:

; 错误写法
lea ebx, [esp + 8]
; 正确写法
mov ebx, [esp + 8]

这个错误导致内核无法识别你传递的"文件名",直接触发打开失败。

2. 错误码处理逻辑错误

file_open_error段中,你错误地将eax赋值为5(sys_open的调用号),但实际上sys_open失败时,eax返回的是负数错误码(比如-2对应文件不存在,-13对应权限不足)。正确处理需要保留原错误码并取绝对值:

; 错误写法
mov eax, 5
; 正确处理
neg eax ; 将负数错误码转为正数
add eax, '0'

3. 文件描述符保存与关闭错误

close_file段中,你将ebx赋值为[esp + 4](这是argc的值),而非之前打开文件得到的文件描述符。需要新增一个变量存储文件描述符:

; 在.bss段新增
fd resb 4

; 文件打开成功后保存描述符
mov [fd], eax

; 关闭文件时使用
mov eax, 6
mov ebx, [fd]
int 0x80

4. 调试输出的冗余问题

调试打印文件名时,edx设为100会打印文件名后的垃圾数据,建议改为手动计算文件名长度,或暂时注释该调试代码避免干扰。

修复后的核心代码片段

section .bss
    buffer resb 1024
    error_code resb 4
    fd resb 4 ; 新增存储文件描述符的变量

; ...

open_file:
    ; 获取正确的文件名指针
    mov ebx, [esp + 8]
    ; 调试打印文件名(可选,建议控制长度)
    mov eax, 4
    mov ecx, ebx
    mov edx, 20 ; 假设文件名不超过20字符
    int 0x80

    ; 打开文件
    mov eax, 5
    mov ecx, 0 ; O_RDONLY
    int 0x80

    cmp eax, 0
    jl file_open_error

    ; 保存文件描述符
    mov [fd], eax

; ...

close_file:
    mov eax, 6
    mov ebx, [fd]
    int 0x80
    jmp exit_program

file_open_error:
    mov eax, 4
    mov ebx, 1
    mov ecx, error_open
    mov edx, 30
    int 0x80

    ; 处理错误码
    neg eax
    call print_error_code
    jmp exit_program

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.15 14:49:51