x86 CPU的实模式——调用与跳转(三)


查看系列文章点这里: 操作系统真象还原

前言

  在上一节x86 CPU的实模式——寻址(二)中,我们介绍了如何获取数据,但是光有数据没有什么用,还要有代码才行。我们知道在内存中有非常多少代码段,它们互相配合共同为我们提供各种各样的服务,接下来我们来看看如何将这些代码段联系起来。


三、实模式下的调用(call、ret)

  无论使用什么语言编写程序,为了方便简洁,程序员们会设计各种各样的函数,它们有各种各样的功能,在代码中被程序员调用,完成工作后就返回继续执行源代码。

间接通过这种方式使用别的地方的代码,我们称之为调用,通过 call 和 ret 指令实现,其中call负责“ ”,ret负责“ 回来 ”,根据被调用的代码是否在一个段,地址给出的方式,分为以下四类:

1、直接相对近调用

  被调用的代码和当前代码在同一个代码段,目标地址通过立即数给出。

  call near 立即数地址(标号)   ;near可以省略
   call near near_proc
     ...
 near_proc:
     ...
   ret

  值得注意的是,因为在同一个代码段,call指令在被编译的时候,操作数是当前地址与目标地址的增量。因此,如果操作数是以标号的形式给出,则需要多一步处理才能得到真正的操作数。

2、间接绝对近调用

  被调用的代码和当前代码在同一个代码段,目标地址在寄存器或内存中。

  call 寄存器地址
  call 内存地址
   mov word[addr],near_proc
   call [addr] ;给出内存地址
     ...
 near_proc:
     ...
   ret

  值得注意的是,这里的地址是真正的地址,不需要像相对近调用那样转换地址才能使用。

3、直接绝对远调用

  被调用的代码和当前代码不在同一个代码段,直接给出目标地址的段基址和段内偏移地址。

  call far 段基址(立即数):段内偏移地址(立即数)   ;far可以省略
   call far 0 : far_proc     ;这里为了方便,故还是在一个段,far_proc代表偏移地址
     ...
far_proc:
     ...
   retf

  值得注意的是,远调用返回需要使用 retf 指令。

4、间接绝对远调用

  被调用的代码和当前代码不在同一个代码段,目标地址在内存中,一共四个字节,高2字节是段基址,低2字节是段内偏移地址。

  call far 内存地址   ;far不可以省略
addr dw far_proc,0  ;这里为了演示方便,故还是在一个段,far_proc代表偏移地址
     ...
   call [addr]     
     ...
far_proc:
     ...
   retf

四、实模式下的跳转(jmp、jxx)

  跳转也是去执行别的地方的代码,和调用最大的区别就是跳转“ 一去不复返 ”,在具体使用上分为无条件转移和有条件转移,咱们挨个介绍。

1、无条件转移

(1)相对短转移

  跳转的代码和当前代码在同一个代码段,目标地址通过立即数给出。

  jmp short 立即数地址(标号)   ;操作数范围-128~127
   jmp short near_proc
     ...
 near_proc:
     ...

(2)相对近转移

  跳转的代码和当前代码在同一个代码段,目标地址通过立即数给出。

  jmp near 立即数地址(标号)   ;操作数范围-32768~32767
   jmp near near_proc
     ...
 near_proc:
     ...

  值得注意的是,因为在同一个代码段,jmp short/near 指令在被编译的时候,操作数是当前地址与目标地址的增量,与call指令相同。
  除此之外,short和near可以省略,编译器会根据立即数的大小,自动添加short或者near,但前提是操作数在范围之内。

(3)间接绝对近转移

  跳转的代码和当前代码在同一个代码段,目标地址在寄存器或内存中。

  jmp near 寄存器地址
  jmp near 内存地址
   mov ax,near_proc
   jmp near ax ;给出内存地址
     ...
 near_proc:
     ...

  值得注意的是,这里的地址是真正的地址,不需要像相对近调用那样转换地址才能使用。

