Сборка: Исключение, выданное в 0x9999999A в Lab09_Task03.exe: 0xC0000005: Местоположение выполнения нарушения прав доступа 0x9999999A - PullRequest
0 голосов
/ 05 ноября 2019

Я написал некоторый ассемблерный код, который делает некоторые текстовые файлы 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

1 Ответ

3 голосов
/ 05 ноября 2019

У вас есть два места с этой последовательностью:

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

Ни в одном случае вы никогда не восстановите указатель стека. В конце вашей функции при выполнении инструкции ret она не вернется к вызывающей стороне, а к некоторому значению, основанному на последнем значении, которое вы сохранили в стеке. Вам необходимо сбалансировать все вычитания из esp с добавлениями, чтобы значение esp в конце функции было таким же, как при вводе функции.

(инструкция movsd xmm0, real8 ptr [esp]в верхней части также неверно, так как часть загруженных данных будет адресом возврата.)

...