Tuesday, April 17, 2012

The Function Stack


For getting the knowledge about function call stack you should be aware of some general purpose registers used during program execution especially related to stack.

Some of the general purpose register used during program execution are:
  • AX/EAX/RAX: Accumulator
  • BX/EBX/RBX: Base index (for use with arrays)
  • CX/ECX/RCX: Counter
  • DX/EDX/RDX: Data/general
  • SI/ESI/RSI: Source index for string operations.
  • DI/EDI/RDI: Destination index for string operations.
  • SP/ESP/RSP: Stack pointer for top address of the stack.
  • BP/EBP/RBP: Stack base pointer for holding the address of the current stack frame.
  • IP/EIP/RIP: Instruction pointer. Holds the program counter, the current instruction address.
Segment registers:
  • CS: Code
  • DS: Data
  • SS: Stack
  • ES: Extra
  • FS
  • GS
So what happens when function call take place?

When the function call takes place, data elements are stored on the stack in the following way
  • The function parameters are pushed on the stack before the function is called.  The parameters are pushed from right to left.
  • The function return address is placed on the stack by the x86 CALL instruction, which stores the current value of the RIP register.
  • Then, the frame pointer that is the previous value of the RBP register is placed on the stack.
  • The callee save registers such as ESI, EDI, and EBX are stored if they are used at any point during the functions execution.
  • Next, the locally declared variables.
  • Then the buffers are allocated for temporary data storage.  
I will illustrate you by simple add program regarding function call.
sample program:
#include<stdio.h>
int add(int a,int b)
{
int c;
c=a+b;
return c;
}
int main()
{
int k=add(2,3);
printf("%d\n",k);
return 0;
}
compile program using gcc. 
gcc hello.c

objdump in linux is a good tool for getting information related to object file. it can be used to display assembler context of object file.
objdump -d a.out

it display a lot of information but i am displaying only of our concern.
0000000000400498 <add>:
  400498:       55                      push   %rbp
  400499:       48 89 e5             mov    %rsp,%rbp
  40049c:       89 7d ec                mov    %edi,0xffffffffffffffec(%rbp)
  40049f:       89 75 e8                mov    %esi,0xffffffffffffffe8(%rbp)
  4004a2:       8b 45 e8                mov    0xffffffffffffffe8(%rbp),%eax
  4004a5:       03 45 ec                add    0xffffffffffffffec(%rbp),%eax
  4004a8:       89 45 fc                mov    %eax,0xfffffffffffffffc(%rbp)
  4004ab:       8b 45 fc                mov    0xfffffffffffffffc(%rbp),%eax
  4004ae:       c9                      leaveq
  4004af:       c3                      retq

00000000004004b0 <main>:
  4004b0:       55                      push   %rbp
  4004b1:       48 89 e5                mov    %rsp,%rbp
  4004b4:       48 83 ec 10             sub    $0x10,%rsp
  4004b8:       be 03 00 00 00          mov    $0x3,%esi
  4004bd:       bf 02 00 00 00          mov    $0x2,%edi
  4004c2:       e8 d1 ff ff ff          callq  400498 <add>
  4004c7:       89 45 fc                mov    %eax,0xfffffffffffffffc(%rbp)
  4004ca:       8b 75 fc                mov    0xfffffffffffffffc(%rbp),%esi
  4004cd:       bf e8 05 40 00          mov    $0x4005e8,%edi
  4004d2:       b8 00 00 00 00          mov    $0x0,%eax
  4004d7:       e8 bc fe ff ff          callq  400398 <printf@plt>
  4004dc:       b8 00 00 00 00          mov    $0x0,%eax
  4004e1:       c9                      leaveq
  4004e2:       c3                      retq

you can also use disas to get the assembly code of function while using gdb.

gdb a.out
(gdb) disas main
Dump of assembler code for function main:
0x00000000004004b0 <main+0>:    push   %rbp
0x00000000004004b1 <main+1>:    mov    %rsp,%rbp
0x00000000004004b4 <main+4>:    sub    $0x10,%rsp
0x00000000004004b8 <main+8>:    mov    $0x3,%esi
0x00000000004004bd <main+13>:   mov    $0x2,%edi
0x00000000004004c2 <main+18>:   callq  0x400498 <add>
0x00000000004004c7 <main+23>:   mov    %eax,-0x4(%rbp)
0x00000000004004ca <main+26>:   mov    -0x4(%rbp),%esi
0x00000000004004cd <main+29>:   mov    $0x4005e8,%edi
0x00000000004004d2 <main+34>:   mov    $0x0,%eax
0x00000000004004d7 <main+39>:   callq  0x400398 <printf@plt>
0x00000000004004dc <main+44>:   mov    $0x0,%eax
0x00000000004004e1 <main+49>:   leaveq
0x00000000004004e2 <main+50>:   retq
End of assembler dump.
(gdb) disas add
Dump of assembler code for function add:
0x0000000000400498 <add+0>:     push   %rbp
0x0000000000400499 <add+1>:     mov    %rsp,%rbp
0x000000000040049c <add+4>:     mov    %edi,-0x14(%rbp)
0x000000000040049f <add+7>:     mov    %esi,-0x18(%rbp)
0x00000000004004a2 <add+10>:    mov    -0x18(%rbp),%eax
0x00000000004004a5 <add+13>:    add    -0x14(%rbp),%eax
0x00000000004004a8 <add+16>:    mov    %eax,-0x4(%rbp)
0x00000000004004ab <add+19>:    mov    -0x4(%rbp),%eax
0x00000000004004ae <add+22>:    leaveq
0x00000000004004af <add+23>:    retq
End of assembler dump.


To get the information about current values in registers you can use info command in gdb.
(gdb) info reg
rax            0x3810753a60     240794286688
rbx            0x380f61bbc0     240776231872
rcx            0x400500 4195584
rdx            0x7fff417a37b8   140734291916728
rsi            0x3      3
rdi            0x2      2
rbp            0x7fff417a36a0   0x7fff417a36a0
rsp            0x7fff417a36a0   0x7fff417a36a0
r8             0x38107522d0     240794280656
r9             0x380f40d620     240774075936
r10            0x0      0
r11            0x381041d8a0     240790919328
r12            0x0      0
r13            0x7fff417a37a0   140734291916704
r14            0x0      0
r15            0x0      0
rip            0x4004a2 0x4004a2 <add+10>
eflags         0x202    [ IF ]
cs             0x33     51
ss             0x2b     43
ds             0x0      0
es             0x0      0
fs             0x0      0
gs             0x0      0
fctrl          0x37f    895
fstat          0x0      0
ftag           0xffff   65535
fiseg          0x0      0
fioff          0x0      0
foseg          0x0      0
fooff          0x0      0
fop            0x0      0
mxcsr          0x1f80   [ IM DM ZM OM UM PM ]

These all registers are hardware architecture dependent.

No comments:

Post a Comment