x86 Assembly Language: Filling an array with values generated by a subroutine

0

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 

arrays
assembly
x86
fill
subroutine
asked on Stack Overflow Oct 29, 2019 by Madeline Do • edited Oct 30, 2019 by Madeline Do

1 Answer

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.

answered on Stack Overflow Oct 30, 2019 by Peter Cordes

User contributions licensed under CC BY-SA 3.0