Linux系统上64位ATT风格汇编语言计算乘方堆栈图分析(只有一层调用)

参考博文:《怎样深入理解堆和栈》
《关于寻址方式一篇就够了》
《堆栈、栈帧、函数调用过程》
《gdb 调试中-i frame命令之堆栈信息说明》
《【TARS】GDB 调试进阶「0x02」》

栈与栈帧的关系

一个程序在运行过程中,操作系统会在内存中分配多个区域给这个程序。有以下几个区:

栈区(stack)
堆区(heap)
全局区(静态区)(static)
文字常量区
程序代码区

栈区是一段内存,主要作用是保存函数之间需要传递的参数并且保存被调用函数的返回地址。栈帧(stack )是一种逻辑划分,就是程序占用内存中的一个逻辑单元——特定一个函数所对应的栈区,它只保留一个函数的特定信息,一般会有局部变量、返回地址和旧的rbp值,甚至还有函数参数。

实例

运行程序的环境

sudo lsb_release -a看到操作系统是Ubuntu 22.04 LTS
sudo uname -r看到内核版本是5.15.0-86-generic
sudo as --version看到as的版本是2.38
sudo ld --version看到ld的版本是2.38
sudo gcc --version看到gcc版本是11.2.0
sudo gdb --version看到gdb版本是12.1

在这里插入图片描述

计算乘方(只有一层调用)

代码

runexponentInStack.s(计算3的2次方)代码如下:

.global _start
.section .text
_start: 
 
    # 将rbp里边的值压入到栈中
    pushq %rbp
    movq %rsp,%rbp
    # 请注意在C语言调用约定中,要是参数少于6个,不会使用栈来传递参数,这里只是为了说明栈的使用
    # 将2压入到栈中,在下边exponent函数中可以使用24(%rbp)对值进行操作
    pushq $2
    # 将3压入到栈中,在下边exponent函数中可以使用16(%rbp)对值进行操作
    pushq $3
    call exponent

    movq %rbp,%rsp
    popq %rbp
    # rdi里边会放入给操作系统的返回值,而此处是把rax里边的值放入到rdi
    movq %rax,%rdi
    # rax里边放入60,这是退出的系统调用号
    movq $60,%rax
    syscall


.global exponent
.type exponent,@function

.section .text
exponent:
    # 将rbp里边的值压入到栈中
    pushq %rbp
    movq %rsp,%rbp
    # rax = 1
    movq $1,%rax
mainloop:
    # 此处,mulq指令会计算rax乘以16(%rbp),最后乘积还会放到rax里边
    # 16(%rbp) = 3
    mulq 16(%rbp)
    # 刚开始的时候,24(%rbp) = 2,这里表示将24(%rbp)-1,然后结果放到24(%rbp)里边
    decq 24(%rbp)
    # 如果24(%rbp)不等于0,那么就会跳转到mainloop
    jnz mainloop
    

complete:
    movq %rbp,%rsp
    popq %rbp
    ret

汇编、链接与运行

sudo vim runexponentInStack.s把上边代码写入runexponentInStack.s里边,sudo as -g runexponentInStack.s -o runexponentInStack.o进行汇编,sudo ld -g runexponentInStack.o -o runexponentInStack进行链接,sudo ./runexponentInStack运行,sudo echo $?查看运行结果。
在这里插入图片描述

堆栈图

这里使用栈在main函数和exponent函数之间传递两个参数,接下来一行代码一行代码分析堆栈图,使用sudo gdb -q ./runexponentInStack开始进行分析对照。
在这里插入图片描述

而在gdb中,btbacktrace的缩写)命令可以查看当前函数向上的堆栈的函数的堆栈信息。i frameinfo frame的缩写)可以查看当前调试函数的堆栈帧信息。
break 6可以把断点打到第6行代码处,run开始运行。
在这里插入图片描述

info frame可以看到以下信息:

Stack level 0, frame at 0x7fffffffe668:
 rip = 0x401000 in _start (runexponentInStack.s:5); saved rip = 0x1
 source language asm.
 Arglist at 0x7fffffffe658, args:
 Locals at 0x7fffffffe658, Previous frame's sp is 0x7fffffffe668
 Saved registers:
  rip at 0x7fffffffe660

Stack level 0, frame at 0x7fffffffe668表明当前_start函数(也就是相当于C语言main函数)的栈帧起始地址是0x7fffffffe668
rip = 0x401000 in _start (runexponentInStack.s:5); saved rip = 0x1表明下一行执行的代码以内存0x401000开始,调用_start函数的内存地址以0x1开始。
Arglist at 0x7fffffffe658, args:表明参数变量的内存地址从0x7fffffffe658开始。
Locals at 0x7fffffffe658, Previous frame's sp is 0x7fffffffe668表明局部变量的内存地址从0x7fffffffe658开始,而上一个函数的栈帧从0x7fffffffe668开始。

 Saved registers:
  rip at 0x7fffffffe660

表示这个函数的调用位置是在内存0x7fffffffe660处。

