首页
社区
课程
招聘
[求助]指令的字节占用计算方法
发表于: 2008-12-20 10:12 4329

[求助]指令的字节占用计算方法

2008-12-20 10:12
4329
对于学习的汇编有一点不太明白就是什么样的指令占3个字节,什么样的占两个字节,能请懂的人讲解一下么?16位和32位的指令长度有啥区别么,我目前学的是16位的

[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课

收藏
免费 0
支持
分享
最新回复 (2)
雪    币: 2110
活跃值: (21)
能力值: (RANK:260 )
在线值:
发帖
回帖
粉丝
2
先说16位和32位,你指的应该是代码段的属性吧:

在实模式下,代码段默认是16位,可以用0x66和0x67前缀执行部分32位操作。

在保护模式下,代码段的属性由CS选择子指向的段描述符中的D/B域定义,该位为1时为32位段,为0则为16位段。

至于16位和32位指令长度,有不同的情况。
有些指令,同一个机器指令码,当段长度属性不同时仅仅是寄存器操作数的位数不同。例如,机器指令0x55,在32位段中,执行push ebp的功能,而在16位段中,是push bp。类似的还有pop ecx/pop cx,movsw/movsd,ADD AX,CX/ADD EAX,ECX,等等。

还有很少的指令,在16位和32位意义是不同的,比如双字节指令0x88,0x07,在16位是mov [bx],al,在32位是mov [edi],al,因为0x07中的寄存器编码在16位和32位不一致。

还有一些指令,是我调试软件时发现的,使用0x66前缀后它的执行结果与最初的预料不一样,比如0x0FC8,bswap eax,如果加上0x66,OD将它反汇编成bswap ax。但是,它并不是交换al和ah,而是将ax清零。意外???其实不是。原因在于,bswap指令是纯32位的,在8086时代并没有这样一条指令。也就是说,实际上bswap ax不是有效的16位指令!至于INTEL为什么不让它产生一个异常而是将AX清零,我也不知道,反正情况是这样的。

那为16位代码不需要bswap操作吗?答案是:在16位代码中,用xchg ah,al指令就可以实现了!不过这里又有一个情况,32位也可以xchg ah,al,而实验结果是,16位和32位的xchg ah,al的机器码是不一样的!我也不知道是不是汇编器的原因,但我的实验是xchg ah,al和xchg al,ah的16位和32位机器指令刚好相反。

再说说变长指令。

INTEL的处理器虽然一次又一次地升级,但指令编码却越来越复杂,这都是出于“兼容”的考虑。

因为它是变长指令,指令的长度取决于具体的指令,只有在对指令动态地解码才能决定,不像很多RISC机器,比如ARM,指令的边界就是4字节对齐的地址(ARM状态)或偶地址对齐的地址(THUMB状态)。

虽然CPU的实际译码过程是非常复杂的,不过为了便于理解,可以简化地进行想象,类似反汇编引擎的解码过程:

比如,pop ecx的机器码是0x59,push ebp是0x55,是单字节指令。CPU的指令译码逻辑发现它是单字节指令,于是直接进入下一轮的译码周期。

而mov eax, edi的机器码是0x8b 0xc7,译码先看到0x8b,根据译码表,知道它还有ModRM域,没有IMM域,于是把下一个字节当作ModRM域来译码,根据ModRM译码结果,后面没有SIB和地址偏移,于是该条指令解码结果,进入下一个周期。

依此类推,译码器通过对指令字节的解析来确定是否到达指令的边界。

其实我只是凭自己的感觉说的,不是搞专业的,不保证正确。更专业的分析,可以看一下mik写机器指令的分析文章:

http://bbs.pediy.com/search.php?searchid=1212752

以及egogg写的相关文章:

http://bbs.pediy.com/search.php?searchid=1212760
2008-12-20 13:10
0
雪    币: 230
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
3
顶,谢谢斑竹回答。学习 了
2008-12-20 13:29
0
游客
登录 | 注册 方可回帖
返回
//