Author Topic: Calling Standards  (Read 8734 times)

Offline iVision

  • Jr. Member
  • *
  • Posts: 22
Calling Standards
« on: July 23, 2013, 08:59:37 AM »
Hello I'm new to assembly and I picked NASM. And I like it alot :) However I noticed that I forgot to cleanup the stack. So I'm wondering what is the recommend way to this? By adding 8 to the esp or (as the __stdcall) ret 8? (In a function with two parameters of course :P)
And (I didn't read the whole docs) would you save registers before or in the function?

Code: [Select]
; Parameters: int a, int b
; Returns: a % b

modulus:
push ebp
mov ebp, esp

push ecx
push edx

xor edx, edx
mov eax, [ebp + 8] ;a
mov ecx, [ebp + 12] ;b

div ecx ;edx holds remainder (a % b)
mov eax, edx ;return remainder

pop edx
pop ecx

mov esp, ebp
pop ebp

ret 8
;modulus

In this code I use ret 8 and save registers in the function. Is this the recommend way to do this or..?

I'm programming on Windows 8 btw.

Regards

Offline encryptor256

  • Full Member
  • **
  • Posts: 250
  • Country: lv
  • Win64 .
    • On Youtube: encryptor256
Re: Calling Standards
« Reply #1 on: July 23, 2013, 10:16:09 AM »
Hey!

"Is this the recommend way to do this or..?"

Assassins creed protocol states: "Nothing is true, everything is permitted". :D

I usualy use RET X, to clean up stack.
But cleaning stack after function call, can be usable too,
for example, like pointers, or vectors, require more operations on the same parameters.

Lets say, push vector, call function vector.normalize, then dont push again, just call next funtion on the same stack parameters, the same vector, like dot product or else.

Cleaning stack after function call, those stack entries could server as a place holders.
MAYBE. :)

Worst case scenario, would be if you forget about cleaning stack generaly, ... w...what? why do i need to clean stack. :D

Encryptor256's Investigation \ Research Department.

Offline iVision

  • Jr. Member
  • *
  • Posts: 22
Re: Calling Standards
« Reply #2 on: July 23, 2013, 02:41:29 PM »
Okay thanks for response! So its more like user choice and not any recommend thing to follow? That seems nice:)

Haha I didn't know I had to and had a stack overflow.. Spent like 2 hours finding what causing it:p ah well learning from mistakes prevents you from making them again:)

Offline Rob Neff

  • Forum Moderator
  • Full Member
  • *****
  • Posts: 429
  • Country: us
Re: Calling Standards
« Reply #3 on: July 23, 2013, 04:31:47 PM »
In this code I use ret 8 and save registers in the function. Is this the recommend way to do this or..?

Depends on whether your function is being called from another language or if your will be making syscalls.
Google for either Pascal, stdcall, or C calling conventions for more in-depth info.  Windows stdcall is like a bastardized C/Pascal convention but with mangled names.

Also - a simple rule of thumb: when discussing calling conventions you don't normally need to preserve the state (ie: push/pop) of the EAX, ECX, and EDX registers within your own function's entry/exit as these are considered volatile by most conventions;  However you will normally perserve the state of all other registers as they are considered non-volatile ( like you did with the EBP register ).

Offline iVision

  • Jr. Member
  • *
  • Posts: 22
Re: Calling Standards
« Reply #4 on: July 23, 2013, 04:46:08 PM »
In this code I use ret 8 and save registers in the function. Is this the recommend way to do this or..?

Depends on whether your function is being called from another language or if your will be making syscalls.
Google for either Pascal, stdcall, or C calling conventions for more in-depth info.  Windows stdcall is like a bastardized C/Pascal convention but with mangled names.

Also - a simple rule of thumb: when discussing calling conventions you don't normally need to preserve the state (ie: push/pop) of the EAX, ECX, and EDX registers within your own function's entry/exit as these are considered volatile by most conventions;  However you will normally perserve the state of all other registers as they are considered non-volatile ( like you did with the EBP register ).

Okay thanks, yea I'm calling this from C. But I guess I should learn the calling conventions carefully, the only thing I know that stdcall and the c calling convention the parameters are passed right to left.

