Question

How do I pass parameters to a function in Assembly? I did push Last Param, push Second Param, push First Param..

But I cannot access the parameters within Meh Function.. What I'm doing crashes the program..

format PE console                                ;Format PE OUT GUI 4.0
entry main

include 'macro/import32.inc'

section '.idata' import data readable           ;Import Section.
library msvcrt,'msvcrt.dll'
import msvcrt, printf, 'printf',\
exit,'exit', getchar, 'getchar'

section '.data' data readable writeable         ;Constants/Static Section.
InitialValue dd 0

section '.code' code readable executable
main:    
   push 67
   push 66
   push 65
   call MEH

   call [getchar]
   mov eax, 0
   ret 0

MEH:
   push ebx
   mov ebp, esp
   sub esp, 0

   mov eax, [ebp + 8]   ; Trying to print first parameter..
   push eax
   call [printf]
   add esp, eax

   mov esp, ebp
   pop ebx
ret
Was it helpful?

Solution 2

Let's see...

Say your ESP is 0x00180078 on the outset, then after the three pushes you have

00180078: 67
00180074: 66
00180070: 65

then you call MEH, which immediately pushes ebx so now you have the stack as

00180078: 67
00180074: 66
00180070: 65
0018006C: return address
00180068: ebx value

you now load EBP with ESP = 00180068

sub esp,0 does nothing

mov eax, [ebp+8] ~ 00180068 + 8 = 00180070 = 65 

so not the first but rather the last argument

   call [printf]

Here comes your problem, though:

   add esp, eax

What good was this supposed to do? Assuming printf preserves this argument passed in (which it is incidentally not required to do), why would you add the argument to the stack pointer? That is sure to mess up your return. What you want to do is restore esp to the value of ebp and pop back the saved ebx value.

OTHER TIPS

Small additional notes. The proper header/footer of the procedure uses push/pop ebp:

MEH:
   push ebp
   mov ebp, esp

   mov esp, ebp
   pop ebp
   ret

The reason is that we need to save/restore ebp register before using it as a pointer to the arguments and local variables.

Second, CCALL calling convention where the caller restores the stack pointer after procedure return is common for C/C++ language, but not for assembly programming. The reason is obvious - the compiler can properly compute how many parameters are pushed in the stack. In hand written assembly program, using this convention will make the code not legible.

Better approach is to use STDCALL calling convention:

MEH:
   push ebp
   mov  ebp, esp

   mov  esp, ebp
   pop  ebp
   retn 12   ; how many bytes to be automatically 
             ; removed from the stack after return.

Even better practice is to use some macros in order to automate the creation of the standard procedure elements and to provide human readable labels for the arguments and local variables. For example, macros provided in FreshLib library have following syntax:

proc MEH, .arg1, .arg2, .arg3
; define local variables here, if needed.
begin
     ; place your code here without headers and footers
     return  ; will clean the stack automatically.
endp

; pushes the arguments in the stack and call MEH
stdcall MEH, 65, 66, 67   

The standard macro library provided with FASM packages has slightly different syntax, that is covered in details by FASM programmers manual.

If the calling convention for printf() is correct (it is for 32-bit MinGW and 32-bit gcc on Linux), then you're completely ignoring what the function expects and there's no surprise in you not getting the desired output.

The function's prototype is:

int printf(const char* format, ...);

format, the first parameter, is a pointer to an ASCIIZ string, which contains the text to print and/or special tokens like %d to be replaced by the appropriate interpretation of the optional parameters following format.

So, if you want printf() to print 'A', then this is what you need to do in C:

printf("A");

or

printf("%c", 'A');

And here's how you'd do the same in assembly:

myformatstring db "A", 0 ; this line goes into section .data

push myformatstring ; push address of the string
call [printf]
add esp, 4 ; remove all parameters from the stack

or

myformatstring db "%c", 0 ; this line goes into section .data

push 'A'    
push myformatstring ; push address of the string
call [printf]
add esp, 2*4 ; remove all parameters from the stack
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top