存档

文章标签 ‘fun’

CALL指令有多少种写法

2010年4月4日 6 条评论

最近有一个需求,给你个地址,看看这个地址前面是不是一个CALL指令(请同学们自行联想该需求的来源)。作为团队的救火队员+炮灰,这个简单的事情自然落在了我的头上。

这个事情很简单,作为一个善于站在别人肩膀上的程序员我们可以考虑使用 libdisasm;如果要考虑x64,就试试udis86;如果需要用Python,就有Python包装好的 pydasm。不过这两个400KB+的库,显然不值得为了一个CALL指令导入到编译出来大小仅仅100K不到的项目代码里面。

那么就自己抽一个CALL指令解码逻辑出来好了。这个逻辑的复杂性在于,你无法知道前面一个CALL指令有多长。因此,首先需要枚举出所有的CALL指令格式。

Intel有公开的指令集格式文档,你需要的是第二卷的上半部分,指令集从A到M。这篇文档的难度超出一般人想象,里面有众多晦涩的标识、与硬件紧密相关的介绍,拿到这后,即使直接翻到目录的CALL 指令一节,也不见得能够弄清楚。不相信?我们就翻到那里看看:

CALL指令格式一览表

CALL指令格式一览表

虽然很明确的列出,第一列是指令的二进制形式,第二列是指令的汇编形式,但是面对着 E8 cw, FF/2这样的标识,一样不知道究竟对应的二进制格式是什么样的。

那好,我们就从理解这些标识开始。文档向前翻,有一个专门的节(3.1.1 Instruction Format)讲述这些标识的含义。这里抽出其中两个用得着的翻译一下:

表格中的“Opcode”列列出了所有的所有可能的指令对应的二进制格式。有可能的话,指令代码使用十六进制显示它们在内存当中的字节。除了这些16进制代码之外的部分使用下面的标记:

cb, cw, cd, cp, co, ct — opcode后面跟着的一个1字节(cb),2字节(cw),4字节(cd),6字节 (cp),8字节(co) 或者 10字节(ct) 的值。这个值用来表示代码偏移地址,有可能的话还包括代码段寄存器的值。

/digit — digit为0到7之间的数字,表示指令的 ModR/M byte 只使用 r/m字段作为操作数,而其reg字段作为opcode的一部分,使用digit指定的数字。

红字部分不知道什么含义?没关系,我们先不看它。对于cb/cw之类的,基本上能够简单看明白其中的一些指令含义了:

E8 cw 的含义是:字节 0xE8 后面跟着一个2字节操作数表示要跳转到的地址与当前地址的偏移量。
E8 cd 的含义是:字节 0xE8 后面跟着一个4字节的操作数表示要跳转的地址与当前地址的偏移量。
9A cd 的含义是:字节 0x9A 后面跟着一个6字节的操作数表示要跳转的地址和代码段寄存器的值。

那么,同样的0xE8开头的指令,CPU如何区分后面的操作数是2字节还是4字节?答案是和CPU的模式有关,在实模式下,0xE8接受2字节操作数,而32位保护模式下接受4个字节,64位保护模式下同样接受4字节,同时需要对该操作数进行带符号扩展。

因此,CALL指令的前两种格式是:E8 xx xx xx xx,和 9A xx xx xx xx xx xx。一个是5字节长,一个是7字节长。其实E8 那种,就是我们在汇编指令里面写 CALL lable之后产生的,最常见的CALL指令。

然后是下面的FF /2。这个是0xFF字节后面跟上一个blablabla的东西。这个blablabla的东西是什么呢?要解释这个,首先需要知道红字标出来的部分,即ModR/M是什么东西。

这个要先回到最基本的一个问题:IA32的指令格式。

IA32,64指令格式

IA-32,Intel 64指令格式

其中每个部分是什么含义呢?

首先是指令前缀。有印象的应该记得当年学习微机原理的时候提到过得循环前缀 repnz/repne,这个前缀就是被编码在指令的前面部分的。每个前缀最多一个字节,一条指令最多4个前缀。

