How does ESP and EBP registers act when a new program is executed? - c

I recently went through an Assembly language book by Richard Blum wherein there was a subject on the C program to assembly conversion.
Consider the following C program:
#include <stdio.h>
int main(){
int a=100;
int b=25;
if (a>b)
printf("The higher value is %d\n", a);
else
printf("The higher value is %d\n", b);
return 0;
}
when I compiled the above program using -S parameter as:
gcc -S abc.c
I got the following result:
.file "abc.c"
.section .rodata
.LC0:
.string "The higher value is %d\n"
.text
.globl main
.type main, #function
main:
.LFB0:
.cfi_startproc
leal 4(%esp), %ecx
.cfi_def_cfa 1, 0
andl $-16, %esp
pushl -4(%ecx)
pushl %ebp
.cfi_escape 0x10,0x5,0x2,0x75,0
movl %esp, %ebp
pushl %ecx
.cfi_escape 0xf,0x3,0x75,0x7c,0x6
subl $20, %esp
movl $100, -16(%ebp)
movl $25, -12(%ebp)
movl -16(%ebp), %eax
cmpl -12(%ebp), %eax
jle .L2
subl $8, %esp
pushl -16(%ebp)
pushl $.LC0
call printf
addl $16, %esp
jmp .L3
.L2:
subl $8, %esp
pushl -12(%ebp)
pushl $.LC0
call printf
addl $16, %esp
.L3:
movl $0, %eax
movl -4(%ebp), %ecx
.cfi_def_cfa 1, 0
leave
.cfi_restore 5
leal -4(%ecx), %esp
.cfi_def_cfa 4, 4
ret
.cfi_endproc
.LFE0:
.size main, .-main
.ident "GCC: (Ubuntu 6.2.0-5ubuntu12) 6.2.0 20161005"
.section .note.GNU-stack,"",#progbits
What I cant understand is this:
Snippet
.LFB0:
.cfi_startproc
leal 4(%esp), %ecx
.cfi_def_cfa 1, 0
andl $-16, %esp
pushl -4(%ecx)
pushl %ebp
.cfi_escape 0x10,0x5,0x2,0x75,0
movl %esp, %ebp
pushl %ecx
.cfi_escape 0xf,0x3,0x75,0x7c,0x6
subl $20, %esp
I am unable to predict what is happening with the ESP and EBP register. About EBP, I can understand to an extent that it is used as a local stack and so it's value is saved by pushing onto stack.
Can you please elaborate the above snippet?

This is a special form of function entry-sequence suitable for the main()
function. The compiler knows that main() really is called as main(int argc, char **argv, char **envp), and compiles this function according to that very special behavior. So what's sitting on the stack when this code is reached is four long-size values, in this order: envp, argv, argc, return_address.
So that means that the entry-sequence code is doing something like this
(rewritten to use Intel syntax, which frankly makes a lot more sense
than AT&T syntax):
; Copy esp+4 into ecx. The value at [esp] has the return address,
; so esp+4 is 'argc', or the start of the function's arguments.
lea ecx, [esp+4]
; Round esp down (align esp down) to the nearest 16-byte boundary.
; This ensures that regardless of what esp was before, esp is now
; starting at an address that can store any register this processor
; has, from the one-byte registers all the way up to the 16-byte xmm
; registers
and esp, 0xFFFFFFF0
; Since we copied esp+4 into ecx above, that means that [ecx] is 'argc',
; [ecx+4] is 'argv', and [ecx+8] is 'envp'. For whatever reason, the
; compiler decided to push a duplicate copy of 'argv' onto the function's
; new local frame.
push dword ptr [ecx+4]
; Preserve 'ebp'. The C ABI requires us not to damage 'ebp' across
; function calls, so we save its old value on the stack before we
; change it.
push ebp
; Set 'ebp' to the current stack pointer to set up the function's
; stack frame for real. The "stack frame" is the place on the stack
; where this function will store all its local variables.
mov ebp, esp
; Preserve 'ecx'. Ecx tells us what 'esp' was before we munged 'esp'
; in the 'and'-instruction above, so we'll need it later to restore
; 'esp' before we return.
push ecx
; Finally, allocate space on the stack frame for the local variables,
; 20 bytes worth. 'ebp' points to 'esp' plus 24 by this point, and
; the compiler will use 'ebp-16' and 'ebp-12' to store the values of
; 'a' and 'b', respectively. (So under 'ebp', going down the stack,
; the values will look like this: [ecx, unused, unused, a, b, unused].
; Those unused slots are probably used by the .cfi pseudo-ops for
; something related to exception handling.)
sub esp, 20
At the other end of the function, the inverse operations are used to put
the stack back the way it was before the function was called; it may be
helpful to examine what they're doing as well to understand what's happening
at the beginning:
; Return values are always passed in 'eax' in the x86 C ABI, so set
; 'eax' to the return value of 0.
mov eax, 0
; We pushed 'ecx' onto the stack a while back to save it. This
; instruction pulls 'ecx' back off the stack, but does so without
; popping (which would alter 'esp', which doesn't currently point
; to the right location).
mov ecx, [ebp+4]
; Magic instruction! The 'leave' instruction is designed to shorten
; instruction sequences by "undoing" the stack in a single op.
; So here, 'leave' means specifically to do the following two
; operations, in order: esp = ebp / pop ebp
leave
; 'esp' is now set to what it was before we pushed 'ecx', and 'ebp'
; is back to the value that was used when this function was called.
; But that's still not quite right, so we set 'esp' specifically to
; 'ecx+4', which is the exact opposite of the very first instruction
; in the function.
lea esp, [ecx+4]
; Finally, the stack is back to the way it was when we were called,
; so we can just return.
ret

