
以为上面两个人永远不会同框。
有的人认为用 Linux 很高端,有的人觉得 macOS 很牛逼,然后很多人觉得 Windows 很 Low,不知道是从什么时候开始的,也不知道这是为什么。
各种语言的程序员之间互相鄙视,然后用个电脑上的操作系统也互相鄙视;有的还是开发多年的老手,也有语言的鄙视和操作系统的鄙视,真的不知道为什么!
如果是两个操作系统的厂家,比如上图中间的两个人,当初互相仇恨,我觉得还是可以理解,大家的设计哲学不同,宏内核和微内核站在自己的角度都觉得自己好,然后都想在操作系统上当老大。那么使用者呢,到底鄙视和被鄙视在哪里呢?搞不懂!
可以回顾一下之前的文章:
好了~!风吹哪页读哪页,哪页不懂撕哪页!今天来简单的说说 CALL 指令机器码的一种形式。
CALL 是函数调用的重要指令,它的硬编码有几种形式吧,其中一种形式是,是 Opcode 后面跟着一个偏移。比如下面这样:

看上面第一行的地址是 00411046,这行对应的汇编代码是 call 0041105F,对应的硬编码是 E8 0F 00 00 00,是这样的形式。
其中 E8 是 CALL 的硬编码的一种形式,0F 00 00 00 是一个 32 位的偏移,这个偏移是怎么算的呢?很简单,有公式可以套,公式如下
目标地址 - (当前地址 + 指令长度) = 偏移
按照公式,我们的目标地址是 0041105A,当前地址是 00411046,指令长度是 5,这个指令的机器码是 5 个字节。
最后,我们带入公式来算一下:
0041105A - (00411046 + 5) = 0041105A - 0041104B = F
在 Intel x86 架构下是小端存储,所以最后的格式是 E8 0F 00 00 00 这样的形式。
为什么 CALL 指令用的是偏移呢(当然了也有不用偏移的,那是其他格式一些间接寻址)。其实 CALL 的步骤有好几步。
当执行到 CALL 的时候,在 CALL 真正完成之前,会有一个压栈的动作,它需要把下一条指令的地址压栈,以方便被调用函数在执行完成后能正确返回。
在 CPU 执行指令时,会把下一条指令的地址自动更新到 EIP 寄存器中,以便 CPU 下次从 EIP 的地址取指令,通常是这样的。
但是,CALL 指令的本质是修改 EIP 从而改变程序的执行流程,所以,下一条指令不是 EIP 中的指令了。EIP 已经成为 CALL 的下面的一条指令的地址了,而不是真正要执行的下一条指令的地址了。
看上面的图,CALL 指令的下一条指令的地址是 0041104B,CPU 会把它设置为 EIP 的值。但是,由于当前执行的是 CALL 指令,CPU 不会顺序往下执行了,而是要去 CALL 指令后面的地址了,也就是要去 0041105A 这个地址了。
这是,让 EIP 中的值加上 CALL 指令硬编码后面的偏移地址就可以了。
返回来看一下上面的公式,CALL 的当前地址 + CALL 指令的长度,其实就是下一条指令的地址,下一条指令的地址 + CALL 硬编码的偏移,就得到了 CALL 指令真正要执行的目标地址了。
就这么简单!
最后来分享一些资源吧~!
如何打造高绩效的研发团队:https://pan.quark.cn/s/fde0729aa1fc
《创新公司:皮克斯的启示录》:https://pan.quark.cn/s/2d869862db37
机房制度精品文档:https://pan.quark.cn/s/1526da48fe71
管理咨询师必备的思维模型:https://pan.quark.cn/s/84a66176073c
实用的纯干货文档:https://pan.quark.cn/s/bac30cc680b5