info register rsp可以看到rsp里边的值是0x7fffffffe660,开始画堆栈图。
在这里插入图片描述

next执行到下一步,这时是把旧的rbp压到栈里边,info register rsp rbp可以看到rsp里边的值是0x7fffffffe658,而rbp的值是0x0
在这里插入图片描述

堆栈图如下:

在这里插入图片描述

next会暂时停留在pushq $2这里。
在这里插入图片描述

堆栈图如下:
在这里插入图片描述

next再次执行,会把数字2压入栈帧中。
在这里插入图片描述
堆栈图如下:
在这里插入图片描述

next再次执行,会把数字3压入栈帧中。
在这里插入图片描述

堆栈图如下:
在这里插入图片描述

step执行,就会跳转至新的函数exponent里边。
在这里插入图片描述

堆栈图如下:
在这里插入图片描述

next会把旧的rbp的值压入栈帧中。
在这里插入图片描述
堆栈图如下:
在这里插入图片描述

next执行一下,那么rbp=rsp
在这里插入图片描述

堆栈图如下:
在这里插入图片描述

这里可以知道16(%rbp)等于rbp+1624(%rbp)等于rbp+24

next接着执行,发现rsprbp都没有改变,所以堆栈图也没有任何改变。
在这里插入图片描述

接下来连续按五下next,都没涉及栈帧操作,堆栈图没有发生任何改变。
在这里插入图片描述

next执行,现在rsp=rbp,堆栈图没有发生改变。
在这里插入图片描述

next执行,栈顶值被弹出到rbp里边。
在这里插入图片描述

堆栈图如下:
在这里插入图片描述

next执行,返回到_start函数里边。
在这里插入图片描述
堆栈图如下:
在这里插入图片描述

next执行,rsp=rbp
在这里插入图片描述
堆栈图如下:
在这里插入图片描述

next执行,栈顶值被弹出到rbp里边。
在这里插入图片描述

堆栈图如下:
在这里插入图片描述

再连续按三下next
在这里插入图片描述
堆栈图如下:
在这里插入图片描述

相当于全部把栈区还给操作系统了。
此文章为11月Day 12学习笔记,内容来源于极客时间《Rust 语言从入门到实战》。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/137667.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

设计模式-工厂方法

工厂方法是一种创建型设计模式,其在父类中提供一个创建对象的方法,允许子类决定实例化对象的类型。 问题 假设你开设了一个汽车工厂。创业初期工厂只能生产宝马这一款车,因此大部分代码都位于名为宝马的类中。 工厂效益非常好,为…

牛客刷题记录11.12 (10/6)

操作复杂度 map vector set deque 抽线类 C11 :两个新特性 : override, finnal override:子类必须覆写父类的虚函数,否则报错, finnal:类中函数使用后,子类不能重写该函数;若修饰类,该类不能被继承&#…

生成只需要4step,像lora一样使用LCM

SDXL in 4 steps with Latent Consistency LoRAs 在comfyui里实测LCM lora 原先需要20步一张图,现在20步,4张图。comfyui最新版新增了lcm采样器,支持lcm lora的工作流。 LCM lora模型下载: huggingface.co/latent-consistency/lcm…

BGP属性实验

一、实验拓扑 二、实验要求 按照图示配置IP地址以及在路由器上配置BGP,使其全网通 1、配置IP地址 2、配置AS 200内的OSPF [AR2]ospf 1 router-id 2.2.2.2 [AR2-ospf-1]a 0 [AR2-ospf-1-area-0.0.0.0]network 2.2.2.2 0.0.0.0 [AR2-ospf-1-area-0.0.0.0]network 1…

深入了解SpringMvc接收数据

目录 一、访问路径(RequestMapping) 1.1 访问路径注解作用域 1.2 路径精准(模糊)匹配 1.3 访问路径限制请求方式 1.4 进阶访问路径请求注解 1.5 与WebServlet的区别 二、接收请求数据 2.1 请求param参数 2.2 请求路径参数 2.3 请求…

【GEE】10、使用 Google 地球引擎创建图形用户界面【GUI开发】

1简介 在本模块中,我们将讨论以下概念: 用于生成图形用户界面的 GEE 对象。如何开发具有交互元素的面板。如何将地理处理元素连接到交互式元素。 2背景 在过去的十个单元中,我们展示了 Google Earth Engine 可以成为一种重要且高效的资源&a…

代码分析之-广东省公共资源交易平台

