汇编程序出现Segmentation Fault问题求助:输入10整数计算统计量
x86汇编程序段错误排查与修复
问题描述
编写的汇编程序计划实现:让用户输入10个整数,输出它们的总和、平均值、极差及质数数量,但运行时触发Segmentation Fault错误。
核心错误原因
1. str_to_int函数递归调用导致栈溢出
原函数处理负数时采用递归调用,会引发无限递归:每次递归都会重新检查当前字符,导致函数不断调用自身,最终栈空间耗尽触发段错误。
2. 极差计算时寄存器值被覆盖
在计算平均值时使用了div ebx,此时ebx被设为10、edx存储除法余数;而极差需要的是之前计算的最大值与最小值,原代码错误地使用了被覆盖后的寄存器值,不仅逻辑错误,还可能导致非法内存访问。
3. 重复计算总和/平均值(非致命但低效)
原代码在compute阶段已算出总和,但在display_results中又重新遍历数组计算,冗余且浪费资源。
修复后的完整代码
section .data prompt db "Enter integer: ", 0 newline db 10, 0 sum_msg db "Sum: ", 0 avg_msg db "Average: ", 0 range_msg db "Range: ", 0 prime_msg db "Number of primes: ", 0 buffer db 20 dup(0) section .bss input resb 20 numbers resd 10 sum_val resd 1 ; 存储总和 min_val resd 1 ; 存储最小值 max_val resd 1 ; 存储最大值 section .text global _start _start: mov ecx, 0 ; Counter for number of inputs read_loop: cmp ecx, 10 jge compute ; Display prompt mov eax, 4 ; sys_write mov ebx, 1 ; stdout mov ecx, prompt mov edx, 15 int 0x80 ; Read input mov eax, 3 ; sys_read mov ebx, 0 ; stdin mov ecx, input mov edx, 20 int 0x80 ; eax contains the number of bytes read ; Handle EOF (Ctrl+D) cmp eax, 0 je exit_program ; Replace newline with null terminator mov ebx, eax cmp ebx, 1 jl skip_null dec ebx mov byte [input + ebx], 0 skip_null: ; Convert input to integer mov esi, input call str_to_int mov [numbers + ecx*4], eax inc ecx jmp read_loop compute: ; Initialize variables xor eax, eax ; Sum mov ebx, [numbers] ; Min mov [min_val], ebx mov edx, [numbers] ; Max mov [max_val], edx xor edi, edi ; Prime count xor ecx, ecx ; Index calc_loop: cmp ecx, 10 jge prepare_display mov esi, [numbers + ecx*4] add eax, esi ; Sum += number ; Update min cmp esi, [min_val] jl update_min jmp check_max update_min: mov [min_val], esi check_max: ; Update max cmp esi, [max_val] jg update_max jmp check_prime update_max: mov [max_val], esi check_prime: push eax push ebx push ecx push edx push esi call is_prime cmp eax, 1 jne not_prime inc edi not_prime: pop esi pop edx pop ecx pop ebx pop eax inc ecx jmp calc_loop prepare_display: mov [sum_val], eax ; 保存计算好的总和 display_results: ; Display Sum mov ecx, sum_msg call print_string mov eax, [sum_val] call print_int call print_newline ; Display Average mov ecx, avg_msg call print_string mov eax, [sum_val] mov ebx, 10 xor edx, edx div ebx call print_int call print_newline ; Display Range mov ecx, range_msg call print_string mov eax, [max_val] sub eax, [min_val] call print_int call print_newline ; Display Number of Primes mov ecx, prime_msg call print_string mov eax, edi call print_int call print_newline exit_program: ; Exit program mov eax, 1 xor ebx, ebx int 0x80 ; ------------------------------- ; Function: str_to_int ; Converts string at ESI to integer in EAX str_to_int: xor eax, eax xor ebx, ebx mov ecx, 1 ; 符号标记:1=正,-1=负 mov bl, byte [esi] cmp bl, '-' jne .parse_start mov ecx, -1 inc esi ; 跳过负号 .parse_start: xor eax, eax .next_digit: mov bl, byte [esi] cmp bl, 0 je .done cmp bl, '0' jl .done cmp bl, '9' jg .done sub bl, '0' imul eax, eax, 10 add eax, ebx inc esi jmp .next_digit .done: imul eax, ecx ; 应用符号 ret ; ------------------------------- ; Function: is_prime ; Checks if ESI is a prime number; result in EAX (1 = prime, 0 = not) is_prime: mov eax, esi cmp eax, 2 jl .not_prime_flag ; 小于2的数不是质数 mov ebx, 2 mov ecx, eax shr ecx, 1 ; 检查到一半即可 .prime_loop: cmp ebx, ecx jg .prime_flag mov edx, 0 mov eax, esi div ebx cmp edx, 0 je .not_prime_flag inc ebx jmp .prime_loop .prime_flag: mov eax, 1 ret .not_prime_flag: xor eax, eax ret ; ------------------------------- ; Function: print_string ; Prints null-terminated string at ECX print_string: push eax push ebx push edx mov edx, 0 .count: cmp byte [ecx + edx], 0 je .print inc edx jmp .count .print: mov eax, 4 mov ebx, 1 int 0x80 pop edx pop ebx pop eax ret ; ------------------------------- ; Function: print_int ; Prints integer in EAX print_int: push eax push ebx push ecx push edx mov ecx, buffer add ecx, 19 mov byte [ecx], 0 dec ecx test eax, eax jns .convert neg eax mov bl, '-' mov [ecx], bl dec ecx .convert: mov ebx, 10 .repeat: xor edx, edx div ebx add dl, '0' mov [ecx], dl dec ecx test eax, eax jnz .repeat inc ecx mov eax, 4 mov ebx, 1 mov edx, 20 sub edx, ecx int 0x80 pop edx pop ecx pop ebx pop eax ret ; ------------------------------- ; Function: print_newline ; Prints a newline character print_newline: mov eax, 4 mov ebx, 1 mov ecx, newline mov edx, 1 int 0x80 ret
修复说明
- 重构
str_to_int函数:去掉递归逻辑,用符号标记变量处理负数,避免栈溢出。 - 保存极值到内存:将最小值、最大值、总和存入
.bss段的变量中,避免寄存器值被后续操作覆盖。 - 复用计算结果:直接使用
compute阶段算出的总和,避免重复遍历数组。 - 增加EOF处理:当用户输入Ctrl+D时,直接退出程序,避免非法输入处理。
内容的提问来源于stack exchange,提问作者Bob saggat
相关产品推荐
相关产品推荐

