C++内存模型以及寄存器指针rsp和rbp
汇编及C/C++汇编调用约定讲解
专栏目录(文章在更新中)
> 汇编及C/C++汇编调用约定(汇总帖)
> 汇编编译和gdb调试命令列表
> gdb TUI使用方法
> 汇编C语言调用约定(标准函数)
> 汇编C语言调用约定(递归函数)
> C++内存模型以及寄存器指针rsp和rbp
文章目录
- 汇编及C/C++汇编调用约定讲解
- 专栏目录(文章在更新中)
- 1. 先放一张内存模型的图
- 2. gcc 命令参数
- 3. 示例代码
- 4. 生成
- 5. gdb 调试
- 6. 进入函数时 rsp 指针的偏移
- 3. main函数中 rsp 指针的偏移
- 4. 进入 fn() 函数中
- 此后内容与在 main() 函数中的讲述基本相同
学C++的时候跨过来的, 这个也磕磕绊绊拖了好长时间, 上手比较费劲, 大概整理了一下用到的东西.
1. 先放一张内存模型的图
2. gcc 命令参数
- 控制何时停止从C语言文件产生可执行文件的过程
-E
Preprocess only; do not compile, assemble or link.-S
Compile only; do not assemble or link.-c
Compile and assemble, but do not link.-o <file>
Place the output into file.
- 优化级别
-O0
: 不做任何优化,默认的编译选项。-O1
:优化会消耗更多的编译时间,它主要对代码的分支,常量以及表达式等进行优化。-O2
:会尝试更多的寄存器级的优化以及指令级的优化,它会在编译期间占用更多的内存和编译时间。-O3
: 在O2的基础上进行更多的优化。-Os
:相当于-O2.5。是使用了所有-O2的优化选项,但又不缩减代码尺寸的方法。
3. 示例代码
int fn(int a, int b){int rsp_move = 4;int c = a + b;return c;}int main() {int a = 1;int b = 2;int c = fn(a, b);return 0;}
4. 生成
gcc t.c -o t.s -m32 -S -O0
在此从gcc得到未经编译优化的汇编文件
汇编代码(为了简洁删去了一些行):.file "t.c".text.globl fn.type fn, @function fn:endbr32pushl %ebpmovl %esp, %ebpsubl $16, %espmovl $4, -8(%ebp)movl 8(%ebp), %edxmovl 12(%ebp), %eaxaddl %edx, %eaxmovl %eax, -4(%ebp)movl -4(%ebp), %eaxleaveret.globl main.type main, @function main:endbr32pushl %ebpmovl %esp, %ebpsubl $16, %espmovl $1, -12(%ebp)movl $2, -8(%ebp)pushl -8(%ebp)pushl -12(%ebp)call fnaddl $8, %espmovl %eax, -4(%ebp)movl $0, %eaxleaveret
- 因为这是依赖于gcc的汇编代码,所以这里对其进行一些修改,让其可以通过汇编器编译
函数结束时,通常在发出ret指令前通过以下指令清理栈:movl %ebp, %esp popl %ebp # ret
但是,gcc输出只包括指令leave,这条指令只是上面两条指令的组合
.section .data.section .text.globl _start _start:pushl $2pushl $1call fnmovl %eax, %ebxmovl $1, %eaxint $0x80.type fn, @function
fn:pushl %ebpmovl %esp, %ebpsubl $16, %espmovl $4, -8(%ebp)movl 8(%ebp), %edxmovl 12(%ebp), %eaxaddl %edx, %eaxmovl %eax, -4(%ebp)movl -4(%ebp), %eaxmovl %ebp, %esppopl %ebpret
as t.s -o t.o --32 --gstabs
ld t.o -o t -m elf_i386
5. gdb 调试
6. 进入函数时 rsp 指针的偏移
- 在此之前先提一下push和mov的区别:
- push指令可以分解为两条更基本的汇编指令:
sub $指针移动长度 %rsp
# 栈指下移
mov 源数据 (%rsp)
# 推入数据至栈顶
使用push时,栈指针同时会移动到此入栈数据的地址上,数据不会被覆盖掉 - 当使用mov将数据移入栈中时,如果栈指针在此地址之上,那么这个数据是无意义的,随时可能被覆盖
- push指令可以分解为两条更基本的汇编指令:
- 栈指针的偏移并不一定是局部变量,例如在进行文件读取时,提前为读取出的两个文件描述符预留了位置
.equ ST_SIZE_RESERVE, 8 .equ ST_FD_IN, -4 .equ ST_FD_OUT, -8
之后使用mov就可以保存这两个文件描述符
# 保存返回的文件描述符 movl %eax, ST_FD_IN(%ebp) movl %eax, ST_FD_OUT(%ebp)
# 后边还没改完
3. main函数中 rsp 指针的偏移
- 在 AT&T 汇编风格中
sub $0x10, %rsp
表示 rsp 寄存器指针向下偏移 16
- 通过x /12x $rsp 查看和访问寄存器 rsp 及 rsp 之后的变量(x 命令使用方法见下图)
- 换十进制输出内存中的数据, 可见是a 和 b, 所以 rsp 指针偏移给局部变量留出了空间(开头那个图)
4. 进入 fn() 函数中
- 再进入 rsp_m() 函数中, 观察寄存器监视器可见此时 rsp 和 sbp 地址相同, 这是因为 rsp_m() 函数中没有局部变量, 所以 rsp 指针不需要向下偏移来为变量留出空间
此后内容与在 main() 函数中的讲述基本相同
- 返回到fn()函数查看此时寄存器 rsp 和 rbp
可见函数 rbp 后的地址的内容是<main() + 40>, 即需要返回的地址, rsp 后也是变量的地址(开头那个图)
C++内存模型以及寄存器指针rsp和rbp相关推荐
- 深入理解C语言-二级指针三种内存模型
二级指针相对于一级指针,显得更难,难在于指针和数组的混合,定义不同类型的二级指针,在使用的时候有着很大的区别 第一种内存模型char *arr[] 若有如下定义 char *arr[] = {&quo ...
- 【C 语言】二级指针内存模型 ( 指针数组 | 二维数组 | 自定义二级指针 | 将 一、二 模型数据拷贝到 三 模型中 并 排序 )
文章目录 一.指针数组 和 二维数组 数据 拷贝到 自定义二级指针 中 1.函数形参 设计规则 2.三种内存模型 对应 函数形参 指针退化规则 二.完整代码示例 一.指针数组 和 二维数组 数据 拷贝 ...
- 【C 语言】二级指针 内存模型图 ( 指针数组 | 二维数组 | 自定义二级指针内存 )
文章目录 前言 一.指针数组 二.二维数组 三.自定义二维指针内存 前言 绘制如下 333 种二级指针的内存模型 : // I. 指针数组 char *p1 []= {"12", ...
- 【C 语言】字符串 一级指针 内存模型 ( 指定大小字符数组 | 未指定大小字符数组 | 指向常量字符串的指针 | 指向堆内存的指针 )
文章目录 一.字符串 一级指针 内存模型 1.指定大小字符数组 2.未指定大小字符数组 3.指向常量字符串的指针 4.指向堆内存的指针 一.字符串 一级指针 内存模型 #include <std ...
- 第三天2017/03/30(上午:二级指针的(输入)内存模型:(共三种模型))
二级指针 char a[10][10]; char (*a)[10]; char *a[10]; char **a; char **a; char **a; 字符数组的操作易犯错误: 1.字符数组在使 ...
- 第三天2017/03/30(下午:二级指针的(输出)内存模型)
[备用知识--字符串的操作] 模块讲解:数组.数组指针 void *memset(void *s, int ch, size_t n); 函数解释:将s中当前位置后面的n个字节 (typedef un ...
- C语言二级指针内存模型建立
C语言二级指针内存模型建立 代码 解析 代码 void main() {int i = 0;//指针数组char * p1[] = {"123", "456"
- C语言字符串相关一级指针内存模型
C语言字符串相关一级指针内存模型 通过实例探索一级指针内存模型 通过实例探索一级指针内存模型 void main() {char buf[20]= "aaaa";char buf2 ...
- 11.JDK8内存模型、本地方法栈、虚拟机栈、栈帧结构(局部变量表、操作数栈、方法出口、虚拟机栈与本地方法栈的关系、寄存器、方法区、堆(Heap)、jvm中的常量池、Metaspace(元空间))
11.JDK8内存模型 11.1.本地方法栈(Native Method Stacks) 11.2.虚拟机栈(Java Virtual Machine Stacks) 11.3.栈帧结构 11.3.1 ...
最新文章
- 深度并非一切:普林斯顿、英特尔提出ParNet,速度和准确性显著优于ResNet
- Windows Server 2016 禁止自动更新后重启
- Leetcode 1 Two Sum
- 【Linux】一步一步学Linux——crontab命令(132)
- zookeeper的名词复盘-会话
- 删除weblogic域
- 在线js拼接html代码,关于js拼接html元素?
- 史上最全Oracle文件损坏处理办法(附实验步骤)
- Android APP 稳定性测试工具—Fastboot使用教程
- XP高仿win7宽栏风格主题
- Matlab运行时报License错误
- hdoj 5510 Bazinga
- 天龙八部TLBB系列 - 网单服务端各目录文件说明【超详细】
- jQuery+Ajax+PHP无刷新分页
- 【PCB软件技巧】OrCAD与PADS相互搭配使用的相关要点
- 【《关于我一个小学生用C++写了个抽奖游戏这件事》】
- css 恢复ulli_CSS Ul(列表样式)
- 开机提示小娜无法在本计算机运行,win10 20h2提示此应用无法在你的电脑上运行解决方法...
- ESP32 连接到免费的公共 MQTT 服务器
- CH340 MAC驱动使用教程
热门文章
- 虚幻4 游戏引擎(二):蓝图教学
- bzoj4372 烁烁的游戏 动态点分治+线段树
- VS:如何离线使用Nuget安装包
- c# picturebox 刷新_C# picturebox画图问题
- 攻防世界——MISC--练习区解题步骤(持续更新)
- 神经网络从产生到现在的发展历史--科普
- 计算机专业必要要买游戏本吗,吾空:致大学想买游戏笔记本的学生,这几个点必须要知道...
- 自媒体怎么快速入门?这几个技巧一定要掌握好
- IDEA 2019.1离线安装lombok
- 【考研数学】高等数学知识点整理——第一章 函数、极限、连续