Related

Why this asm code not doubling the value the pointer points

I am trying to interface c code with asm.
But it is not working correctly and I am not able to find the problem.
program.c
#include<stdio.h>
int *asm_multi(int *ptr);
int main()
{
int i=10;
int *p=&i;
asm_multi(p);
printf("%d\n",*p);
return 0;
}
code.asm
.section .text
.global asm_multi
.type asm_multi,#function
asm_multi:
pushl %ebp
movl %esp,%ebp
movl 8(%ebp),%eax
movl %eax,%edx
leal (%edx,%edx,1),%edx
movl %edx,%eax
movl %ebp,%esp
popl %ebp
ret
I am creating the final executable by
as code.asm -o code.o
gcc program.c code.o -o output
./output
The output it prints is :10 whereas I am expecting: 20
What is the problem in the code? Don't consider the efficiency of the program. I have just started asm programming.
I created above code after reading from a more complex example kept at this link. This works perfectly.
You should learn to use a debugger as soon as possible. It not only helps you find bugs, but also allows you to exactly see what the cpu is doing at each instruction and you can compare that to your intentions.
Also, comment your code, especially when asking for help, so we can tell you where the instructions don't match your intentions, if you were unable to do so yourself.
Let's comment your code then:
asm_multi:
pushl %ebp
movl %esp,%ebp
movl 8(%ebp),%eax # fetch first argument, that is p into eax
movl %eax,%edx # edx = p too
leal (%edx,%edx,1),%edx # edx = eax + edx = 2 * p
movl %edx,%eax # eax = edx = 2 * p
movl %ebp,%esp
popl %ebp
ret
As you can see, there are two problems:
You are doubling the pointer not the value it points to
You are not writing it back into memory, just returning it in eax which is then ignored by the C code
A possible fix:
asm_multi:
pushl %ebp
movl %esp,%ebp
movl 8(%ebp),%eax # fetch p
shll $1, (%eax) # double *p by shifting 1 bit to the left
# alternatively
# movl (%eax), %edx # fetch *p
# addl %edx, (%eax) # add *p to *p, doubling it
movl %ebp,%esp
popl %ebp
ret

Understanding x86 Assembly Code from C code

