gcc优化导致的错误
来源:互联网 发布:域名期限查询 编辑:程序博客网 时间:2024/05/06 21:01
在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的值覆盖了,调用结束后寄存中将得不到正确的值。
至此,原因找到了。
看来,关键时刻还得汇编啊。
- gcc优化导致的错误
- gcc参数错误导致的makefile错误
- 安装错误的gcc导致一些错误
- gcc版本不同导致的编译错误?
- gcc版本太高导致编译错误
- Spark优化-troubleshooting-解决各种序列化导致的错误
- GCC版本不兼容导致的链接错误:undefined reference to `SomeFunction'
- gcc error: 'class A' has no member named 'b':误用多态导致的错误
- gcc 的printf() 优化?
- GCC 的优化选项
- gcc的优化选项
- gcc的三级优化
- gcc的三级优化
- XIB 导致的错误
- strlen导致的错误
- &导致的错误
- 导错包导致的错误
- GCC版本导致的Floating Point Exception
- aa
- 原来bold for delphi有for 2005和2006的升级!
- [转载]学生成绩管理系统C源代码
- [转载]海阳顶端网ASP木马@2005α版全部源代码
- 关于周六
- gcc优化导致的错误
- Displacement map water wave
- 今年看的几部连续剧,感谢他们陪伴了我这一年
- 准备改行了
- STL websites
- 利用OpenGL实现三维绘图
- 一种可恶的木马病毒
- 《35岁以前成功的12条黄金法则》(转载)
- .Net常用的工具小结