然后是指令代码(opcode),这部分标识了指令是什么。这个是指令当中唯一必需的部分。前面例子当中的 0xE8,0xFF都是opcode。

再后面就是我们要重点关心的 ModR/M字段了,还有和它密切相关的SIB字节。手册2.1.3当中有对于它们的详细描述。

许多指令需要引用到一个在内存当中的值作为操作数,这种指令需要一个称为寻址模式标识字节(addressing-form specifier byte),或者叫做ModR/M字节紧跟在主opcode后面。ModR/M字节包含下面三个部分的信息:

  • mod(模式)域,连同r/m(寄存器/内存)域共同构成了32个可能的值:8个寄存器和24个寻址模式。
  • reg/opcode(寄存器/操作数)域指定了8个寄存器或者额外的3个字节的opcode。究竟这三个字节用来做什么由主opcode指定。
  • r/m(寄存器/内存)域可以指定一个寄存器作为操作数,或者可以和mod域联合用来指定寻址模式。有时候,它和mod域一起用来为某些指令指定额外的信息。

这一段有些晦涩。其意思解释一下是这样的:一个指令往往需要引用一个在内存当中的值,典型的就是如mov:

MOV eax, dword ptr [123456]
MOV eax, dword ptr [esi]

这其中的 123456 或者 esi 就是 MOV 指令引用的内存地址,而MOV关心的是这个地址当中的内容。这个时候,需要某种方式来为指令指定这个操作数的类型:是一个立即数表示的地址,还是一个存放在寄存器当中的地址,或者,就是寄存器本身。

这个用来区分操作数类型的指令字节就是 ModR/M,确切的说是其中的5个位,即mod和r/m域。剩下的三个位,可能用来做额外的指令字节。因为,IA32的指令个数已经远超过一个字节所能表示的256个了。因此,有的指令就要复用第一个字节,然后依据ModR/M当中的reg/opcode域进行区分。

现在回头看前面的红字标识的部分,能不能理解 /digit 这种表示法了?

对于SIB的介绍,我们先忽略,看看对于CALL指令的枚举我们已经能做什么了。

CALL指令的表示法:FF /2,是 0xFF 后面跟着一个 /digit 表示的东西。就是说,0xFF后面需要跟一个 ModR/M 字节,ModR/M字节使用 reg/opcode 域 = 2 。那么,reg/opcode = 2 的字节有32个,正如ModR/M的解释,这32个值代表了32种不同的寻址方式。是哪32种呢?手册上面有张表:

32字节寻址模式下的ModR/M字节

32字节寻址模式下的ModR/M字节

非常复杂的一张表。现在就看看这张表怎么读。

首先是列的定义。由于 reg/opcode 域可以用来表示opcode,也可以用来表示reg,因此同一个值在不同的指令当中可能代表不同的含义。在表当中,就表现为每一列的表头都有很多个不同的表示。我们需要关心的就是 opcode 这一个。注意看我用红圈圈出来的部分,这一列就是 opcode=2 的一列。而我们需要的 CALL 指令,也就是在这一列当中,0xFF后面需要跟着的内容。

行的定义就是不同的寻址模式。正如手册所说,mod + R/M域,共5个字节,定义了32种寻址模式。0x10 – 0x17 对应于寄存器寻址。例如指令 CALL dword ptr [eax] :[eax]寻址对应的是 0x10,因此,该指令对应的二进制就是 FF 10。同理, CALL dword ptr [ebx] 是 FF 13,CALL dword ptr [esi] 是 FF 16,这些指令都是2个字节。有人也许问 CALL word ptr [eax] 是什么?抱歉,这不是一个合法的32位指令。

