I386 build question: why should I bother with the stack pointer?

I decided it would be interesting to study the x86 build during the summer break. So, I started with a very simple world program, borrowing for free gcc -S examples could give me. I ended up with this:

 HELLO: .ascii "Hello, world!\12\0" .text .globl _main _main: pushl %ebp # 1. puts the base stack address on the stack movl %esp, %ebp # 2. puts the base stack address in the stack address register subl $20, %esp # 3. ??? pushl $HELLO # 4. push HELLO address on the stack call _puts # 5. call puts xorl %eax, %eax # 6. zero %eax, probably not necessary since we didn't do anything with it leave # 7. clean up ret # 8. return # PROFIT! 

It compiles and even works! And I think that I understand most of this.

Although, the magic happens in step 3. If I delete this line, my program will die between calling puts and xor from an error stack error. And I would change $20 to another value, that would work too. Therefore, I came to the conclusion that this value is very important.

The problem is that I do not know what she is doing and why she is needed.

Can someone explain to me? (I'm on Mac OS, that will make a difference.)

+6
assembly x86 gas
source share
3 answers

On x86 OSX, the stack must be 16 byte aligned for function calls, see the ABI doc here . So the explanation

  push stack pointer (# 1) -4
 strange increment (# 3) -20
 push argument (# 4) -4
 call pushes return address (# 5) -4
 total -32

To check, change line # 3 from $ 20 to $ 4, which also works.

In addition, Ignacio Vasquez-Abrams points out, No. 6 is optional. Registers contain the remains of previous calculations, so they must be explicitly reset to zero.

I recently learned (still learning) the assembly. To save you shock, 64-bit calling conventions are much different (parameters are passed in a register). Found this very useful for 64-bit build.

+3
source share

The general comment form should be "Allocates space for local variables." Why change it arbitrarily, I'm not sure. I can see how it crashes if you reduce it. And the correct comment for 6 is "Get ready to return 0 from this function."

+3
source share

Note that if you compile with -fomit-frame-pointer, part of this %ebp pointer pattern will disappear. The base pointer is useful for debugging, but not really needed on x86.

I also highly recommend using Intel syntax, which is supported by all GCC / binutils materials. I used to think that the difference between the AT & T and Intel syntax was just a matter of taste, but one day I came across this example where AT & T mnemonics are just completely different from Intel. And since all the official x86 documentation uses Intel syntax, it seems like this is the best way.

Good luck

+1
source share

All Articles