汇编及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 命令参数

  1. 控制何时停止从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.
  2. 优化级别
    • -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. 生成

  1. 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
    
  2. 因为这是依赖于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
  1. as t.s -o t.o --32 --gstabs
  2. ld t.o -o t -m elf_i386

5. gdb 调试



6. 进入函数时 rsp 指针的偏移

  1. 在此之前先提一下push和mov的区别:

    • push指令可以分解为两条更基本的汇编指令:
      sub $指针移动长度 %rsp # 栈指下移
      mov 源数据 (%rsp) # 推入数据至栈顶
      使用push时,栈指针同时会移动到此入栈数据的地址上,数据不会被覆盖掉
    • 当使用mov将数据移入栈中时,如果栈指针在此地址之上,那么这个数据是无意义的,随时可能被覆盖
  2. 栈指针的偏移并不一定是局部变量,例如在进行文件读取时,提前为读取出的两个文件描述符预留了位置
    .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 指针的偏移

  1. 在 AT&T 汇编风格中sub $0x10, %rsp表示 rsp 寄存器指针向下偏移 16
  2. 通过x /12x $rsp 查看和访问寄存器 rsp 及 rsp 之后的变量(x 命令使用方法见下图)
  3. 换十进制输出内存中的数据, 可见是a 和 b, 所以 rsp 指针偏移给局部变量留出了空间(开头那个图)

4. 进入 fn() 函数中

  1. 再进入 rsp_m() 函数中, 观察寄存器监视器可见此时 rsp 和 sbp 地址相同, 这是因为 rsp_m() 函数中没有局部变量, 所以 rsp 指针不需要向下偏移来为变量留出空间

此后内容与在 main() 函数中的讲述基本相同

  1. 返回到fn()函数查看此时寄存器 rsp 和 rbp



    可见函数 rbp 后的地址的内容是<main() + 40>, 即需要返回的地址, rsp 后也是变量的地址(开头那个图)

C++内存模型以及寄存器指针rsp和rbp相关推荐

  1. 深入理解C语言-二级指针三种内存模型

    二级指针相对于一级指针,显得更难,难在于指针和数组的混合,定义不同类型的二级指针,在使用的时候有着很大的区别 第一种内存模型char *arr[] 若有如下定义 char *arr[] = {&quo ...

  2. 【C 语言】二级指针内存模型 ( 指针数组 | 二维数组 | 自定义二级指针 | 将 一、二 模型数据拷贝到 三 模型中 并 排序 )

    文章目录 一.指针数组 和 二维数组 数据 拷贝到 自定义二级指针 中 1.函数形参 设计规则 2.三种内存模型 对应 函数形参 指针退化规则 二.完整代码示例 一.指针数组 和 二维数组 数据 拷贝 ...

  3. 【C 语言】二级指针 内存模型图 ( 指针数组 | 二维数组 | 自定义二级指针内存 )

    文章目录 前言 一.指针数组 二.二维数组 三.自定义二维指针内存 前言 绘制如下 333 种二级指针的内存模型 : // I. 指针数组 char *p1 []= {"12", ...

  4. 【C 语言】字符串 一级指针 内存模型 ( 指定大小字符数组 | 未指定大小字符数组 | 指向常量字符串的指针 | 指向堆内存的指针 )

    文章目录 一.字符串 一级指针 内存模型 1.指定大小字符数组 2.未指定大小字符数组 3.指向常量字符串的指针 4.指向堆内存的指针 一.字符串 一级指针 内存模型 #include <std ...

  5. 第三天2017/03/30(上午:二级指针的(输入)内存模型:(共三种模型))

    二级指针 char a[10][10]; char (*a)[10]; char *a[10]; char **a; char **a; char **a; 字符数组的操作易犯错误: 1.字符数组在使 ...

  6. 第三天2017/03/30(下午:二级指针的(输出)内存模型)

    [备用知识--字符串的操作] 模块讲解:数组.数组指针 void *memset(void *s, int ch, size_t n); 函数解释:将s中当前位置后面的n个字节 (typedef un ...

  7. C语言二级指针内存模型建立

    C语言二级指针内存模型建立 代码 解析 代码 void main() {int i = 0;//指针数组char * p1[] = {"123", "456"

  8. C语言字符串相关一级指针内存模型

    C语言字符串相关一级指针内存模型 通过实例探索一级指针内存模型 通过实例探索一级指针内存模型 void main() {char buf[20]= "aaaa";char buf2 ...

  9. 11.JDK8内存模型、本地方法栈、虚拟机栈、栈帧结构(局部变量表、操作数栈、方法出口、虚拟机栈与本地方法栈的关系、寄存器、方法区、堆(Heap)、jvm中的常量池、Metaspace(元空间))

    11.JDK8内存模型 11.1.本地方法栈(Native Method Stacks) 11.2.虚拟机栈(Java Virtual Machine Stacks) 11.3.栈帧结构 11.3.1 ...

最新文章

  1. 深度并非一切:普林斯顿、英特尔提出ParNet,速度和准确性显著优于ResNet
  2. Windows Server 2016 禁止自动更新后重启
  3. Leetcode 1 Two Sum
  4. 【Linux】一步一步学Linux——crontab命令(132)
  5. zookeeper的名词复盘-会话
  6. 删除weblogic域
  7. 在线js拼接html代码,关于js拼接html元素?
  8. 史上最全Oracle文件损坏处理办法(附实验步骤)
  9. Android APP 稳定性测试工具—Fastboot使用教程
  10. XP高仿win7宽栏风格主题
  11. Matlab运行时报License错误
  12. hdoj 5510 Bazinga
  13. 天龙八部TLBB系列 - 网单服务端各目录文件说明【超详细】
  14. jQuery+Ajax+PHP无刷新分页
  15. 【PCB软件技巧】OrCAD与PADS相互搭配使用的相关要点
  16. 【《关于我一个小学生用C++写了个抽奖游戏这件事》】
  17. css 恢复ulli_CSS Ul(列表样式)
  18. 开机提示小娜无法在本计算机运行,win10 20h2提示此应用无法在你的电脑上运行解决方法...
  19. ESP32 连接到免费的公共 MQTT 服务器
  20. CH340 MAC驱动使用教程

热门文章

  1. 虚幻4 游戏引擎(二):蓝图教学
  2. bzoj4372 烁烁的游戏 动态点分治+线段树
  3. VS:如何离线使用Nuget安装包
  4. c# picturebox 刷新_C# picturebox画图问题
  5. 攻防世界——MISC--练习区解题步骤(持续更新)
  6. 神经网络从产生到现在的发展历史--科普
  7. 计算机专业必要要买游戏本吗,吾空:致大学想买游戏笔记本的学生,这几个点必须要知道...
  8. 自媒体怎么快速入门?这几个技巧一定要掌握好
  9. IDEA 2019.1离线安装lombok
  10. 【考研数学】高等数学知识点整理——第一章 函数、极限、连续