I don't entirely understand the line with comment in it below. I read a few posts on SO and in the gcc
manual and learned that it is for stack address alignment but fail to understand how it does so. The code is show below:
(gdb) disas main
Dump of assembler code for function main:
0x08048414 <+0>: push ebp
0x08048415 <+1>: mov ebp,esp
0x08048417 <+3>: and esp,0xfffffff0 ; why??
0x0804841a <+6>: sub esp,0x10
0x0804841d <+9>: mov DWORD PTR [esp],0x8048510
0x08048424 <+16>: call 0x8048320 <puts@plt>
0x08048429 <+21>: mov DWORD PTR [esp],0x8048520
0x08048430 <+28>: call 0x8048330 <system@plt>
0x08048435 <+33>: leave
0x08048436 <+34>: ret
End of assembler dump.
The code was generated using gcc
(version 4.6.3) on linux. Thanks.
and esp, 0xfffffff0 does a bitwise AND between the stack pointer and a constant, and stores the result back in the stack pointer. The constant is chosen so that its low four bits are zero. Therefore the AND operation will set these bits to zero in the result, and leave the other bits of esp intact.
The register 'ESP' is used to point to the next item on the stack and is referred to as the 'stack pointer'. EBP aka the 'frame pointer' serves as an unchanging reference point for data on the stack. This allows the program to work out how far away something in the stack is from this point.
The stack pointer: ESP register contents The register ESP (literally "extended stack pointer") holds the top of the stack. This is the point where the instructions which use the stack (PUSH, POP, CALL and RET) actually use the stack.
and esp, 0xfffffff0
does a bitwise AND between the stack pointer and a constant, and stores the result back in the stack pointer.
The constant is chosen so that its low four bits are zero. Therefore the AND operation will set these bits to zero in the result, and leave the other bits of esp
intact. This has the effect of rounding the stack pointer down to the nearest multiple of 16.
It looks like it's part of some code to set up shop at the start of main
.
Function start: save the base frame pointer on the stack (needed by the leave
instruction later):
0x08048414 <+0>: push ebp
Now we align the stack pointer to a 16-byte bound, because the compiler (for whatever reason) wants it. This could be that it always wants 16-byte aligned frames, or that the local variables need 16-byte alignment (maybe someone used a uint128_t
or they're using a type that uses gcc vector extensions). Basically, since the result will always be less than or equal to the current stack pointer, and the stack grows downward, it's just discarding bytes until it gets to a 16-byte aligned point.
0x08048415 <+1>: mov ebp,esp
0x08048417 <+3>: and esp,0xfffffff0
Next we subtract 16 from the stack pointer, creating 16 bytes of local variable space:
0x0804841a <+6>: sub esp,0x10
puts((const char*)0x8048510);
0x0804841d <+9>: mov DWORD PTR [esp],0x8048510
0x08048424 <+16>: call 0x8048320 <puts@plt>
system((const char*)0x8048520);
0x08048429 <+21>: mov DWORD PTR [esp],0x8048520
0x08048430 <+28>: call 0x8048330 <system@plt>
Exit the function (see another answer about what leave
does):
0x08048435 <+33>: leave
0x08048436 <+34>: ret
Example of "discarding bytes": say esp = 0x123C at the start of main
. The first lines of code:
0x08048414 <+0>: push ebp
0x08048415 <+1>: mov ebp,esp
result in this memory map:
0x123C: (start of stack frame of calling function)
0x1238: (old ebp value) <-- esp, ebp
Then:
0x08048417 <+3>: and esp,0xfffffff0
forces the last 4 bits of esp to 0, which does this:
0x123C: (start of stack frame of calling function)
0x1238: (old ebp value) <-- ebp
0x1234: (undefined)
0x1230: (undefined) <-- esp
There's no way for the programmer to rely on a certain amount of memory being between esp
and ebp
at this point; therefore this memory is discarded and not used.
Finally, the program allocates 16 bytes of stack (local) storage:
Next we subtract 16 from the stack pointer, creating 16 bytes of local variable space:
0x0804841a <+6>: sub esp,0x10
giving us this map:
0x123C: (start of stack frame of calling function)
0x1238: (old ebp value) <-- ebp
0x1234: (undefined)
0x1230: (undefined)
0x123C: (undefined local space)
0x1238: (undefined local space)
0x1234: (undefined local space)
0x1230: (undefined local space) <-- esp
At this point, the program can be sure there are 16 bytes of 16-byte aligned memory being pointed to by esp
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With