1) Debug与Release的区别:前者称调试版,后者称发行版。调试版基本不优化,而发行版会经过编译器的极致优化,往往与优化前的高级语言执行流程会大相径庭,但是实现的功能是等价的。

2) 如下for循环语句:

 int MyFunction(int a,int b)
 {
     int c = a + b;
     int i;
      ; i <  ; i ++ )
     {
            c = c + i;
     }
     return c;
 }  

Debug版汇编后代码为:

 int MyFunction(int a, int b)
 {
     //省略现场保护代码
     int c = a + b;
 ]       ;取参数1
 0040D4BB    add eax,dword ptr [ebp+0Ch]     ;取参数2
 ],eax       ;存放局部变量c
     int i;
     for ( i =  ; i < 50 ; i ++ )
 ],         ;局部变量i
 0040D4C8    jmp MyFunction+33h (0040d4d3)   ;跳至第一次循环
 ]       ;改变循环变量
                        ;i自增操作
 ],ecx       ;保存
 ],32h       ;循环条件比较
 0040D4D7    jge MyFunction+44h (0040d4e4)   ;大于等于则跳
     {
         c = c + i;
 ]       ;读变量c到edx
 ]       ;加上i
 ],edx       ;保存
     }
 0040D4E2    jmp MyFunction+2Ah(0040d4ca)    ;继续循环
     return c;
 ]        ;取结果到eax
 }
 //省略现场恢复代码  

大体结构为:

     MOV <循环变量>    <初始值>      ;给循环变量赋初值
     JMP     B                    ;跳至第一次循环
 A:  (改动循环变量)                ;修改循环变量
     …
 B:  CMP <循环变量>    <限制变量>      ;检查循环条件
     JGE     跳出循环
     (循环体)
     …
     JMP     A                   ;跳回去继续修改循环变量  

3) 上述的for循环改为以下do循环:

 ;
 do{
     c = c + i;
 } );  

Debug版本汇编:

 ;
 ],       ;循环变量i初始化
 do{
     c = c + i;
 ]
 ]
 ],ecx       ;相加并保存
 }while( ++i<=  );
 ]  

 ],edx       ;改变循环变量
 ],32h       ;比较循环条件
 0040D4DE    jl  MyFunction+28h (0040d4c8)   ;小于则跳,继续循环  

4) 上述的do循环改为以下while循环:

 ;
 )
 {
      c= c + i;
 }  

Debug版本汇编:

 ;
 ],       ;循环变量i初始化
 while( i++ < )
 ]       ;自增前的循环变量
 ]  

 ],edx       ;循环变量自增并保存
 0040D4D4    cmp ecx,32h                  ;比较(自增前的)
 0040D4D7    jge MyFunction+44h (0040d4e4)   ;不小于则跳转,退出循环
 {
     c = c + i;
 ]
 ]
 ],eax       ;相加并保存
 }
 0040D4E2    jmp MyFunction+28h (0040d4c8)   ;绝对跳转,集训循环  

5) 如下if-else判断分支:

 ,j;
  )
 {
          j= ;
 }
  && i <= )
 {
          j= ;
 }
 else
 {
          j= ;
 }  

Debug版本汇编:

 ,j;
 ],0Ah       ;仅声明的变量不分配内存
 if ( i <=  )
 ],       ;比较
 0040D4C3    jg  MyFunction+2Eh (0040d4ce)   ;大于则跳下一分支
 {
     j = ;
 ],       ;赋值
 }
 else if ( i >  && i <= )
 0040D4CC    jmp MyFunction+4Ah (0040d4ea)   ;结束整个分支
 ],       ;else-if分支开始
 0040D4D2    jle MyFunction+43h (0040d4e3)   ;不大于0则转入else
 ],0Ah       ;判断第二个条件
 0040D4D8    jg  MyFunction+43h (0040d4e3)   ;大于则转入else
 {
     j = ;
 ],       ;赋值
 }
 else
 0040D4E1    jmp MyFunction+4Ah (0040d4ea)   ;结束整个分支
 {
     j = ;
 ],       ;赋值
 }
 0040D4EA    …  

If-else语句使用CMP加绝对跳转指令实现(跳转到下一分支或者整个分支的结束位置),从上可知要排列好比较条件的顺序,以达到最少的比较次数的效果。