That is nice, thanks:) how about the EBX?
Regards

Offline Rob Neff

  • Forum Moderator
  • Full Member
  • *****
  • Posts: 429
  • Country: us
Re: Calling Standards
« Reply #5 on: July 24, 2013, 02:03:33 PM »
Okay thanks, yea I'm calling this from C.  But I guess I should learn the calling conventions carefully, the only thing I know that stdcall and the c calling convention the parameters are passed right to left.

Correct.  The C calling convention says parameters are pushed onto the stack by the caller from right to left. This is the reason why functions such as printf(), which can take a variable number of parameters, can execute properly. It is also the callers responsibility to clean up the stack when the called function returns.    This means that the caller is responsible for popping the arguments off the stack ( usually done with ADD ESP, X ).  Thus your function should execute a simple RET to exit.

However, stdcall uses the Pascal convention for function returns.  This means the called function cleans up the stack.  Thus it will normally execute a RET X ( where X is the number of bytes pushed on the stack by the caller ).  So depending on how you define your function prototype in the C header is rather critical to ensure that your function will be called correctly and who's responsible for restoring the stack.

That is nice, thanks:) how about the EBX?

If you use the EBX register in your code it should always be saved at function entry and restored to its original value right before function exit.  This is also true for registers such as ESI and EDI.  So your code will normally be framed like this:

Code: [Select]
myfunc:
    push ebp     ; create frame
    mov ebp, esp ; access function parameters using [ebp + x ]
    push ebx     ; non-volatile registers must be pushed if used
    push esi     ;     "
    push edi     ;     "
    .
    .   ; your code here
    .
    pop edi      ; restore the registers original values
    pop esi
    pop ebx
    pop ebp
    ret          ; ret X if your function was called with params
                 ; and defined as Pascal or stdcall convention

Offline iVision

  • Jr. Member
  • *
  • Posts: 22
Re: Calling Standards
« Reply #6 on: July 24, 2013, 03:01:32 PM »
Okay thanks, yea I'm calling this from C.  But I guess I should learn the calling conventions carefully, the only thing I know that stdcall and the c calling convention the parameters are passed right to left.

Correct.  The C calling convention says parameters are pushed onto the stack by the caller from right to left. This is the reason why functions such as printf(), which can take a variable number of parameters, can execute properly. It is also the callers responsibility to clean up the stack when the called function returns.    This means that the caller is responsible for popping the arguments off the stack ( usually done with ADD ESP, X ).  Thus your function should execute a simple RET to exit.

However, stdcall uses the Pascal convention for function returns.  This means the called function cleans up the stack.  Thus it will normally execute a RET X ( where X is the number of bytes pushed on the stack by the caller ).  So depending on how you define your function prototype in the C header is rather critical to ensure that your function will be called correctly and who's responsible for restoring the stack.

That is nice, thanks:) how about the EBX?

If you use the EBX register in your code it should always be saved at function entry and restored to its original value right before function exit.  This is also true for registers such as ESI and EDI.  So your code will normally be framed like this:

Code: [Select]
myfunc:
    push ebp     ; create frame
    mov ebp, esp ; access function parameters using [ebp + x ]
    push ebx     ; non-volatile registers must be pushed if used
    push esi     ;     "
    push edi     ;     "
    .
    .   ; your code here
    .
    pop edi      ; restore the registers original values
    pop esi
    pop ebx
    pop ebp
    ret          ; ret X if your function was called with params
                 ; and defined as Pascal or stdcall convention

Okay great, that also explains why a variable number of parameters functions aren't available in the WinAPI, because they use the stdcall/Pascal convention (why is it named Pascal, because it was first implemented in that language?)

Okay that explains why I often see eax, ecx and edx. Myself would use ebx too before I knew this (because a - d)

Thanks for all information!
Regards

Offline Rob Neff

  • Forum Moderator
  • Full Member
  • *****
  • Posts: 429
  • Country: us
Re: Calling Standards
« Reply #7 on: July 24, 2013, 03:34:21 PM »
why is it named Pascal, because it was first implemented in that language?

https://en.wikipedia.org/wiki/Pascal_(programming_language)