0x50-0x57部分需要带一个 disp8,即 8bit 立即数,也就是一个字节。这个是基地址+8位偏移量的寻址模式。例如 CALL dword ptr [eax+10] 就是 FF 50 10 。注意虽然表当中写的是 [eax] + disp8 这种形式,但是并不表示是取得 eax 指向的地址当中的值再加上 disp8,而是在eax上加上disp8再进行寻址。因此写成 [eax+disp8] 更不容易引起误解。后面的disp32也是一样的。这个类型指令是3个字节。

0x90 – 0x97部分需要带 disp32,即4字节立即数。这个是基地址+32位偏移量。例如 CALL dword ptr [eax+12345] 就是 FF 90 00 01 23 45。有趣的是, CALL dword ptr [eax+10] 也可以写成 FF 90 00 00 00 10。至于汇编成哪个二进制形式,这是汇编器的选择。这个类型的指令是6个字节。

0xD0 – 0xD7部分则直接是寄存器。这边引用的寄存器的类型有很多,但是在CALL指令当中只能引用通用寄存器,因此 CALL eax 就是 FF D0,臭名昭著的 CALL esp 就是 FF D4。注意 CALL eax 和 CALL [eax] 是不一样的。这些指令也是2个字节。

仔细的人也许主要到了,在表当中,0x14, 0x15, 0x54和0x94是不一样的。0x15比较简单,这个要求 ModR/M后面跟上一个32位立即数作为地址。即常见的 CALL dword ptr [004F778e] 这种格式的,直接跳转到一个固定内存地址处存放的值,常见于调用Windows的导出表。对应的二进制是 FF 15 00 4F 77 8E ,有6个字节。

0x14,0x54,0x94部分是最复杂的,因为这个时候,ModR/M不足以指定寻址方式,而是需要一个额外的字节,这个字节就是指令当中的第4个字节,SIB。同样在手册的2.1.3,紧跟着ModR/M的定义:

某些特定的ModR/M字节需要一个后续字节,称为SIB字节。32位指令的基地址+偏移量,以及 比例*偏移量 的形式的寻址方式需要SIB字节。 SIB字节包括下列信息:

  • scale(比例)域指定了放大的比例。
  • index(偏移)域指定了用来存放偏移量 的寄存器。
  • base (基地址)域用来标识存放基地址的寄存器。

0x14, 0x54, 0x94就是这里所说的“特定的ModR/M字节。这个字节后面跟着的SIB表示了一个复杂的寻址方式,典型的见于虚函数调用:

CALL dword ptr [ecx+4*eax]

就是调用ecx指向的虚表当中的第eax个虚函数。这个指令当中,因为没有立即数,因此FF后面的字节就是0x14,而 [ecx+4*eax] 就需要用SIB字节来表示。在这个指令当中,ecx就是 Base,4是Scale,eax是Index。

那么,Base, Scale和Index是如何确定的呢?手册上同样有一张表(又是巨大的表):

32位寻址模式当中的SIB字节

32位寻址模式当中的SIB字节

列是Base,行是Index*Scale,例如[ecx+4*eax] 就是0x81。

根据这张表,CALL dword ptr [ecx+4*eax] 就是 FF 14 81 。由此可见,对于 0x14系列的来说,CALL指令就是 3个字节。
而 0x54 带 8bit 立即数,就是对应于 CALL指令:CALL dword ptr [ecx+4*eax+xx],这个指令就是 FF 54 81 xx,是4个字节。
同理,0x94带32位立即数,对应于CALL指令:CALL dword ptr [ecx+4*eax+xxxxxxxx],这个指令就是 FF 94 81 xx xx xx xx,是7个字节。

OK,截止到目前,我们基本上能够列出常见的CALL指令的格式了:

