由一个vc内嵌asm的BUG引出的思考
从语法上来说,我们通常认为以下两个语句是等价的:
mov ecx,offset data _ label//其中data _ label是数据定义标签
leaecx,data _ label。
再者,我们还认为下面两句话是等价的:
mov ecx,ebp-8
leaecx,[ebp-8]
首先,使用内存寻址方法;第二种采用寄存器寻址和寄存器间接寻址。让我惊讶的是,在第二种情况下,vc的处理并没有让寄存器寻址和寄存器间接寻址的mov和lea等价。用_asm{}编译完语句“mov ecx,ebp-8”后,很不幸的是,我在vc的反汇编窗口发现变成了这个。到目前为止,我还没有找到这种现象的原因,只能暂时归为vc bug。
gcc下会存在这个问题吗?为了进一步确认,我用gcc重写了这段代码:“mov ecx,ebp-8”,但是重写后的代码从原来的一句话变成了两句话:
MOVL% EBP,% ECX
SUBL ,% ECX。
之所以改写这两句话,是因为我发现在美国电话电报公司的汇编语法中,对于双寄存器寻址的操作,寄存器的值是不能改变的,也就是不能写成“movl %ebp-8,%ecx”的形式,但是间接寄存器寻址的操作是可以改变的,比如:
movl -8(%ebp)。%ecx这句话相当于:mov ecx,[ebp-8]
movl (%ebp,% eax),%ecx在intel asm中这句话相当于:mov ecx,[ebp+eax]
movl (%ebp,% eax,4 %ecx相当于:mov ecx,[ebp+eax * 4]
movl-8 (%ebp,% eax,4),% ecx相当于:mov ecx,[ebp+eax
从上面的说法来看,美国电话电报公司文法对寄存器间接寻址的支持似乎没有intel asm那么人性化,但我怀疑美国电话电报公司采用这种方式可能也是为了在一定程度上提高微指令级的执行效率。
当然“mov ecx,ebp-8”这句话也可以改写成这样的两句话:
SUBL ,% EBP
MOVL% EBP,% ECX
但是,一般不做。原因很明显。ebp通常用作函数中的基址寄存器,用来存储函数入口点的栈头地址。该值的变化将直接影响后续语句中对局部变量和函数参数的引用。所以ebp通常是不允许在函数头之后的执行器中更改的,这也是我们在设计自己的汇编代码时应该遵循的原则。
想知道为什么vc会在ebp之后马上丢弃数据,这显然是不道德的。这让我想起了这句话:不要试图帮助用户改正错误,而是在出现错误的时候提醒用户,因为再聪明的程序也不会总是理解设计者的真实意图。我们需要做的是“为异常捕获提供尽可能详细的日志,并及时通知用户这个异常。试图纠正这种例外是错误和愚蠢的方法”
位律师回复
0条评论