6 Replies - 1327 Views - Last Post: 15 May 2012 - 05:24 PM

base pointer offset question

This problem came about when a friend of mine challenged me to swap two numbers without a temp variable. After writing it in C, I felt it was time to start really digging into assembly.

I finished writing this swap function earlier today, first in c, then in assembly, and I understand everything except lines 9 and 10 which access the parameters to the function. I figured out the offsets 32 and 28 by using the -S option with gcc and examining the .s file. This is solely for my own learning purpose, so I really want to take the time to understand why the offsets are what they are. I understand that parameters are passed in backwards in cdecl, and that they are ints, which is why the difference between them is 4. I am guessing they are in a new stack frame, which is why it is so high, but I am not sure.

Re: base pointer offset question

Posted 15 May 2012 - 10:16 AM

Your args should start at ebp+ 8, that not being the case means stack is not balanced properly. On my cell, the code looks all bunched up so will havr to wait till I get home from work later to get a better look. Not sure about inline asm, but c sets up a stack frame THEN YOU set up one on top of that with enter.

Your args should start at ebp+ 8, that not being the case means stack is not balanced properly. On my cell, the code looks all bunched up so will havr to wait till I get home from work later to get a better look. Not sure about inline asm, but c sets up a stack frame THEN YOU set up one on top of that with enter.

That is what I thought, which is why I was confused when +8 and +12 didn't work. To my understanding, the return will be at ebp +4, args at +8, +12 etc and locals at -4, -8....

Re: base pointer offset question

Posted 15 May 2012 - 03:54 PM

First, if you are getting into Assembly don't use any of the High Level data types in your grammar, there is no such thing as an int. The CPU (and us Assembly programmers) only know the following data types:
BYTE - 8 bits
WORD - 16 bits
DWORD - 32 bits
QWORD - 64 bits
REAL
and a signed versions of those. The x86 "Natural Boundry" is a DWORD, so any offsets of pointers are 4 bytes. The stack is DWORD aligned and just about everything passed on the stack is a DWORD that is why the offsets are a multiple of 4.

The INTEL ABI says 4 registers have to be saved in each procedure (down in Assembly you don't have to if your not interacting with the OS or other software), C saved EBX, ESI, EDI, and EBP at the beginning of every proc.

but, you added ENTER on top of all that so now there is an extra push in there - push ebp was added so your params should be: Param1 = [ebp + 24] Param2 [ebp + 28] but somehow somewhere there is a push that was never popped or the stack was not correctly cleaned up which is why your param1 starts at [ebp + 28]

When I said your args should start at [ebp + 8] that is when you don't have a normal prologue at the proc start.

Re: base pointer offset question

Posted 15 May 2012 - 04:50 PM

GunnerInc, on 15 May 2012 - 03:54 PM, said:

First, if you are getting into Assembly don't use any of the High Level data types in your grammar, there is no such thing as an int. The CPU (and us Assembly programmers) only know the following data types:
BYTE - 8 bits
WORD - 16 bits
DWORD - 32 bits
QWORD - 64 bits
REAL
and a signed versions of those. The x86 "Natural Boundry" is a DWORD, so any offsets of pointers are 4 bytes. The stack is DWORD aligned and just about everything passed on the stack is a DWORD that is why the offsets are a multiple of 4.

The INTEL ABI says 4 registers have to be saved in each procedure (down in Assembly you don't have to if your not interacting with the OS or other software), C saved EBX, ESI, EDI, and EBP at the beginning of every proc.

but, you added ENTER on top of all that so now there is an extra push in there - push ebp was added so your params should be: Param1 = [ebp + 24] Param2 [ebp + 28] but somehow somewhere there is a push that was never popped or the stack was not correctly cleaned up which is why your param1 starts at [ebp + 28]

When I said your args should start at [ebp + 8] that is when you don't have a normal prologue at the proc start.

Let me make sure I am understanding this; ebx, esi, edi, and ebp were all automatically pushed by C. They each are one DWORD in size, which means 32 bits * 4 DWORDS => 16 bytes, which is why the normal ebp offset is for param1 is 16+8 => 24. Is this correct?

Without setting up a stack frame and using esp directly, your args start at [esp + 4] since the return address is at [esp + 0]. But we really don't do it this way because you have to keep track of the offsets since they change with every push.

You should learn to use a debugger or something that prints out values. The most important one is ESP, notice when I am playing around I print out the value of ESP before AND after a call to make sure the addresses are the same. If they are different, then something is screwed up somewhere.