6) 如下switch-case判断分支:

 ,j;
 switch( i ){
 :
          j= ;
 :
          j= ;
          break;
 default:
          j= ;
 }  

Debug版本汇编:

 ,j;
 ],0Ah       ;赋初值
 switch( i )
 {
 ]
 0040D4C2    mov dword ptr [ebp-0Ch],eax     ;转移内存单元
        ;与0比较
 0040D4C9    je  MyFunction+33h (0040d4d3)   ;等于则转
        ;与1比较
 0040D4CF    je  MyFunction+3Ah (0040d4da)
 0040D4D1    jmp MyFunction+43h (0040d4e3)   ;绝对跳转到default
 case :
     j = ;
 ],       ;无break转入下一分支
 case :
     j = ;
 ],
 break;
 0040D4E1    jmp MyFunction+4Ah (0040d4ea)   ;break,绝对跳转到结束
 default:
     j = ;
 ],
 }
 0040D4EA    …  

期间对i进行转储是Debug版本的特点,目的并不明确。每一个case对应一个cmp与跳转指令je,最后的default要是没有,则跳转到结束处。Case中有break则跳转到结束,没有则继续往下执行。

7) 如下C语言结构体和数组:

 typedef struct {
     float a;
     char b;
     int c;
 }mystruct;  

 int MyFunction(void)
 {
     unsigned ];
     mystruct* strs = (mystruct *)buf;
     int i;
      ; i <  ; i++)
     {
         strs[i].a= 1.2;
         strs[i].b= 'a';
         strs[i].c= ;
     }
     ;
 }  

Debug版本汇编MyFunction函数如下:

 int MyFunction(void)
 {
     push ebp
     mov  ebp,esp
     sub  esp,1D8h                ;1D8H = 472字节
     push ebx
 0040102A    push esi
 0040102B    push edi
 0040102C    lea edi,[ebp-1D8h]
     mov ecx,76h
     mov eax,0CCCCCCCCh
 0040103C    rep stos dword ptr [edi]        ;标准现场保护
     unsigned char *buf[];
 tystruct *strs =(mystruct *)buf;
 0040103E    lea eax,[ebp-190h]
     mov dword ptr [ebp-194h],eax    ;将ebp – 190h送入ebp – 194h
                                       ;ebp– 190h为缓存区地址首址(char)
                                       ;ebp– 194h为str指针(tystruct *strs)
     int i;
     for (i =  ; i< 5 ; i++)  

     )
     mov ecx,dword ptr [ebp-198h]  

 0040105F    mov dword ptr [ebp-198h],ecx  

 0040106C    jge MyFunction+91h (004010b1)    ;标准for循环结构
     {
         strs[i].a = .;
 0040106E    mov edx,dword ptr [ebp-198h]     ;ebp – 198h为循环变量i
     imul edx,edx,0Ch                ;结构体长度为常量0CH,得偏移
     mov eax,dword ptr [ebp-194h]     ;取str中的指针值
 0040107D    mov dword ptr [eax+edx],3F99999Ah
                                       ;得strs[i].a地址,并赋值
         strs[i].b = 'a';
     mov ecx,dword ptr [ebp-198h]
 0040108A    imul ecx,ecx,0Ch
 0040108D    mov edx,dword ptr [ebp-194h]
     ],61h   ;相对与之上多偏移4个字节
         strs[i].c = ;
     mov eax,dword ptr [ebp-198h]
 0040109E    imul eax,eax,0Ch
 004010A1    mov ecx,dword ptr [ebp-194h]
 ],     ;相对与之上,再偏移4个字节
     }
 )
     return ;
 004010B1    xor eax,eax
 }
 //省略现场恢复  

第一点:系统预分配的临时变量堆栈区可变且足够(暂时不知道怎么计算的);第二点:Struct的大小编译以后作为常数保存,对结构体中的变量的访问(点运算符)汇编后采用的偏移量的形式;第三点:偏移量的大小为结构体定义时各个成员变量于系统字长对齐后大小的叠加(mystruct第二个成员为char类型,理论上来说只占用一个字节,但是与4字节对齐,实际占用4个字节)