C code:
#include <stdio.h>
main() {
int i;
for (i = 0; i < 10; i++) {
printf("%s\n", "hello");
}
}
ASM:
.file "simple_loop.c"
.section .rodata
.LC0:
.string "hello"
.text
.globl main
.type main, #function
main:
.LFB0:
.cfi_startproc
pushl %ebp # push ebp onto stack
.cfi_def_cfa_offset 8
.cfi_offset 5, -8
movl %esp, %ebp # setup base pointer or stack ?
.cfi_def_cfa_register 5
andl $-16, %esp # ?
subl $32, %esp # ?
movl $0, 28(%esp) # i = 0
jmp .L2
.L3:
movl $.LC0, (%esp) # point stack pointer to "hello" ?
call puts # print "hello"
addl $1, 28(%esp) # i++
.L2:
cmpl $9, 28(%esp) # if i < 9
jle .L3 # goto l3
leave
.cfi_restore 5
.cfi_def_cfa 4, 4
ret
So I am trying to improve my understanding of x86 assembly code. For the above code, I marked off what I believe I understand. As for the question marked content, could someone share some light? Also, if any of my comments are off, please let me know.
andl $-16, %esp # ?
subl $32, %esp # ?
This reserves some space on the stack. First, the andl instruction rounds the %esp register down to the next lowest multiple of 16 bytes (exercise: find out what the binary value of -16 is to see why). Then, the subl instruction moves the stack pointer down a bit further (32 bytes), reserving some more space (which it will use next). I suspect this rounding is done so that access through the %esp register is slightly more efficient (but you'd have to inspect your processor data sheets to figure out why).
movl $.LC0, (%esp) # point stack pointer to "hello" ?
This places the address of the string "hello" onto the stack (this instruction doesn't change the value of the %esp register itself). Apparently your compiler considers it more efficient to move data onto the stack directly, rather than to use the push instruction.

Understand the assembly code generated by a simple C program

I am trying to understand the assembly level code for a simple C program by inspecting it with gdb's disassembler.
Following is the C code:
#include <stdio.h>
void function(int a, int b, int c) {
char buffer1[5];
char buffer2[10];
}
void main() {
function(1,2,3);
}
Following is the disassembly code for both main and function
gdb) disass main
Dump of assembler code for function main:
0x08048428 <main+0>: push %ebp
0x08048429 <main+1>: mov %esp,%ebp
0x0804842b <main+3>: and $0xfffffff0,%esp
0x0804842e <main+6>: sub $0x10,%esp
0x08048431 <main+9>: movl $0x3,0x8(%esp)
0x08048439 <main+17>: movl $0x2,0x4(%esp)
0x08048441 <main+25>: movl $0x1,(%esp)
0x08048448 <main+32>: call 0x8048404 <function>
0x0804844d <main+37>: leave
0x0804844e <main+38>: ret
End of assembler dump.
(gdb) disass function
Dump of assembler code for function function:
0x08048404 <function+0>: push %ebp
0x08048405 <function+1>: mov %esp,%ebp
0x08048407 <function+3>: sub $0x28,%esp
0x0804840a <function+6>: mov %gs:0x14,%eax
0x08048410 <function+12>: mov %eax,-0xc(%ebp)
0x08048413 <function+15>: xor %eax,%eax
0x08048415 <function+17>: mov -0xc(%ebp),%eax
0x08048418 <function+20>: xor %gs:0x14,%eax
0x0804841f <function+27>: je 0x8048426 <function+34>
0x08048421 <function+29>: call 0x8048340 <__stack_chk_fail#plt>
0x08048426 <function+34>: leave
0x08048427 <function+35>: ret
End of assembler dump.
I am seeking answers for following things :
how the addressing is working , I mean (main+0) , (main+1), (main+3)
In the main, why is $0xfffffff0,%esp being used
In the function, why is %gs:0x14,%eax , %eax,-0xc(%ebp) being used.
If someone can explain , step by step happening, that will be greatly appreciated.
The reason for the "strange" addresses such as main+0, main+1, main+3, main+6 and so on, is because each instruction takes up a variable number of bytes. For example:
main+0: push %ebp
is a one-byte instruction so the next instruction is at main+1. On the other hand,
main+3: and $0xfffffff0,%esp
is a three-byte instruction so the next instruction after that is at main+6.
And, since you ask in the comments why movl seems to take a variable number of bytes, the explanation for that is as follows.
Instruction length depends not only on the opcode (such as movl) but also the addressing modes for the operands as well (the things the opcode are operating on). I haven't checked specifically for your code but I suspect the
movl $0x1,(%esp)
instruction is probably shorter because there's no offset involved - it just uses esp as the address. Whereas something like:
movl $0x2,0x4(%esp)
requires everything that movl $0x1,(%esp) does, plus an extra byte for the offset 0x4.
In fact, here's a debug session showing what I mean:
Microsoft Windows XP [Version 5.1.2600]
(C) Copyright 1985-2001 Microsoft Corp.
c:\pax> debug
-a
0B52:0100 mov word ptr [di],7
0B52:0104 mov word ptr [di+2],8
0B52:0109 mov word ptr [di+0],7
0B52:010E
-u100,10d
0B52:0100 C7050700 MOV WORD PTR [DI],0007
0B52:0104 C745020800 MOV WORD PTR [DI+02],0008
0B52:0109 C745000700 MOV WORD PTR [DI+00],0007
-q
c:\pax> _
You can see that the second instruction with an offset is actually different to the first one without it. It's one byte longer (5 bytes instead of 4, to hold the offset) and actually has a different encoding c745 instead of c705.
You can also see that you can encode the first and third instruction in two different ways but they basically do the same thing.
The and $0xfffffff0,%esp instruction is a way to force esp to be on a specific boundary. This is used to ensure proper alignment of variables. Many memory accesses on modern processors will be more efficient if they follow the alignment rules (such as a 4-byte value having to be aligned to a 4-byte boundary). Some modern processors will even raise a fault if you don't follow these rules.
After this instruction, you're guaranteed that esp is both less than or equal to its previous value and aligned to a 16 byte boundary.
The gs: prefix simply means to use the gs segment register to access memory rather than the default.
The instruction mov %eax,-0xc(%ebp) means to take the contents of the ebp register, subtract 12 (0xc) and then put the value of eax into that memory location.
Re the explanation of the code. Your function function is basically one big no-op. The assembly generated is limited to stack frame setup and teardown, along with some stack frame corruption checking which uses the afore-mentioned %gs:14 memory location.
It loads the value from that location (probably something like 0xdeadbeef) into the stack frame, does its job, then checks the stack to ensure it hasn't been corrupted.
Its job, in this case, is nothing. So all you see is the function administration stuff.
Stack set-up occurs between function+0 and function+12. Everything after that is setting up the return code in eax and tearing down the stack frame, including the corruption check.
Similarly, main consist of stack frame set-up, pushing the parameters for function, calling function, tearing down the stack frame and exiting.
Comments have been inserted into the code below:
0x08048428 <main+0>: push %ebp ; save previous value.
0x08048429 <main+1>: mov %esp,%ebp ; create new stack frame.
0x0804842b <main+3>: and $0xfffffff0,%esp ; align to boundary.
0x0804842e <main+6>: sub $0x10,%esp ; make space on stack.
0x08048431 <main+9>: movl $0x3,0x8(%esp) ; push values for function.
0x08048439 <main+17>: movl $0x2,0x4(%esp)
0x08048441 <main+25>: movl $0x1,(%esp)
0x08048448 <main+32>: call 0x8048404 <function> ; and call it.
0x0804844d <main+37>: leave ; tear down frame.
0x0804844e <main+38>: ret ; and exit.
0x08048404 <func+0>: push %ebp ; save previous value.
0x08048405 <func+1>: mov %esp,%ebp ; create new stack frame.
0x08048407 <func+3>: sub $0x28,%esp ; make space on stack.
0x0804840a <func+6>: mov %gs:0x14,%eax ; get sentinel value.
0x08048410 <func+12>: mov %eax,-0xc(%ebp) ; put on stack.
0x08048413 <func+15>: xor %eax,%eax ; set return code 0.
0x08048415 <func+17>: mov -0xc(%ebp),%eax ; get sentinel from stack.
0x08048418 <func+20>: xor %gs:0x14,%eax ; compare with actual.
0x0804841f <func+27>: je <func+34> ; jump if okay.
0x08048421 <func+29>: call <_stk_chk_fl> ; otherwise corrupted stack.
0x08048426 <func+34>: leave ; tear down frame.
0x08048427 <func+35>: ret ; and exit.
I think the reason for the %gs:0x14 may be evident from above but, just in case, I'll elaborate here.
It uses this value (a sentinel) to put in the current stack frame so that, should something in the function do something silly like write 1024 bytes to a 20-byte array created on the stack or, in your case:
char buffer1[5];
strcpy (buffer1, "Hello there, my name is Pax.");
then the sentinel will be overwritten and the check at the end of the function will detect that, calling the failure function to let you know, and then probably aborting so as to avoid any other problems.
If it placed 0xdeadbeef onto the stack and this was changed to something else, then an xor with 0xdeadbeef would produce a non-zero value which is detected in the code with the je instruction.
The relevant bit is paraphrased here:
mov %gs:0x14,%eax ; get sentinel value.
mov %eax,-0xc(%ebp) ; put on stack.
;; Weave your function
;; magic here.
mov -0xc(%ebp),%eax ; get sentinel back from stack.
xor %gs:0x14,%eax ; compare with original value.
je stack_ok ; zero/equal means no corruption.
call stack_bad ; otherwise corrupted stack.
stack_ok: leave ; tear down frame.
Pax has produced a definitive answer. However, for completeness, I thought I'd add a note on getting GCC itself to show you the assembly it generates.
The -S option to GCC tells it to stop compilation and write the assembly to a file. Normally, it either passes that file to the assembler or for some targets writes the object file directly itself.
For the sample code in the question:
#include <stdio.h>
void function(int a, int b, int c) {
char buffer1[5];
char buffer2[10];
}
void main() {
function(1,2,3);
}
the command gcc -S q3654898.c creates a file named q3654898.s:
.file "q3654898.c"
.text
.globl _function
.def _function; .scl 2; .type 32; .endef
_function:
pushl %ebp
movl %esp, %ebp
subl $40, %esp
leave
ret
.def ___main; .scl 2; .type 32; .endef
.globl _main
.def _main; .scl 2; .type 32; .endef
_main:
pushl %ebp
movl %esp, %ebp
subl $24, %esp
andl $-16, %esp
movl $0, %eax
addl $15, %eax
addl $15, %eax
shrl $4, %eax
sall $4, %eax
movl %eax, -4(%ebp)
movl -4(%ebp), %eax
call __alloca
call ___main
movl $3, 8(%esp)
movl $2, 4(%esp)
movl $1, (%esp)
call _function
leave
ret
One thing that is evident is that my GCC (gcc (GCC) 3.4.5 (mingw-vista special r3)) doesn't include the stack check code by default. I imagine that there is a command line option, or that if I ever got around to nudging my MinGW install up to a more current GCC that it could.
Edit: Nudged to do so by Pax, here's another way to get GCC to do more of the work.
C:\Documents and Settings\Ross\My Documents\testing>gcc -Wa,-al q3654898.c
q3654898.c: In function `main':
q3654898.c:8: warning: return type of 'main' is not `int'
GAS LISTING C:\DOCUME~1\Ross\LOCALS~1\Temp/ccLg8pWC.s page 1
1 .file "q3654898.c"
2 .text
3 .globl _function
4 .def _function; .scl 2; .type
32; .endef
5 _function:
6 0000 55 pushl %ebp
7 0001 89E5 movl %esp, %ebp
8 0003 83EC28 subl $40, %esp
9 0006 C9 leave
10 0007 C3 ret
11 .def ___main; .scl 2; .type
32; .endef
12 .globl _main
13 .def _main; .scl 2; .type 32;
.endef
14 _main:
15 0008 55 pushl %ebp
16 0009 89E5 movl %esp, %ebp
17 000b 83EC18 subl $24, %esp
18 000e 83E4F0 andl $-16, %esp
19 0011 B8000000 movl $0, %eax
19 00
20 0016 83C00F addl $15, %eax
21 0019 83C00F addl $15, %eax
22 001c C1E804 shrl $4, %eax
23 001f C1E004 sall $4, %eax
24 0022 8945FC movl %eax, -4(%ebp)
25 0025 8B45FC movl -4(%ebp), %eax
26 0028 E8000000 call __alloca
26 00
27 002d E8000000 call ___main
27 00
28 0032 C7442408 movl $3, 8(%esp)
28 03000000
29 003a C7442404 movl $2, 4(%esp)
29 02000000
30 0042 C7042401 movl $1, (%esp)
30 000000
31 0049 E8B2FFFF call _function
31 FF
32 004e C9 leave
33 004f C3 ret
C:\Documents and Settings\Ross\My Documents\testing>
Here we see an output listing produced by the assembler. (Its name is GAS, because it is Gnu's version of the classic *nix assembler as. There's humor there somewhere.)
Each line has most of the following fields: a line number, an address in the current section, bytes stored at that address, and the source text from the assembly source file.
The addresses are offsets into that portion of each section provided by this module. This particular module only has content in the .text section which stores executable code. You will typically find mention of sections named .data and .bss as well. Lots of other names are used and some have special purposes. Read the manual for the linker if you really want to know.
It will be better to try the -fno-stack-protector flag with gcc to disable the canary and see your results.
I'd like to add that for simple stuff, GCC's assembly output is often easier to read if you turn on a little optimization. Here's the sample code again...
void function(int a, int b, int c) {
char buffer1[5];
char buffer2[10];
}
/* corrected calling convention of main() */
int main() {
function(1,2,3);
return 0;
}
this is what I get without optimization (OSX 10.6, gcc 4.2.1+Apple patches)
.globl _function
_function:
pushl %ebp
movl %esp, %ebp
pushl %ebx
subl $36, %esp
call L4
"L00000000001$pb":
L4:
popl %ebx
leal L___stack_chk_guard$non_lazy_ptr-"L00000000001$pb"(%ebx), %eax
movl (%eax), %eax
movl (%eax), %edx
movl %edx, -12(%ebp)
xorl %edx, %edx
leal L___stack_chk_guard$non_lazy_ptr-"L00000000001$pb"(%ebx), %eax
movl (%eax), %eax
movl -12(%ebp), %edx
xorl (%eax), %edx
je L3
call ___stack_chk_fail
L3:
addl $36, %esp
popl %ebx
leave
ret
.globl _main
_main:
pushl %ebp
movl %esp, %ebp
subl $24, %esp
movl $3, 8(%esp)
movl $2, 4(%esp)
movl $1, (%esp)
call _function
movl $0, %eax
leave
ret
Whew, one heck of a mouthful! But look what happens with -O on the command line...
.text
.globl _function
_function:
pushl %ebp
movl %esp, %ebp
leave
ret
.globl _main
_main:
pushl %ebp
movl %esp, %ebp
movl $0, %eax
leave
ret
Of course, you do run the risk of your code being rendered completely unrecognizable, especially at higher optimization levels and with more complicated stuff. Even here, we see that the call to function has been discarded as pointless. But I find that not having to read through dozens of unnecessary stack spills is generally more than worth a little extra scratching my head over the control flow.

why is the call stack set up like this?

I was just playing with the call stack, trying to change the return address of a function etc, and wound up writing this program in C:
#include<stdio.h>
void trace(int);
void func3(int);
void func2(int);
void func1(int);
int main(){
int a = 0xAAAA1111;
func1(0xFCFCFC01);
return 0;
}
void func1(int a){
int loc = 0xBBBB1111;
func2(0xFCFCFC02);
}
void func2(int a){
int loc1 = 0xCCCC1111;
int loc2 = 0xCCCC2222;
func3(0xFCFCFC03);
}
void func3(int a){
int loc1 = 0xDDDD1111;
int loc2 = 0xDDDD2222;
int loc3 = 0xDDDD3333;
trace(0xFCFCFC04);
}
void trace(int a){
int loc = 0xEEEE1111;
int *ptr = &loc;
do {
printf("0x%08X : %08X\n", ptr, *ptr, *ptr);
} while(*(ptr++) != 0xAAAA1111);
}
(sorry for the length)
This produced the following output (with comments that I added):
0xBF8144D4 : EEEE1111 //local int in trace
0xBF8144D8 : BF8144F8 //beginning of trace stack frame
0xBF8144DC : 0804845A //return address for trace to func3
0xBF8144E0 : FCFCFC04 //int passed to trace
0xBF8144E4 : 08048230 //(possibly) uninitialized padding
0xBF8144E8 : 00000000 //padding
0xBF8144EC : DDDD3333 //local int in func3
0xBF8144F0 : DDDD2222 //local int in func3
0xBF8144F4 : DDDD1111 //local int in func3
0xBF8144F8 : BF814518 //beginning of func3 stack frame
0xBF8144FC : 08048431 //return address for func3 to func2
0xBF814500 : FCFCFC03 //parameter passed to func3
0xBF814504 : 00000000 //padding
0xBF814508 : 00000000 //padding
0xBF81450C : 00000000 //padding
0xBF814510 : CCCC2222 //local int in func2
0xBF814514 : CCCC1111 //local int in func2
0xBF814518 : BF814538 //beginning of func2 stack frame
0xBF81451C : 0804840F //return address for func2 to func1
0xBF814520 : FCFCFC02 //parameter passed to func2
0xBF814524 : 00000000 //padding
0xBF814528 : BF816728 //uninitialized padding
0xBF81452C : B7DF3F4E //uninitialized padding
0xBF814530 : B7EA61D9 //uninitialized padding
0xBF814534 : BBBB1111 //local int in func1
0xBF814538 : BF814558 //beginning of func1 stack frame
0xBF81453C : 080483E8 //return address for func1 to main
0xBF814540 : FCFCFC01 //parameter passed to func1
0xBF814544 : 08049FF4 //(maybe) padding
0xBF814548 : BF814568 //(maybe) padding
0xBF81454C : 080484D9 //(maybe) padding
0xBF814550 : AAAA1111 //local int in main
I was wondering if anybody could fill me in on the blank spots here... I'm running Ubuntu linux compiling with gcc 4.3.3 (on an x86 -- AMD Turion 64)
What are the 0804... numbers? What's the third address up from the bottom? Is that the return address for main? If so, why is it out of order compared to the rest of the stack?
The 0x0804 numbers are return addresses, or pointers to code/data or something, while the 0xBF814 numbers are stack pointers
What's this:
0xBF814524 : 00000000 //padding?
0xBF814528 : BF816728 //I have no idea
0xBF81452C : B7DF3F4E //????
0xBF814530 : B7EA61D9 //????
seen just after the local int in func1?
Okay I have my stack dump almost completely filled in.
It looks like the the compiler wants to have the parameters pushed onto the stack starting at a 0x.......0 address, and everything between the local variables from the function before and the first parameter of the function being called seems to be padding (whether 0x00000000 or some uninitialized value). Some of them I'm unsure about because they look like code/data segment pointers, but I can't see them being used in the code: they're just there when the stack pointer gets reduced.
and I know it's a HUGE nono to touch the call stack in any kind of project, but that's okay. It's fun, right?
also
Greg wants to see the assembly,
here it is
.file "stack.c"
.text
.globl main
.type main, #function
main:
leal 4(%esp), %ecx
andl $-16, %esp
pushl -4(%ecx)
pushl %ebp
movl %esp, %ebp
pushl %ecx
subl $20, %esp
movl $-1431695087, -8(%ebp)
movl $-50529279, (%esp)
call func1
movl $0, %eax
addl $20, %esp
popl %ecx
popl %ebp
leal -4(%ecx), %esp
ret
.size main, .-main
.globl func1
.type func1, #function
func1:
pushl %ebp
movl %esp, %ebp
subl $24, %esp
movl $-1145368303, -4(%ebp)
movl $-50529278, (%esp)
call func2
leave
ret
.size func1, .-func1
.globl func2
.type func2, #function
func2:
pushl %ebp
movl %esp, %ebp
subl $24, %esp
movl $-859041519, -4(%ebp)
movl $-859037150, -8(%ebp)
movl $-50529277, (%esp)
call func3
leave
ret
.size func2, .-func2
.globl func3
.type func3, #function
func3:
pushl %ebp
movl %esp, %ebp
subl $24, %esp
movl $-572714735, -4(%ebp)
movl $-572710366, -8(%ebp)
movl $-572705997, -12(%ebp)
movl $-50529276, (%esp)
call trace
leave
ret
.size func3, .-func3
.section .rodata
.LC0:
.string "0x%08X : %08X\n"
.text
.globl trace
.type trace, #function
trace:
pushl %ebp
movl %esp, %ebp
subl $40, %esp
movl $-286387951, -4(%ebp)
leal -4(%ebp), %eax
movl %eax, -8(%ebp)
.L10:
movl -8(%ebp), %eax
movl (%eax), %edx
movl -8(%ebp), %eax
movl (%eax), %eax
movl %edx, 12(%esp)
movl %eax, 8(%esp)
movl -8(%ebp), %eax
movl %eax, 4(%esp)
movl $.LC0, (%esp)
call printf
movl -8(%ebp), %eax
movl (%eax), %eax
cmpl $-1431695087, %eax
setne %al
addl $4, -8(%ebp)
testb %al, %al
jne .L10
leave
ret
.size trace, .-trace
.ident "GCC: (Ubuntu 4.3.3-5ubuntu4) 4.3.3"
.section .note.GNU-stack,"",#progbits
Inspecting the stack like this seems like one step too far away. I might suggest loading your program in a debugger, switching to the assembly language view, and single stepping through every machine instruction. Understanding of the CPU stack necessarily requires an understanding of the machine instructions operating on it, and this will be a more direct way to see what's going on.
As others mentioned, the structure of the stack is also highly dependent on the processor architecture you're working with.
Most likely those are stack canaries. Your compiler adds code to push additional data to the stack and read it back afterwards to detect stack overflows.
I'm guessing those values starting with 0x0804 are addresses in your program's code segement (like return addresses for function calls). The ones starting with 0xBF814 that you've labeled as return addresses are addresses on the stack -- data, not code. I'm guessing they're probably frame pointers.
As already pointed out, the 0xBF... are frame pointers and 0x08... return addresses.
The padding is due to alignment issues. Other unrecognized values are also padding as the stack is not initalized to zero or any other value. Uninitialized variables and unused padding space will contain whatever bytes are in those memory locations.
The 0xBF... addresses will be links to the previous stack frame:
0xBF8144D8 : BF8144F8 //return address for trace
0xBF8144DC : 0804845A //
0xBF8144F8 : BF814518 //return address for func3
0xBF8144FC : 08048431 //????
0xBF814518 : BF814538 //return address for func2?
0xBF81451C : 0804840F //????
0xBF814538 : BF814558 //return address for func1
0xBF81453C : 080483E8 //????
The 0x08... addresses will be the addresses of the code to return to in each case.
I can't speak for the other stuff on the stack; you would have to step through the assembly language and see exactly what it is doing. I guess that it is aligning the start of each frame to a specific alignment so that __attribute__((align)) (or whatever it's called these days...) works.
The compiler uses EBP to store the frame's base address. It's been a while so I looked at this, so I may get the details a bit wrong, but the idea is like this.
You have three steps when calling a function:
The caller pushes the function's parameters onto the stack.
The caller uses the call instruction, which pushes the return address onto the stack, and jumps to the new function.
The called function pushes EBP onto the stack, and copies ESP into EBP:
(Note: well behaved functions will also push all the GPRs onto the stack with PUSHAD)
push EBP
mov EBP, ESP
When the function returns it:
pops EBP
executes the ret instruction, which pops off the return address and jumps there.
pop EBP
ret
The question is, why is EBP pushed, and why does ESP get copied into it?
When you enter the function ESP points to the lowest point on the stack for this function. Any variables you declare on the stack can be accessed as [ESP + offset_to_variable]. This is easy! But note that ESP must always point to the top of the stack, so when you declare a new variable on the stack, ESP changes. Now [ESP + offset_to_variable] isn't so great, because you have to remember what ESP was at the time the variable was allocated.
Instead of doing that, the first thing the function needs to do is to copy ESP into EBP. EBP won't change during the life of the function, so you can access all variables using `[EBP + offset_to_variable]. But now you have another problem, because if the called functions calls another function, EBP will be overwritten. That's why before copying EBP it needs to be saved onto the stack, so that it can be restored before the returning to the calling function.
Is this a debug or release build? I'd expect some padding with the debug builds for detecting Stack Overflows.

