汇编程序调试求助:无法显示字符串与数值,跳转指令报错
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
IntToAscdoesn't handle negative numbers (your array has negatives, so this would produce garbage).WriteNumstarts with an unnecessarydec esiand doesn't properly find the end of the converted string, leading to incorrect output.- You didn't add a null terminator to the
ansarray 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
- 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
totalso it's available for printing. - Average Calculation: Replaced the manual subtraction loop with the
divinstruction, which is the correct way to do integer division in x86. This gives us both the average (quotient) and remainder in one step. - 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.
- String Conversion & Printing:
IntToAscnow handles negative numbers by adding a '-' sign before converting the absolute value.WriteNumproperly 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.
- 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




