Assembly:在Lab09_Task03.exe中的0x9999999A处引发异常:0xC0000005:执行位置0x9999999A的访问冲突

问题描述 投票:0回答:1

我写了一些汇编代码来执行一些文本文件IO。该代码可以正常工作并提供正确的输出。问题是执行代码后,显示错误:

Exception thrown at 0x9999999A in Lab09_Task03.exe: 0xC0000005: Access violation executing location 0x9999999A.

我使用的是Visual Studio 2019,但我尝试调试代码,但错误在ret语句后出现。

.686
.model flat,c
.xmm

includelib libcmt.lib
includelib libvcruntime.lib
includelib libucrt.lib
includelib legacy_stdio_definitions.lib 

extern fopen_s:proc, fscanf_s:proc, exit:proc,
    printf_s:proc, rewind:proc,fclose:proc
.data
sumGrades real8 0.0
countGrades dword 0
countAboveAverage dword 0
countAverage dword 0
countBelowAverage dword 0

readingMode byte "r",0
fileName byte "grades.txt",0
errorMsg byte "Error in opening grades.txt",13,10,0
doubleFormat byte "%lf",0
fileEmptyError byte "Error: The input file is empty",13,10,0
outputFormat1 byte "The average is %.2f",13,10,0
outputFormat2 byte "The frequency of grades above average is %d",13,10,0
outputFormat3 byte "The frequency of grades equal to the average is %d", 13,10,0
outputFormat4 byte "The frequency of grades below average is %d", 13,10,0

.data?
inFilePtr dword ? ;File pointer
errorNum dword ?
grade real8 ?
average real8 ?

.code
main proc
push offset readingMode     ; reading a file
push offset fileName        ;
push offset inFilePtr       ;
call fopen_s                ;
add esp,12                  ;
mov errorNum, eax           ; checking if there is a file with the name "grades.txt"
cmp eax , 0                 ;
je noerror                  ;
push offset errorMsg        ;
call printf_s               ;
add esp,4                   ;
                            ;
push 1                      ;
call exit                   ; exit if there is no such file

noerror:
StartLoop:                  ; reading grades and finding the sumGrades
    push offset grade       ;
    push offset doubleFormat;
    push inFilePtr          ;
    call fscanf_s           ;
    add esp,12              ;
                            ;
    cmp eax , 0FFFFFFFFH    ; check if eax == EOF (end of file) character
    je endLoop              ;

    movsd xmm0, real8 ptr [esp] ;
    inc countGrades             ;
    addsd xmm0 , grade          ;
    sub esp,8                   ;
    movsd real8 ptr [esp], xmm0 ;
    jmp StartLoop               ;
endLoop:                    ;
movsd xmm0, real8 ptr [esp] ;
movsd sumGrades, xmm0       ;
cmp countGrades, 0          ; check if there is any grades or none
    jne noFileEmptyError    ;

    push offset fileEmptyError  ; if the file has no grades print error message
    call printf_s               ;
    add esp,4                   ;

    jmp endOfProgram

noFileEmptyError:               ; else 
    movsd xmm0, sumGrades       ; find the average
    cvtsi2sd xmm1, countGrades  ;
    divsd xmm0, xmm1            ;
    movsd average, xmm0         ;

    push inFilePtr              ; move the file pointer to the beginning of the file
    call rewind                 ;
    add esp,4                   ;

    start_Loop:                 ; find the frequency of the grades that is ( > || < || = )
        push offset grade       ; reading grades from "grades.txt" file
        push offset doubleFormat;
        push inFilePtr          ;
        call fscanf_s           ;
        add esp, 12             ;

        cmp eax, 0ffffffffH     ; if eax == EOF
        je end_Loop             ;

        movsd xmm0, grade       ;   comparing the grades to the average to determine
        movsd xmm1, average     ;   whether a grade is above, below or equal to the average
        ucomisd xmm0,xmm1       ;
            jne notEqual        ;
            inc countAverage    ;   increment number of grades that is equal to the average
            jmp start_Loop      ;   
        notEqual:               ;
        ucomisd xmm0, xmm1      ;
            jna notGreater      ;
            inc countAboveAverage;  increment number of grades that is above the average
            jmp start_Loop      ;
        notGreater:             ;
            inc countBelowAverage;  increment number of grades that is below the average
            jmp start_Loop      ;
    end_Loop:   

    movsd xmm0, average         ;   display the results: average, number of grades that is above the average,
    sub esp,8                   ;                       number of grades that is equal to the average and
    movsd real8 ptr [esp], xmm0 ;                       number of grades that is below the average  
    push offset outputFormat1   ;
    call printf_s               ;
    add esp,12                  ;

    push countAboveAverage      ;
    push offset outputFormat2   ;
    call printf_s               ;
    add esp,8                   ;

    push countAverage           ;
    push offset outputFormat3   ;
    call printf_s               ;
    add esp,8                   ;

    push countBelowAverage      ;
    push offset outputFormat4   ;
    call printf_s               ;
    add esp,8                   ;
endOfProgram:                   ;
    push inFilePtr              ; closing the file
    call fclose                 ;
    add esp, 4                  ;
ret
main endp
end
assembly x86 masm
1个回答
3
投票

您按此顺序有两个地方:

sub esp,8
movsd real8 ptr [esp], xmm0

在任何情况下,您都不会还原堆栈指针。在函数结束时,执行ret指令时,它不会返回到调用方,而是返回到基于您存储在堆栈中的最后一个值的某个值。您需要平衡从esp的所有减法与加法之间的平衡,以使该函数末尾的esp值与输入该函数时的值相同。

((顶部附近的movsd xmm0, real8 ptr [esp]指令也是错误的,因为部分加载的数据将是返回地址。)

© www.soinside.com 2019 - 2024. All rights reserved.