You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

汇编程序调试求助:无法显示字符串与数值,跳转指令报错

Troubleshooting & Fixes for Your Assembly Program

Hey there, let's break down the key issues in your code that are causing incorrect output and crashes, then walk through the fixes step by step:

Core Issues Identified

1. Sum Calculation & total Variable Misuse

Your Sum loop correctly accumulates the total in eax, but you never save that value to the total variable. Later, when you try to print the sum with mov eax, total, you're pulling the initial 0 value instead of the actual sum. Also, your loop termination logic (cmp edx, [esi]) relies on edx being 0 and the last array element being 0, which works here but is fragile—we'll make it more explicit.

2. Average Calculation Logic is Broken

Your manual subtraction loop to compute the average isn't how integer division works in x86 assembly. You should use the div instruction, which automatically gives you the quotient (average) and remainder in registers, instead of reinventing the wheel with subtraction. Those inc ecx/inc eax lines were also corrupting your sum and remainder values.

3. Print Code is Never Executed

You placed all your print logic after the Largest loop, but the je OutOfHere in that loop jumps directly to DumpRegs and exit. That means your print code never runs—so you only see register values instead of your labels and results!

4. IntToAsc & WriteNum Have Critical Flaws

  • IntToAsc doesn't handle negative numbers (your array has negatives, so this would produce garbage).
  • WriteNum starts with an unnecessary dec esi and doesn't properly find the end of the converted string, leading to incorrect output.
  • You didn't add a null terminator to the ans array after conversion, which can cause random garbage characters to print.

5. Removing je OutOfHere Causes Crashes

Without that jump, your Largest loop has no valid termination condition—it keeps reading past the end of the array, accessing invalid memory, which triggers a crash.


Fixed Full Code

TITLE SUM & AVERAGE & LARGEST w/ Print (Program3.asm)
COMMENT !
3rd Program - Sum, Avg, Largest, w/ Print
CS340 Summer 2020
This program places an array of numbers to find the sum, avg, and largest with the ASCII labels.
!
INCLUDE Irvine32.inc

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;; sum = eax, avg = ebx, remainder = ecx, largest = edx ;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
.data
ary dword 50,-20,34,14,45,-37,82,134,83 ; Array to hold the required values
dword 59,-24,1,-19,30,55,81,74,83,0 ; End with 0 as sentinel value
cnt dword 0 ; Count value holder
lrg dword ? ; Largest value holder
reset dword 0 ; Reset value to avoid garbage
avg dword 0 ; Holder for the quotient
rem dword ? ; Remainder value holder
ans byte 16 dup(0) ; Larger array to handle negatives + more digits
total dword ? ; Total value of the array
NULL equ 0 ; Zero value holder
CR equ 13 ; Carriage Return
LF equ 10 ; Line Feed
labelSum byte "SUM = ", 0 ; Displays Sum String
labelAvg byte "AVERAGE = ", 0 ; Displays Avg String
labelLrg byte "LARGEST = ", 0 ; Displays Large String
labelRem byte "REMAINDER = ", 0 ; Displays Remainder string

.code
WriteLine PROC ;Procedure writes the strings
    push esi ; Preserve esi for caller
Top:
    mov al, [esi] ; Move current char to AL
    call WriteChar ; Print the char
    inc esi ; Move to next char
    cmp al, NULL ; Check for string terminator
    jne Top ; Loop until end of string
    pop esi ; Restore esi
    ret
WriteLine ENDP

WriteNum PROC ;Procedure writes the integer values
    push esi ; Preserve registers
    push ecx
    mov ecx, 0
    ; First find the end of the converted ASCII string
FindEnd:
    cmp [esi], byte ptr NULL
    je StartWrite
    inc esi
    inc ecx
    jmp FindEnd
StartWrite:
    dec esi ; Back to last valid char
WriteLoop:
    mov al, [esi] ; Get char to print
    call WriteChar
    dec esi
    loop WriteLoop ; Print all chars
    pop ecx
    pop esi
    ret
WriteNum ENDP

IntToAsc PROC ;Procedure converts ints to ascii (supports negatives)
    push ebx ; Preserve caller's registers
    push edx
    push esi
    mov ebx, 10 ; Divisor for base-10 conversion
    ; Check if number is negative
    cmp eax, 0
    jge ConvertPositive
    ; Handle negative sign
    neg eax ; Make number positive for conversion
    mov [esi], byte ptr '-' ; Add negative sign to string
    inc esi
