程序的机器级表示——函数调用过程讲解(gdb实例分析)

往期地址:

本期主题:
程序的机器级表示—— 过程



1. 过程的定义

过程是软件中一种重要的抽象,提供了代码的封装方式,用一组指定的参数和可选的返回值实现了某种功能。
不同编程语言中,过程的形式多样:

函数(function)、方法(method)、子例程(subroutine)、处理函数(handler) 等等。

现在假设这么一个场景:
过程P调用过程Q,Q执行后返回到P。这些动作包括下面这些机制:

  • 传递控制。 在进入到过程Q的时候,程序计数器必须被设置为Q的起始地址,然后在返回时,要把程序计数器设置为P调用Q后面那条指令的地址
  • 传递数据。 P必须能够向Q提供一个或多个参数,Q必须能向P返回一个值。
  • 分配和释放空间。 在开始时,Q要为局部变量分配空间,而在返回前,又要释放掉这些存储空间。

2. 运行时的栈

下图展示了一个较为通用的栈帧结构。
在这里插入图片描述

展示的过程是从过程P调用到过程Q,从上图可以看到这么一些信息:

  1. 当前正在执行的过程的帧总是在栈顶;
  2. 当过程P调用过程Q时,会把返回地址压入栈中。指明当Q返回时,要从P程序的哪个位置继续执行。
  3. 当过程Q执行时,会扩展当前栈的边界,分配自己所需要的栈帧空间,用来保存 寄存器的值、分配局部空间变量、为过程设置参数等。

3. 一些gdb的基础调试命令

  1. 开始运行gdb,gdb xxx
  2. 打断点,break xxx,例如在main函数打断点就是break main
  3. 想同步看汇编代码、源码,layout split命令,也可以layout next不停切换,找到自己想要的布局
  4. 单步执行,step和next,两者差异在于是否会跳进函数,step会进入函数,next不会
  5. 单步执行汇编,si
  6. 看当前栈帧信息, info frame
  7. 看当前栈帧回溯,backtrace
  8. 看寄存器信息,info register xxx
  9. 看memory信息,x/[n][f][u] address
  • n 表示要查看的单位数目(例如:4 表示查看4个单位)。
  • f 表示显示格式,可以是以下选项之一:

x:十六进制
d:十进制
u:无符号十进制
o:八进制
t:二进制
f:浮点数
a:地址
i:指令(反汇编指令)
c:字符
s:字符串

  • u 表示每个单位的大小,可以是以下选项之一:

b:字节(1字节)
h:半字(2字节)
w:字(4字节)
g:巨字(8字节)

例如想看某个address开始的 连续20个word的内容,并用16进制显示,就输入如下命令:

x/20wx address

4.例子

1. 前提

看一个非常简单的代码,预期通过这份代码理解

  1. 当前栈帧的结构
  2. 当调用时,如何压栈,返回地址和调用参数的布局
  3. 当返回时,如何变化

2. c源码

#include <stdio.h>

int func1(int a, int b) {
    int c = a + b;
    return c;
}

int main() {
    int arg1 = 10, arg2 = 20;
    int ret;
    ret = func1(arg1, arg2);
    return 0;
}

3.调试过程

编译

使用-g -O0 编译选项

$ gcc -g -O0 -o example example.c 
$ file example
example: ELF 64-bit LSB shared object, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, for GNU/Linux 3.2.0, BuildID[sha1]=aef991cd91436aeb886bbc89ab23cb7f4e252fc3, with debug_info, not stripped

gdb调试基础

gdb example //开始启动调试
break main //在main函数处打断点
run //运行
layout split //同时显示源码和汇编代码

输入上面的命令之后,能看到如下状态:
在这里插入图片描述

在main处一开始打断点的状态

  1. rip寄存器和栈帧信息
  • rip寄存器指向下一条指令的地址
  • 栈帧 level0,表示是当前栈帧
    在这里插入图片描述
  1. 存的rip寄存器信息(调用帧的信息)
    在这里插入图片描述

即将跳转到func1的状态

  1. 此时rbp、rsp、rip寄存器的状态如下:
    在这里插入图片描述

跳转到func1之后的状态

在这里插入图片描述
当前栈帧地址的上面一段地址里的内容就返回地址,对应着我们这个示意图
在这里插入图片描述

在这里插入图片描述
TODO: 但是这里的两个参数 0xa和0x14没有对应上
按照我的预期,这两个参数应该在0x5…54639这个地址的前面,但是不知道为什么在f…fe270的栈帧里
有懂的朋友可以在评论区指导一下,谢谢

从func1返回

在这里插入图片描述

  • 26
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值