呵呵,写普及贴可以,不过要整理好才行。
罗聪的错误实在多,现在可以拿罗聪贴子来点评一下它的错误:
就拿它这一点,来说说,汗一下,整个篇幅都有问题。
http://www.luocong.com/learningopcode/doc/2._从哪里开始,到哪里结束.htm
一、eb 这个字节,他理解为:jmp imm8
正确应该为 jmp disp8,这是一个 displacement 值,而非 immediate 值。
凡是 displacement 值都是一个 single value (符号数),它会产生一个符号扩展行为。
也就是说: eb fe 其它等于: eip = eip + FFFFFFFE
二、 以下是他的原话:
问题来了,我们用肉眼一看就知道,这代表2个字节,我们也知道这条指令应该是从EB开始,总长度是2个字节,到imm8为结束,可是计算机是怎么知道这一点的呢?假如有一串OpCode发送给处理器,例如“90EB0090”,让它从中找到这个jmp指令,它会不会认不出来呢?
又或者,传送一串OpCode给处理器,例如“EB1234”,它会不会把后面的34也算进了jmp的跳转范围呢?
答案是,不会的。
----------------------------------------------------
opcode 只是 instruction 序列的一部分,一串opcode发送给处理器,汗~~
指令序列被从 L1 instruction-cache 里取出来,确实是从 opcode 里解析指令。从而确定指令长度,操作数。
三、重点看看以下他所说的:
00401000 EB FE JMP 00000000
00401002 90 NOP
此时EIP = 00401000,但是为什么EBFE会是JMP 00000000呢?想想看?
答案:
FE + 02 = 100
-----------------------------------------------------------------------------
应是这样:eb fe 这个 fe (disp8) 值被符号扩展为 fffffffe
结果是: eip = eip + ffffffffe = 00401002 + FFFFFFFe = 00401000
此时,eip 值是 00401000
所以:下条指令边界是 00401000
四、在运行完一条指令后,EIP并不总是指向下一条指令的开始!
这句是严重错误。
除非处理器发生 abort 类型的异常,导致跑飞的情况。
原因综上所述。
五、 下面的论述,错误的太离谱了,哎~~~ 不说了
OpCode:04 AC
00401000 04 AC ADD AL, 0AC
我们已经知道,AC是助记符lodsb的OpCode,00401000是OpCode 04AC的开始地址,而00401002将会是它的结束(这个指令只有2个字节的关系)。但是,我们一直以来都没讨论的是:如果把这条OpCode从中间截断!即从00401001地址处开始的指令会是什么呢?
如果我们把寄存器EIP的内容设置成00401001,我们就会发现:
处理器会把AC看作lodsb,而不是:
ADD AL, 0AC
04:imm8(AL+imm8)中的imm8
应用这个原理,我们来看一个小例子,假设要实现下面的算法:
IF zf = 0
lodsb
ELSE
add al, 0AC
试试写成助记符?不知道读者朋友们会怎么写——我会写成这样:
jnz $+1
add al, 0AC
解释如下:
如果标志位zf等于0,则EIP会指向add al, 0AC的第2个字节,也就是AC——我们知道AC表示助记符lodsb
明白了吗?使人惊奇的是,整个算法的实现只用了区区4个字节!
这个算法的OpCode:
00401000 75 01 JNZ SHORT 3
00401002 04 AC ADD AL, 0AC
让我们来看看每个字节表示什么意思:
75:imm8 是 7501 的域格式
75是JNZ的OpCode,imm8在这里是01,会加到EIP里面去,整个7501表示如果这条指令被执行了,则EIP会指向下一条指令的第2个字节的地址。
04AC的域格式:
04:imm8 其中:
04 - {code}
AC - {Immediate}
整个算法实现的思路如下:
如果zf=0,7501这条指令就会把下一条指令的起始地址+1(75后面的操作数就是需要跳的字节数:0不跳,1跳一个,n就跳n个……但是字节是有符号的,负的就往后跳……所以jnz short xxx是有最大的跳跃限制的),然后把跳跃后的地址赋值给EIP——也就是00401003,从而迫使处理器认为AC所在的地址才是下一条指令的开始(跳过了OpCode 04),这时,AC会被当成{code}。
否则,EIP会指向04AC所在的地址00401002,所以下一条指令的开始就会从04开始算起,处理器会认出域格式:
04:imm8(add al, imm8)
这时,AC会被当成{Immediate},而不是{code}。
呵呵,是不是有点儿迷糊了?
为了加深理解,最后再给大家看一个算法及其实现:
IF zf = 0
inc eax
ELSE
mov al, 40
答案:
00401000 75 01 JNZ SHORT 3
00401002 B0 40 MOV AL, 40
嗯……提示一下:40表示的是inc eax……聪明的你,明白了吗
这个罗聪大侠也错得离谱,估计他是很久很久以前写的吧