Re: Newbie question...



"Magno Yu" <magno.yu@xxxxxxxxx> wrote in message
news:1079256d-3161-49c9-a274-a7b75f7f961f@xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
I'm recently learning assembly code and I compiled int main() {} with
gcc 4.3.2 and generated the assembly code with Intel syntax..

gcc -S -masm=intel

Nice feature. I didn't know about that. Too bad you didn't mention it.

The other option, besides "intel", for -masm= is "att" which is the default.
Too bad it doesn't have "nasm"...

_main:
lea ecx, [esp+4]
and esp, -16
push DWORD PTR [ecx-4]
push ebp
mov ebp, esp
push ecx
....
pop ecx
pop ebp
lea esp, [ecx-4]
ret

gcc 4.1.0 generates similar code.

By playing around and declare some local variables, I understand all
of the codes but one line [and esp, -16]... what does that achieve
specifically?

This question comes up every six months or so. It's believed that the "and
esp, -16" is for stack alignment. -16 is 0xFFFFFFF0 in 32-bit hexadecimal.
So, the "and" clears the lowest nybble (4-bits), or aligns esp to 16 bytes.
The "and" basically "pushes" from 1 to 16 values, as needed, onto the stack.
Since the x86 increments esp with "pop", the new stack pointer is aligned
and is below the old stack pointer. Stack use should't overwrite any
existing stack values.

and why can't we push esp in the stack first,

Uh, AFAICT, the code is *not* pushing esp directly anywhere... It does need
to push ebp, as part of the prolog, to setup the stackframe. What "push
DWORD PTR [ecx-4]" does is push a value at the new (aligned) esp. The value
that is pushed is already on the stack at the old esp. It's a stack to
stack copy. The value is at "ecx-4" or "(esp+4)-4" or from the original esp
location. The value there is likely the saved eip from a call instruction.

but
instead it does [push DWORD PTR ecx - 4].. doesn't that take longer?
(given that we have to minus 4... )

I see no reason for them to add four, subtract four... It seems useless
from this code. But, this code does nothing. In code that actually does
something, they might be using ecx, as esp+4, to simplify stack operations.
However, they already have ebp which can be used for doing that... The only
advantage I can think of is that it eliminates a bunch of [ebp+4]
references. Of course, they could've used ebp to do that... So, I don't
understand why they used ecx here. (Someone else want to speculate?
Frank?)

Anyway, gcc 3.4.1 generates this:

_main:
push ebp
mov ebp, esp
sub esp, 8
and esp, -16
mov eax, 0
add eax, 15
add eax, 15
shr eax, 4
sal eax, 4
sub esp, eax
....
leave
ret


The two should have the same functionality. Let's look at the older version
first:

_main:
push ebp
mov ebp, esp

prolog, sets up stackframe

sub esp, 8

allocates space for two unknown variables

and esp, -16

possibly aligns stack to 16 bytes

mov eax, 0
add eax, 15
add eax, 15
shr eax, 4
sal eax, 4
sub esp, eax

appears to subtract 32 from esp. reasons unknown. the generated code is
far more than needed to subtract 32. it's possible that the constants are
adjusted to fit other situations.

...

C code

leave

epilog, undoes stackframe

ret

return


The "leave" instruction is the same as:

mov esp, ebp
pop ebp

You should notice that "leave" is the reverse of the "push ebp; mov ebp,
esp" at the beginning of code.

You should also notice that the gcc 4.3.2 code isn't using "leave" or "mov
esp, ebp; pop ebp". It's using "pop ebp" with "lea" to restore "ebp"
instead...

Let's look at the gcc 4.3.2 code:

_main:
lea ecx, [esp+4]

saves esp+4 in ecx

and esp, -16

possibly, aligns stack pointer to 16 bytes.

push DWORD PTR [ecx-4]

saves value already on stack to new stack pointer location. the value
already on the stack is probably the saved "eip" register from a "call"
instruction. It looks to me like this instruction is completely unecessary.
(Can someone else confirm this? Herbert?) The "lea esp, [ecx-4]"
instruction below uses the original on stack value. The value from this
instruction is never used AFAICT, at least for this simple code.

push ebp
mov ebp, esp

prolog, sets up stackframe

push ecx
...
pop ecx

wrapper around C code to save/restore ecx or esp+4 value

pop ebp
lea esp, [ecx-4]

epilog, undoes stackframe

ret

return


HTH,


Rod Pemberton


.



Relevant Pages

  • Re: uncertain: x87 or SSE2
    ... FPU control word, and clear the stack on return, unless you're ... needed almost as often as 'eax' and 'edx'). ... push ebp; mov ebp, esp ... mov eax, ...
    (alt.lang.asm)
  • Re: Newbie question...
    ... "and esp, 0xFFFFFFF0" probably makes it clearer that we're aligning the stack to 16 bytes. ... Make ebp a kind of "semi stack frame pointer". ... We "return foo " in eax. ...
    (alt.lang.asm)
  • Re: Standard NASM Macros
    ... This is where the macro implementation of HLL-like constructs starts to ... // The statement above computes true or false in EAX and the ... // on the top of the 80x86 stack. ... mul((type dword [esp])); ...
    (alt.lang.asm)
  • Re: newbie questions
    ... mov ebp, esp ... What's a stack? ... in calls directly between compiled functions. ...
    (alt.lang.asm)
  • Re: Stack frames and local variables vs. globals
    ... original module) variables on the stack are distinct to each instance. ... If you are tempted to use globals because you know what you ... On your other point you don't need to address stack variables off EBP. ... replace all EBP references with references off ESP such as ...
    (comp.lang.asm.x86)