张羿的CSDN专栏

CLR (Common Lanaguage Runtime) & Managed/Unmanaged Interop

用户操作
[即时聊天] [发私信] [加为好友]
张羿ID:ATField
153777次访问,排名499好友0人,关注者31
目前在微软公司从事CLR/.NET Framework的Interop功能(COM Interop, P/Invoke, Reverse P/Invoke)的开发工作。微软CLR上海开发团队的成员之一
ATField的文章
原创 89 篇
翻译 1 篇
转载 11 篇
评论 109 篇
张羿的公告
作者简介

目前在微软公司从事CLR(公共语言运行时,Common Language Runtime)的Interop功能(COM Interop, P/Invoke, Reverse P/Invoke...)的开发工作。微软CLR上海开发团队的成员之一

CLR上海开发团队Blog

联系方式

转载清注明作者和出处

我的其他Blog
我的MSDN Blog
最近评论
ATField:对于同时使用前置声明而出现Warning,同时又出现交叉引用的情况,我觉得可能比较合理的方法应该还是像你说的,修改设计,把Dependency移到其他的地方。
据我所知c++并没有指定类的特性的语法,通过模板可以支持一些类似的特性。似乎c++ 0x在计划加入一些这样的东西。Anyway,即使C++可以支持这样的特性,在编译的时候,c++仍然不知道destructor的实现在哪里,除……
Microsoft_China_Vip:



www.soAsp.net 编程学习网 技术+ 实例应用 讲解不错。 推荐大家!

有很多 技术资料也很好!


zhaoyang0618:要是能够引进国内就好了, 看英文的还是有些慢.
fuadam:不但免费了还是第二版,真是大好事
limzustc:#include方法会解决掉一部分情况,但对交叉引用的情况就不灵了,似乎只能修改类设计。博主对交叉引用的情况有什么好办法?

