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. # C语言程序设计预备作业

    一.针对老师和学生是怎样的关系的看法 ==首先我认同邹欣老师的看法,下面也是我自己的一点见解.== #### (1)师生在教育内容的教学上结成授受关系 .从教师与学生的社会角色规定意义上看,在知识上, ...

  2. VTL(Velocity Templates Language,即Velocity模板语言)初识语法总结

    1.velocity是一门基于Java语言的视图表现层模板引擎,它可以取代jsp,比jsp更高效. 2.velocity变量的定义与引用 (1).定义一个变量:#set ($a = "vel ...

  3. Python实战之列表简单练习

    ['__add__', '__class__', '__contains__', '__delattr__', '__delitem__', '__dir__', '__doc__', '__eq__ ...

  4. Python系列之多线程、多进程

    线程是操作系统直接支持的执行单元,因此,高级语言通常都内置多线程的支持,Python也不例外,并且,Python的线程是真正的Posix Thread,而不是模拟出来的线程. Python的标准库提供 ...

  5. DataGrid 如何得到DataGridRow 和DataGridCell 对象

    第一行为不可编辑  DataGridRow row = (DataGridRow)dataGrid1.ItemContainerGenerator.ContainerFromIndex(0);     ...

  6. 学习总结---OVS

    OVS的组成 OVS的匹配条件和动作 OVS的发展方向 OVS的实践 OVS与Namespace配合模拟租户之间的数据通信 基本思路: Namespace模拟出不同的主机,这些主机之间的通信需要通过S ...

  7. 【NOIP2012】提高组初赛试题(个人错题解析+相关知识点扩展)C++版

    初赛14号就要开始了,从今天到14号还有三天,已经请了两节的自习来刷题,每天三四套题,尽量把01年到16年的题目全刷一遍.[fighting!!!] 4.无论是TCP/IP模型还是OSI模型,都可以视 ...

  8. win10 uwp 兴趣线

    本文讲的是如何去做一个时间轴样子的东西但我们放的不一定是时间,可能是我们的时间.我把它放在我的CSDN阅读,我的界面做出来很差,但是应该读者能做出很漂亮的. 行间距 我们在ViewModel写一个Ob ...

  9. Java中数组的遍历

    (I)标准for循环遍历数组 例如代码片段: int [] nums = new int [] {0,1,2,3,4,5,6,7,8,9}; for(int i=0;i<11;i++){ Sys ...

  10. UVa437,The Tower of Babylon

    转:http://blog.csdn.net/wangtaoking1/article/details/7308275 题意为输入若干种立方体(每种若干个),然后将立方体堆成一个塔,要求接触的两个面下 ...