• 2024王道考研计算机组成原理——指令系统


    零、本章概要

    指令寻址:解决的是PC+"1"的问题
    数据寻址:使用寄存器/内存/结合


    基址寻址:用于多道程序的并发执行
    直接寻址:call 0x12345678
    变址寻址:esi edi用于循环,因为使用直接寻址需要一堆地址很麻烦,速度也慢
    相对寻址:地址针对的是相对于PC的位置,在代码位置发生改变的情况下用于实现跳转
    PSW就是EFLAGS


    x86汇编:
    使用cmp+jnz(等)实现跳转指令;cmp会修改PSW的内容,jnz指令执行的适合会根据psw来判断需不需要跳转
    循环语句:for(int i=0;i<10;i++){s+=arr[i];}:i++后面紧跟cmp
    函数调用底层实现:
    堆栈平衡:函数调用前后esp和ebp的位置不变,一个线程内的所有函数共用一个堆栈
    x86的push和pop默认是按照4字节压栈/出栈的

    esp指向的是栈顶的位置(有元素)

    push eax:①先sub esp,4 ②再mov [esp],eax

    pop eax:①先mov eax,[esp] ②再add esp,4

    call eax:①push eip ②jmp eax

    ret:pop eip(默认是ret 4)
    真实的函数堆栈以及函数调用(见C语言函数调用的汇编视角)
    CICS和RISC指令集的对比

    一、指令格式 

    操作码:做什么 地址码:对谁做

    当然停机指令特殊,不需要地址码,就是执行一个特殊的命令而已

    Intel的CPU使用的是x86架构,x86架构的指令集和AMD的指令集是不兼容的,不能跨不同指令系统的机器执行,苹果公司宣布要抛弃Intel的CPU,转而开发自己的基于ARM架构的CPU,这样手机和电脑就能通用了

    了解即可:

    堆栈型计算机通过零地址指令来进行算术运算:操作数是隐藏在栈里面的,而不会显示地在栈中指明,扫描到操作符就相当于扫描到了一个零地址指令,会把操作数计算/弹出堆栈

    所有指令访存次数都要加上取指令的那一次 

    注意:指令字长的长度是可变的(但是得是比如1B的整数倍),机器字长和存储字长都是不可变的

    如果指令字长超过机器字长的话就需要多次的取指令操作,CPU可以根据操作码的类型来判断

    我们所有的指令都是遵循操作码+地址码这种格式,只是地址码有可能为0,只有操作码这种情况出现,表示仅执行一次特殊的操作

    二、扩展操作码指令格式

    操作码全1用于区分是几地址指令

    这里重点讨论的是n位操作码,能表示2^n种对于3/2/1地址的操作

    三地址:15条0000-1110 A1 A2 A3

    二地址(12条):1111 0000-1011 A1 A2

    一地址(62条):1111 11 000000-111101 A1

    零地址(32条):1111 11 11111 00000-11111 

    cpu分析指令的时候就根据前几位是1来判断他是几地址指令

    三、指令寻址 

    PC+“1” 

    指令系统采用定长指令字结构: 定长指令+可变长操作码

    因为每一条指令的长度是确定的,所以+"1"即可处理下一条指令

    指令执行的时候先读入一个字 

    这里我想给大家重点讲解一下!!!!!!!!!!!!!!!!!!!!!!!

    你CPU不是要从内存当中取指令吗?因为CPU一次最多只能同时处理一个字的数据,你就直接去指令所在的内存单元(在PC里存放地址)去取出一个字的内容,但是啊这一个字不是都有效啊!我CPU处理第一个字节的时候发现是55,后面直接扔掉就是了,然后根据55我就能知道这条指令的长度了,也就能知道PC应该加几了!然后可以继续去取下一条地址了!!!!!!!!

    四、数据寻址 

    根据寻址特征和形式地址可以确定操作数的真实地址(EA)

    了解即可,不用看: 

    立即寻址:立即数#010

    直接寻址:call 0x12345678

    间接寻址:lea [0x123456],地址放在某个内存单元里面

    寄存器寻址:push ebp;mov eax,ecx

    寄存器间接寻址:push [eax+4]

    基址寻址就是用于多道程序并发执行的 

    直接寻址的bug:要用一堆地址

    如何解决? esi edi就是变址寄存器,用于实现循环:rep stosw 

    直接寻址:地址是几就是几,你位置移动也是跳到2那里

    (如何解决这个问题?)

    你移动代码对顺序执行的指令没啥影响,但是跳转指令难绷啊😂😂😂 

    所以只要修改跳转指令的解释方式:因为PC会自动+1,所以使用-4(补码)来指示当前的CPU情况下应该跳转到哪里去执行

    转移指令使用的都是相对寻址!!!

    基址寻址:整个代码在内存当中的浮动;相对寻址:一段代码在程序内部的浮动 

    比较(相减)和跳转是分开的

    PSW就是我们熟悉的ELAPGS

    五、x86汇编语言基础

    指令格式是什么样的取决于你的CPU,硬编码就是指令集里面的指令

    55就是opcode,66就是前缀,CPU根据值来判断

    55为啥是push ebp而不是push bp和当前CPU的模式有关,x86的保护模式默认是32位

    前缀指令分成4个组,每个组有n个最多出现一个

    定长指令:opcode确定了,指令的长度就确定了

    变长指令:即使opcode确定了,指令的长度依然无法确定

    opcode决定了有没有ModR/M,也决定了是不是定长指令

    比如opcode是88那它后面一定根一个opcode

    地址偏移和立即数

    比如这种考题:

    为啥x86汇编语言不允许两个操作数都同时来自主存?

    1、指令长度太长了

    2、访问2次主存太慢了吧。。。

     

    x86:intel的8086/80286 80386

    一条指令由操作码和若干地址码组成

    进行除法运算的时候要对被除数进行位扩展:32->64(edx:eax) ,商存入eax,余数存入edx

    intel格式(Windows)&AT&T(Linux&Unix)格式(汇编格式)

    六、C语言选择语句的汇编实现

    在x86当中IP就是PC

    和前面提到的一样,我们这样写汇编代码,但是其实最后变成机器码的时候他会给我们翻译成与PC有关的指令,这样代码段即使移动位置,当PC指向这条语句的时候也能够跳转到正确的地址(使用PC+一个补码)

    使用标号可以更方便程序员去编写汇编代码,最后编译器要做的就是把这个标号改成对于的地址

    条件转移指令通常与cmp指令配合食用🤣🤣🤣 

    switch语句:离散情况不生成大表和if...else效率一样,连续的时候生成大表,先比较数值-1超过第二大的数就直接跳到default,否则直接根据edx*4+func(函数首地址) 来去查大表,直接得到跳转地址而不用像if..else那样进行多次的比较!!!

    只有特定的指令(比如运算指令,和ALU有关,本质上不就是加法器那些产生的符号位吗?)才会修改PSW寄存器里面的标志位,cmp指令本质上就是做了一个减法(但是结果不保存,只改变符号位),产生了符号位,然后条件转移指令再根据减法所产生的标志位(去PSW寄存器中获取)来决定要不要进行跳转!!!

    六、C语言循环语句的汇编实现

    i++后面紧跟的就是cmp,一旦越界就跳出循环

    for:①先初始化,第一次直接判断是否跳出循环

    ②循环主体&i++③cmp i ,cnt(没结束就往上跳是for循环的一大重要特征!)

    七、C语言函数调用的汇编视角 

      

    x86的push和pop默认是按照4字节压栈/出栈的

    esp指向的是栈顶的位置(有元素)

    push eax:①先sub esp,4 ②再mov [esp],eax

    pop eax:①先mov eax,[esp] ②再add esp,4

    call eax:①push eip ②jmp eax

    ret:pop eip(默认是ret 4)

    真实的堆栈以及函数调用:

    所谓堆栈平衡就是函数调用前和调用后esp和ebp的位置保持不变! 

    试试看能不能画到堆栈平衡?

    外平栈(默认采用的调用约定):cdcall(右左,外平栈:add esp,8)

    内平栈:stdcall(右左,内平栈:ret 8(相当于add esp,8))

    注意:一个线程里面的所有函数都使用同一个堆栈

    int main(){

    fun(2,3);  push 3 push 2 call fun(push eip + jmp fun)

    fun:

    八、CICS和RISC指令集的对比

    你RISC只能通过寄存器来访存,寄存器可不得比CICS多吗? 

  • 相关阅读:
    7.java三大特征之一:多态
    查询自己电脑能够支持Win11系统升级的方法分享
    MySQL:日期函数整理
    整理最新java面试宝典2019
    20230912java面经整理
    实现人工智能的去中心化,权力下放是最佳途径!
    commonjs和esmodule
    Waiting for table metadata lock
    找不到conda可执行文件:解决方法
    Spring基础篇:MVC框架整合
  • 原文地址:https://blog.csdn.net/Tandy12356_/article/details/133852073