每天学点GDB(七)

简介: 近两周在做一个trouble shooting,需要对函数调用栈进行分析以找出入参和局部变量。因为在编译生成可执行程序的时候,用gcc进行了O2的优化,许多假设的函数调用栈模型都不成立了。花了一番周折,终于正确的翻译出入参和局部变量,此一旅程中的一些经验还是值得记录下来。

近两周在做一个trouble shooting,需要对函数调用栈进行分析以找出入参和局部变量。因为在编译生成可执行程序的时候,用gcc进行了O2的优化,许多假设的函数调用栈模型都不成立了。花了一番周折,终于正确的翻译出入参和局部变量,此一旅程中的一些经验还是值得记录下来。

在32位x86系统上,函数调用栈的布局如下图所示。

0397c89f8884fe5cef54f7a1b3de79e2b7aed0c6

栈底在高地址段,栈顶在低地址段。

从栈底到栈顶的内容分别为:

  1. 函数入参
  2. 返回地址
  3. 保存的寄存器值
  4. 被调用函数的局部变量

如果带有调试信息,则要获取上述4个部分的值很容易,对应的指令分别如下。

  1. info args
  2. info frame
  3. info registers
  4. info locals

如果没有调试信息,则可以根据这一模型并结合反汇编的结果来算出入参与局部变量的存储位置。针对32位的具体例子比较容易找到。

现在专门提一提在x86 64位下的不同,在x86 64下,因为寄存器数量增多,为了提高效率,入参基本上都是通过寄存器来传递。示例程序如下:

#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>

int demo_func(char* msg, int a, int b); 


int main(int argc, char** argv) {
    char* info = "just a demo";
    int a,b;
    a = 320;
    b = 100;
    demo_func(info, a, b);
    return 0;
}


int demo_func(char* msg, int a, int b) {
    int sum;
    sum = a + b;
    return  sum;
}

main函数反汇编结果如下:

Dump of assembler code for function main:
   0x00000000004004b0 <+0>:    push   %rbp
   0x00000000004004b1 <+1>:    mov    %rsp,%rbp
   0x00000000004004b4 <+4>:    sub    $0x20,%rsp
   0x00000000004004b8 <+8>:    mov    %edi,-0x14(%rbp)
   0x00000000004004bb <+11>:    mov    %rsi,-0x20(%rbp)
   0x00000000004004bf <+15>:    movq   $0x400594,-0x8(%rbp)
   0x00000000004004c7 <+23>:    movl   $0x140,-0xc(%rbp)
   0x00000000004004ce <+30>:    movl   $0x64,-0x10(%rbp)
   0x00000000004004d5 <+37>:    mov    -0x10(%rbp),%edx
   0x00000000004004d8 <+40>:    mov    -0xc(%rbp),%ecx
   0x00000000004004db <+43>:    mov    -0x8(%rbp),%rax
   0x00000000004004df <+47>:    mov    %ecx,%esi
   0x00000000004004e1 <+49>:    mov    %rax,%rdi
   0x00000000004004e4 <+52>:    callq  0x4004f0 <demo_func>
   0x00000000004004e9 <+57>:    mov    $0x0,%eax
   0x00000000004004ee <+62>:    leaveq 
   0x00000000004004ef <+63>:    retq   
End of assembler dump.

注意callq 0x4004f0 <demo_func>上的三行代码,它们表示demo_func的入参,可以看出入参是通过寄存器来进行传递的。
而寄存器在demo_func中可以会被改写,于是在改写之前,这些入参会被再次保存,它们保存在stack frame中,具体位置需要根据反汇编结果进行计算。即需要根据被调用函数的反汇编代码来计算入参。

demo_func的反汇编结果如下:

Dump of assembler code for function demo_func:
   0x00000000004004f0 <+0>:    push   %rbp
   0x00000000004004f1 <+1>:    mov    %rsp,%rbp
   0x00000000004004f4 <+4>:    mov    %rdi,-0x18(%rbp)
   0x00000000004004f8 <+8>:    mov    %esi,-0x1c(%rbp)
   0x00000000004004fb <+11>:    mov    %edx,-0x20(%rbp)
   0x00000000004004fe <+14>:    mov    -0x20(%rbp),%eax
   0x0000000000400501 <+17>:    mov    -0x1c(%rbp),%edx
   0x0000000000400504 <+20>:    add    %edx,%eax
   0x0000000000400506 <+22>:    mov    %eax,-0x4(%rbp)
   0x0000000000400509 <+25>:    mov    -0x4(%rbp),%eax
   0x000000000040050c <+28>:    pop    %rbp
   0x000000000040050d <+29>:    retq   
End of assembler dump.

编译时如果加上-O2优化,则反汇编结果变为:

