I have been a C/C++ programmer for 4 years now, and now that I'm actually reading a tut on it, I have to say, I am impressed! The whole concept of the DS really is cool; and it's flexability is the best I have seen.

While I was reading one of the lessons I noticed how they mentioned that the ESP changed according the data pushed.
So, would the following code be considered valid?

mov ebx, esp
push dword [first_var]
push dword [middle_var]
push dword [last_var]
call [my_function]
mov esp, ebx

Dani AI

Generated

Short answer: the CPU will happily let you save ESP in a register and restore it after a call, but it is fragile and rarely the best choice in real code.

As and already hinted, whether this survives a call depends on ABI and on the code you call. On common 32-bit calling conventions the callee is expected to preserve EBX/ESI/EDI/EBP, so using one of those to stash a stack pointer is normally safe — provided every callee you touch actually follows the ABI (handwritten asm, mixed-language calls, PIC/JIT code or bad asm can break that assumption). Also watch platform-specific uses of registers (for example, EBX can be special in some PIC setups).

Practical pitfalls you will not see from the single example:

  • Stack alignment: pushing three 4-byte values changes alignment by 12 bytes. Some toolchains or libraries expect a particular alignment (SSE/ABI constraints); misalignment can cause crashes with aligned SIMD loads.
  • Argument order and cleanup: make sure you push arguments in the order the callee expects, and account for whether the caller or callee cleans the stack (cdecl vs stdcall).
  • Exceptions/longjmp/interrupts: abnormal control flow can skip your restore, leaving ESP corrupted.

Safer alternatives: reserve and use a stack frame (push ebp; mov ebp, esp or sub esp, N), write arguments into that reserved space, then add esp, N to restore; or let the caller clean with a single add esp, N when appropriate. If you must stash ESP in a register, pick a documented callee-saved register, document it, and test across all target compilers and build modes (PIC, debug, optimized). In short: it works technically, but prefer explicit stack-frame or stack-adjust patterns for maintainability and portability.

Recommended Answers

All 3 Replies

Assuming EBX isn't clobbered by the function, then yes, it should work.

In my opinion its bad practice to do that. Though as already said its valid if EBX remains unchanged after the function returns.

Yes, it is bad practice. But the caller's question was, as I understood it, more to the way the stack actually works than to the propriety of doing it.

I could be wrong.

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.