(4)直接绝对远转移

  跳转的代码和当前代码不在同一个代码段,直接给出目标地址的段基址和段内偏移地址。

  jmp 段基址(立即数):段内偏移地址(立即数)  
   jmp 0 : far_proc     ;这里为了方便,故还是在一个段,far_proc代表偏移地址
     ...
far_proc:
     ...

(5)间接绝对远转移

  跳转的代码和当前代码不在同一个代码段,目标地址在内存中,一共四个字节,高2字节是段基址,低2字节是段内偏移地址。

  jmp far 内存地址   ;far不可以省略
addr dw far_proc,0  ;这里为了演示方便,故还是在一个段,far_proc代表偏移地址
     ...
   call [addr]     
     ...
far_proc:
     ...

2、有条件转移

  上面介绍的都是无条件转移指令,也就是说执行到这条指令必转移,但这很明显不能满足我们的需要,所以还必须要有有条件转移,使用与无条件转移一模一样,只需要将 jmp 替换为对应的条件转移指令即可,具体如下表所示:

转移指令条件意义
jz/jeZF=1结果等于0
jnz/jneZF=0
jsSF=1负数
jnsSF=0
joOF=1溢出
jnoOF=0
jp/jpePF=1低字节中有偶数个1
jnp/jpoPF=0
jbe/jnaCF=1或ZF=1小于等于
jnbe/jaCF=ZF=0大于
jc/jb/jnaeCF=1进位
jnc/jnb/jaeCF=0
jl/jngeSF!=OF小于
jnl/jgeSF=OF大于等于
jle/jngZF!=OF或ZF=1小于等于
jnle/jgSF=OF且ZF=0大于
jcxzCX寄存器=0

  直接记忆非常困难,建议通过含义在使用的时候用对应的字母进行组合,如下所示:

简写jnabzeglscop
含义jmpnotabovebelowzeroequalgreatlesssigncarryoverflowparity

总结

  这一节的东西非常多,但还是有有一些规律的,不过大多数时候,不会全部用到的,记住一些常用的,就足够啦!

  持续更新~~

  • 54
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
基于PyTorch的Embedding和LSTM的自动写诗验LSTM (Long Short-Term Memory) 是一种特殊的循环神经网络(RNN)架构,用于处理具有长期依赖关系的序列数据。传统的RNN在处理长序列时往往会遇到梯度消失或梯度爆炸的问题,导致无法有效地捕捉长期依赖。LSTM通过引入门控机制(Gating Mechanism)和记忆单元(Memory Cell)来克服这些问题。 以下是LSTM的基本结构和主要组件: 记忆单元(Memory Cell):记忆单元是LSTM的核心,用于存储长期信息。它像一个传送带一样,在整个链上运行,只有一些小的线性交互。信息很容易地在其上保持不变。 输入门(Input Gate):输入门决定了哪些新的信息会被加入到记忆单元中。它由当前时刻的输入和上一时刻的隐藏状态共同决定。 遗忘门(Forget Gate):遗忘门决定了哪些信息会从记忆单元中被丢弃或遗忘。它也由当前时刻的输入和上一时刻的隐藏状态共同决定。 输出门(Output Gate):输出门决定了哪些信息会从记忆单元中输出到当前时刻的隐藏状态中。同样地,它也由当前时刻的输入和上一时刻的隐藏状态共同决定。 LSTM的计算过程可以大致描述为: 通过遗忘门决定从记忆单元中丢弃哪些信息。 通过输入门决定哪些新的信息会被加入到记忆单元中。 更新记忆单元的状态。 通过输出门决定哪些信息会从记忆单元中输出到当前时刻的隐藏状态中。 由于LSTM能够有效地处理长期依赖关系,它在许多序列建模任务中都取得了很好的效果,如语音识别、文本生成、机器翻译、时序预测等。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值