Understanding empty main()'s translation into assembly

Could somebody please explain what GCC is doing for this piece of code? What is it initializing? The original code is:
#include <stdio.h>
int main()
{
}
And it was translated to:
.file "test1.c"
.def ___main; .scl 2; .type 32; .endef
.text
.globl _main
.def _main; .scl 2; .type 32; .endef
_main:
pushl %ebp
movl %esp, %ebp
subl $8, %esp
andl $-16, %esp
movl $0, %eax
addl $15, %eax
addl $15, %eax
shrl $4, %eax
sall $4, %eax
movl %eax, -4(%ebp)
movl -4(%ebp), %eax
call __alloca
call ___main
leave
ret
I would be grateful if a compiler/assembly guru got me started by explaining the stack, register and the section initializations. I cant make head or tail out of the code.
EDIT:
I am using gcc 3.4.5. and the command line argument is gcc -S test1.c
Thank You,
kunjaan.
I should preface all my comments by saying, I am still learning assembly.
I will ignore the section initialization. A explanation for the section initialization and basically everything else I cover can be found here:
http://en.wikibooks.org/wiki/X86_Assembly/GAS_Syntax
The ebp register is the stack frame base pointer, hence the BP. It stores a pointer to the beginning of the current stack.
The esp register is the stack pointer. It holds the memory location of the top of the stack. Each time we push something on the stack esp is updated so that it always points to an address the top of the stack.
So ebp points to the base and esp points to the top. So the stack looks like:
esp -----> 000a3 fa
000a4 21
000a5 66
000a6 23
ebp -----> 000a7 54
If you push e4 on the stack this is what happens:
esp -----> 000a2 e4
000a3 fa
000a4 21
000a5 66
000a6 23
ebp -----> 000a7 54
Notice that the stack grows towards lower addresses, this fact will be important below.
The first two steps are known as the procedure prolog or more commonly as the function prolog. They prepare the stack for use by local variables (See procedure prolog quote at the bottom).
In step 1 we save the pointer to the old stack frame on the stack by calling
pushl %ebp. Since main is the first function called, I have no idea what the previous value of %ebp points too.
Step 2, We are entering a new stack frame because we are entering a new function (main). Therefore, we must set a new stack frame base pointer. We use the value in esp to be the beginning of our stack frame.
Step 3. Allocates 8 bytes of space on the stack. As we mentioned above, the stack grows toward lower addresses thus, subtracting by 8, moves the top of the stack by 8 bytes.
Step 4; Aligns the stack, I've found different opinions on this. I'm not really sure exactly what this is done. I suspect it is done to allow large instructions (SIMD) to be allocated on the stack,
http://gcc.gnu.org/ml/gcc/2008-01/msg00282.html
This code "and"s ESP with 0xFFFF0000,
aligning the stack with the next
lowest 16-byte boundary. An
examination of Mingw's source code
reveals that this may be for SIMD
instructions appearing in the "_main"
routine, which operate only on aligned
addresses. Since our routine doesn't
contain SIMD instructions, this line
is unnecessary.
http://en.wikibooks.org/wiki/X86_Assembly/GAS_Syntax
Steps 5 through 11 seem to have no purpose to me. I couldn't find any explanation on google. Could someone who really knows this stuff provide a deeper understanding. I've heard rumors that this stuff is used for C's exception handling.
Step 5, stores the return value of main 0, in eax.
Step 6 and 7 we add 15 in hex to eax for unknown reason. eax = 01111 + 01111 = 11110
Step 8 we shift the bits of eax 4 bits to the right. eax = 00001 because the last bits are shift off the end 00001 | 111.
Step 9 we shift the bits of eax 4 bits to the left, eax = 10000.
Steps 10 and 11 moves the value in the first 4 allocated bytes on the stack into eax and then moves it from eax back.
Steps 12 and 13 setup the c library.
We have reached the function epilogue. That is, the part of the function which returns the stack pointers, esp and ebp to the state they were in before this function was called.
Step 14, leave sets esp to the value of ebp, moving the top of stack to the address it was before main was called. Then it sets ebp to point to the address we saved on the top of the stack during step 1.
Leave can just be replaced with the following instructions:
mov %ebp, %esp
pop %ebp
Step 15, returns and exits the function.
1. pushl %ebp
2. movl %esp, %ebp
3. subl $8, %esp
4. andl $-16, %esp
5. movl $0, %eax
6. addl $15, %eax
7. addl $15, %eax
8. shrl $4, %eax
9. sall $4, %eax
10. movl %eax, -4(%ebp)
11. movl -4(%ebp), %eax
12. call __alloca
13. call ___main
14. leave
15. ret
Procedure Prolog:
The first thing a function has to do
is called the procedure prolog. It
first saves the current base pointer
(ebp) with the instruction pushl %ebp
(remember ebp is the register used for
accessing function parameters and
local variables). Now it copies the
stack pointer (esp) to the base
pointer (ebp) with the instruction
movl %esp, %ebp. This allows you to
access the function parameters as
indexes from the base pointer. Local
variables are always a subtraction
from ebp, such as -4(%ebp) or
(%ebp)-4 for the first local variable,
the return value is always at 4(%ebp)
or (%ebp)+4, each parameter or
argument is at N*4+4(%ebp) such as
8(%ebp) for the first argument while
the old ebp is at (%ebp).
http://www.milw0rm.com/papers/52
A really great stack overflow thread exists which answers much of this question.
Why are there extra instructions in my gcc output?
A good reference on x86 machine code instructions can be found here:
http://programminggroundup.blogspot.com/2007/01/appendix-b-common-x86-instructions.html
This a lecture which contains some of the ideas used below:
http://csc.colstate.edu/bosworth/cpsc5155/Y2006_TheFall/MySlides/CPSC5155_L23.htm
Here is another take on answering your question:
http://www.phiral.net/linuxasmone.htm
None of these sources explain everything.
Here's a good step-by step breakdown of a simple main() function as compiled by GCC, with lots of detailed info: GAS Syntax (Wikipedia)
For the code you pasted, the instructions break down as follows:
First four instructions (pushl through andl): set up a new stack frame
Next five instructions (movl through sall): generating a weird value for eax, which will become the return value (I have no idea how it decided to do this)
Next two instructions (both movl): store the computed return value in a temporary variable on the stack
Next two instructions (both call): invoke the C library init functions
leave instruction: tears down the stack frame
ret instruction: returns to caller (the outer runtime function, or perhaps the kernel function that invoked your program)
Well, dont know much about GAS, and i'm a little rusty on Intel assembly, but it looks like its initializing main's stack frame.
if you take a look, __main is some kind of macro, must be executing initializations.
Then, as main's body is empty, it calls leave instruction, to return to the function that called main.
From http://en.wikibooks.org/wiki/X86_Assembly/GAS_Syntax#.22hello.s.22_line-by-line:
This line declares the "_main" label, marking the place that is called from the startup code.
pushl %ebp
movl %esp, %ebp
subl $8, %esp
These lines save the value of EBP on the stack, then move the value of ESP into EBP, then subtract 8 from ESP. The "l" on the end of each opcode indicates that we want to use the version of the opcode that works with "long" (32-bit) operands;
andl $-16, %esp
This code "and"s ESP with 0xFFFF0000, aligning the stack with the next lowest 16-byte boundary. (neccesary when using simd instructions, not useful here)
movl $0, %eax
movl %eax, -4(%ebp)
movl -4(%ebp), %eax
This code moves zero into EAX, then moves EAX into the memory location EBP-4, which is in the temporary space we reserved on the stack at the beginning of the procedure. Then it moves the memory location EBP-4 back into EAX; clearly, this is not optimized code.
call __alloca
call ___main
These functions are part of the C library setup. Since we are calling functions in the C library, we probably need these. The exact operations they perform vary depending on the platform and the version of the GNU tools that are installed.
Here's a useful link.
http://unixwiz.net/techtips/win32-callconv-asm.html
It would really help to know what gcc version you are using and what libc. It looks like you have a very old gcc version or a strange platform or both. What's going on is some strangeness with calling conventions. I can tell you a few things:
Save the frame pointer on the stack according to convention:
pushl %ebp
movl %esp, %ebp
Make room for stuff at the old end of the frame, and round the stack pointer down to a multiple of 4 (why this is needed I don't know):
subl $8, %esp
andl $-16, %esp
Through an insane song and dance, get ready to return 1 from main:
movl $0, %eax
addl $15, %eax
addl $15, %eax
shrl $4, %eax
sall $4, %eax
movl %eax, -4(%ebp)
movl -4(%ebp), %eax
Recover any memory allocated with alloca (GNU-ism):
call __alloca
Announce to libc that main is exiting (more GNU-ism):
call ___main
Restore the frame and stack pointers:
leave
Return:
ret
Here's what happens when I compile the very same source code with gcc 4.3 on Debian Linux:
.file "main.c"
.text
.p2align 4,,15
.globl main
.type main, #function
main:
leal 4(%esp), %ecx
andl $-16, %esp
pushl -4(%ecx)
pushl %ebp
movl %esp, %ebp
pushl %ecx
popl %ecx
popl %ebp
leal -4(%ecx), %esp
ret
.size main, .-main
.ident "GCC: (Debian 4.3.2-1.1) 4.3.2"
.section .note.GNU-stack,"",#progbits
And I break it down this way:
Tell the debugger and other tools the source file:
.file "main.c"
Code goes in the text section:
.text
Beats me:
.p2align 4,,15
main is an exported function:
.globl main
.type main, #function
main's entry point:
main:
Grab the return address, align the stack on a 4-byte address, and save the return address again (why I can't say):
leal 4(%esp), %ecx
andl $-16, %esp
pushl -4(%ecx)
Save frame pointer using standard convention:
pushl %ebp
movl %esp, %ebp
Inscrutable madness:
pushl %ecx
popl %ecx
Restore the frame pointer and the stack pointer:
popl %ebp
leal -4(%ecx), %esp
Return:
ret
More info for the debugger?:
.size main, .-main
.ident "GCC: (Debian 4.3.2-1.1) 4.3.2"
.section .note.GNU-stack,"",#progbits
By the way, main is special and magical; when I compile
int f(void) {
return 17;
}
I get something slightly more sane:
.file "f.c"
.text
.p2align 4,,15
.globl f
.type f, #function
f:
pushl %ebp
movl $17, %eax
movl %esp, %ebp
popl %ebp
ret
.size f, .-f
.ident "GCC: (Debian 4.3.2-1.1) 4.3.2"
.section .note.GNU-stack,"",#progbits
There's still a ton of decoration, and we're still saving the frame pointer, moving it, and restoring it, which is utterly pointless, but the rest of the code make sense.
It looks like GCC is acting like it is ok to edit main() to include CRT initialization code. I just confirmed that I get the exact same assembly listing from MinGW GCC 3.4.5 here, with your source text.
The command line I used is:
gcc -S emptymain.c
Interestingly, if I change the name of the function to qqq() instead of main(), I get the following assembly:
.file "emptymain.c"
.text
.globl _qqq
.def _qqq; .scl 2; .type 32; .endef
_qqq:
pushl %ebp
movl %esp, %ebp
popl %ebp
ret
which makes much more sense for an empty function with no optimizations turned on.

Resources