考研408《计算机组成原理》复习笔记,第四章(3)——指令集、汇编语言

首先别乱学

一、学习思路框架

这一章就先理解基本的汇编机器指令,能基本看懂题目

二、Intel x86格式指令集

首先,先按照最常用最正常的【Intel x86格式】的指令集学习,【AT&T格式】的很少用,最后对比一下即可。

1、数据在哪?

1)在【寄存器】里

首先我们直接粗暴记忆:

  • E】开头的都是表示【寄存器】,都是【32bit
  • 然后前4种寄存器:【EAX】、【EBX】、【ECX】、【EDX】还可以再细分
    • 它可以指定它的【后2字节(低16位)】位置作为一个更小的寄存器
    • 分别是【AX 】、【BX】、【CX】、【DX】,记住都是【16bit】就行
  • 然后这4个寄存器各自还能再分2个寄存器,分别在最后面【各占1字节(8bit)
    • 【AX】对应的就是分别是【AH】、【AL
    • 【BX】对应的就是分别是【BH】、【BL
    • 【CX】对应的就是分别是【CH】、【CL
    • 【DX】对应的就是分别是【DH】、【DL
    • 反正记住都是【8bit】就行

;

回忆知识点:对应的寻址方式是那种?

  • 【寄存器寻址】
  • 【寄存器间接寻址】
  • 【基址寻址】
  • 【变址寻址】
  • 【堆栈寻址里的 "硬堆栈"】
  • 【还有别的 "复合寻址方式"】(反正凡是涉及【寄存器】的.......)

2)在【主存】里

  • 有【中括号 " [...] "】的就是主存!!!!
    • 例子(先别管别的文字,只用看红色标记)
    • 留意:
      • [ 直接是数字 ]:表示主存的地址,【直接寻址】
      • [ 寄存器的名字 ]:表示寄存器里是主存地址,【间接寻址】
      • [ 一堆加减乘除 ]:表示【偏移寻址(相对寻址)】或【复合寻址】,具体还要后面细学分析

;

回忆知识点:对应的寻址方式是那种?

  • 【直接寻址】
  • 【间接寻址】
  • 【隐含寻址】
  • 【相对寻址】
  • 【堆栈寻址里的 "软堆栈"】
  • 【还有别的 "复合寻址方式"】(反正凡是涉及【主存】的.......)

3、在【指令】里

  • 就是我们学的【立即寻址】!!!
    • 数据以 **"立即数"**形式直接给出在指令中,执行时无需访问主存、寄存器,直接从指令里提取数据。
    • 所以都是【已知常数(二进制、十进制...)】,而不是【未知变量】
    • 例子(先别管别的文字,只用看红色标记)

;

回忆知识点:对应的寻址方式是那种?

  • 只有【直接寻址】!!!!!!!!!!

4)结合指令例子

先记住数据转移的格式

【Intel x86格式里】:

  • 【,】逗号左边是【d:目的操作数】、逗号右边是【s:来源操作数
    • 其中【d:目的操作数】还往往是【最终结果要存回去的地方
    • 比如:假设X存在EBX寄存器,X=X+1,就是**(EBX)+1--->EBXX+1的结果仍存回X**
    • d , s】意思就是把【右边的内容 复制到 左边

而在【AT&T格式里】:

  • 是完全反过来!!!
    • s , d】意思就是把【左边的内容 复制到 右边
然后,关于上面三个【数据来源】的普通指令例子:

还要注意的细节:

  • 如果前面还有【dword ptr】、【word ptr】、【byte ptr】这3字样,表示【偏移量】
    • 在【s:源操作数 】前面:表示这个【源操作数的 这个大小 的数据】复制走
    • 在【d:目的操作数】前面:表示数据复制到【目的操作数的 这个大小 的位置】
      • dword ptr】:是双字大小,32bit(ptr是必带的字符,不用管啥意思)
      • word ptr】:是单字大小,16bit(ptr是必带的字符,不用管啥意思)
      • byte ptr】:是字节大小,8bit(ptr是必带的字符,不用管啥意思)
王道书和一些试卷上的另一种写法

还有一种指令写法,会用 < ... > 的写法表示【数据来自哪里

  • < reg >:寄存器 (无需管是什么寄存器,具体多大,题目会给出数字)
    • 当然,如果非要表明是什么寄存器,也可以把【具体寄存器名字】写进**< ... >**里
    • 比如:< AH >< CL >< EBX >< AX >< EBP >****......
  • < mem >:内存(具体多大,题目会给出数字)
  • < con >:常数 (具体多大,题目会给出数字)
  • 另外 / 的意思是【

