1

Edit: Thank you so much for all your help! I really appreciate it because for some reason I am having some trouble conceptualizing assembly but I'm piecing it together.

1) I am using the debugger to step through line by line. The problem, Unhandled exception at 0x0033366B in Project2.exe: 0xC0000005: Access violation writing location 0x00335FF8 occurs at this line:

mov [arrayfib + ebp*4], edx     

Is think maybe this because the return statement from the other loop is not able to be accessed by the main procedure, but not sure - having a hard time understanding what is happening here.

2) I have added additional comments, hopefully making this somewhat clearer. For context: I've linked the model I've used to access the Fibonacci numbers, and my goal is to fill this array with the values, looping from last to first.

.386
.model flat, stdcall 
.stack 4096
INCLUDE Irvine32.inc
ExitProcess PROTO, dwExitCode: DWORD

.data
arrayfib DWORD 35 DUP (99h)

COMMENT !
eax =  used to calculate fibonacci numbers
edi =  also used to calculate fibonacci numbers
ebp =  number of fibonacci sequence being calculated  
edx =  return value of fibonacci number requested
!

.code
main PROC   
;stores n'th value to calculate fibonacci sequence to
mov ebp, 30
mov edx, 0
;recursive call to fibonacci sequence procedure
call FibSequence
mov [arrayfib + ebp*4], edx        
dec ebp
jnz FibSequence 


mov esi, OFFSET arrayfib
mov ecx, LENGTHOF arrayfib 
mov ebx, TYPE arrayfib 
call DumpMem
INVOKE ExitProcess, 0 
main ENDP

;initializes 0 and 1 as first two fibonacci numbers
FibSequence PROC           
mov eax, 0          
mov edi, 1 

;subrracts 2 from fibonacci number to be calculated. if less than 0, jumps to finish, 
;else adds two previous fibonacci numbers together
L1: 
sub ebp, 2          
cmp ebp, 0 
js FINISH
add eax, edi
add edi, eax
LOOP L1

;stores odd fibonacci numbers 
FINISH:
test eax, 1 
jz FINISHEVEN
mov edx, eax
ret    

;stores even fibonacci numbers
FINISHEVEN:
mov edx, edi
ret


FibSequence ENDP
END main 
  • 1
    Not sure what the "commented syntax" refers to but `mov [DWORD + (edx-1)],edx` makes no sense. You probably meant `mov [arrayfib + ebp], edx`. Also `LOOP L1` makes no sense especially since you haven't even initialized `ecx`. It's unclear what you want the code to do. Comment your code especially if you want others to help. PS: the last 3 `mov` instructions before `FibSequence ENDP` probably belong further up, before the `call DumpMem`. – Jester Oct 29 '19 at 23:40
  • More likely `mov [arrayfib + ebp*4], edx` because you have an array of 4-byte dwords that you want to index with `ebp`. Also, you might want to use EAX for return values. That's traditional for x86 calling conventions. Writing by hand in assembly means you can make up whatever calling convention you want, like writing functions that return in EDX, as long as you document it with comments like you're doing. So you're not wrong to use EDX, just unconventional. – Peter Cordes Oct 30 '19 at 04:23
  • As far as the debugging question; what debugger are you using? Tag and/or edit your question. If you're using single-step by instruction (not "continue"), you should be able to single-step one instruction at a time, including seeing when an instruction faults. – Peter Cordes Oct 30 '19 at 04:24
  • @PeterCordes My question has been edited accordingly. Thank you – Madeline Do Oct 30 '19 at 05:12
  • 1
    You're writing in assembly, not JavaScript. Don't use "JS code snippet" formatting for your code; this can't run in a browser. I already fixed the previous version of your question but you reintroduced JS formatting. Just use indenting (the default if you select your code and hit control-k or the gui icon), or triple backticks. Also, inside your code you should indent instructions one tab-stop to the right of labels and directives. Much more readable. See [this code-review](//codereview.stackexchange.com/a/204965) for an example of good style. – Peter Cordes Oct 30 '19 at 05:19
  • *maybe this because the return statement from the other loop is not able to be accessed by the main procedure,* No idea what you mean there. In assembly language, every instruction has a specific effect on the architectural state (register values and memory contents). `ret` is just how we write `pop eip`. There are no non-local effects, you just have to make sure that ESP is pointing to the address (pushed by `call`) that you want to jump to. Aka the return address. – Peter Cordes Oct 30 '19 at 05:25

1 Answers1

1

Your Fibonacci function destroys EBP, returning with it less than zero.

If your array is at the start of a page, then arrafib + ebp*4] will try to access the previous page and fault. Note the fault address of 0x00335FF8 - the last 3 hex digits are the offset within a 4k virtual page, an 0x...3FF8 = 0x...4000 + 4*-2.

So this is exactly what happened: EBP = -2 when your mov store executed.

(It's normal for function calls to destroy their register args in typical calling conventions, although using EBP for arg-passing is unusual. Normally on Windows you'd pass args in ECX and/or EDX, and return in EAX. Or on the stack, but that sucks for performance.)

(There's a lot of other stuff that doesn't make sense about your Fibonacci function too, e.g. I think you want jmp L1 not loop L1 which is like dec ecx / jnz L1 without setting flags).


In assembly language, every instruction has a specific effect on the architectural state (register values and memory contents). You can look up this effect in an instruction-set reference manual like https://www.felixcloutier.com/x86/index.html.

There is no "magic" that preserves registers for you. (Well, MASM will push/pop for you if you write stuff like proc foo uses EBP, but until you understand what that's doing for you it's better not to have the assembler adding instructions to you code.)

If you want a function to preserve its caller's EBP value, you need to write the function that way. (e.g. mov to copy the value to another register.) See What are callee and caller saved registers? for more about this idea.

maybe this because the return statement from the other loop is not able to be accessed by the main procedure

That doesn't make any sense.

ret is just how we write pop eip. There are no non-local effects, you just have to make sure that ESP is pointing to the address (pushed by call) that you want to jump to. Aka the return address.

Peter Cordes
  • 328,167
  • 45
  • 605
  • 847