x86 function call and return --- stack save the return address.
2015-12-09 15:02
330 查看
ARM has LR register to store the return address of the caller.
But X86 has no this kind register.
So how the function call return to the caller ?
The answer is the function call stack and the register EBP and ESP.
EBP stores caller's stack top address.
ESP stores function stack top address.
call instruction will push the return address( the address of next instruction of call) in to ESP stack, then jump to the function.
In the function: 0x80483e4 <func_a>: push %ebp
0x80483e5 <func_a+1>: mov %esp,%ebp
0x80483e7 <func_a+3>: push %ebx
0x80483e8 <func_a+4>: sub $0x24,%esp // new stack
0x80483eb <func_a+7>: mov 0xc(%ebp),%eax
0x80483ee <func_a+10>: mov 0x8(%ebp),%edx
0x80483f1 <func_a+13>: add %edx,%eax
0x80483f3 <func_a+15>: mov %eax,-0x10(%ebp)
0x80483f6 <func_a+18>: mov 0x4(%ebp),%ebx
0x80483f9 <func_a+21>: mov %ebx,-0xc(%ebp)
0x80483fc <func_a+24>: mov $0x8048540,%eax
0x8048401 <func_a+29>: mov -0xc(%ebp),%edx
0x8048404 <func_a+32>: mov %edx,0x4(%esp)
0x8048408 <func_a+36>: mov %eax,(%esp)
0x804840b <func_a+39>: call 0x8048300 <printf@plt>
0x8048410 <func_a+44>: mov -0x10(%ebp),%eax
0x8048413 <func_a+47>: add $0x24,%esp // return to call stack
0x8048416 <func_a+50>: pop %ebx
0x8048417 <func_a+51>: pop %ebp // pop EBP
0x8048418 <func_a+52>: ret
Attention: the stack is still caller's stack.
The first instruction of the function is push EBP to the ESP stack(save caller's caller stack address).
The second instruction is mov ESP to EBP (save caller's stack in EBP) .
The fourth instruction create the new stack for this function and set it in ESP. Here start to run with function's stack.
leave instruction will restore EBP to ESP, then pop the EBP from the ESP stack.
ret instruction will pop the return address to EIP.
So we could get the caller's return address by access EBP+4 memory. Following is the code.
#include <stdio.h>
static volatile int func_a(int a, int b)
{
int c=a+b;
unsigned int caller;
asm("mov 4(%%ebp),%0":"=r"(caller):);
printf("caller address is 0x%x\n",caller);
return c;
}
int main(int argc,char** argv)
{
int a = 5;
int b = 9;
int c = 0;
c=func_a(a,b);
printf("c is %d\n",c);
return 0;
}
But X86 has no this kind register.
So how the function call return to the caller ?
The answer is the function call stack and the register EBP and ESP.
EBP stores caller's stack top address.
ESP stores function stack top address.
call instruction will push the return address( the address of next instruction of call) in to ESP stack, then jump to the function.
In the function: 0x80483e4 <func_a>: push %ebp
0x80483e5 <func_a+1>: mov %esp,%ebp
0x80483e7 <func_a+3>: push %ebx
0x80483e8 <func_a+4>: sub $0x24,%esp // new stack
0x80483eb <func_a+7>: mov 0xc(%ebp),%eax
0x80483ee <func_a+10>: mov 0x8(%ebp),%edx
0x80483f1 <func_a+13>: add %edx,%eax
0x80483f3 <func_a+15>: mov %eax,-0x10(%ebp)
0x80483f6 <func_a+18>: mov 0x4(%ebp),%ebx
0x80483f9 <func_a+21>: mov %ebx,-0xc(%ebp)
0x80483fc <func_a+24>: mov $0x8048540,%eax
0x8048401 <func_a+29>: mov -0xc(%ebp),%edx
0x8048404 <func_a+32>: mov %edx,0x4(%esp)
0x8048408 <func_a+36>: mov %eax,(%esp)
0x804840b <func_a+39>: call 0x8048300 <printf@plt>
0x8048410 <func_a+44>: mov -0x10(%ebp),%eax
0x8048413 <func_a+47>: add $0x24,%esp // return to call stack
0x8048416 <func_a+50>: pop %ebx
0x8048417 <func_a+51>: pop %ebp // pop EBP
0x8048418 <func_a+52>: ret
Attention: the stack is still caller's stack.
The first instruction of the function is push EBP to the ESP stack(save caller's caller stack address).
The second instruction is mov ESP to EBP (save caller's stack in EBP) .
The fourth instruction create the new stack for this function and set it in ESP. Here start to run with function's stack.
leave instruction will restore EBP to ESP, then pop the EBP from the ESP stack.
ret instruction will pop the return address to EIP.
So we could get the caller's return address by access EBP+4 memory. Following is the code.
#include <stdio.h>
static volatile int func_a(int a, int b)
{
int c=a+b;
unsigned int caller;
asm("mov 4(%%ebp),%0":"=r"(caller):);
printf("caller address is 0x%x\n",caller);
return c;
}
int main(int argc,char** argv)
{
int a = 5;
int b = 9;
int c = 0;
c=func_a(a,b);
printf("c is %d\n",c);
return 0;
}
相关文章推荐
- Mootools 1.2教程 函数
- autoit InputBox 函数
- 文件遍历排序函数
- Oracle 函数大全[字符串函数,数学函数,日期函数]第1/4页
- ASP下经常用的字符串等函数参考资料
- PostgreSQL教程(五):函数和操作符详解(1)
- DOS批处理 函数定义与用法
- asp Chr 函数 数字转字母的方法
- Lua中的函数精讲笔记
- Lua中的闭合函数、非全局函数与函数的尾调用详解
- Lua中调用C++函数示例
- Lua实现split函数
- Lua常用时间函数使用实例
- Lua函数与字符串处理简明总结
- Lua学习笔记之表和函数
- Lua中实现sleep函数功能的4种方法
- Lua函数用法研究
- Lua基础教程之赋值语句、表达式、流程控制、函数学习笔记
- PowerShell函数简明教程
- 探索PowerShell(十一)函数介绍