还要注意两点,可以发现:

  • 1、【目的地址】不可能是【常数
    • 因为【目的地址】是要用来存结果的,得是个容器
  • 2、【逗号左右】绝对不可能都是【主存
    • 因为把【主存数据】存回【主存】要访问2次主存,要尽量减少访问主存的次数,尽量【寄存器 存到 主存】或者【主存 存到 寄存器】

5)总结

2、操作码怎么处理?

接下来看指令的前半部分【操作码】,要解决的问题是------"怎么处理数据?做什么操作?"

1)算数运算指令

就是背单词就完事了,英语6000单词背完的这些简单词汇肯定会,不会的就回家吧好吗

  • 然后留意这几点:
    • 乘法指令里的【有符号乘法】
      • 如果出现3个数,说明只有【后面两个数】参与计算
      • 【第一个数】永远是存结果的寄存器而已
    • 除法指令里【有符号、无符号都是】
      • 【被除数】不用给出,只会隐含在【eax】和【edx】里
      • 【商】放【eax】、【余数】放【edx】
      • 所以仅按人类理解的完整写法应该是【eax:edx / s】(":"表示"和",这不是标准汇编指令,只是方便大家理解)

2)逻辑运算指令

依旧小学英语单词,不会的就回家吧

  • 另外补充一个

3)其他指令

大体分类如下:

【实现选择分支结构】------【jmp指令(以及搭配指令)】

【选择分支结构】:就是【if-else】语句

(跨考专业不会代码的,自己去学数据结构会学到)

注意!!!:Intel x86计算机里,【PC】通常也被叫做【IP】,【PC】就等于【IP】

那么对应最典型的指令就是:【jmp】指令

  • 他会改变正常的【PC = PC + "1"】的指令默认步数,而跳到任意一个指定的【指令的位置】

  • 写法是:【jmp 地址

    • 可以写指令的常数地址(指令在主存的位置)、寄存器名字(寄存器里是指令在主存的位置)、主存地址(主存里存着指令在主存的位置,套娃)
    • 另外如果标记**【NEXT】,则一定能指定跳到【你想要执行的那条指令】**,不管这条指令的具体位置变到哪里(类似C语言的【goto】语句)
      • (当然起始也不局限于【NEXT】这个单词,它只是一个【自定义标记符】,你也可以写【jmp fuck】、【jmp ass 】、【jmp stupid】......随便你怎么想,只要能找到对应这个【标记】的指令位置就行)
  • 【jxxx】指令

    • 还没结束!!!那不管是【jmp 地址】还是【jmp NEXT】,都是指定跳到某个【指令】,这不就没法实现【if-else判断语句】了?
      • 所以还有这么一堆恶心的指令,用来具体进行【条件判断】的,理解一下就行,有能力的最强大脑可以背熟记忆方法
  • 还有!!!!

    • 有的时候jmp跳转指令还会以【函数名】作为【指令跳转的偏移计算】的【起始位置】
    • 比如下面例子:函数名叫做【f1】,它里面的【第一个指令 】就是这个函数的起始位置;然后后面【jmp指令的地址】就可以写成【f1 + 地址】
  • 还他妈有**【cmp】指令**!!!(作为扩展吧,爱学学,不爱学跳过)

    • 【cmp】对比指令的底层原理是【ALU】对两个数作【减法
【实现循环结构】

第一种是:【条件转移指令】

  • 通过纯粹的【jxxx 跳转指令】来实现循环
  • 快速理解方法就是记住3点:
    • 1、先判断是否【不满足循环条件】,若不满足,则【跳到最下面(循环体之外)】
      • (满足的话,PC寄存器正常往下一步一步走)
    • 2、然后进入循环体,执行各个指令
    • 3、执行完循环体内容,再判断是否【满足循环条件】,若满足,则【跳回上面(循环体开始)】
      • (不满足的话,PC寄存器正常往下一步一步走)

第二种是:【loop循环指令】

  • 快速理解方法就是记住3点:
    • 1、循环体开头自定义一个【标记】,比如 "Looptop"
    • 2、中间循环指令
    • 3、结尾的【loop 标记】隐含意思就是【ecx寄存器--、jxxx指令判断是否满足跳转条件】
      • 满足则跳回【标记】处;不满足则【IP】正常往下走
  • 那么注意一个重点,【loop】只会自动减【ecx寄存器】的值
    • 【ecx寄存器】是一个循环计数器,只有它有资格搭配【loop】!!!!
【实现函数调用】

首先理解【整个函数】视角的:调用、执行、执行完毕return的流程

  • 就是数据结构的栈,我不想解释,没学过的自己学

