七、CPU 指令

7.1 一个实例

了解寄存器和内存模型以后,就可以来看汇编语言到底是什么了。下面是一个简单的程序example.c。

 
  1. int add_a_and_b(int a, int b) {

  2.   return a + b;
    }

    int main() {

  3.   return add_a_and_b(2, 3);
    }

gcc 将这个程序转成汇编语言。

$ gcc -S example.c

上面的命令执行以后,会生成一个文本文件example.s,里面就是汇编语言,包含了几十行指令。这么说吧,一个高级语言的简单操作,底层可能由几个,甚至几十个 CPU 指令构成。CPU 依次执行这些指令,完成这一步操作。

example.s经过简化以后,大概是下面的样子。

 
  1. _add_a_and_b:

  2.   push   %ebx

  3.   mov    %eax, [%esp+8]

  4.   mov    %ebx, [%esp+12]

  5.   add    %eax, %ebx

  6.   pop    %ebx

  7.   ret  

  8. _main:

  9.   push   3

  10.   push   2

  11.   call   _add_a_and_b

  12.   add    %esp, 8

  13.   ret

可以看到,原程序的两个函数add_a_and_b和main,对应两个标签_add_a_and_b和_main。每个标签里面是该函数所转成的 CPU 运行流程。

每一行就是 CPU 执行的一次操作。它又分成两部分,就以其中一行为例。

push   %ebx

这一行里面,push是 CPU 指令,%ebx是该指令要用到的运算子。一个 CPU 指令可以有零个到多个运算子。

下面我就一行一行讲解这个汇编程序,建议读者最好把这个程序,在另一个窗口拷贝一份,省得阅读的时候再把页面滚动上来。

7.2 push 指令

根据约定,程序从_main标签开始执行,这时会在 Stack 上为main建立一个帧,并将 Stack 所指向的地址,写入 ESP 寄存器。后面如果有数据要写入main这个帧,就会写在 ESP 寄存器所保存的地址。

然后,开始执行第一行代码。

push   3

push指令用于将运算子放入 Stack,这里就是将3写入main这个帧。

虽然看上去很简单,push指令其实有一个前置操作。它会先取出 ESP 寄存器里面的地址,将其减去4个字节,然后将新地址写入 ESP 寄存器。使用减法是因为 Stack 从高位向低位发展,4个字节则是因为3的类型是int,占用4个字节。得到新地址以后, 3 就会写入这个地址开始的四个字节。

push   2

第二行也是一样,push指令将2写入main这个帧,位置紧贴着前面写入的3。这时,ESP 寄存器会再减去 4个字节(累计减去8)。

7.3 call 指令

第三行的call指令用来调用函数。

call   _add_a_and_b

上面的代码表示调用add_a_and_b函数。这时,程序就会去找_add_a_and_b标签,并为该函数建立一个新的帧。

下面就开始执行_add_a_and_b的代码。

push   %ebx

这一行表示将 EBX 寄存器里面的值,写入_add_a_and_b这个帧。这是因为后面要用到这个寄存器,就先把里面的值取出来,用完后再写回去。

这时,push指令会再将 ESP 寄存器里面的地址减去4个字节(累计减去12)。

7.4 mov 指令

mov指令用于将一个值写入某个寄存器。

mov    %eax, [%esp+8] 

这一行代码表示,先将 ESP 寄存器里面的地址加上8个字节,得到一个新的地址,然后按照这个地址在 Stack 取出数据。根据前面的步骤,可以推算出这里取出的是2,再将2写入 EAX 寄存器。

下一行代码也是干同样的事情。

mov    %ebx, [%esp+12] 

上面的代码将 ESP 寄存器的值加12个字节,再按照这个地址在 Stack 取出数据,这次取出的是3,将其写入 EBX 寄存器。

7.5 add 指令

add指令用于将两个运算子相加,并将结果写入第一个运算子。

add    %eax, %ebx

上面的代码将 EAX 寄存器的值(即2)加上 EBX 寄存器的值(即3),得到结果5,再将这个结果写入第一个运算子 EAX 寄存器。

7.6 pop 指令

pop指令用于取出 Stack 最近一个写入的值(即最低位地址的值),并将这个值写入运算子指定的位置。

pop    %ebx

上面的代码表示,取出 Stack 最近写入的值(即 EBX 寄存器的原始值),再将这个值写回 EBX 寄存器(因为加法已经做完了,EBX 寄存器用不到了)。

注意,pop指令还会将 ESP 寄存器里面的地址加4,即回收4个字节。

7.7 ret 指令

ret指令用于终止当前函数的执行,将运行权交还给上层函数。也就是,当前函数的帧将被回收。

ret

可以看到,该指令没有运算子。

随着add_a_and_b函数终止执行,系统就回到刚才main函数中断的地方,继续往下执行。

add    %esp, 8 

上面的代码表示,将 ESP 寄存器里面的地址,手动加上8个字节,再写回 ESP 寄存器。这是因为 ESP 寄存器的是 Stack 的写入开始地址,前面的pop操作已经回收了4个字节,这里再回收8个字节,等于全部回收。

ret

最后,main函数运行结束,ret指令退出程序执行。

转载于:https://blog.csdn.net/DP29syM41zyGndVF/article/details/79766788 仅用于个人笔记学习,若有违规,请联系我删帖,学习