8) 如下C语言共用体和枚举类型:

 typedef enum {
          ENUM_1= ,
          ENUM_2= ,
          ENUM_3,
          ENUM_4,
 }myenum;  

 typedef  struct{
          inta;
          intb;
          intc;
 }mystruct;  

 typedef union{
          mystructs;
          myenume[];
 }myunion;  

 int MyFunction(void)
 {
          unsigned ] = {  };
          myunion* uns = (myunion *)buf;
          int i;
           ; i <  ; i++)
          {
                    uns[i].s.a= ;
                    uns[i].s.b= ;
                    uns[i].e[]= ENUM_4;
          }
          return0;
 }  

Debug版本汇编MyFunction函数如下:

 int MyFunction(void)
 {
     //现场保护代码省略
     unsigned charbuf[] = {  };
         ;ebp – 64的1个字节置0
     mov ecx,18h                  ;循环18H(24)次
     xor eax,eax                  ;eax置0
     lea edi,[ebp-63h]             ;从ebp – 63位置开始清
 0040104C    rep stos dword ptr [edi]        ;内存清0(24*4=96字节)
 0040104E    stos word ptr [edi]             ;继续清2个字节
     stos byte ptr [edi]             ;继续清1个字节
                                       ;合计100字节
     myunion *uns =(myunion *)buf;
     lea eax,[ebp-64h]
     mov dword ptr [ebp-68h],eax     ;ebp-68h为myunion *uns指针变量
     int i;
     for (i =  ; i< 5 ; i++)
            ; ebp-6Ch为局部变量i
 )
     mov ecx,dword ptr [ebp-6Ch]  

     mov dword ptr [ebp-6Ch],ecx  

 0040106D    jge MyFunction+83h (004010a3)   ;标准for循环
     {
         uns[i].s.a = ;
 0040106F    mov edx,dword ptr [ebp-6Ch]
     imul edx,edx,0Ch              ;0CH为共用体大小
     mov eax,dword ptr [ebp-68h]
            ;偏移,赋值
         uns[i].s.b = ;
 0040107F    mov ecx,dword ptr [ebp-6Ch]
     imul ecx,ecx,0Ch
     mov edx,dword ptr [ebp-68h]
     ],     ;相对上面多偏移4字节
         uns[i].e[]= ENUM_4;
     mov eax,dword ptr [ebp-6Ch]
     imul eax,eax,0Ch
     mov ecx,dword ptr [ebp-68h]
     ],     ;相对上面再偏移4字节
     }
 )
     return ;
 004010A3    xor eax,eax
 }
 //省略现场恢复代码  

第一:从100字节缓存区的初始化可知,Debug版本的代码没经过优化,很stupid;第二:这两种类型的汇编访问方式同数组与结构体如出一辙,并没有什么不同。

《天书夜读:从汇编语言到windows内核编程》二 C语言的流程与处理的更多相关文章

  1. 《天书夜读:从汇编语言到windows内核编程》五 WDM驱动开发环境搭建

    (原书)所有内核空间共享,DriverEntery是内核程序入口,在内核程序被加载时,这个函数被调用,加载入的进程为system进程,xp下它的pid是4.内核程序的编写有一定的规则: 不能调用win ...

  2. 《天书夜读:从汇编语言到windows内核编程》八 文件操作与注册表操作

    1)Windows运用程序的文件与注册表操作进入R0层之后,都有对应的内核函数实现.在windows内核中,无论打开的是文件.注册表或者设备,都需要使用InitializeObjectAttribut ...

  3. 《天书夜读:从汇编语言到windows内核编程》六 驱动、设备、与请求

    1)跳入到基础篇的内核编程第7章,驱动入口函数DriverEnter的返回值决定驱动程序是否加载成功,当打算反汇编阅读驱动内核程序时,可寻找该位置. 2)DRIVER_OBJECT下的派遣函数(分发函 ...

  4. 《天书夜读:从汇编语言到windows内核编程》十一 用C++编写内核程序

    ---恢复内容开始--- 1) C++的"高级"特性,是它的优点也是它的缺点,微软对于使用C++写内核程序即不推崇也不排斥,使用C++写驱动需注意: a)New等操作符不能直接使用 ...

  5. 《天书夜读:从汇编语言到windows内核编程》四 windows内核调试环境搭建

    1) 基础篇是讲理论的,先跳过去,看不到代码运行的效果要去记代码是一个痛苦的事情.这里先跳入探索篇.其实今天的确也很痛苦,这作者对驱动开发的编译与调试环境介绍得太模糊了,我是各种尝试,对这个环境的搭建 ...

  6. 《天书夜读:从汇编语言到windows内核编程》十 线程与事件

    1)驱动中使用到的线程是系统线程,在system进程中.创建线程API函数:PsCreateSystemThread:结束线程(线程内自行调用)API函数:PsTerminateSystemThrea ...

  7. 《天书夜读:从汇编语言到windows内核编程》九 时间与定时器

    1)使用如下自定义函数获取自系统启动后经历的毫秒数:KeQueryTimeIncrement.KeQueryTickCount void MyGetTickCount(PULONG msec) { L ...

  8. 《天书夜读:从汇编语言到windows内核编程》七 内核字符串与内存

    1)驱动中的字符串使用如下结构: typedef struct _UNICODE_STRING{ USHORT Length; //字符串的长度(字节数) USHORT MaximumLength; ...

  9. 《天书夜读:从汇编语言到windows内核编程》三 练习反汇编C语言程序

    1) Debug版本算法反汇编,现有如下3×3矩阵相乘的程序: #define SIZE 3 int MyFunction(int a[SIZE][SIZE],int b[SIZE][SIZE],in ...