Dump of assembler code for function demo_func:
   0x00000000004004b0 <+0>:    lea    (%rsi,%rdx,1),%eax
   0x00000000004004b3 <+3>:    retq   
End of assembler dump.

内容极度简化,在具体计算时,一定要根据反汇编的结果来进行。

相关实践学习
阿里云图数据库GDB入门与应用
图数据库(Graph Database,简称GDB)是一种支持Property Graph图模型、用于处理高度连接数据查询与存储的实时、可靠的在线数据库服务。它支持Apache TinkerPop Gremlin查询语言,可以帮您快速构建基于高度连接的数据集的应用程序。GDB非常适合社交网络、欺诈检测、推荐引擎、实时图谱、网络/IT运营这类高度互连数据集的场景。 GDB由阿里云自主研发,具备如下优势: 标准图查询语言:支持属性图,高度兼容Gremlin图查询语言。 高度优化的自研引擎:高度优化的自研图计算层和存储层,云盘多副本保障数据超高可靠,支持ACID事务。 服务高可用:支持高可用实例,节点故障迅速转移,保障业务连续性。 易运维:提供备份恢复、自动升级、监控告警、故障切换等丰富的运维功能,大幅降低运维成本。 产品主页:https://www.aliyun.com/product/gdb
目录
相关文章
|
jenkins Devops 持续交付
【devops】七、集成Sonar Qube(下)
【devops】七、集成Sonar Qube(下)
482 0
|
6月前
|
Java Linux Apache
Apache NetBeans 29 (macOS, Linux, Windows) - Java 等多语言开源跨平台 IDE
Apache NetBeans 29 (macOS, Linux, Windows) - Java 等多语言开源跨平台 IDE
304 1
Apache NetBeans 29 (macOS, Linux, Windows) - Java 等多语言开源跨平台 IDE
|
存储 供应链 物联网
RFID鞋服应用大大提升消费者体验感
RFID技术在鞋服行业实现全流程智能化管理,通过电子标签提升商品追踪、库存盘点、防伪防盗效率,优化消费者体验,助力企业数字化转型。
|
9月前
|
机器学习/深度学习 搜索推荐 算法
广告系统:广告引擎如何做到在 0.1s 内返回广告信息?
广告系统是互联网公司核心营收支柱,如Google、Facebook超80%收入来自广告。其背后依赖高性能广告引擎,实现高并发、低延迟的精准投放。本文深入解析广告引擎架构,涵盖标签检索、向量匹配、打分排序与索引优化四大关键技术,揭示如何在0.1秒内完成从请求到返回的全流程,支撑千人千面的智能广告体验。
|
存储 自然语言处理 搜索推荐
分布式搜索引擎ElasticSearch
Elasticsearch是一款强大的开源搜索引擎,用于快速搜索和数据分析。它在GitHub、电商搜索、百度搜索等场景中广泛应用。Elasticsearch是ELK(Elasticsearch、Logstash、Kibana)技术栈的核心,用于存储、搜索和分析数据。它基于Apache Lucene构建,提供分布式搜索能力。相比其他搜索引擎,如Solr,Elasticsearch更受欢迎。倒排索引是其高效搜索的关键,通过将词条与文档ID关联,实现快速模糊搜索,避免全表扫描。
978 120
|
云安全 人工智能 安全
用AI来做云安全是怎样一种体验?阿里云安全AI能力大曝光
用AI来做云安全是怎样一种体验?阿里云安全AI能力大曝光
Vue3使用hook封装常见的几种异步请求函数场景,让开发更加丝滑🚀🚀🚀
Vue3使用hook封装常见的几种异步请求函数场景,让开发更加丝滑🚀🚀🚀
|
数据采集 机器学习/深度学习 存储
使用 Python 清洗日志数据
使用 Python 清洗日志数据
596 2
|
开发框架 缓存 前端开发
实战.NET Framework 迁移到 .NET 5/6
从.NET Framework 迁移到.NET 5/6 是一次重要的技术革新,涵盖开发环境与应用架构的全面升级。本文通过具体案例详细解析迁移流程,包括评估现有应用、利用.NET Portability Analyzer 工具识别可移植代码、创建新项目、逐步迁移代码及处理依赖项更新等关键步骤。特别关注命名空间调整、JSON 序列化工具更换及数据库访问层重构等内容,旨在帮助开发者掌握最佳实践,确保迁移过程平稳高效,同时提升应用性能与可维护性。
661 2
|
Kubernetes 负载均衡 应用服务中间件
使用 Kubeadm 部署 Kubernetes(K8S) 安装 -- Ingress-Ngnix
使用 Kubeadm 部署 Kubernetes(K8S) 安装 -- Ingress-Ngnix
589 0

热门文章

最新文章