【汇编】CPU 指令相关推荐

  1. 汇编为什么分段执行总是执行不了_iOS汇编教程(六)CPU 指令重排与内存屏障...

    系列文章 iOS 汇编入门教程(一)ARM64 汇编基础 iOS 汇编入门教程(二)在 Xcode 工程中嵌入汇编代码 iOS 汇编入门教程(三)汇编中的 Section 与数据存取 iOS 汇编教程 ...

  2. 汇编call指令详解_我也能写出雷军的的代码吗?最好的汇编语言入门教程在这里!...

    作者:阮一峰 链接:http://www.ruanyifeng.com/blog/2018/01/ 之前,嵌入式Arm曾经发送过一篇名<给跪了!来看看雷军 1994 年写的代码,经典老古董(附完 ...

  3. 四十年前的 6502 CPU 指令翻译成 JS 代码会是怎样

    去年折腾的一个东西,之前 blog 里也写过,不过那时边琢磨边写,所以比较杂乱,现在简单完整地讲解一下. 前言 当时看到一本虚拟机相关的书,正好又在想 JS 混淆相关的事,无意中冒出个想法:能不能把某 ...

  4. 中国自主可控的全数字实时仿真软件SkyEye支持龙芯CPU指令级仿真

    传统的系统开发过程,都是由工程师根据项目需求书来编写代码完成系统的开发,但随着功能的完善和版本迭代,系统中庞大的代码量很难确保正确无误,给后期测试和仿真带来了很大的压力和成本,在航空航天.卫星系统.核 ...

  5. 汇编语言基础--汇编操作指令概述

    本文是接续"汇编语言基础--机器级数据存储",主要介绍汇编指令的构造.寻址和指令主要分类. 操作指令 指令的基本要素:       在"计算机处理器(CPU)基础&quo ...

  6. CPU指令的流水线执行

    指令集是CPU体系架构的重要组成部分.C语言的语法是对解决现实问题的运算和流程的方法的高度概况和抽象,其主要为算术.逻辑运算和分支控制,而指令集就是对这些抽象的具体支持,汇编只不过是为了让开发人员更好 ...

  7. CPU指令解析及函数调用机制

    目录 一.CPU指令解析 最常用的mov指令 对栈进行push和pop 二.函数的调用机制 一.CPU指令解析 最常用的mov指令 指令中最常使用的是对寄存器和内存进行数据存储的 mov 指定数据的存 ...

  8. 当我们在谈论cpu指令乱序的时候,究竟在谈论什么?

    原文:https://zhuanlan.zhihu.com/p/45808885 背景 在极客星球的群里面讨论 极客星球 很多现代高级语言多提供了多线程并发技术,今天服务器CPU基本上都是多核架构,在 ...

  9. 计算机指令要素,【计算机系统】CPU指令执行流程与指令流水线原理

    [计算机系统]CPU指令执行流程与指令流水线原理 一.指令执行流程 冯诺依曼架构CPU指令执行的五个阶段: 阶段 涉及的功能部件 IF 指令寄存器IR.程序计数器PC ID 指令译码器ID EXE C ...

最新文章

  1. [luogu4571 JSOI2009] 瓶子和燃料 (数论)
  2. (转载)VS2010/MFC编程入门之一(VS2010与MSDN安装过程图解)
  3. python设置函数执行时间
  4. proxmoxve打造云桌面_基于PROXMOX VE的家庭NAS搭建方案
  5. C++创建对象的两种方式
  6. 光学模拟 Android,基于Android的光学字符识别研究与实现
  7. 服务器系统wlanapi,没有找到wlanapi.dll怎么办?
  8. 判断两个链表是否相交,若相交,求交点。(假设链表可能带环)【升级版】(C语言)
  9. ASP.Net下使用ExtJS报“Ext未定义”错误的原因
  10. Lua的多任务机制——协程(coroutine)
  11. MongoDB的入门使用
  12. 《怎样解题》思维导图
  13. 【竞赛篇-竞赛定级及含“金”量】ABC类竞赛如何区分?哪些竞赛被认可?哪些竞赛不太被认可但“值”得参加?
  14. 复变函数和积分变换(Complex Function I)
  15. 【POI1999】【BZOJ2936】降 水
  16. “熵”详细学习笔记——什么是熵?有什么性质?联合熵等其他熵的作用
  17. 图像处理之高斯金字塔
  18. 云服务器做系统,云服务器如何做系统
  19. python3--日期时间处理最近n个自然周计算
  20. 精心整理了30个Python数据分析项目,拿走就用!

热门文章

  1. 国际象棋缺乏下棋伙伴儿!Ai棋盘“智能陪练”如何陪伴成长?
  2. 【web】HTTP工作原理及应用
  3. vue项目繁体字切换,台湾语言
  4. 屏的像素与传输速率_高像素时代 究竟多少万像素才够你用?
  5. 条款M33:将非尾端类设计为抽象类:将抽象类赋值运算符函数设为protected
  6. D2Admin基本使用
  7. 什么是网站监控,网站监控软件有什么用?
  8. 你硬盘里的那些电影都是如何被保存的?
  9. 统计学习方法读书笔记(九)-EM算法及其推广
  10. python闹钟界面源码_Python编程练习:简单的闹钟提醒