指令 二进制形式
CALL rel32 E8 xx xx xx xx
CALL dword ptr [EAX] FF 10
CALL dword ptr [ECX] FF 11
CALL dword ptr [EDX] FF 12
CALL dword ptr [EBX] FF 13
CALL dword ptr [REG*SCALE+BASE] FF 14 xx
CALL dword ptr [abs32] FF 15 xx xx xx xx
CALL dword ptr [ESI] FF 16
CALL dword ptr [EDI] FF 17
CALL dword ptr [EAX+xx] FF 50 xx
CALL dword ptr [ECX+xx] FF 51 xx
CALL dword ptr [EDX+xx] FF 52 xx
CALL dword ptr [EBX+xx] FF 53 xx
CALL dword ptr [REG*SCALE+BASE+off8] FF 54 xx xx
CALL dword ptr [EBP+xx] FF 55 xx
CALL dword ptr [ESI+xx] FF 56 xx
CALL dword ptr [EDI+xx] FF 57 xx
CALL dword ptr [EAX+xxxxxxxx] FF 90 xx xx xx xx
CALL dword ptr [ECX+xxxxxxxx] FF 91 xx xx xx xx
CALL dword ptr [EDX+xxxxxxxx] FF 92 xx xx xx xx
CALL dword ptr [EBX+xxxxxxxx] FF 93 xx xx xx xx
CALL dword ptr [REG*SCALE+BASE+off32] FF 94 xx xx xx xx xx
CALL dword ptr [EBP+xxxxxxxx] FF 95 xx xx xx xx
CALL dword ptr [ESI+xxxxxxxx] FF 96 xx xx xx xx
CALL dword ptr [EDI+xxxxxxxx] FF 97 xx xx xx xx
CALL EAX FF D0
CALL ECX FF D1
CALL EDX FF D2
CALL EBX FF D3
CALL ESP FF D4
CALL EBP FF D5
CALL ESI FF D6
CALL EDI FF D7
CALL FAR seg16:abs32 9A xx xx xx xx xx xx

有了这个列表,写一段代码来完成最初我们的需求也就不难了。

标签: ,

Firefox更新了一把

2009年10月18日 1 条评论
标签: ,

[zz]汉编

2009年3月10日 1 条评论

这个是老段子了。


#define 趁还 while
#define 那个啥 int
#define 总的来说 main
#define 买 cin
#define 卖 cout
#define 进 >>
#define 出 <<
#define 拜拜了 return
#define 去掉 -=
#define 等于 =
#define 屁 100e4
#define 我说 (
#define 是吧 )
#define 啊 a
#define 那么就 {
#define 得了 }
#define 呀 ;

#include <iostream>

using namespace std;

那个啥 总的来说 我说 那个啥 啊 是吧
那么就 那个啥 有钱 等于 屁 呀
趁还 我说 有钱 是吧    那么就
那个啥 多少 呀 买 进 多少 呀 卖 出 多少 呀 有钱 去掉 多少 呀
卖 出 多少 呀 得了
拜拜了 啊 呀 得了

标签: ,

[转载] 菜园子里的道理

2008年8月12日 1 条评论

转自老茂的blog.
http://savycm.spaces.live.com/blog/cns!1AF201418B02D448!649.entry

菜园子里面的道理

 
不管怎么样, 首先,我必须把自己当根葱。没有人会把自己都不把自己当回事的人当回事(这个句子稍微有点长)。
其次,就算我把自己当根葱,也不能在外面太显摆。因为现在的季节可能芹菜比葱更贵。
最后,对于那些把自己太当回事的葱们,我必须学会在他们面前装成一颗蒜。

最后加一句:就算周围都是洋葱,到头来我还是一棵葱。

标签: ,

HONDA的机器人ASIMO

2008年7月30日 4 条评论

今天偶尔在电视上看到的,HONDA(本田)的工程师带着他们的类人形机器人ASIMO到四川灾区给孩子们表演。电视上只有很短的一些片断,但是仍然展示了ASIMO的一些很强大的特性,比如奔跑。

随即Google了一下这款机器人的资料,发现这个机器人还真是不简单:
根据wikipedia上面的介绍,这款机器人高130公分,重54公斤,Airborne time(这是什么,反应时间?)0.03秒,具有34个自由度(可以理解成34个关节么……)。可以识别移动的物体、姿势、手势、环境、10张运动中的人脸、以及不同的声音。

