gcc优化导致的错误

在MyOS中,有这样一段系统调用代码:

void sys_win_draw(regs_t reg)
{
  HWND  hWnd = (HWND)reg.ebx;
  unsigned long* buffer = (unsigned long*)reg.ecx;
  DrawWindow(hWnd, buffer);
}

平时都很正常,今天想测试一下效率,就写了个循环调用,结果调用次数老是不对,令我十分奇怪。

如果把代码改成这样,

void sys_win_draw(regs_t reg)
{
  HWND  hWnd = (HWND)reg.ebx;
  unsigned long* buffer = (unsigned long*)reg.ecx;
  DrawWindow(hWnd, buffer);
  reg.eax = 0;
}

其实就是在DrawWindow下加一条语句,随便什么都行,代码就没问题。

在百思不得其解的情况下,查看了两种情况下的汇编语句,真相终于大白:

我们先看正确的代码,汇编如下:

 pushl %ebp
 movl %esp, %ebp
 subl $16, %esp
 movl 32(%ebp), %eax
 pushl %eax
 movl 24(%ebp), %eax
 pushl %eax
 call _DrawWindow
 leave
 ret

代码很容易理解,建立堆栈框架,然后从参数中取值并压入堆栈作为DrawWindow的参数。

下面是错误的代码:

 pushl %ebp
 movl %esp, %ebp
 movl 32(%ebp), %eax
 movl %eax, 12(%ebp)
 movl 24(%ebp), %eax
 movl %eax, 8(%ebp)
 popl %ebp
 jmp _DrawWindow

同样从堆栈中取出参数,但没有压入堆栈中,而是直接又赋给了自己的第一和第二个参数,最后

直接就Jmp到DrawWindow中。

本来这样的优化是没有错的,而且效率还很高,但在MyOS的系统调用中就不对了,具体如下:

reg_t的结构如下所示

  unsigned edi, esi, ebp, esp, ebx, edx, ecx, eax;  //by pusha
  unsigned gs, fs, es, ds;
  unsigned eip, cs, eflags, user_esp, user_ss;

其中的参数都是系统重要的寄存器参数,视调用函数不同,eax,ebx,ecx,edx,esi,edi作为参数,

但处了eax最后要作为返回值返回给应用程序外,其它的值都要在系统调用结束后从堆栈恢复到各寄存器,

而上面的优化中esi和edi的值被ebx和ecx的值覆盖了,调用结束后寄存中将得不到正确的值。

至此,原因找到了。

看来,关键时刻还得汇编啊。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值