-1

In Assembly Language, Seventh Edition for x86 Processors by Kip Irvine, on page 325, it says under 8.2.4 32-Bit Calling Conventions,

The C Calling Convention ... The C calling convention solves the problem of cleaning up the runtime stack in a simple way: When a program calls a subroutine, it follows the CALL instruction with a statement that adds a value to the stack pointer (ESP) equal to the combined sizes of the subroutine parameters. Here is an example in which two arguments (5 and 6) are pushed on the stack before executing a CALL instruction,

Example1 PROC
  push 6
  push 5
  call AddTwo
  add esp, 8
  ret
Example1 ENDP

Therefore programs written in C/C++ always remove arguments from the stack in the calling program after a subroutine has returned.

It goes on to say

STDCALL Calling Convention Another common way to remove parameters from the stack is to use the convention named STDCALL. In the following AddTwo procedure, we supply an interger parameter to the RET instruction, which in turn adds 8 to ESP after returning to the calling procedure. The integer must equal the number of bytes of stack space consumed by the procedure's parameters:

AddTwo PROC
  push ebp
  mov ebp,esp
  mov eax,[ebp+12]
  add eax,[ebp+8]
  pop ebp
  ret 8
AddTwo ENDP

It should be pointed out that STDCALL, like C, pushes arguments onto the stack in reverse order. By having a prameter in the RET instruction, STDCALL reduces the amount of code generated for subroutine calls (by one instruction) and ensures that calling programs will never forget to clean up the stack. The C calling convention on the other hand, permits subroutines to declare a variable number of parameters. The caller can decide how many arguments it will pass.

Community
  • 1
  • 1
Evan Carroll
  • 78,363
  • 46
  • 261
  • 468
  • 1
    A: well, obviously yes? The calling convention does define how the subroutine should return (i.e. what mechanism is used to give subroutine point of return) and in what state should be CPU, so clean-up code at the end of subroutines is relevant to calling convention (although you can implement it in alternative way too, if you find some which fits better for your situation, like jump-to-tail of other subroutine instead of calling it, etc..) = so I'm not sure what is the question and what precisely is expected in answer? – Ped7g Oct 09 '18 at 20:42
  • What is the question? The main difference between STDCALL and CDECL *conceptually* is that CDECL allows for var args and that STDCALL handles the arguments as *expected* by the *caller* while CDECL handles them as used by the *caller* (yes, the early C allowed this). – Margaret Bloom Oct 09 '18 at 22:40

1 Answers1

-4

That code is kind of confusing because one shows the call, and other shows the function. And for simplicity they should both show both. There are two stages of modification to the stack for the purpose of calling conventions,

  • In preparation for the call, where the arguments and pushed onto the stack.
  • In the called function, where locals are allocated on the stack.

The difference between the two conventions isn't "one instruction" nor does it have anything to do with RET per say, but where the cleanup happens. The arguments are placed on the stack prior to the call, so should they

  1. Be cleaned up when the function cleans itself (the locals) up.
  2. Be cleaned up when after the function returns.

As an import note there are advantages to the first option, namely that you declare a function with a variable amount of arguments.

The whole RET piece seems to be a distraction, as there is nothing about the calling convention that is specific to x86. In fact, Windows 10 runs on ARM which doesn't even support RET Moreover, in the first example with cdecl the compiler could have written,

ret 8

Rather than

 add esp,8
 ret

And it would have had the same effect. In fact, it would have saved an instruction

Evan Carroll
  • 78,363
  • 46
  • 261
  • 468
  • 4
    `ret 8` and `add esp,8` `ret` are not the same. `ret 8` pops the return address off the stack **first** and then adjusts _ESP_ by adding the immediate value to it. – Michael Petch Oct 09 '18 at 20:12
  • 1
    also the the stdcall convention forces you to "free" the local stack space after every call, while with C convention you can keep `esp` modified, and use that local area for other purposes after the original function returned, like preparing arguments for next call or simply storing some locals there, or just releasing all arguments after several calls with single `sub esp,...`, etc... as always in assembly, the more context/interpretation/logic you give to instruction group, the more risk you have to actually miss some subtle detail or optimization possibility, would you not overthink it. – Ped7g Oct 09 '18 at 20:39