I am trying to figure out how to print out both rows and columns of an array. The program asks how many rows and columns and depending on user input it would display "Enter a number for [0][0]" "Enter a number for [0][1]" and etc.
Here is what I have written so far:
%include "io.inc"
SECTION .data ; Data section, initialized variables
num_rows db "How many rows?: ",0
num_col db "How many columns?: ",0
prompt db "Enter a number for [%d][%d]:",10,0
sum db "The sum is: ",10,0
number db "%d",10,0
rows times 4 dd "%d",0
col times 4 dd "%d",0
arrayLen dd 9 ; length of array
;size equ rows*col
formatin db "%d", 0
section .bss
array resd 6; this is a test array for testing purposes
SECTION .text ; Code section.
global CMAIN ; the standard gcc entry point
extern printf ,scanf
CMAIN: ; the program label for the entry point
;-----Ask for the number of rows and display
push num_rows
call printf
add esp,4 ;remove the parameter
push rows ;address of rows
push formatin ;arguments are right to left
call scanf
add esp,8
;move the values into the registers
mov ebp,[rows]
push ebp
push number
call printf
add esp,8
;----Ask for the number of cols and display
push num_col
call printf
add esp,4
push col
push formatin
call scanf
add esp,8
;move the values into the registers
mov ebx, [col]
push ebx
push number
call printf
add esp,8
mov ebp,array
push ecx
push number
call printf
add esp,8
mov ecx,0
xor ebp,ebp
outerLoop:
mov edx,ecx
push ecx
mov ecx,0
inner:
push ecx
;output
push ecx
push edx
push prompt
call printf
add esp,12
;Get addr
push ecx
push edx
push esi
;call GetElement
add esp,12
;input
push eax
push number
call scanf
add esp,8
pop ecx
inc ecx
cmp ecx,[col]
jl inner
pop ecx
end_outer:
inc ecx
cmp ecx,[rows]
jl outerLoop
push sum
call printf
add esp,4
xor ebp,ebp <- My professor told me never to use this
ret
;GetElement: THIS WHOLE SUBPROGRAM IS COMMENTED
; mov ebx,[ebp+8] ;addr of array
; mov ecx,[ebp+12] ;row
; mov esi,[ebp+16] ;col
; mov eax,ecx
; mul dword [col]
; add eax,esi
; imul eax,4
; add eax,ebx
; leave
; ret
When I run the code the indexes [rows][cols] do not print correctly. Can someone guide me?
Your problem has nothing to do with accessing array elements - your logic is correct (although imul eax,4
is a bad idea and should be replaced by a shl eax,2
or lea eax,[eax*4]
or lea eax,[ebx+eax*4]
, because the offset in the array is not a signed value and it's faster to avoid this multiplication).
Instead; your problem is that C calling conventions are nasty. They pollute the code with lots of extra instructions to manipulate the stack that make it harder to read and debug the code; and optimizing it (e.g. using sub esp, ...
to reserve space for the max. parameters you want to pass to any child function and mov [rsp+ ...], ...
instead of push ...
to set parameters before calling a child function) is painful; and the whole thing ends up being an error prone and slow mess (that is unnecessary for assembly unless you're calling functions compiled by a C compiler).
More specifically; for your GetElement
, you're using ebp
as stack frame but not setting up ebp
as the stack frame, so when the function tries to get the parameters from the stack into registers the function doesn't get the parameters from the right location.
To actually comply with C calling conventions (CDECL), it would want to be more like:
GetElement:
push ebp
mov ebp,esp ;Set up ebp as stack frame
push ebx ;ebx is "callee preserved" (not "caller saved") and is modified, so it must be saved/restored
push esi ;esi is "callee preserved" (not "caller saved") and is modified, so it must be saved/restored
mov ebx,[ebp+3*4+4] ;addr of array
mov ecx,[ebp+3*4+4+4] ;row
mov esi,[ebp+3*4+4+8] ;col
mov eax,ecx
mul dword [col]
add eax,esi
lea eax,[ebx+eax*4]
pop esi
pop ebx
leave
ret
Ironically, for your code the parameters are already in registers - the only caller is doing this:
push ecx ;col
push edx ;row
push esi ;address of array
call GetElement
add esp,12
..which means that (if you forget about C calling conventions) your GetElement
could be like this (10 unnecessary instructions deleted):
;Inputs:
; ecx = column
; edx = row
; esi = address of array
;
;Outputs:
; eax = address of element in the array
;
;Trashed:
; edx
GetElement:
mov eax,edx
mul dword [col]
add eax,ecx
lea eax,[esi+eax*4]
ret
..and the calling code could be like this (4 unnecessary instructions deleted):
call GetElement