我写了一些汇编代码来执行一些文本文件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
您按此顺序有两个地方:
sub esp,8
movsd real8 ptr [esp], xmm0
在任何情况下,您都不会还原堆栈指针。在函数结束时,执行ret
指令时,它不会返回到调用方,而是返回到基于您存储在堆栈中的最后一个值的某个值。您需要平衡从esp
的所有减法与加法之间的平衡,以使该函数末尾的esp
值与输入该函数时的值相同。
((顶部附近的movsd xmm0, real8 ptr [esp]
指令也是错误的,因为部分加载的数据将是返回地址。)