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

Windows 64位汇编调用C库函数读写文件打印异常问题

问题描述

在Windows 10 64位系统上使用NASM和MinGW编写汇编程序,目标是调用C库函数fopen、fread、fclose读取文件内容并打印到控制台。目前文件能成功打开,程序也能打印出"File content:"提示,但文件内容无法正常显示,甚至完全不打印。

代码

; read file and print content

section .data
    filename db "test.txt", 0
    read_mode db "r", 0
    prompt db "File content:", 10, 0
    buffer_size equ 1024
    bytes_read dq 0
    hFile dq 0
    buffer db buffer_size dup(0)
    error_msg db "Failed to open the file.", 10, 0

section .text
    extern printf, fopen, fread, fclose
    global main

main:
    push rbp
    mov rbp, rsp

    ; Open the file
    lea rcx, [rel filename]  ; Filename
    lea rdx, [rel read_mode] ; Read mode
    call fopen
    mov [rel hFile], rax         ; Store file handle

    ; Check if the file was opened successfully
    cmp rax, 0
    je file_error

    ; Read file content
    lea rcx, [rel buffer]       ; Buffer
    mov rdx, buffer_size        ; Buffer size
    lea r8, [rel bytes_read]    ; Bytes read
    mov r9, [rel hFile]         ; File handle
    call fread

    ; Print the content
    lea rcx, [rel prompt]       ; Print the prompt
    call printf

    lea rcx, [rel buffer]       ; Print the buffer content
    call printf

    ; Close the file
    mov rcx, [rel hFile]
    call fclose

    ; Clean up and exit
    jmp program_end

file_error:
    lea rcx, [rel error_msg]
    call printf

program_end:
    mov rsp, rbp
    pop rbp
    ret

遇到的问题

  • 文件读取与缓冲区处理:使用fread函数将文件内容读取到缓冲区,但内容无法正确显示。
  • 缓冲区打印:内容完全不打印,推测可能是缓冲区未正确以空字符终止。

已尝试的操作

  • 在fread读取后为缓冲区添加空字符终止。
  • 验证文件路径正确且文件可访问。
  • 确保文件句柄正确传递给fread和fclose。

问题总结

  • 此处使用fread的方式是否存在错误?
  • 在汇编中调用C库函数时,使用printf打印缓冲区是否存在已知问题?
  • 如何确保缓冲区被正确处理并打印?

补充信息

  • 文件与可执行文件在同一目录下。
  • fopen、fread、fclose已正确声明为extern。
  • 使用Windows 10 x64系统,NASM和mingw-w-64作为开发环境。

解答

1. fread参数传递错误

x86_64的System V AMD64调用约定(MinGW采用该规范)中,fread的C原型是:

size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream);

对应寄存器传递顺序为:

  • rcx: 缓冲区地址(ptr)
  • rdx: 单个元素的大小(size)
  • r8: 元素数量(nmemb)
  • r9: 文件句柄(stream)

你的代码错误地将buffer_size直接传给rdx,还把bytes_read的地址传给r8——fread不会把读取字节数写入指定地址,而是返回值就是成功读取的元素总数。如果要读取最多1024字节,应设置size=1、nmemb=buffer_size,此时返回值就是实际读取的字节数。

2. 缓冲区打印的潜在问题

即使手动添加空字符,若文件内容包含\0(二进制数据),printf("%s", buffer)会在第一个\0处停止打印;另外如果没正确处理fread返回值,可能根本没读到有效内容。

修复后的代码

; read file and print content

section .data
    filename db "test.txt", 0
    read_mode db "r", 0
    prompt db "File content:", 10, 0
    buffer_size equ 1024
    hFile dq 0
    buffer db buffer_size dup(0)
    error_msg db "Failed to open the file.", 10, 0
    print_format db "%.*s", 10, 0 ; 按指定长度打印,避免\0截断

section .text
    extern printf, fopen, fread, fclose
    global main

main:
    push rbp
    mov rbp, rsp

    ; Open the file
    lea rcx, [rel filename]
    lea rdx, [rel read_mode]
    call fopen
    mov [rel hFile], rax

    cmp rax, 0
    je file_error

    ; Read file content: fread(buffer, 1, buffer_size, hFile)
    lea rcx, [rel buffer]       ; ptr
    mov rdx, 1                  ; size per element
    mov r8, buffer_size         ; number of elements
    mov r9, [rel hFile]         ; stream
    call fread                  ; rax = 实际读取字节数

    ; Print prompt
    lea rcx, [rel prompt]
    call printf

    ; 安全打印缓冲区:%.*s指定长度,避免\0截断
    lea rcx, [rel print_format]
    mov rdx, rax                ; 读取到的字节数
    lea r8, [rel buffer]         ; 缓冲区地址
    call printf

    ; Close file
    mov rcx, [rel hFile]
    call fclose

    jmp program_end

file_error:
    lea rcx, [rel error_msg]
    call printf

program_end:
    mov rsp, rbp
    pop rbp
    ret

关键修复点

  • 修正fread参数:设置size=1、nmemb=buffer_size,利用返回值获取实际读取字节数。
  • 使用%.*s格式串:指定打印长度,既避免内容中\0的截断问题,也无需手动为缓冲区补\0(若缓冲区被读满,建议手动补一个\0防止越界)。
  • 用fread返回值作为打印长度,确保所有读取到的内容都被输出。

额外注意事项

  • 若test.txt是二进制文件,printf打印会出现乱码,属于正常现象——printf是文本处理函数,打印二进制内容需改用逐个字节输出十六进制的方式。
  • 编译命令示例:nasm -f win64 readfile.asm -o readfile.obj && gcc readfile.obj -o readfile.exe

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.20 09:12:04