几段Youtube上面的视频:
CES 2007上面的demo
http://www.youtube.com/watch?v=cfaAiujrX_Y

 

以及在HONDA实验室里面的demo:
http://www.youtube.com/watch?v=Q3C5sc8b3xM

 

相当的强大。

这款机器人不仅具有类人的外观、自主行走、上楼梯的能力,而且可以以时速6公里奔跑,以时速5公里转弯。从demo里面看,还可以感受到人对其手臂的作用力而跟人一起转弯。不仅如此,看demo上面推一个推车的部分,启动时多加的一点力道,以及转弯时两只手不同的力道都相当的好。

另外就是精度。看机器人体操表演的一段,明显能够看出其手臂在快速的运动之后仍然可以快速的停在正确的位置上。这个看起来很cool,而且我相信也是有相当难度的。

看它推推车的那一段,真想弄个回来帮我去超市买东西……

不过据说,制造一个需要106,710,325日元,折合人民币6829460.8元。

HONDA的网站上面还有更多的视频

最后用HONDA的ASIMO墙纸上面的一句话来描述:The power of Dreams。翻译过来就是:梦想的力量。

标签: , ,

垃圾邮件,30岁生日快乐

2008年4月27日 2 条评论

自从1978年5月2日开始,已经三十年了。

我们还在反垃圾邮件。

标签: , ,

几款专用电子书籍阅读器的比较

2008年4月4日 4 条评论

最近在评估几款电子书籍阅读器,考虑为自己添置一个,但是目前还处在观望状态,毕竟价钱不菲。

之所以开始对电子书籍阅读器感兴趣是发现自己看书的时间越来越少,坐在计算机前面看书总会被各种各上的事情打断,例如不期而至的邮件和即时消息,而脱离计算机的时候能看的书太少。所以考虑一个设备,可以专门用来读书,而且真的像一本纸质的书一样便于携带,而且随时随地可以阅读。另一方面这个东西功能不能太强大——内置WIFI,浏览器或者内置电子邮件处理的话,很可能会演变成另一台笔记本电脑;而如果直接用PDA或者智能手机或者PSP之类的非专用设备的话,一方面那种屏幕读书很累,另一方面设备上面另外的功能可能会成为看书的影响。添置这个设备的目的本身就在于能够获得像普通书籍一样的使用方式,所以专用的书籍阅读器是一个很好的选择。

这次评估的基本需求是:
1. 便携性:设备至少不能比一本书大,否则太难携带。电池必须足够强劲。
2. 屏幕阅读感觉:不能太伤眼睛(基本上就是E-Ink了,背光的LCD就是太伤眼睛)。
3. 文档格式支持:至少应该可以支持PDF,CHM,DOC。如果能够支持CBZ/CBR格式就更好了。
4. 二次开发的可能性:这样至少可以给我一个对它进行自定义的可能。
5. 售后服务:这种专用设备最怕的就是硬件损坏,因此有一个好的售后服务还是非常重要的。
6. 价格:如果买设备的钱超过了可能的潜在的买书的钱,那么就算了。

在网上搜索了很多的资料加以评估之后,目标基本上锁定在下面的三款:
1. Sony PRS-505
2. 津科翰林V3
3. iRex iLiad

现在非常火爆的Amazon Kindle不在考虑之列,原因有三:通用格式支持不好(主要是PDF);不方便购买和售后服务(在中国大陆没有销售);无线功能在中国不可用(这个是最大的问题,看看Kindle的介绍,只能用美国的3G网络,中国的3G标准不一样啊……没有了无线网络,这个阅读器并没有什么出彩的地方)。

下面分别比较一下锁定的三款阅读器的优势和劣势。

