NASM中使用scanf读取字符串触发段错误的问题排查
问题分析与解决方案
核心错误点
- 野指针访问触发段错误:
msg1是.bss段用resb 33定义的33字节缓冲区,你却将malloc返回的8字节指针写入[msg1],覆盖了缓冲区前8个字节。后续调用scanf时,你把msg1的地址传给rsi,scanf会将输入字符串写入该地址,直接冲掉之前存储的malloc指针。最后调用printStr时,mov rsi, [msg1]会把输入字符串的前8个字节当作指针,这是无效地址,必然触发段错误。 - 冗余的动态内存操作:提示字符串是固定内容,完全不需要
malloc和strcpy动态分配,直接使用.data段的静态字符串即可,既简化代码又避免内存管理错误。 scanf传参逻辑混淆:scanf("%s", buf)的第二个参数是缓冲区的地址,你传递msg1地址的操作是对的,但后续错误地试图读取[msg1]作为指针,导致逻辑混乱。
修正后的代码
SECTION .data prompt db 'hello, insert your name. ', 0 string_format db '%s', 10, 0 SECTION .bss input_buf resb 33 ; 33字节缓冲区,可存储32字符+空终止符 SECTION .text extern printf, scanf global main printStr: mov rdi, string_format xor rax, rax call printf ret exit_program: mov rdi, 0 mov rax, 60 syscall main: ; 打印提示信息 mov rsi, prompt mov rdi, string_format xor rax, rax call printf ; 读取用户输入 mov rsi, input_buf mov rdi, string_format xor rax, rax call scanf ; 回显输入内容 mov rsi, input_buf call printStr call exit_program
修正说明
- 简化提示字符串定义:将固定提示语移到
.data段,避免手动逐个字节初始化,提升代码可读性和维护性。 - 移除冗余内存操作:删除不必要的
malloc、strcpy和自定义strlen,减少出错点。 - 明确
scanf传参逻辑:直接传递input_buf的地址作为输入缓冲区,确保scanf写入合法内存区域。 - 规范回显操作:直接使用
input_buf的地址调用printStr,避免野指针访问。
额外注意事项
scanf("%s")会自动在输入末尾添加空终止符,但要确保缓冲区大小足够,防止溢出;如果需要读取含空格的字符串,建议使用fgets替代。- 严格遵循x86_64 System V调用约定:函数参数通过
rdi、rsi等寄存器传递,简单场景下无需额外保存寄存器,但复杂逻辑中需注意寄存器的保存与恢复。
内容的提问来源于stack exchange,提问作者Hrodebert
相关产品推荐
相关产品推荐

