精华内容
下载资源
问答
  • 程序代码的本质就是一条一条指令,我们需要通过编码的方式让CPU知道我们需要它干什么,最后由译码器翻译成一条条的机器指令。机器指令主要有两部分组成:操作码、地址码。地址码直接给出操作数和操作数的地址,分...

    什么是指令:

    程序代码的本质就是一条一条的指令,我们需要通过编码的方式让CPU知道我们需要它干什么,最后由译码器翻译成一条条的机器指令。机器指令主要有两部分组成:操作码、地址码。地址码直接给出操作数和操作数的地址,分三地址指令、二地址指令和一地址指令,最后还有零地址指令,零地址指令在机器指令中没有地址码,用来进行空操作、停机操作、中断返回操作等。

     

    那么一条简单的指令执行,涉及到了那些组件?

    控制器(CU)和运算器(ALU)

    PC寄存器(程序计数器):用于存放下一条需要执行的指令地址信息,注意是下一条指令的地址!

    指令寄存器:用于存放当前正在执行的指令,注意是当前的指令!

    指令译码器:用于翻译指令信息,与指令寄存器相连

     

    那么一条指令的执行就应该包含

     

    1.取指令:CU根据PC寄存器中的指令地址,去内存或者指令缓存中获取具体的指令,并加载到指令寄存器中。

    2.分析指令:拿到指令之后,指令译码器将指令寄存器中的指令进行翻译,向ALU发起控制信号和指令信息。此时PC寄存器自增即+1,加载下一个要执行的指令地址(至少此时是这样的,此为顺序寻址)。

    3.执行指令:ALU拿到相关信息之后进行相关的计算。

    4.访问内存(或缓存):如果涉及到相关数据需要去缓存中拿,那就去取数据。

    5.数据写回:将计算结果写入到寄存器中,写入到缓存中,甚至写入到内存中。

     

    看到这里你肯定会想,并不是所有的指令都是顺序执行的,比如if····else,比如方法调用,此时PC寄存器也是自增加1嘛?我们来讲讲if····else和方法调用。

    先来看if····else,下边有一小块代码

    int r = 1;
    int a = 10;
      if (r == 0)
      {
        a = 1;
      } else {
        a = 2;
      } 

    很简单的一个if判断以C语言为例 if部分翻译为汇编代码就是

    if (r == 0)
      3b:   83 7d fc 00             cmp    DWORD PTR [rbp-0x4],0x0
      3f:   75 09                   jne    4a <main+0x4a>
        {
            a = 1;
      41:   c7 45 f8 01 00 00 00    mov    DWORD PTR [rbp-0x8],0x1
      48:   eb 07                   jmp    51 <main+0x51>
        }
        else
        {
            a = 2;
      4a:   c7 45 f8 02 00 00 00    mov    DWORD PTR [rbp-0x8],0x2
      51:   b8 00 00 00 00          mov    eax,0x0
        } 

    可以看到,这里对于 r == 0 的条件判断,被编译成了 cmp 和 jne 这两条指令。

    这两条指令中cmp表示比较的意思,这明显是一条二地址指令,cmp是操作码,后边两个是地址码,意思就是将rbp寄存器中偏移量为4的位置的数取32位(DWORD PTR)出来,和0(0x0)比较,并将比较结果存到条件码寄存器中。

    跟着的 jne 指令,是 jump if not equal 的意思,它会查看对应的零标志位。如果为 0,会跳转到后面跟着的操作数 4a 的位置。这个 4a,对应这里汇编代码的行号,也就是上面设置的 else 条件里的第一条指令。当跳转发生的时候,PC 寄存器就不再是自增变成下一条指令的地址,而是被直接设置成这里的 4a 这个地址。

    那么CPU 再把 4a 地址里的指令加载到指令寄存器中来执行。mov 指令把 2 设置到对应的寄存器里去,相当于一个赋值操作。然后,PC 寄存器里的值继续自增,执行下一条 mov 指令。

    最后一条mov指令的第一个操作数 eax,代表累加寄存器,第二个操作数 0x0 则是 16 进制的 0 的表示。这条指令其实没有实际的作用,代表我执行完了,给 main 函数生成了一个默认的为 0 的返回值到累加器里面。

    然后是if条件之后我们注意到有个jmp指令,它之前的mov指令和4a是一样的意思,jmp指令,也就是jump的缩写,这是一个无条件跳转指令。跳转的地址就是这一行的地址 51,也就是说这个指令同样会改变PC寄存器中的地址信息,即将PC寄存器中的值设置为51(51大家都能使用,没必要生成两条指令)。具体流程如图所示,for循环也是同样的道理,不过涉及到具体的指令意义需要大家自己探索,但是流程是一样的,都是通过指令改变PC寄存器中的指令地址,引导CPU执行自己想要执行的指令。

     

    下面是方法调用

    方法调用之前,我们先了解一个数据结构-栈

    是内存中一段连续的物理地址组成的一个后进先出(LIFO)的数据结构,这种栈结构大小确定,满了就溢出,所以底部确定,被称为栈底,我们向里边写入数据被称为压栈(PUSH),读取数据被称为出栈(POP),我们每次POP都是拿栈的最后一个数据,被称为栈顶,栈底地址最大,因为每次从栈顶拿数据,可以减少寻址时间。

     

    函数 A 在调用 B 的时候,需要传输一些参数数据,这些参数数据在寄存器不够用的时候也会被压入栈中。整个函数 A 所占用的所有内存空间,就是函数 A 的栈帧(Stack Frame)。

    以一段程序作为举例

    int static add(int a, int b)
    {
        return a+b;
    }
     
     
    int main()
    {
        int x = 5;
        int y = 10;
        int u = add(x, y);
    }

    汇编为

    int static add(int a, int b)
    {
       0:   55                      push   rbp
       1:   48 89 e5                mov    rbp,rsp
       4:   89 7d fc                mov    DWORD PTR [rbp-0x4],edi
       7:   89 75 f8                mov    DWORD PTR [rbp-0x8],esi
        return a+b;
       a:   8b 55 fc                mov    edx,DWORD PTR [rbp-0x4]
       d:   8b 45 f8                mov    eax,DWORD PTR [rbp-0x8]
      10:   01 d0                   add    eax,edx
    }
      12:   5d                      pop    rbp
      13:   c3                      ret    
    0000000000000014 <main>:
    int main()
    {
      14:   55                      push   rbp
      15:   48 89 e5                mov    rbp,rsp
      18:   48 83 ec 10             sub    rsp,0x10
        int x = 5;
      1c:   c7 45 fc 05 00 00 00    mov    DWORD PTR [rbp-0x4],0x5
        int y = 10;
      23:   c7 45 f8 0a 00 00 00    mov    DWORD PTR [rbp-0x8],0xa
        int u = add(x, y);
      2a:   8b 55 f8                mov    edx,DWORD PTR [rbp-0x8]
      2d:   8b 45 fc                mov    eax,DWORD PTR [rbp-0x4]
      30:   89 d6                   mov    esi,edx
      32:   89 c7                   mov    edi,eax
      34:   e8 c7 ff ff ff          call   0 <add>
      39:   89 45 f4                mov    DWORD PTR [rbp-0xc],eax
      3c:   b8 00 00 00 00          mov    eax,0x0
    }
      41:   c9                      leave  
      42:   c3                      ret    

    这里需要先介绍几个专用的寄存器,简要介绍如下:

    • ax(accumulator): 可用于存放函数返回值
    • bp(base pointer): 用于存放执行中的函数对应的栈帧的栈底地址
    • sp(stack poinger): 用于存放执行中的函数对应的栈帧的栈顶地址
    • ip(instruction pointer): 指向当前执行指令的下一条指令

    从汇编代码中可以看出一个函数被call调用,首先默认要完成以下动作:

       push   rbp
       mov    rbp,rsp

    1.将调用函数的栈帧栈底地址入栈,即保存调用函数的栈帧的栈底地址

    2.建立新的栈帧,把 rsp 这个栈指针(Stack Pointer)的值复制到 rbp 里,并保存rsp的值,而 rsp 始终会指向栈顶。这个命令意味着,rbp 这个栈帧指针指向的地址,变成当前最新的栈顶。

    而调用结束栈帧出栈,跳转到方法调用方的调用位置的下一个位置,即call的下一行继续执行。

    //以下两步等同于leave
    mov    rsp,rbp
    pop    rbp
    //以下两步等同于ret
    pop rip
    jmp rip

    所以一个完整的方法调用过程

    调用方使用call指令调用方法,此时rip中存放的是call的下一条指令的地址,将rip压栈到栈底,生成新的栈帧,将栈帧压栈,执行方法,栈帧弹出,弹出rip,跳转到rip继续运行调用方的方法。

     

     

     
    展开全文
  • iret指令

    2020-02-19 14:29:58
    IRET(interrupt return)中断返回,中断服务程序最后一条指令。 汇编指令IRET 【指令格式】IRET 【指令功能】IRET(interrupt return)中断返回,中断服务程序最后一条指令。IRET指令将推入堆栈的段地址和偏移地址...

    IRET(interrupt return)中断返回,中断服务程序的最后一条指令。
    汇编指令IRET
    【指令格式】IRET
    【指令功能】IRET(interrupt return)中断返回,中断服务程序的最后一条指令。IRET指令将推入堆栈的段地址和偏移地址弹出,使程序返回到原来发生中断的地方。其作用是从中断中恢复中断前的状态,具体作用有如下三点:
    1.恢复IP(instruction pointer):IP←((SP)+1:(SP)),SP←SP+2
    2.恢复CS(code segment):CS←((SP)+1:(SP)), SP←SP+2
    3.恢复中断前的PSW(program status word),即恢复中断前的标志寄存器的状态。
    FR←((SP)+1:(SP)),SP←SP+2
    4.恢复ESP(返回权限发生变化)
    5.恢复SS(返回权限发生变化)
    以上操作按顺序进行。
    【指令手册原文】
    the IRET instruction pops the return instruction pointer, return code segment selector, and EFLAGS image from the stack to the EIP, CS, and EFLAGS registers, respectively, and then resumes execution of the interrupted program or procedure. If the return is to another privilege level, the IRET instruction also pops the stack pointer and SS from the stack, before resuming program execution.
    IRET指令影响所有标志位。 [1]

    展开全文
  • 汇编_指令_IRET

    2018-07-16 19:01:00
    IRET(interrupt return)中断返回,中断服务程序最后一条指令。 汇编指令IRET 【指令格式】IRET 【指令功能】IRET(interrupt return)中断返回,中断服务程序最后一条指令。IRET指令将推入堆栈的段地址和...
    IRET(interrupt return)中断返回,中断服务程序的最后一条指令。
     
    汇编指令IRET
    指令格式】IRET
     
    【指令功能】IRET(interrupt return)中断返回,中断服务程序的最后一条指令。IRET指令将推入堆栈的段地址和偏移地址弹出,使程序返回到原来发生中断的地方。其作用是从中断中恢复中断前的状态,具体作用有如下三点:
     
    1.恢复IP(instruction pointer):(IP)←((SP)+1:(SP)),(SP)←(SP)+2
     
    2.恢复CS(code segment):(CS)←((SP)+1:(SP)),(SP)←(SP)+2
     
    3.恢复中断前的PSW(program status word),即恢复中断前的标志寄存器的状态。
    (FR)←((SP)+1:(SP)),(SP)←(SP)+2
     
    4.恢复ESP(返回权限发生变化)
     
    5.恢复SS(返回权限发生变化)
     
    以上操作按顺序进行。

    转载于:https://www.cnblogs.com/chuijingjing/p/9319406.html

    展开全文
  • 一、STM32的启动过程:1、复位第一条指令:Reset_Handler PROC,这里指定为 LDR R0, =__main。表示调用库函数__main,当然,我们可以在__main前做点事情,比如PLL初始化等。2、__main()的执行。3、最后调用用户的...

    一、STM32的启动过程:

    1、复位第一条指令:Reset_Handler PROC,这里指定为 LDR R0, =__main。表示调用库函数__main,当然,我们可以在__main前做点事情,比如PLL初始化等。

    2、__main()的执行。

    3、最后调用用户的main()函数。

    二、如何跑到中断入口地址

    我们也知道怎么跳到main函数了,那么,中断发生后,又是怎么跑到中断入口地址的呢?

    从stm32f10x.s可以看到,已经定义好了一大堆的中断响应函数,这就是中断向量表,标号__Vectors,表示中断向量表入口地址,例如:

    AREA RESET, DATA, READONLY ; 定义只读数据段,实际上是在CODE区(假设STM32从FLASH启动,则此中断向量表起始地址即为0x8000000)

    EXPORT __Vectors

    IMPORT OS_CPU_SysTickHandler

    IMPORT OS_CPU_PendSVHandler

    __Vectors DCD __initial_sp ; Top of Stack

    DCD Reset_Handler ; Reset Handler

    DCD NMI_Handler ; NMI Handler

    DCD HardFault_Handler ; Hard Fault Handler

    DCD MemManage_Handler ; MPU Fault Handler

    DCD BusFault_Handler ; Bus Fault Handler

    DCD UsageFault_Handler ; Usage Fault Handler

    这个向量表的编写是有讲究的,跟硬件一一对应不能乱写的,CPU找入口地址就靠它了,bin文件开头就是他们的地址,参考手册RM0008的10.1.2节可以看到排列。

    我们再结合CORTEX-M3的特性,他上电后根据boot引脚来决定PC位置,比如boot设置为flash启动,则启动后PC跳到0x08000000。此时CPU会先取2个地址,第一个是栈顶地址,第二个是复位异常地址,故有了上面的写法,这样就跳到reset_handler。

    那么这个reset_handler的实际地址是多少.?下面的一堆例如Nmi_handler地址又是多少呢?发生中断是怎么跑到这个地址的呢?下面挨个讲解。

    1、我们可以通过反向来得知这些入口地址,查看工程下的map文件就可以看到了,这个地址跟keil里面设置的target->flash起始地址息息相关,实际上我们不太需要关心,让编译器分配,中断向量表放的就是他们的地址。

    2、对比ARM7/ARM9内核,Cortex-M3内核则是固定了中断向量表的位置而起始地址是可变化的。

    3、进到C语言后会先配置NVIC,NVIC_SetVectorTable()里面可以配置中断向量表的起始地址和偏移,主要是告诉CPU该向量表是位于Flash还是Ram,偏移是多少。例如设置为位于Flash内,偏移就是烧入的程序地址,可在Keil target中设置。这样CPU就知道入口地址了。

    4、发生中断后,CPU找到中断向量表地址,然后根据偏移(对号入座)再找到中断地址,这样就跳过去了。

    我们截一个图说明一下,map文件:

    64ba692a1ba82c002d4345b498815d3d.gif

    对应的bin文件,看是不是放的上面地址:

    a2559c4f3793951f14f4facaa8fb0a1a.gif

    显然,200039c0就是栈顶地址,而08006F21就是reset_handler地址!

    如何定位?以放到0x20000000为例

    1、keil设置ram起始为0x20000100,我们在0x20000000~0x20000100放中断向量表,其他给程序用

    2、设置NVIC_SetVectorTable(NVIC_VectTab_FLASH,0);

    3、跳到C时把中断向量表拷贝到0x20000000

    展开全文
  • RET 返回指令,子程序最后一条指令必须是RET 2.中断控制指令 是一个远过程调用,需要记录FLAGS INT n 之后n4就是存放中断服务子程序入口地址的单元偏移地址 执行过程 FLAGS压栈 INT 指令的下一条指令的CS\IP压栈 n4...
  • 中断——执行过程

    2021-04-13 08:52:24
    ⑥查询可以执行中断,将CPU将要执行的下一条存于PC中的指令存入栈内(PC:程序计数器,存放CPU要执行的下一条指令) ⑦将中断入口地址送入PC,PC再送入CPU,进入中断服务函数 ⑧进入中断服务函数,擦除中断标志位...
  • 匿名用户1级2016-12-27 回答方法:在得到ax、dx结果后,紧接着加一“int3”中断指令,在debug中调试运行程序程序暂停时的ax、dx寄存器中的值即为所求。方法二:编个显示16位二进制数的显示子程序,然后分别...
  • 单片机之中断

    2018-06-28 17:05:48
    最近,学习了单片机的一些知识,今天我想说说中断,所谓中断其实就是指单片机由于收到某个请求而停止手头上的事情转而去... 第二步,接下来将下一条指令的地址送到堆栈中保存起来,我们将这称之为中断响应。 第三...
  • 中断为什么能够被cpu立即响应?

    千次阅读 2005-07-21 11:52:00
    cpu在执行每条指令周期的最后一个时钟周期,一旦检测到此信号有效,并且中断允许标志IF=1时,cpu在当前指令执行完后,转入中断响应周期,读取外设接口的中断类型码,然后在存储器的中断向量表中找到中断服务程序的...
  • 假设地址空间中的一个地址保存一条指令,先执行某个地址中的指令(如“将值置位到CPU中”处理),接着执行下一个地址中的指令,接下来再执行下一个地址中的指令……,像这样通过连续执行指令,便可执行程序
  • 文章字数:1600 干货指数:⭐⭐⭐⭐⭐导读:这里讲的内容主要是原理,文章最后小创会送大家一个【福利】(《Linux...这就需要预设置,我们需要固化一段代码在ROM里面,然后预先设置CPU上电执行的第一条指令的地址,在...
  • windows环境下32位汇编语言程序设计

    热门讨论 2011-09-20 13:02:19
    带着这样一个疑问学习汇编,在分析乒乓病毒的过程中啃一条条不懂的指令,病毒分析完了,汇编课也学完了,而且反过来看那些复杂的计算程序都是那么顺理成章,不攻自破了。实际上,从一些实用的系统功能开始学习汇编远...
  • 修改扩展界面支持库,添加“工具.置标题()”方法。 13. 修改高级表格支持库在表格空白处(所有单元格之外)单击鼠标导致当前光标处单元格自动进入编辑状态的BUG。 14. 修改扩展界面支持库,为“超级列表框...
  • Proteus仿真—40个单片机初学程序.

    热门讨论 2009-04-13 13:00:56
    作为单片机的指令的执行的时间是很短,数量大微秒级,因此,我们要求的闪烁时间间隔为0.2秒,相对于微秒来说,相差太大,所以我们在执行某一指令时,插入延时程序,来达到我们的要求,但这样的延时程序是如何设计呢...
  • 4、CPU在每条指令执行周期的最后时刻扫描中断寄存器,查看是否有中断信号 5、中断向量:个内存单元,存放中断处理程序入口地址和程序运行时所需的处理机状态字 6、中断执行流程按中断号/异常类型的不同,通过...
  • 2) 处理器在响应中断前结束当前指令的执行 3) 处理器对中断进行测定,确定存在未响应的中断,并给提交中断的设备发送...9) 最后的操作是从栈中恢复PSW和程序计数器的值,其结果是下一条要执行的之类来自前面被中断程序.
  • 单步:Flags寄存器中的标志位,CPU每执行一条指令后会检查IF位值。如为1则产生调试异常。 断点:使用INT 3替代目标指令头,执行时候则产生调试异常切换到调试器,而后返回时恢复 分支踪迹存储:记录最后一次JMP的...
  • 编译原理之基本块和流图

    千次阅读 2019-11-26 22:00:48
    基本块和流图 ...②除了基本块的最后一条指令,控制流在离开基本块前不会停机或者跳转 2.基本块形成了流图(flow graph)的结点,流图的边指明了哪些基本块可能紧随一个基本块之后执行 ä中断程序行为...
  • OSCtxSw()是任务级切换函数,其实就是一...//调用子程序,PROC和ENDP是配对使用的,过程的最后一条指令一般是返回指令(RET)。  PUSHA //将所有通用寄存器按顺序存储到堆栈:EAX、ECX、EDX、EBX、EBP、ESP、EBP、ES
  • 计算机系统概述

    2020-05-24 20:34:47
    ​ 进一步分析:CPU必须具有控制程序的顺序执行(指令控制)、产生完成每条指令所需要的控制命令(操作控制)、对各种操作加上时间上的控制(时间控制)、对数据进行算术运算和逻辑运算(数据加工)以及处理中断等...
  • 每个程序开始要执行的第一条指令应是取指操作,因为程序复位后,PC和uPC的值都为0,所以微程序的0地址处就是程序执行的第一条取指的微指令。取指操作要做的工作是从程序存储器EM中读出下条将要执行的指令,并将...
  • 用来存储 CPU正在执行的指令位置、或者即将执行的下一条指令位置 CPU 上下文切换 通俗理解:将前一个任务的CPU 上下文(也就是 CPU 寄存器和程序计数器)保存起来,加载新任务的上下文到这些寄存器和程序计数器,...
  • 16.子程序最后一条指令是什么指令? 17. 用堆栈存放返回地址,则转子指令和返回指令都要使用的寄存器是什么? 18.CPU内部的IR、PSW、PC、MAR、MBR的中文名称是什么?里面存放的是什么内容? 19.PSW与控制/...
  • 而逐条地讲解每一条指令的功能,不是本书的重点所在,它应该是一本指令手册的核心内容.这就好像文学作品和字典的区别,前者的重心在于用文字表达思想,后者讲解每个字的用法. (2)编程的平台是硬件而不是操作系统 这...
  • A、当前指令前一条指令的地址 B、当前正在执行指令的地址 C、下一条指令的地址 D、控制器中指令寄存器的地址 5、下列指令或指令序列中,能将外部数据存储器3355H单元的内容传送给A的是( )。 A、MOVX A,3355H B...
  • 操作系统实验

    2013-12-30 11:30:48
    ③在前地址[0,m+1]中随机选取一条指令并执行,该指令的地址为m’;④顺序执行一条指令,其地址为m’+1;⑤在后地址[m’+2,319]中随机选取一条指令并执行;⑥重复上述步骤①~⑤,直到执行320次指令。 (2)将指令序列...
  • 操作系统精髓与设计原理答案

    热门讨论 2011-11-19 15:15:08
    PC中包含第一条指令的地址300,该指令的内容被送入MAR中。 b. 地址为300的指令的内容(值为十六进制数1940)被送入MBR,并且PC增1。这两个步骤是并行完成的。 c. MBR中的值被送入指令寄存器IR中。 2. a. 指令...
  • asm 汇编语言基础知识

    2010-11-26 17:14:09
    这样,当程序执行到主程序最后一条指令RET时,由于该过程具有FAR属性,故存在堆栈内的两个字就分别弹出到CS和IP,从而执行INT 20H指令,使控制返回到DOS状态。返回DOS的标志就是程序运行完后出现一个DOS的标识符,...
  • 启动中cs:eip == 0xffff:0x00000 === 0xffff0 这是最开始启动的(BIOS执行的第一条指令) 下面是BIOS程序执行的内容: 1、在0x00000处开始的1kb内存空间(0x00000~0x003fff)安装中断向量表(256个中断,c

空空如也

空空如也

1 2 3 4
收藏数 78
精华内容 31
关键字:

中断程序最后一条指令