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;
}
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
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.
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