Sony PRS-505:
6寸e-ink屏,显示效果不错,便携性也毋庸置疑。7500页翻页的电池能力(e-ink屏只有翻页的时候才耗电,而且没有背光,因此这种设备的电池续航能力都不是用时间,而是用翻页次数衡量的)。
$299,据说一般会有折扣,让美国的朋友帮我买或者从淘宝上面买,大概2000块左右。
专有数据格式(LRF格式),原生支持TXT和图片,有PDF支持,但是几乎不可用。
没有找到SDK,但是网上有围绕开源的反向工程库libprs500的健康发展的社区,转换工具和库也很多,可以将各种书籍格式转成LRF格式,而且有模拟器可以预览转换后的效果。下过来用了一下,CBZ/CBR、DOC转换效果不错,PDF尚可接受。唯独比较不爽的是处理效率,当PDF文件过大的时候,这些工具都是内存杀手(400页大概消耗400M内存的样子),而且运行速度很慢(大概2秒钟一页纸的转换速度)。
主要问题是需要刷机才可以支持中文,且在国内没有正式销售,因此没有国内售后。

津科翰林V3(评测):
国产产品,因此中文支持、国际化和售后服务都没得说。
6寸e-ink屏,7500页+翻页,电池为诺基亚薄电池,可自行更换(包装盒里面还有赠送螺丝刀一个,用于开启电池盒Orz)。
淘宝上面报价2600左右,比Sony的稍贵。
文件支持格式很全,除了CBR/CBZ不支持其他都支持,而且PDF可三级缩放。虽然不支持CBR/CBZ但是支持统一目录下的一坨图片的格式,因此可以把CBR解开看。原生支持WOLF格式,是一种基于图像的格式,有一些第三方工具,但是不太好用。
看起来似乎有SDK,但是需要注册才可下载,因此还没有看。
颜色看到的都是黑色的,不知道有没有银色的。

iRex iLiad(评测
这个本来不在我的评估之列的,但是看过之后觉得这个东西真tm酷。
不过价钱也是真tm酷,¥5600,基本打消了我买的念头。但是既然评估过了,还是拿出来谈谈。
8寸e-ink屏,大啊,大就表明字大啊,字大自然看着爽。
支持手写。
支持802.11b/g,以太网和CDMA
原生中文界面支持(但是据说中文文件名和文件内容支持不好)。
有SDK(需要在Linux上面运行),而且看了一下,SDK有不错的架构。
大陆有售后服务中心。
最大的缺点是电池续航能力差,大约只能支持5小时(不开启无线)。
另一个缺点是文件类型支持少(但是有SDK了,而且有个不错的架构,估计会多起来的)。

最后考虑一下,暂时还是不要买了——价钱太贵。如果将来要买的话,首选翰林V3(而且这个在淘宝旧货上面淘到的可能性还很大),其次是Sony PRS-505。iLiad的话,虽然我很喜欢这个,但是目前来说,还是算了,如果有人愿意送我一个,我没意见。

最后写一句,关于为什么不考虑EeePC或者其他的设备:因为他们不是e-ink。

标签: , ,

我的博客2007报告

2008年2月2日 没有评论

我的博客2007报告

   
2007我很忙“2007我很忙!” 你呢?点这里测测看!

有点意思。

— Update —
因为Live Space会把一些标签过滤掉,所以不一定能够show出来上面的flash,所以直接贴图了。





标签: , ,

好歹我们也是搞网络的

2008年1月15日 1 条评论

虽然确实比较难,但是周围大部分人都还是搞定了,包括我,虽然耗时近3个小时,而且在amen指导之下。
不管怎么说,好歹我们也是搞网络的。

来挑战一下吧:尝试使所有的线都不交叉:
http://www.nonoba.com/chris/untangle

Show最后一关:

结果:

标签: ,

It’s not a bug, it’s a feature

2008年1月13日 没有评论

这不是Bug,这是Feature。
SQLiteWMF,和Firefox有感。

It is not a bug, it is a feature From Explodingdog

标签: , ,