不知道C++中有没有类似C#中限定类特性的语法(比如指明该类有析构函数:))?
文章分类
收藏
    相册
    ACM & Algorithms
    Top Coder
    Ural Online Judge
    UVa Online Judge
    Blog Links
    Adam Nathan(RSS)
    BCL Team Blog(RSS)
    Chris Brumme(RSS)
    David Notario(RSS)
    Jeffrey Richter's Blog(RSS)
    Josh Williams(RSS)
    Junfeng Zhang(RSS)
    Mason Bendixen(RSS)
    Matt Pietrek's Blog(RSS)
    Mike Stall(RSS)
    Patrick Dussud(RSS)
    Raymond Chen's Blog(RSS)
    Scott Guthrie(RSS)
    Silverlight上海开发团队Blog(RSS)
    Suzanne Cook(RSS)
    Thottam R. Sriram(RSS)
    Varun Sekhri(RSS)
    VBCTI team blog(RSS)
    Yun Jin(RSS)
    Compilers
    GCC
    Java Hotspot VM
    Python
    www.compilers.net
    存档
    订阅我的博客
    XML聚合  FeedSky
    订阅到鲜果
    订阅到Google
    订阅到抓虾
    订阅到BlogLines
    订阅到Yahoo
    订阅到GouGou
    订阅到飞鸽
    订阅到Rojo
    订阅到newsgator
    订阅到netvibes

    原创 C++反汇编揭秘1 – 一个简单C++程序反汇编解析 (Rev. 3)收藏

    新一篇: Python源码分析1 - Building Python | 

    如果想要了解C++内部的实现原理,没有什么比观察C++代码对应的汇编代码来的更直接了。本系列主要从汇编角度研究C++代码和汇编的对应关系,揭示C++内部的机制和原理。在第一篇文章中我将从一个简单的C++程序着手快速解释一下C++反汇编代码的基本的结构和内容,相当于一个简单的Preview。而在后续的文章中,我将根据不同的Topic,详细解释C++代码对应的反汇编代码。

    一个简单的C++程序示例如下:

    class my_class

    {

    public :

        my_class()

        {

            m_member = 1;

        }

     

        void method(int n)

        {

            m_member = n;

        }

     

        ~my_class()

        {

            m_member = 0;

        }

     

    private :

        int m_member;

    };

     

    int _tmain(int argc, _TCHAR* argv[])

    {

        my_class a_class;

        a_class.method(10);

     

        return 0;

    }

    可以直接Debug的时候看到Assembly代码,不过这样获得的代码注释比较少。比较理想的方法是利用VC编译器的一个选项/FAs来生成对应的汇编代码。/FAs还会在汇编代码中加入注释注明和C++代码的对应关系,十分有助于分析。在VS2005中可以这样打开/FAs

    Build代码,可以在输出目录下发现对应的.ASM文件。本文将逐句分析汇编代码和C++的对应关系。

    首先是WinMain

    _TEXT SEGMENT

    _wmain      PROC

          push  ebp                                 ; 保存旧的ebp

          mov   ebp, esp                            ; ebp保存当前栈的位置

          push  -1                                  ; 建立SEH(Structured Exception Handler)

                                                    ; -1表示表头,没有Prev

          push  __ehhandler$_wmain                  ; SEH异常处理程序的地址

          mov   eax, DWORD PTR fs:0                 ; fs:0指向TEB的内容,头4个字节是当前SEH链的地址

          push  eax                                 ; 保存起来

          sub   esp, d8H                            ; 分配d8H字节的空间

          push  ebx

          push  esi

          push  edi

          lea   edi, DWORD PTR [ebp-e4H]            ; 确定局部变量的起始地址。e4H = d8H + 4 * 3,跳过之前建立SEH链所用的3个Push指令所占用的栈的空间,以及sub esp, d8h为局部变量分配的d8H字节空间

          mov   ecx, 36H                            ; 36H*4H=d8H,也就是用36HccccccccH填满刚才分配的d8H字节空间

          mov   eax, ccccccccH

          rep stosd

          mov   eax, DWORD PTR ___security_cookie  

          xor   eax, ebp   

          push  eax                                 ; ebp ^ __security_cookie压栈保存

          lea   eax, DWORD PTR [ebp-0cH]            ; ebp-0cH是之前main的起始代码中在堆栈中建立的SEH结构的首地址

          mov   DWORD PTR fs:0, eax                 ; 设置到TEB中作为当前ActiveSEH链表末尾

    到此为止栈的内容是这样的:

    低地址

    Security cookie after XOR

    Edi

    Esi

    Ebx

    Local stack: d8H

    Old fs:0

    __ehhandler$_wmain

    ffffffffH

    Old ebp

    高地址

    main接着后面调用my_class的构造函数

          lea   ecx, DWORD PTR [ebp-14H]

          call  ??0my_class@@QAE@XZ                 ; 调用my_class::my_class, ??my_class@@QAE@XZ是经过Name Mangling后的名字

          mov   DWORD PTR [ebp-4], 0                ; 进入__try块,在Main中有一个隐式的__try/__except

    接着调用my_class::method

          push  10                                  ; 参数入栈

          lea   ecx, DWORD PTR [ebp-14H]            ; 遵循thiscall调用协定,ecx存放的是this指针

          call  ?method@my_class@@QAEXH@Z           ; 调用子程序my_class:method(10)

    之后是析构:

          mov   DWORD PTR [ebp-e0H], 0              ; 用来放置返回值

          mov   DWORD PTR [ebp-4], -1               ; 标记TRY的正常结束

          lea   ecx, DWORD PTR [ebp-14H]            ; a_class的地址作为this存入ECX

          call  ??1my_class@@QAE@XZ                 ; my_class::~my_class

          mov   eax, DWORD PTR [ebp-e0H]            ; 返回值按照约定放入eax

    Main函数退出代码如下:

          push  edx

          mov   ecx, ebp

          push  eax

          lea   edx, DWORD PTR $LN7@wmain

          call  @_RTC_CheckStackVars@8              ; 检查栈

          pop   eax

          pop   edx

          mov   ecx, DWORD PTR [ebp-0cH]            ; 取出之前保存的旧的fs:0,并恢复

          mov   DWORD PTR fs:0, ecx

          pop   ecx

          pop   edi

          pop   esi

          pop   ebx

          add   esp, e4H                            ; 退掉分配的d8H + 建立SEH链所需的0cH字节

          cmp   ebp, esp

          call  __RTC_CheckEsp                      ; 检查esp值,这个时候esp应该和ebp匹配,否则说明出现了栈不平衡的情况,这种情况下调用子程序报错

          mov   esp, ebp                            ; 恢复ebpesp

          pop   ebp                                 ; 恢复原来的ebp

          ret   0

    _wmain      ENDP

    专门用于SEH的子程序。__unwindfunclet$_wmain$0当异常发生的时候被调,负责进行栈展开,主要是调用析构函数。__ehhandler$_wmain则是在exception被抛出的时候调用。

    Text$x      SEGMENT

    __unwindfunclet$_wmain$0:                       ; SEH发生的时候会调用该函数,析购a_class

          lea   ecx, DWORD PTR [ebp-14H]            ; ecx = [ebp – 14H],也就是a_class的地址

          jmp   ??1my_class@@QAE@XZ                 ; 调用my_class::~my_class

    __ehhandler$_wmain:

          mov   edx, DWORD PTR [esp+8]              ; esp = 当前的fs:0, [esp + 8] = 之前的SEH结构,也就是main中建立的

          lea   eax, DWORD PTR [edx+0cH]            ; edx + 0Ch = 当前的ebp,也就是mainebp,此时不能直接使用ebp因为可能会从任意函数调过来,此时ebp是该函数的ebp,而不是mainebp

          mov   ecx, DWORD PTR [edx-e0H]            ; 之前存下去的__security_cookie ^ ebp

          xor   ecx, eax                            ; 再次和ebp相异或

          call  @__security_check_cookie@4          ; 此时ecx应该等于__security_cookie,否则说明栈的内容被恶意改动(或者编程错误)

          mov   eax, OFFSET __ehfuncinfo$_wmain

          jmp   ___CxxFrameHandler3

    text$x      ENDS

    My_class::my_class构造函数如下。构造函数本质上就是一个全局函数,名字是经过打乱的(Name Mangling),这样可以和同一Class和其他Class的同名方法区别开来。不同编译器有不同规则,因此不必过于深究。

    _TEXT SEGMENT

    ??0my_class@@QAE@XZ PROC

          push  ebp                                 ; 保存旧的ebp

          mov   ebp, esp                            ; ebp保存当前栈的位置

          sub   esp, ccH                            ; 给栈分配ccH个字节

          push  ebx                                 ; 保存常用寄存器