然后到函数调用的指令【call】、【ret】

  • call】是**【函数调用】**
  • ret】是**【函数结束返回】**
  • 然后按照【函数视角】来看这两个指令(注意,例子里的caller、add只是函数自定义的名字,跟任何指令本身没有任何一丁点没半毛钱关系)
  • 所以得出重点:
    • 【call指令】作用: 将【旧IP】压栈保存;将设置【新IP】,用【jmp无条件跳转】到被调用函数的开始
    • 【ret指令】作用: 被调用函数执行完【新IP】出栈,然后找到【旧IP】,恢复【IP寄存器】值
【数据传送指令】(访问栈帧内数据的指令)
【push、pop指令】

前面我们知道了函数调用的本质就是【函数堆栈】的【IP栈帧的入栈】、【IP栈帧出栈】

可是【call】、【ret】指令只负责设置【新IP值】、找回【旧IP值】,具体是怎么访问数据的?

第一步:

  • 首先一个函数段代码需要【2个栈指针】来标记,本质就是【2个寄存器】
    • EBP 】专用于作为【堆栈基指针】,指向一个函数【栈底
      • 谐音记忆:BP 就是扁平 ,栈底被压扁平了
    • ESP】专用于作为【堆栈顶指针 】,指向一个函数【栈顶
      • 谐音记忆:SP 就是上坡 ,栈顶就像上坡一样
      • (注意,数据结构的栈是自下往上的,但是实际栈的地址高位是从上往下的,所以下面的栈都画成倒过来的)

第二步:

  • 【push 数据】:顾名思义,把数据压入栈顶(数据可以是立即数、主存地址、寄存器)
  • 【pop 数据】:顾名思义,把数据压入栈顶(数据可以是主存地址、寄存器)
  • 然后重点流程就是:
    • 不管【push】还是【pop】,都只能操作栈顶,而不是跳过栈顶操作栈内
      • 也就是说只移动【ESP】(堆栈基指针
    • push】是先移动【ESP】指针,也就是【ESP】往栈顶移动,再进行入栈
      • 对应【ESP地址 "减"】
    • pop】则是先出栈再移动【ESP】指针,也就是【ESP】往栈里面移动
      • 对应【ESP地址 "加"】
【mov指令】

【mov指令】则是简单的【复制】了

  • 【mov指令】可以结合【esp】、【ebp】两个指针来访问数据

重点就是:

  • 不管是【"复制" 进来】还是【"复制" 出去】,2个指针【esp】、【ebp】都不动!!!
    • 只是根据【它两的偏移量】来访问主存堆栈内的数据("复制" 数据只可能更改,但不会消失、增加)
    • 通常要 "复制" 的数据,往栈顶看,哪个指针离他近,就以哪个指针作为【偏移量导航基准】
      • 比如下面这个主存地址,往栈顶看,就【esp】离得近,就写成【esp + 8】
      • 比如下面这个主存地址,往栈顶看,就【ebp】离得近,就写成【ebp + 8】

拓展:

add/sub 指令也会改动【esp】【ebp】指针位置,知道即可

【总结】

3、【AT&T格式】和【Intel格式】对比

为了以防考到【AT&T格式】,还是简单看一下,其实也没差多少

相关推荐
长桥夜波11 小时前
【第十八周】机器学习笔记07
人工智能·笔记·机器学习
摇滚侠11 小时前
Spring Boot 3零基础教程,yml文件中配置和类的属性绑定,笔记15
spring boot·redis·笔记
元亓亓亓11 小时前
考研408--计算机网络--day1-概念&组成功能&三种交换技术&分类
服务器·计算机网络·考研
摇滚侠11 小时前
Spring Boot 3零基础教程,WEB 开发 HTTP 缓存机制 笔记29
spring boot·笔记·缓存
大白的编程日记.11 小时前
【Linux学习笔记】线程同步与互斥之生产者消费者模型
linux·笔记·学习
新子y11 小时前
【小白笔记】strip的含义
笔记·python
摇滚侠12 小时前
Spring Boot 3零基础教程,WEB 开发 内容协商 接口返回 YAML 格式的数据 笔记35
spring boot·笔记·后端
Chunyyyen12 小时前
【第十八周】自然语言处理的学习笔记03
笔记·学习·自然语言处理
聪明的笨猪猪12 小时前
Java JVM “类加载与虚拟机执行” 面试清单(含超通俗生活案例与深度理解)
java·经验分享·笔记·面试
im_AMBER13 小时前
React 02
前端·笔记·学习·react.js·前端框架