随机推荐

  1. Nginx详细安装部署教程

    一.Nginx简介 Nginx是一个web服务器也可以用来做负载均衡及反向代理使用,目前使用最多的就是负载均衡,具体简介我就不介绍了百度一下有很多,下面直接进入安装步骤 二.Nginx安装 1.下载N ...

  2. SAP 条形码

    使用系统生成的条形码 正常的排列;将扫描由左到右.旋转对齐将从上到下扫描90度倒立定线将扫描所180度从右到左底部对齐将从底部到顶部270度扫描 但在实际应用中,条形码的大小不仅与此处有关,也与字符格 ...

  3. NOIP初赛 之 哈夫曼树

    哈夫曼树 种根据我已刷的初赛题中基本每套的倒数第五或第六个不定项选择题就有一个关于哈夫曼树及其各种应用的题,占:0-1.5分:然而我针对这个类型的题也多次不会做,so,今晚好好研究下哈夫曼树: 概念: ...

  4. 媲美jQuery的JS框架——AngularJS(一)

    前言 相信原生JS大家都不陌生,至于为什么说原生,是因为在JS的基础上衍生出了很多的框架.有些框架的使用非常广泛,甚至已经达到了媲美原生的地步.在之前的文章中给大家介绍了jQuery这一介绍框架.今天 ...

  5. DevOps之归纳总结

    唠叨话 关于德语关我屁事的知识点,仅提供精华汇总,具体知识点细节,参考教程网址,如需帮助,请留言. DevOps归纳总结 <DevOps功能与性能>浏览器(饼干Cookie.会话Sessi ...

  6. JAVAEE企业级应用开发浅谈第二辑:MVC和三层架构

    上海尚学堂警句:一份信心,一份努力,一份成功:十分信心,十分努力,十分成功. Step1.情景概要 Hello,小伙伴们,昨天跟大家分享了JAVA EE 企业级应用开发中大家耳熟能详的概念-三层架构, ...

  7. 【转载】基于vw等viewport视区相对单位的响应式排版和布局

    文章转载自 张鑫旭-鑫空间-鑫生活 http://www.zhangxinxu.com/wordpress/ 原文链接:http://www.zhangxinxu.com/wordpress/?p=5 ...

  8. SAP的 消息 弹出窗口(备忘)

    DATA: i_smesg TYPE tsmesg WITH HEADER LINE. i_smesg-msgty = 'E'. i_smesg-arbgb = '. i_smesg-txtnr = ...

  9. 深入理解计算机系统(4.1)------Y86指令集体系结构

    本章我们将进入处理器体系结构介绍的神秘海洋中,我们熟悉的手机,电脑等设备的核心硬件都离不开处理器.处理器可以称的上是人类创造的最复杂的系统之一,一块手指大小的硅片,可以容纳一个完整的高性能处理器.大的 ...

  10. 从零开始搭建框架SSM+Redis+Mysql(二)之MAVEN项目搭建

    从零开始搭建框架SSM+Redis+Mysql(二)之MAVEN项目搭建 废话不说,直接撸步骤!!! 1.创建主项目:ncc-parent 选择maven创建项目,注意在创建项目中,packing选择 ...