0

It's my first post in stackoverflow. I'm trying to make a stack frame procedure, but I don't know why in the Loop it says" Access violation reading location 0x0033B000." Hope someone can help me with this.

Here's the code:

INCLUDE Irvine32.inc

.data
arr1 SDWORD -4, 7, -5, 3, 6, 2
arr2 SDWORD 4, 7, 5
msg1 byte "Average 1: ",0
msg2 byte "Average 2: ",0

.code
main PROC

push LENGTHOF arr1 
push OFFSET arr1 
call computeAve
mov edx,offset msg1
call writestring
call writeint
call crlf

push LENGTHOF arr2 
push OFFSET arr2 
call computeAve
mov edx,offset msg2
call writestring
call writeint
call crlf

main ENDP

computeAve PROC
push ebp
mov ebp,esp
mov esi,[ebp+8]
mov eax,0
mov ecx,[ebp+12]
add eax, [esi]
L1:
    add eax,[esi]
    add esi,4
    Loop L1
mov edx,0
mov ebx,[ebp+12]
idiv ebx
pop ebp
ret 8
computeAve ENDP

End main
Steven
  • 95
  • 5
  • 2
    (1) Let's see the code that calls this. (2) What compiler/OS are you using, and are you familiar with its calling conventions? In particular, with which registers need to be preserved? – Nate Eldredge Jun 10 '21 at 15:46
  • The call code is : 'push LENGTHOF arr1 push OFFSET arr1 call computeAve' I'm using Visual Studio 2019. I only need to preserved EAX. It's strange that I can run this line of code if I didn't put it in the loop. I'm so confused. – Steven Jun 10 '21 at 15:49
  • So assuming this is using the stdcall convention (because of your `ret 8`), you have to preserve all registers except eax, ecx, edx. Thus you need to either push/pop ebx and esi, or rewrite your code to use eax, ecx, edx only. But that shouldn't cause the crash within your code, though it might make your program crash after your function returns. – Nate Eldredge Jun 10 '21 at 15:52
  • You can use backticks and code blocks to format code more nicely; see https://stackoverflow.com/help/formatting – Nate Eldredge Jun 10 '21 at 15:54
  • 1
    I think we're going to need to see the entire program, as a [mcve]. In particular, where and how is `arr1` defined? – Nate Eldredge Jun 10 '21 at 15:55
  • I'm not sure how to properly preserve the registers...but I will try to work this code. Hope it could work... Thanks for the help. – Steven Jun 10 '21 at 15:58
  • just added the whole program, Thank you so much for the help. – Steven Jun 10 '21 at 15:59
  • 2
    Your `main` proc lacks an `invoke ExitProcess,0` (I think the Irvine library has an `exit` macro that does that). – Michael Jun 10 '21 at 16:01
  • Thanks, Michael, that works...I guess the program didn't stop properly. – Steven Jun 10 '21 at 16:05
  • @Michael: Oh, and that could explain the crash: after the intended code in main finishes, we fall through into `computeAve` again, with bogus values on the stack. – Nate Eldredge Jun 10 '21 at 16:05
  • 2
    A couple other bugs that I guess you'll discover soon: (1) the first array element is included twice in the average (2) Zeroing `edx` before the divide is incorrect for a signed divide and will give you the wrong answer if the sum happens to be negative; you need to sign-extend instead. (3) General efficiency tips: zero registers with `xor reg, reg` instead of `mov reg, 0`, and [don't use `loop`](https://stackoverflow.com/questions/35742570/why-is-the-loop-instruction-slow-couldnt-intel-have-implemented-it-efficiently). – Nate Eldredge Jun 10 '21 at 16:08
  • Thank you, Nate, I didn't notice the importance of invoke ExitProcess,0. Also appreciate your tips for efficiency, still have lots to learn ;-) – Steven Jun 10 '21 at 16:11
  • Yup, asm labels aren't like C functions. Execution just continues in a straight line unless the CPU sees a machine instruction that makes it do something else. Labels are just symbolic names for addresses, not visible to the CPU. [What if there is no return statement in a CALLed block of code in assembly programs](https://stackoverflow.com/q/41205054) explains that, so I think this question is a duplicate. – Peter Cordes Jun 10 '21 at 16:35

0 Answers0