广东省公共资源交易平台 hex: function Xq() {return bg || (bg 1,function(e, t) {(function(n, u) {e.exports u()})(an, function() {var n n || function(u, o) {var r;if (typeof window < "u" && window.crypto && (r window.crypto)…

【差旅游记】启程-新疆哈密(1)

哈喽&#xff0c;大家好&#xff0c;我是雷工。 最近有个新疆罗布泊的项目要去现场&#xff0c;领导安排我过去&#xff0c;这也算第一次到新疆&#xff0c;记录下去新疆的过程。 01、天有不测风云 本来预定的是11月2号石家庄飞成都&#xff0c;成都转机到哈密&#xff0c;但…

数据结构----顺序栈的操作

1.顺序栈的存储结构 typedef int SElemType; typedef int Status; typedef struct{SElemType *top,*base;//定义栈顶和栈底指针int stacksize;//定义栈的容量 }SqStack; 2.初始化栈 Status InitStack(SqStack &S){//初始化一个空栈S.basenew SElemType[MAXSIZE];//为顺序…

【Java SE】类和对象(下)

接着上文 目录 6. 封装 6.1 封装的概念 6.2 访问限定符 6.3 封装扩展之包 6.3.1 包的概念 6.3.2 自定义包 6.3.3 导入包中的类 6.3.4 包的访问权限控制举例 6.3.5 常见的包 7. static成员 7.1 static修饰成员变量 ​编辑 ​编辑 7.2 static修饰成员方法 8. 代…

从0到0.01入门React | 008.精选 React 面试题

🤍 前端开发工程师(主业)、技术博主(副业)、已过CET6 🍨 阿珊和她的猫_CSDN个人主页 🕠 牛客高级专题作者、在牛客打造高质量专栏《前端面试必备》 🍚 蓝桥云课签约作者、已在蓝桥云课上架的前后端实战课程《Vue.js 和 Egg.js 开发企业级健康管理项目》、《带你从入…

CLIP:用文本作为监督信号训练可迁移的视觉模型

Radford A, Kim J W, Hallacy C, et al. Learning transferable visual models from natural language supervision[C]//International conference on machine learning. PMLR, 2021: 8748-8763. CLIP 是 OpenAI 在 2021 年初的工作&#xff0c;文章发表在 ICML-2021&#xff0…

Linux--gcc/g++

一、gcc/g是什么 gcc的全称是GNU Compiler Collection&#xff0c;它是一个能够编译多种语言的编译器。最开始gcc是作为C语言的编译器&#xff08;GNU C Compiler&#xff09;&#xff0c;现在除了c语言&#xff0c;还支持C、java、Pascal等语言。gcc支持多种硬件平台 二、gc…

从0到0.01入门React | 001.精选 React 面试题

🤍 前端开发工程师(主业)、技术博主(副业)、已过CET6 🍨 阿珊和她的猫_CSDN个人主页 🕠 牛客高级专题作者、在牛客打造高质量专栏《前端面试必备》 🍚 蓝桥云课签约作者、已在蓝桥云课上架的前后端实战课程《Vue.js 和 Egg.js 开发企业级健康管理项目》、《带你从入…

Codeforces Round 788 (Div. 2) E. Hemose on the Tree(树上构造)

题目 t(t<5e4)组样例&#xff0c;每次给定一个数p&#xff0c; 表示一棵节点数为的树&#xff0c; 以下n-1条边&#xff0c;读入树边 对于n个点和n-1条边&#xff0c;每个点需要赋权&#xff0c;每条边需要赋权&#xff0c; 权值需要恰好构成[1,2n-1]的排列 并且当你赋…

初阶JavaEE(17)Linux 基本使用和 web 程序部署

接上次博客&#xff1a;初阶JavaEE&#xff08;16&#xff09;博客系统&#xff08;Markdown编辑器介绍、博客系统功能、博客系统编写&#xff1a;博客列表页 、博客详情页、实现登录、实现强制登录、显示用户信息、退出登录、发布博客&#xff09;-CSDN博客 目录 Linux 基本…

【Spring Boot 源码学习】初识 SpringApplication

Spring Boot 源码学习系列 初识 SpringApplication 引言往期内容主要内容1. Spring Boot 应用程序的启动2. SpringApplication 的实例化2.1 构造方法参数2.2 Web 应用类型推断2.3 加载 BootstrapRegistryInitializer2.4 加载 ApplicationContextInitializer2.5 加载 Applicatio…

pta 验证“哥德巴赫猜想” Python3

数学领域著名的“哥德巴赫猜想”的大致意思是&#xff1a;任何一个大于2的偶数总能表示为两个素数之和。比如&#xff1a;24519&#xff0c;其中5和19都是素数。本实验的任务是设计一个程序&#xff0c;验证20亿以内的偶数都可以分解成两个素数之和。 输入格式&#xff1a; 输…

C++ 中的内存分配 -- new 与 delete

c 常用的内存分配 分配释放类别是否可以重载mallocfreeC否newdeleteC 表达式(expressions)否operator new()operator delete()c 函数是operator new[]operator delete[]c 函数&#xff08;用于数组&#xff09;是allocator<T>::allocateallocator<T>::deallocatec …

ConstraintLayout的基本用法

ConstraintLayout的基本用法 1、基线对齐——Baseline 有时候我们需要这样一个场景&#xff1a; app:layout_constraintBaseline_toBaselineOf"id/30"2、链——Chains 用于将多个控件形成一条链&#xff0c;可以用于平分空间。 <?xml version"1.0"…