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

x86汇编实现用户输入时动态扩展存储的问题求助

问题描述

我正在开发一款简易文本编辑器,目前仅能接收用户输入的10字节内容,无法实现无限输入。尝试通过brk系统调用扩展堆内存,但未能实现随输入动态扩容,输入超过10字符时出现分段错误。相关代码及运行报错如下:

输入处理代码

section .bss
    input resb 10 
    info resb 26 
    fd_out resb 1
    fd_in  resb 1

section .text
    global _start

_start:
    ;printing introduce text
    mov eax, 4          ;system_write
    mov ebx, 1          ;std_out
    mov ecx, introduce  ;introduce text
    mov edx, 20         ;bytes to output
    int 0x80            ;make system call

    ;reading user input
    mov eax, 3          ;system_read
    mov ebx, 0          ;std_in
    mov ecx, input      ;input pointer
    mov edx, 10         ;read 10 bytes
    int 0x80            ;make system call

跳转判断代码

;jump to space if there is some error
cmp eax, 10
jge space

内存扩展代码(space标签)

space:          
    ;printing introduce text
    mov eax, 4
    mov ebx, 1
    mov ecx, introduce 
    mov edx, 20
    int 0x80

    ;get current program break
    mov eax, 45
    xor ebx, ebx
    int 0x80
    mov esi, eax

    ;Increase heap by 16kb
    add eax, 16384
    mov ebx, eax
    mov eax, 45
    int 0x80

    ;reading user input
    mov eax, 3          ;system_read
    mov ebx, 0          ;std_in
    mov ecx, esi        ;input pointer
    mov edx, 16384          ;read 10 bytes
    int 0x80            ;make system call

运行报错结果

Put file name here: sadassssssssssssssssssssssssssssssssssssss
Put file name here: Segmentation fault

问题分析与修复方案

核心错误点

  1. 堆内存非法写入:brk返回的当前程序断点地址是堆的起始位置,但你直接把它作为输入缓冲区地址使用——此时堆内存可能还未完成映射,直接写入会触发段错误;另外原input变量在.bss段,和堆属于不同内存区域,逻辑上没有关联。
  2. 输入逻辑混乱:第一次read读取10字节后,剩余输入留在系统缓冲区,跳转扩容后直接读取到堆地址,但没有把之前的10字节内容迁移过去,同时也没考虑输入长度的累加。
  3. 未校验系统调用返回值:brk调用失败会返回-1,你没有做错误检查,后续操作基于无效地址执行必然出错。

修复后的代码示例

section .bss
    input resb 10 
    info resb 26 
    fd_out resb 1
    fd_in  resb 1
    heap_buf resd 1     ; 存储堆缓冲区起始地址

section .text
    global _start
    introduce db "Put file name here: ", 0x0a

_start:
print_prompt:
    ; 打印提示文本
    mov eax, 4
    mov ebx, 1
    mov ecx, introduce
    mov edx, 20
    int 0x80

    ; 首次读取输入到.bss的input缓冲区
    mov eax, 3
    mov ebx, 0
    mov ecx, input
    mov edx, 10
    int 0x80

    ; 读取不足10字节,直接处理输入
    cmp eax, 10
    jl process_input

    ; 初始化堆内存,获取当前程序断点
    mov eax, 45
    xor ebx, ebx
    int 0x80
    cmp eax, -1
    je exit_error       ; 检查brk是否失败

    mov [heap_buf], eax ; 保存堆起始地址
    ; 扩容堆到16KB
    add eax, 16384
    mov ebx, eax
    mov eax, 45
    int 0x80
    cmp eax, -1
    je exit_error

    ; 把input里的10字节复制到堆缓冲区
    mov ecx, 10
    mov esi, input
    mov edi, [heap_buf]
    rep movsb

    ; 继续读取剩余输入到堆缓冲区的剩余空间
    mov eax, 3
    mov ebx, 0
    mov ecx, [heap_buf]
    add ecx, 10         ; 跳过已复制的10字节
    mov edx, 16374      ; 剩余可用空间:16384-10
    int 0x80

    ; 合并后的输入在heap_buf指向的地址,进入处理逻辑
    jmp process_input

exit_error:
    ; 错误处理:退出程序
    mov eax, 1
    xor ebx, ebx
    int 0x80

process_input:
    ; 示例:打印输入内容
    mov eax, 4
    mov ebx, 1
    ; 判断是否使用堆缓冲区
    cmp dword [heap_buf], 0
    je print_input_bss

    ; 打印堆中的完整输入
    mov ecx, [heap_buf]
    mov edx, 10
    add edx, eax        ; 总长度:首次读取的10字节 + 后续读取长度
    int 0x80
    jmp exit_program

print_input_bss:
    ; 打印.bss段的输入
    mov ecx, input
    mov edx, eax        ; 使用首次读取的实际长度
    int 0x80

exit_program:
    mov eax, 1
    xor ebx, ebx
    int 0x80

关键修复说明

  • 堆内存安全使用:调用brk后校验返回值,确保堆地址有效,用变量保存堆起始位置,避免非法地址访问。
  • 输入内容拼接:扩容后先把原.bss段的输入复制到堆缓冲区,再读取剩余输入到堆的后续地址,实现完整输入的存储。
  • 逻辑梳理:区分首次读取和扩容后的读取流程,确保输入缓冲区的合法性,同时保留对短输入的正常处理逻辑。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.13 13:27:03