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

汇编程序出现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

修复说明

  1. 重构str_to_int函数:去掉递归逻辑,用符号标记变量处理负数,避免栈溢出。
  2. 保存极值到内存:将最小值、最大值、总和存入.bss段的变量中,避免寄存器值被后续操作覆盖。
  3. 复用计算结果:直接使用compute阶段算出的总和,避免重复遍历数组。
  4. 增加EOF处理:当用户输入Ctrl+D时,直接退出程序,避免非法输入处理。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.13 00:40:54