AIRobot

AIRobot quick note


  • 首页

  • 关于

  • 标签

  • 分类

  • 归档

  • 搜索

堆栈

发表于 2019-12-27 更新于 2020-12-29
本文字数: 2.9k 阅读时长 ≈ 3 分钟

函数调用栈

EIP, EBP, ESP三个指针寄存器与函数调用的关系

函数调用离不开这三个寄存器,函数调用时三者的作用:

  • EIP中保存CPU下次要执行的指令地址即调用完函数后要执行的指令地址;

  • EBP中保存的是当前函数栈基地址,一直不变,即栈底;

  • ESP 中保存的是当前函数调用栈顶

函数参数与EBP关系

由上图我们可以看出,函数的参数与EBP的关系,第一个参数与EBP之间隔着上一级函数的EIP,EBP。由于EIP, EBP都是指针所以占4个字节, 第一个参数与EBP相隔8个字节。函数参数是由右向左依次压栈的,所以得如下结论:

第一个参数地址 = EBP的值 + 8

第二个参数地址 = EBP的值 + 8 + sizeof(参数1)

第N个参数地址 = EBP的值+8 + sizeof(参数1) + sizeof(参数2) …sizeof(参数N-1);

依此类推可以根据EBP的值和各参数的类型我们可以找到所有参数

注:如果是C++的类型成员函数则第一个参数是this指针

test.c

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#include <stdio.h>

struct teststruct
{
int nTest;
};

int test_fun(struct teststruct *pTs, int n)
{
int b = 3;
int c =4;
pTs->nTest = n;
printf("b = %d\n",b);
return 0;
}
int main()
{
struct teststruct test;
test_fun(&test, 1);

return 0;
}

test.s

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
	.file	"test.c"
.text
.globl test_fun
.type test_fun,@function
test_fun:
pushl %ebp //main函数的 ebp 压栈
movl %esp, %ebp //设置 test_fun()的 ebp
sub $0x8,%esp
movl $0x3,0xfffffffc(%ebp) //%ebp-4; b = 3
movl $0x4,0xfffffff8(%ebp) //%ebp-8; c = 4
mov 0x8(%ebp),%eax
mov 0xc(%ebp),%edx
mov %edx,(%eax)
sub $0x8,%esp
pushl 0xfffffffc(%ebp)
push $0x8048548
call 0x80482e4 <printf>
add $0x10,%esp
mov $0x0,%eax
leave //MOV EBP,ESP;POP EBP
ret
.Lfe1:
.size test_fun,.Lfe1-test_fun
.globl main
.type main,@function
main:
pushl %ebp
movl %esp, %ebp
subl $8, %esp
andl $-16, %esp
movl $0, %eax
subl %eax, %esp
subl $8, %esp

// test_fun(&test, 1); 调用过程
pushl $1
leal -4(%ebp), %eax => 0xfffffffc($ebp)
pushl %eax

call test_fun

addl $16, %esp => 清理栈
movl $0, %eax
leave
ret
.Lfe2:
.size main,.Lfe2-main
.ident "GCC: (GNU) 3.2.2 20030222 (Red Hat Linux 3.2.2-5)"
  • call *8(%eax)
    调用 %eax+8 ,的函数指针指向的函数。
  • incw 0xffffffc8(%ebp,%ecx,2)
    (ebp + 2ecx) - (0x100-0xc8),这个值进行++操作
    这是基址变址寻址方式,disp(base, index, scale),计算方法:base+index
    scale+disp 。
  • movb 0x15 0x16(%esp,1)
    移动字节0x15,到%esp*1+0x16,这个地址上。
    属变址寻址方式

linux中一个进程的内存布局如下图所示:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25

-----------------
高地址 | | ---> 命令行参数和环境变量 (只读) 0xff..ff
-----------------
| 栈 |
|- - - - - - - -|
| | | |
| \ / |
| |
| |
| / \ |
| | | |
|- - - - - - - -|
| 堆 |
|---------------|
           | 未初始化的变量 |
| (bss) | ---> 由 exec 初始化为零
|---------------|
          | 初始化后的变量 | \
|---------------| |
| text(数据区) | | 由 exec 从程序中读取
     | | /
|---------------|
低地址     | 代码区 | 0x00..01
|---------------|

int a=16777220,十六进制是0x01 00 00 04则04属于低字节,01属于高字节

大端 网络 小端 主机
0x0004 04 01
0x0003 00 00
0x0002 00 00
0x0001 01 04

(1)一个整数类型内部

低地址存储低位,高地址存储高位。比如int a=1,则存储情况为0000(高地址) 0000 0000 0001(低地址)

(2)若干个局部变量(在栈中存储的)

先定义的高地址,后定义的低地址

(3)类、结构体或数组的元素

先定义的低地址,后定义的高地址

# C
ldd,nm,readelf,ar,objdump
Linux RSS/RPS/RFS/XPS
  • 文章目录
  • 站点概览
AIRobot

AIRobot

AIRobot quick note
130 日志
15 分类
23 标签
GitHub E-Mail
Creative Commons
  1. 1. 函数调用栈
    1. 1.1. EIP, EBP, ESP三个指针寄存器与函数调用的关系
  2. 2. 函数参数与EBP关系
0%
© 2023 AIRobot | 716k | 10:51