ConvertPositive:
Top:
    mov edx, NULL ; Clear EDX for division
    div ebx ; EAX = quotient, EDX = remainder
    add dl, 30h ; Convert remainder to ASCII
    mov [esi], dl ; Store ASCII char
    inc esi ; Move to next position
    cmp eax, NULL ; Check if we're done converting
    jne Top
    mov [esi], byte ptr NULL ; Add string terminator
    pop esi
    pop edx
    pop ebx
    ret
IntToAsc ENDP

NextLine PROC ;Procedure to create the next line
    push eax ; Preserve eax
    mov al, CR ; Print carriage return
    call WriteChar
    mov al, LF ; Print line feed
    call WriteChar
    pop eax
    ret
NextLine ENDP

main PROC
    ;Clear registers
    mov eax, reset
    mov ebx, reset
    mov ecx, reset
    mov edx, reset

    ;Calculate Sum and Element Count
    mov esi, offset ary ; Point to start of array
Sum:
    mov ebx, [esi] ; Get current element
    cmp ebx, NULL ; Check for sentinel (end of array)
    je SumDone
    add eax, ebx ; Add to sum
    inc cnt ; Increment count
    add esi, 4 ; Move to next DWORD element
    jmp Sum
SumDone:
    mov total, eax ; Save sum to variable

    ;Calculate Average & Remainder with DIV instruction
    mov ebx, cnt ; Divisor = number of elements
    mov edx, 0 ; Clear EDX for division (required for DIV)
    div ebx ; EAX = average (quotient), EDX = remainder
    mov avg, eax
    mov rem, edx

    ;Find Largest Value
    mov esi, offset ary ; Reset to start of array
    mov edx, [esi] ; Initialize largest with first element
    mov lrg, edx
Largest:
    add esi, 4 ; Move to next element
    mov ebx, [esi]
    cmp ebx, NULL ; Check for sentinel
    je LargestDone
    cmp edx, ebx ; Compare current largest to new element
    jge Largest ; Skip if current is bigger
    mov edx, ebx ; Update largest value
    mov lrg, edx
    jmp Largest
LargestDone:

    ;Print Sum
    lea esi, labelSum
    call WriteLine
    mov eax, total
    lea esi, ans
    call IntToAsc
    call WriteNum
    call NextLine

    ;Print Average
    lea esi, labelAvg
    call WriteLine
    mov eax, avg
    lea esi, ans
    call IntToAsc
    call WriteNum
    call NextLine

    ;Print Remainder
    lea esi, labelRem
    call WriteLine
    mov eax, rem
    lea esi, ans
    call IntToAsc
    call WriteNum
    call NextLine

    ;Print Largest
    lea esi, labelLrg
    call WriteLine
    mov eax, lrg
    lea esi, ans
    call IntToAsc
    call WriteNum
    call NextLine

OutOfHere:
    call DumpRegs ; Optional: display registers for debugging
    exit
main ENDP
END main

Key Fix Explanations

  1. Sum Calculation: We now explicitly check for the sentinel value (0) at the end of the array to terminate the loop, and save the sum to total so it's available for printing.
  2. Average Calculation: Replaced the manual subtraction loop with the div instruction, which is the correct way to do integer division in x86. This gives us both the average (quotient) and remainder in one step.
  3. Largest Value Loop: Rewrote the loop to first check for the sentinel value before comparing elements, ensuring it terminates correctly. No more early jumps to exit—so print code runs after all calculations.
  4. String Conversion & Printing:
    • IntToAsc now handles negative numbers by adding a '-' sign before converting the absolute value.
    • WriteNum properly finds the end of the converted string and prints characters in reverse order (since we build the string from least to most significant digit).
    • All procedures push/pop registers they modify to avoid messing up the main program's state.
  5. Print Order: Moved all print logic to after all calculations are complete, so everything gets printed before the program exits.

Now your program should correctly display all labels and their corresponding values, and removing the je OutOfHere line won't cause crashes anymore (since the Largest loop has a valid termination condition).

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

火山引擎 最新活动