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
问题分析与修复方案
核心错误点
- 堆内存非法写入:brk返回的当前程序断点地址是堆的起始位置,但你直接把它作为输入缓冲区地址使用——此时堆内存可能还未完成映射,直接写入会触发段错误;另外原
input变量在.bss段,和堆属于不同内存区域,逻辑上没有关联。 - 输入逻辑混乱:第一次read读取10字节后,剩余输入留在系统缓冲区,跳转扩容后直接读取到堆地址,但没有把之前的10字节内容迁移过去,同时也没考虑输入长度的累加。
- 未校验系统调用返回值: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
相关产品推荐
相关产品推荐

