env:
g++-4.6.real (Ubuntu/Linaro 4.6.3-1ubuntu5) 4.6.3
Ubuntu/Linaro x86 32bit
看了
ptt [問題] 關於Class指標的觀念 系列的文章讓我想
知道  member function pointer 有什麼不一樣的地方。
c.cpp non-virtual member funcion  1  #include <cstdio>   2  
 3  using  namespace  std ; 
 4  
 5      struct  A  {  6          void  func ( )  
 7          {  8            printf ( "i: %d\n " , i_ ) ; 
 9          } 10          void  inc ( ) 
11          { 12            + + i_ ;  
13          } 14          A ( ) 
15          { 16            i_ = 10 ;  
17          } 18          private : 
19            int  i_ ; 
20      } ; 
21  
22  typedef  void  ( A : : * MF ) ( ) ; 
23  
24  int  main ( ) 
25  { 26  
27    void  ( A : : * p ) ( )  =  & A : : func ; 
28    A  a ; 
29    A  aa ; 
30    ( a .* p ) ( ) ; 
31    a .inc ( ) ; 
32  
33    MF  mf  =  & A : : func ; 
34     
35    unsigned  int  addr  =  * ( ( unsigned  int * ) & p ) ; 
36  
37    ( * ( void ( * ) ( ) ) ( addr )  ) ( ) ; 
38    ( * ( void ( * ) ( A * ) ) ( addr )  ) ( & aa ) ; 
39    aa .func ( ) ; 
40  
41    ( MF ) addr ; 
42  
43  
44  
45  
46  
47  #if 1 48    printf ( "p: %p\n " , p ) ; 
49    printf ( "addr: %x\n " , addr ) ; 
50  #endif 51    return  0 ; 
52  }  
http://www.parashift.com/c++-faq-lite/cant-cvt-memfnptr-to-voidptr.html 
看來無法將 void* 轉 member function pointer。
我用的方法其實是把 member function 當成 non member function, 再把 this 傳進去。
那麼為什麼不能轉?
void (A::*p)() = &A::func;
這個指標 assign 的動作原來有兩個部份, non-virtual function 
剛好 可以這樣作。
non-virtual member function:
80486d1:       c7 44 24 14 b4 86 04    movl   $0x80486b4,0x14(%esp)
80486d8:       08
80486d9:       c7 44 24 18 00 00 00    movl   $0x0,0x18(%esp)
80486e0:       00
virtual member function:
804873f:       c7 44 24 14 01 00 00    movl   $0x1,0x14(%esp)
8048746:       00
8048747:       c7 44 24 18 00 00 00    movl   $0x0,0x18(%esp)
804874e:       0
ref 2 提到:
(&a)->func()
被 c++ 編譯器轉成
 (*a->vptr[1])(&a)
只討論 virtual member function, 這個 member function pointer 只存了 1 和 0 這兩個值, 想靠著 1, 0 這兩個資料去找到 A::func() 是不可能的, 所以就算你想了很多辦法轉型成功, 還是得要拿到 virtual table 進而找到 A::func(), 找到 A::func() 的位址還怕不能執行嗎?
c.cpp virtual member funcion  1  #include <iostream>   2  #include <cstdio>   3  
 4  using  namespace  std ; 
 5  
 6  struct  A  
 7  {  8      virtual void  func ( )  
 9      { 10        printf ( "i: %d\n " , i_ ) ; 
11      } 12      void  inc ( ) 
13      { 14        + + i_ ;  
15      } 16      A ( ) 
17      { 18        i_ = 10 ;  
19      } 20      private : 
21        int  i_ ; 
22  } ; 
23  
24  
25  int  main ( ) 
26  { 27    void  ( A : : * p ) ( )  =  & A : : func ; 
28  
29    //cout << "sizeof: " << sizeof(p) << endl; 
30  
31    //cout << "sizeof: " << sizeof(A) << endl; 
32  
33    //printf("addr: %p\n", p); 
34    //cout << "p:" << p << endl; 
35    //unsigned int addr = pp; 
36    //printf("addr: %p\n", pp); 
37  
38    
39    A  a ; 
40    ( a .* p ) ( ) ; 
41  
42    unsigned  int  vptr_addr  =  * ( unsigned  int  * ) & a ; 
43    cout  < <  "vptr_addr:"  < <  hex  < <  vptr_addr  < <  endl ; 
44      
45    unsigned  int  func_addr  =  * ( unsigned  int  * ) vptr_addr ; 
46    cout  < <  "func_addr:"  < <  hex  < <  func_addr  < <  endl ; 
47    a .inc ( ) ; 
48    ( * ( void ( * ) ( A * ) ) ( func_addr )  ) ( & a ) ; 
49  
50    A  aa ; 
51    ( * ( void ( * ) ( A * ) ) ( func_addr )  ) ( & aa ) ; 
52  
53    ( * ( void ( * ) ( A * ) ) ( func_addr )  ) ( & a ) ; 
54  
55    ( * ( void ( * ) ( A * ) ) ( func_addr )  ) ( & aa ) ; 
56  
57    return  0 ; 
58  }  
g++ -g -m32 c.cpp -o c
ideone 執行結果:
http://ideone.com/KLP0gG 
objdump -Sd c   1  
  2  c:     file format elf32-i386
  3  
  4  
  5  Disassembly of section .init:
  6  
  7  08048578 <_init>:
  8   8048578: 53                    push   %ebx
  9   8048579: 83 ec 08              sub    $0x8,%esp
 10   804857c: e8 00 00 00 00        call   8048581 <_init+0x9>
 11   8048581: 5b                    pop    %ebx
 12   8048582: 81 c3 73 1a 00 00     add    $0x1a73,%ebx
 13   8048588: 8b 83 fc ff ff ff     mov    -0x4(%ebx),%eax
 14   804858e: 85 c0                 test   %eax,%eax
 15   8048590: 74 05                 je     8048597 <_init+0x1f>
 16   8048592: e8 39 00 00 00        call   80485d0 <__gmon_start__@plt>
 17   8048597: e8 64 01 00 00        call   8048700 <frame_dummy>
 18   804859c: e8 df 04 00 00        call   8048a80 <__do_global_ctors_aux>
 19   80485a1: 83 c4 08              add    $0x8,%esp
 20   80485a4: 5b                    pop    %ebx
 21   80485a5: c3                    ret    
 22  
 23  Disassembly of section .plt:
 24  
 75  
 76  08048650 <_ZSt4endlIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_@plt>:
 77   8048650: ff 25 24 a0 04 08     jmp    *0x804a024
 78   8048656: 68 48 00 00 00        push   $0x48
 79   804865b: e9 50 ff ff ff        jmp    80485b0 <_init+0x38>
 80  
 81  08048660 <_ZNSolsEPFRSt8ios_baseS0_E@plt>:
 82   8048660: ff 25 28 a0 04 08     jmp    *0x804a028
 83   8048666: 68 50 00 00 00        push   $0x50
 84   804866b: e9 40 ff ff ff        jmp    80485b0 <_init+0x38>
 85  
 86  Disassembly of section .text:
 87  
117  
118  080486a0 <__do_global_dtors_aux>:
119   80486a0: 55                    push   %ebp
120   80486a1: 89 e5                 mov    %esp,%ebp
121   80486a3: 53                    push   %ebx
122   80486a4: 83 ec 04              sub    $0x4,%esp
123   80486a7: 80 3d 0c a1 04 08 00  cmpb   $0x0,0x804a10c
124   80486ae: 75 3f                 jne    80486ef <__do_global_dtors_aux+0x4f>
125   80486b0: a1 10 a1 04 08        mov    0x804a110,%eax
126   80486b5: bb 08 9f 04 08        mov    $0x8049f08,%ebx
127   80486ba: 81 eb 04 9f 04 08     sub    $0x8049f04,%ebx
128   80486c0: c1 fb 02              sar    $0x2,%ebx
129   80486c3: 83 eb 01              sub    $0x1,%ebx
130   80486c6: 39 d8                 cmp    %ebx,%eax
131   80486c8: 73 1e                 jae    80486e8 <__do_global_dtors_aux+0x48>
132   80486ca: 8d b6 00 00 00 00     lea    0x0(%esi),%esi
133   80486d0: 83 c0 01              add    $0x1,%eax
134   80486d3: a3 10 a1 04 08        mov    %eax,0x804a110
135   80486d8: ff 14 85 04 9f 04 08  call   *0x8049f04(,%eax,4)
136   80486df: a1 10 a1 04 08        mov    0x804a110,%eax
137   80486e4: 39 d8                 cmp    %ebx,%eax
138   80486e6: 72 e8                 jb     80486d0 <__do_global_dtors_aux+0x30>
139   80486e8: c6 05 0c a1 04 08 01  movb   $0x1,0x804a10c
140   80486ef: 83 c4 04              add    $0x4,%esp
141   80486f2: 5b                    pop    %ebx
142   80486f3: 5d                    pop    %ebp
143   80486f4: c3                    ret    
144   80486f5: 8d 74 26 00           lea    0x0(%esi,%eiz,1),%esi
145   80486f9: 8d bc 27 00 00 00 00  lea    0x0(%edi,%eiz,1),%edi
146  
147  08048700 <frame_dummy>:
148   8048700: 55                    push   %ebp
149   8048701: 89 e5                 mov    %esp,%ebp
150   8048703: 83 ec 18              sub    $0x18,%esp
151   8048706: a1 0c 9f 04 08        mov    0x8049f0c,%eax
152   804870b: 85 c0                 test   %eax,%eax
153   804870d: 74 12                 je     8048721 <frame_dummy+0x21>
154   804870f: b8 00 00 00 00        mov    $0x0,%eax
155   8048714: 85 c0                 test   %eax,%eax
156   8048716: 74 09                 je     8048721 <frame_dummy+0x21>
157   8048718: c7 04 24 0c 9f 04 08  movl   $0x8049f0c,(%esp)
158   804871f: ff d0                 call   *%eax
159   8048721: c9                    leave  
160   8048722: c3                    ret    
161   8048723: 90                    nop
162  
163  08048724 <main>:
164        int i_;
165  };
166  
167  
168  int main()
169  {
170   8048724: 55                    push   %ebp
171   8048725: 89 e5                 mov    %esp,%ebp
172   8048727: 83 e4 f0              and    $0xfffffff0,%esp
173   804872a: 83 ec 30              sub    $0x30,%esp
174    void (A::*p)() = &A::func;
175   804872d: c7 44 24 10 01 00 00  movl   $0x1,0x10(%esp)
176   8048734: 00 
177   8048735: c7 44 24 14 00 00 00  movl   $0x0,0x14(%esp)
178   804873c: 00 
179    //cout << "p:" << p << endl;
180    //unsigned int addr = pp;
181    //printf("addr: %p\n", pp);
182  
183    
184    A a;
185   804873d: 8d 44 24 18           lea    0x18(%esp),%eax
186   8048741: 89 04 24              mov    %eax,(%esp)
187   8048744: e8 9d 02 00 00        call   80489e6 <_ZN1AC1Ev>188    (a.*p)();
189   8048749: 8b 44 24 10           mov    0x10(%esp),%eax
190   804874d: 83 e0 01              and    $0x1,%eax
191   8048750: 84 c0                 test   %al,%al
192   8048752: 74 19                 je     804876d <main+0x49>
193   8048754: 8b 44 24 14           mov    0x14(%esp),%eax
194   8048758: 8d 54 24 18           lea    0x18(%esp),%edx
195   804875c: 01 d0                 add    %edx,%eax
196   804875e: 8b 10                 mov    (%eax),%edx
197   8048760: 8b 44 24 10           mov    0x10(%esp),%eax
198   8048764: 83 e8 01              sub    $0x1,%eax
199   8048767: 01 d0                 add    %edx,%eax
200   8048769: 8b 00                 mov    (%eax),%eax
201   804876b: eb 04                 jmp    8048771 <main+0x4d>
202   804876d: 8b 44 24 10           mov    0x10(%esp),%eax
203   8048771: 8b 54 24 14           mov    0x14(%esp),%edx
204   8048775: 8d 4c 24 18           lea    0x18(%esp),%ecx
205   8048779: 01 ca                 add    %ecx,%edx
206   804877b: 89 14 24              mov    %edx,(%esp)
207   804877e: ff d0                 call   *%eax208  
209    unsigned int vptr_addr = *(unsigned int *)&a;
210   8048780: 8d 44 24 18           lea    0x18(%esp),%eax
211   8048784: 8b 00                 mov    (%eax),%eax
212   8048786: 89 44 24 28           mov    %eax,0x28(%esp)
213    cout << "vptr_addr:" << hex << vptr_addr << endl;
214   804878a: c7 44 24 04 d7 8a 04  movl   $0x8048ad7,0x4(%esp)
215   8048791: 08 
216   8048792: c7 04 24 80 a0 04 08  movl   $0x804a080,(%esp)
217   8048799: e8 72 fe ff ff        call   8048610 <_ZStlsISt11char_traitsIcEERSt13basic_ostreamIcT_ES5_PKc@plt>
218   804879e: c7 44 24 04 8d 89 04  movl   $0x804898d,0x4(%esp)
219   80487a5: 08 
220   80487a6: 89 04 24              mov    %eax,(%esp)
221   80487a9: e8 b2 fe ff ff        call   8048660 <_ZNSolsEPFRSt8ios_baseS0_E@plt>
222   80487ae: 8b 54 24 28           mov    0x28(%esp),%edx
223   80487b2: 89 54 24 04           mov    %edx,0x4(%esp)
224   80487b6: 89 04 24              mov    %eax,(%esp)
225   80487b9: e8 72 fe ff ff        call   8048630 <_ZNSolsEj@plt>
226   80487be: c7 44 24 04 50 86 04  movl   $0x8048650,0x4(%esp)
227   80487c5: 08 
228   80487c6: 89 04 24              mov    %eax,(%esp)
229   80487c9: e8 72 fe ff ff        call   8048640 <_ZNSolsEPFRSoS_E@plt>
230      
231    unsigned int func_addr = *(unsigned int *)vptr_addr;
232   80487ce: 8b 44 24 28           mov    0x28(%esp),%eax
233   80487d2: 8b 00                 mov    (%eax),%eax
234   80487d4: 89 44 24 2c           mov    %eax,0x2c(%esp)
235    cout << "func_addr:" << hex << func_addr << endl;
236   80487d8: c7 44 24 04 e2 8a 04  movl   $0x8048ae2,0x4(%esp)
237   80487df: 08 
238   80487e0: c7 04 24 80 a0 04 08  movl   $0x804a080,(%esp)
239   80487e7: e8 24 fe ff ff        call   8048610 <_ZStlsISt11char_traitsIcEERSt13basic_ostreamIcT_ES5_PKc@plt>
240   80487ec: c7 44 24 04 8d 89 04  movl   $0x804898d,0x4(%esp)
241   80487f3: 08 
242   80487f4: 89 04 24              mov    %eax,(%esp)
243   80487f7: e8 64 fe ff ff        call   8048660 <_ZNSolsEPFRSt8ios_baseS0_E@plt>
244   80487fc: 8b 54 24 2c           mov    0x2c(%esp),%edx
245   8048800: 89 54 24 04           mov    %edx,0x4(%esp)
246   8048804: 89 04 24              mov    %eax,(%esp)
247   8048807: e8 24 fe ff ff        call   8048630 <_ZNSolsEj@plt>
248   804880c: c7 44 24 04 50 86 04  movl   $0x8048650,0x4(%esp)
249   8048813: 08 
250   8048814: 89 04 24              mov    %eax,(%esp)
251   8048817: e8 24 fe ff ff        call   8048640 <_ZNSolsEPFRSoS_E@plt>
252    a.inc();
253   804881c: 8d 44 24 18           lea    0x18(%esp),%eax
254   8048820: 89 04 24              mov    %eax,(%esp)
255   8048823: e8 aa 01 00 00        call   80489d2 <_ZN1A3incEv>
256    (*(void(*)(A*))(func_addr) )(&a);
257   8048828: 8b 54 24 2c           mov    0x2c(%esp),%edx
258   804882c: 8d 44 24 18           lea    0x18(%esp),%eax
259   8048830: 89 04 24              mov    %eax,(%esp)
260   8048833: ff d2                 call   *%edx
261  
262    A aa;
263   8048835: 8d 44 24 20           lea    0x20(%esp),%eax
264   8048839: 89 04 24              mov    %eax,(%esp)
265   804883c: e8 a5 01 00 00        call   80489e6 <_ZN1AC1Ev>
266    (*(void(*)(A*))(func_addr) )(&aa);
267   8048841: 8b 54 24 2c           mov    0x2c(%esp),%edx
268   8048845: 8d 44 24 20           lea    0x20(%esp),%eax
269   8048849: 89 04 24              mov    %eax,(%esp)
270   804884c: ff d2                 call   *%edx
271  
272    (*(void(*)(A*))(func_addr) )(&a);
273   804884e: 8b 54 24 2c           mov    0x2c(%esp),%edx
274   8048852: 8d 44 24 18           lea    0x18(%esp),%eax
275   8048856: 89 04 24              mov    %eax,(%esp)
276   8048859: ff d2                 call   *%edx
277  
278    (*(void(*)(A*))(func_addr) )(&aa);
279   804885b: 8b 54 24 2c           mov    0x2c(%esp),%edx
280   804885f: 8d 44 24 20           lea    0x20(%esp),%eax
281   8048863: 89 04 24              mov    %eax,(%esp)
282   8048866: ff d2                 call   *%edx
283  
284    return 0;
285   8048868: b8 00 00 00 00        mov    $0x0,%eax
286  }
287   804886d: c9                    leave  
288   804886e: c3                    ret    
289  
290  0804886f <_Z41__static_initialization_and_destruction_0ii>:
291   804886f: 55                    push   %ebp
292   8048870: 89 e5                 mov    %esp,%ebp
293   8048872: 83 ec 18              sub    $0x18,%esp
294   8048875: 83 7d 08 01           cmpl   $0x1,0x8(%ebp)
295   8048879: 75 32                 jne    80488ad <_Z41__static_initialization_and_destruction_0ii+0x3e>
296   804887b: 81 7d 0c ff ff 00 00  cmpl   $0xffff,0xc(%ebp)
297   8048882: 75 29                 jne    80488ad <_Z41__static_initialization_and_destruction_0ii+0x3e>
298    extern wostream wclog; /// Linked to standard error (buffered)
299  #endif
300    //@}
301  
302    // For construction of filebuffers for cout, cin, cerr, clog et. al.
303    static ios_base::Init __ioinit;
304   8048884: c7 04 24 14 a1 04 08  movl   $0x804a114,(%esp)
305   804888b: e8 50 fd ff ff        call   80485e0 <_ZNSt8ios_base4InitC1Ev@plt>
306   8048890: b8 00 86 04 08        mov    $0x8048600,%eax
307   8048895: c7 44 24 08 30 a0 04  movl   $0x804a030,0x8(%esp)
308   804889c: 08 
309   804889d: c7 44 24 04 14 a1 04  movl   $0x804a114,0x4(%esp)
310   80488a4: 08 
311   80488a5: 89 04 24              mov    %eax,(%esp)
312   80488a8: e8 13 fd ff ff        call   80485c0 <__cxa_atexit@plt>
313   80488ad: c9                    leave  
314   80488ae: c3                    ret    
315  
316  080488af <_GLOBAL__sub_I_main>:
317   80488af: 55                    push   %ebp
318   80488b0: 89 e5                 mov    %esp,%ebp
319   80488b2: 83 ec 18              sub    $0x18,%esp
320   80488b5: c7 44 24 04 ff ff 00  movl   $0xffff,0x4(%esp)
321   80488bc: 00 
322   80488bd: c7 04 24 01 00 00 00  movl   $0x1,(%esp)
323   80488c4: e8 a6 ff ff ff        call   804886f <_Z41__static_initialization_and_destruction_0ii>
324   80488c9: c9                    leave  
325   80488ca: c3                    ret    
326  
327  080488cb <_ZStanSt13_Ios_FmtflagsS_>:
328        _S_ios_fmtflags_end = 1L << 16 
329      };
330  
331    inline _GLIBCXX_CONSTEXPR _Ios_Fmtflags
332    operator&(_Ios_Fmtflags __a, _Ios_Fmtflags __b)
333    { return _Ios_Fmtflags(static_cast<int>(__a) & static_cast<int>(__b)); }
334   80488cb: 55                    push   %ebp
335   80488cc: 89 e5                 mov    %esp,%ebp
336   80488ce: 8b 55 08              mov    0x8(%ebp),%edx
337   80488d1: 8b 45 0c              mov    0xc(%ebp),%eax
338   80488d4: 21 d0                 and    %edx,%eax
339   80488d6: 5d                    pop    %ebp
340   80488d7: c3                    ret    
341  
342  080488d8 <_ZStorSt13_Ios_FmtflagsS_>:
343  
344    inline _GLIBCXX_CONSTEXPR _Ios_Fmtflags
345    operator|(_Ios_Fmtflags __a, _Ios_Fmtflags __b)
346    { return _Ios_Fmtflags(static_cast<int>(__a) | static_cast<int>(__b)); }
347   80488d8: 55                    push   %ebp
348   80488d9: 89 e5                 mov    %esp,%ebp
349   80488db: 8b 55 08              mov    0x8(%ebp),%edx
350   80488de: 8b 45 0c              mov    0xc(%ebp),%eax
351   80488e1: 09 d0                 or     %edx,%eax
352   80488e3: 5d                    pop    %ebp
353   80488e4: c3                    ret    
354  
355  080488e5 <_ZStcoSt13_Ios_Fmtflags>:
356    operator^(_Ios_Fmtflags __a, _Ios_Fmtflags __b)
357    { return _Ios_Fmtflags(static_cast<int>(__a) ^ static_cast<int>(__b)); }
358  
359    inline _GLIBCXX_CONSTEXPR _Ios_Fmtflags
360    operator~(_Ios_Fmtflags __a)
361    { return _Ios_Fmtflags(~static_cast<int>(__a)); }
362   80488e5: 55                    push   %ebp
363   80488e6: 89 e5                 mov    %esp,%ebp
364   80488e8: 8b 45 08              mov    0x8(%ebp),%eax
365   80488eb: f7 d0                 not    %eax
366   80488ed: 5d                    pop    %ebp
367   80488ee: c3                    ret    
368  
369  080488ef <_ZStoRRSt13_Ios_FmtflagsS_>:
370  
371    inline const _Ios_Fmtflags&
372    operator|=(_Ios_Fmtflags& __a, _Ios_Fmtflags __b)
373    { return __a = __a | __b; }
374   80488ef: 55                    push   %ebp
375   80488f0: 89 e5                 mov    %esp,%ebp
376   80488f2: 83 ec 18              sub    $0x18,%esp
377   80488f5: 8b 45 08              mov    0x8(%ebp),%eax
378   80488f8: 8b 00                 mov    (%eax),%eax
379   80488fa: 8b 55 0c              mov    0xc(%ebp),%edx
380   80488fd: 89 54 24 04           mov    %edx,0x4(%esp)
381   8048901: 89 04 24              mov    %eax,(%esp)
382   8048904: e8 cf ff ff ff        call   80488d8 <_ZStorSt13_Ios_FmtflagsS_>
383   8048909: 8b 55 08              mov    0x8(%ebp),%edx
384   804890c: 89 02                 mov    %eax,(%edx)
385   804890e: 8b 45 08              mov    0x8(%ebp),%eax
386   8048911: c9                    leave  
387   8048912: c3                    ret    
388  
389  08048913 <_ZStaNRSt13_Ios_FmtflagsS_>:
390  
391    inline const _Ios_Fmtflags&
392    operator&=(_Ios_Fmtflags& __a, _Ios_Fmtflags __b)
393    { return __a = __a & __b; }
394   8048913: 55                    push   %ebp
395   8048914: 89 e5                 mov    %esp,%ebp
396   8048916: 83 ec 18              sub    $0x18,%esp
397   8048919: 8b 45 08              mov    0x8(%ebp),%eax
398   804891c: 8b 00                 mov    (%eax),%eax
399   804891e: 8b 55 0c              mov    0xc(%ebp),%edx
400   8048921: 89 54 24 04           mov    %edx,0x4(%esp)
401   8048925: 89 04 24              mov    %eax,(%esp)
402   8048928: e8 9e ff ff ff        call   80488cb <_ZStanSt13_Ios_FmtflagsS_>
403   804892d: 8b 55 08              mov    0x8(%ebp),%edx
404   8048930: 89 02                 mov    %eax,(%edx)
405   8048932: 8b 45 08              mov    0x8(%ebp),%eax
406   8048935: c9                    leave  
407   8048936: c3                    ret    
408   8048937: 90                    nop
409  
410  08048938 <_ZNSt8ios_base4setfESt13_Ios_FmtflagsS0_>:
411       *
412       *  This function clears @a mask in the format flags, then sets
413       *  @a fmtfl @c & @a mask.  An example mask is @c ios_base::adjustfield.
414      */
415      fmtflags
416      setf(fmtflags __fmtfl, fmtflags __mask)
417   8048938: 55                    push   %ebp
418   8048939: 89 e5                 mov    %esp,%ebp
419   804893b: 83 ec 28              sub    $0x28,%esp
420      {
421        fmtflags __old = _M_flags;
422   804893e: 8b 45 08              mov    0x8(%ebp),%eax
423   8048941: 8b 40 0c              mov    0xc(%eax),%eax
424   8048944: 89 45 f4              mov    %eax,-0xc(%ebp)
425        _M_flags &= ~__mask;
426   8048947: 8b 45 10              mov    0x10(%ebp),%eax
427   804894a: 89 04 24              mov    %eax,(%esp)
428   804894d: e8 93 ff ff ff        call   80488e5 <_ZStcoSt13_Ios_Fmtflags>
429   8048952: 8b 55 08              mov    0x8(%ebp),%edx
430   8048955: 83 c2 0c              add    $0xc,%edx
431   8048958: 89 44 24 04           mov    %eax,0x4(%esp)
432   804895c: 89 14 24              mov    %edx,(%esp)
433   804895f: e8 af ff ff ff        call   8048913 <_ZStaNRSt13_Ios_FmtflagsS_>
434        _M_flags |= (__fmtfl & __mask);
435   8048964: 8b 45 10              mov    0x10(%ebp),%eax
436   8048967: 89 44 24 04           mov    %eax,0x4(%esp)
437   804896b: 8b 45 0c              mov    0xc(%ebp),%eax
438   804896e: 89 04 24              mov    %eax,(%esp)
439   8048971: e8 55 ff ff ff        call   80488cb <_ZStanSt13_Ios_FmtflagsS_>
440   8048976: 8b 55 08              mov    0x8(%ebp),%edx
441   8048979: 83 c2 0c              add    $0xc,%edx
442   804897c: 89 44 24 04           mov    %eax,0x4(%esp)
443   8048980: 89 14 24              mov    %edx,(%esp)
444   8048983: e8 67 ff ff ff        call   80488ef <_ZStoRRSt13_Ios_FmtflagsS_>
445        return __old;
446   8048988: 8b 45 f4              mov    -0xc(%ebp),%eax
447      }
448   804898b: c9                    leave  
449   804898c: c3                    ret    
450  
451  0804898d <_ZSt3hexRSt8ios_base>:
452    }
453  
454    /// Calls base.setf(ios_base::hex, ios_base::basefield).
455    inline ios_base&
456    hex(ios_base& __base)
457    {
458   804898d: 55                    push   %ebp
459   804898e: 89 e5                 mov    %esp,%ebp
460   8048990: 83 ec 18              sub    $0x18,%esp
461      __base.setf(ios_base::hex, ios_base::basefield);
462   8048993: c7 44 24 08 4a 00 00  movl   $0x4a,0x8(%esp)
463   804899a: 00 
464   804899b: c7 44 24 04 08 00 00  movl   $0x8,0x4(%esp)
465   80489a2: 00 
466   80489a3: 8b 45 08              mov    0x8(%ebp),%eax
467   80489a6: 89 04 24              mov    %eax,(%esp)
468   80489a9: e8 8a ff ff ff        call   8048938 <_ZNSt8ios_base4setfESt13_Ios_FmtflagsS0_>
469      return __base;
470   80489ae: 8b 45 08              mov    0x8(%ebp),%eax
471    }
472   80489b1: c9                    leave  
473   80489b2: c3                    ret    
474   80489b3: 90                    nop
475  
476  080489b4 <_ZN1A4funcEv>:
477  
478  using namespace std;
479  
480  struct A 
481  {
482      virtual void func() 
483   80489b4: 55                    push   %ebp
484   80489b5: 89 e5                 mov    %esp,%ebp
485   80489b7: 83 ec 18              sub    $0x18,%esp
486      {
487        printf("i: %d\n", i_);
488   80489ba: 8b 45 08              mov    0x8(%ebp),%eax
489   80489bd: 8b 40 04              mov    0x4(%eax),%eax
490   80489c0: 89 44 24 04           mov    %eax,0x4(%esp)
491   80489c4: c7 04 24 d0 8a 04 08  movl   $0x8048ad0,(%esp)
492   80489cb: e8 50 fc ff ff        call   8048620 <printf@plt>
493      }
494   80489d0: c9                    leave  
495   80489d1: c3                    ret    
496  
497  080489d2 <_ZN1A3incEv>:
498      void inc()
499   80489d2: 55                    push   %ebp
500   80489d3: 89 e5                 mov    %esp,%ebp
501      {
502        ++i_; 
503   80489d5: 8b 45 08              mov    0x8(%ebp),%eax
504   80489d8: 8b 40 04              mov    0x4(%eax),%eax
505   80489db: 8d 50 01              lea    0x1(%eax),%edx
506   80489de: 8b 45 08              mov    0x8(%ebp),%eax
507   80489e1: 89 50 04              mov    %edx,0x4(%eax)
508      }
509   80489e4: 5d                    pop    %ebp
510   80489e5: c3                    ret    
511  
512  080489e6 <_ZN1AC1Ev>:
513      A()
514   80489e6: 55                    push   %ebp
515   80489e7: 89 e5                 mov    %esp,%ebp
516      {
517   80489e9: 8b 45 08              mov    0x8(%ebp),%eax
518   80489ec: c7 00 f8 8a 04 08     movl   $0x8048af8,(%eax)
519        i_=10; 
520   80489f2: 8b 45 08              mov    0x8(%ebp),%eax
521   80489f5: c7 40 04 0a 00 00 00  movl   $0xa,0x4(%eax)
522      }
523   80489fc: 5d                    pop    %ebp
524   80489fd: c3                    ret    
525   80489fe: 90                    nop
526   80489ff: 90                    nop
527  
 
L185 0x18(%esp) 這是 object a 的位址, 為於 stack。
L185 ~ 187 在建構 a, L188 ~ 207 在使用那個 member function pointer。
L187 call A::A() 會設定 virtual table 的位址。
518   80489ec: c7 00 f8 8a 04 08     movl   $0x8048af8,(%eax)
0x8048af8 這就是 vtable 的位址, 查這位址的內容就會看到 A::func() 的位址。
non-virtual member funtion 和 virtual member funtion 基本原理都一樣, 找到 A::func() address, 然後把 &aa 或是 &a 傳進去即可。
virtual member function:
 void (A::*p)() = &A::func;
 804873f:       c7 44 24 14 01 00 00    movl   $0x1,0x14(%esp)
 8048746:       00
 8048747:       c7 44 24 18 00 00 00    movl   $0x0,0x18(%esp)
 804874e:       0
不過我沒搞懂這兩部份是用來幹嘛的?
Member Function Pointers and the Fastest Possible C++ Delegates 對於苦惱這文章的朋友來說可以參考 "深度探索 C++ 物件模型": Virtual member function 這節在介紹這個, 簡單兩頁的介紹就足以解除大部份的疑惑。
深度探索 C++ 物件模型 (繁體版本) p178 ~ p181 提供了更多的資訊。member function pointer 為了支援多重繼承和虛擬繼承, 才會需要這些欄位。
也需要一些手法來判斷這個 member function pointer 是位址還是 index value。
有了這些知識, 應該容易參閱各家編譯器實作的反組譯程式碼。 
ptt Feis 的作法, 不過我看不懂
http://ideone.com/tXALVS  
VC++ 的版本 
env:
vc2010
winxp 32bit
vc 這個要 thiscall (ptt purpose 提供)
http://en.wikipedia.org/wiki/X86_calling_conventions#thiscall 
c.cpp  1  #include <iostream>   2  #include <cstdio>   3  
 4  using  namespace  std ; 
 5  
 6  struct  A  
 7  {  8      virtual  void  func ( )  
 9      { 10        printf ( "i: %d\n " , i_ ) ; 
11      } 12      void  inc ( ) 
13      { 14        + + i_ ;  
15      } 16      A ( ) 
17      { 18        i_ = 10 ;  
19      } 20      private : 
21        int  i_ ; 
22  } ; 
23  
24  
25  int  main ( ) 
26  { 27    void  ( A : : * p ) ( )  =  & A : : func ; 
28  
29    //cout << "sizeof: " << sizeof(p) << endl; 
30  
31    //cout << "sizeof: " << sizeof(A) << endl; 
32  
33    //printf("addr: %p\n", p); 
34    //cout << "p:" << p << endl; 
35    //unsigned int addr = pp; 
36    //printf("addr: %p\n", pp); 
37  
38    
39    A  a ; 
40    ( a .* p ) ( ) ; 
41  
42    unsigned  int  vptr_addr  =  * ( unsigned  int  * ) & a ; 
43    cout  < <  "vptr_addr:"  < <  hex  < <  vptr_addr  < <  endl ; 
44      
45    unsigned  int  func_addr  =  * ( unsigned  int  * ) vptr_addr ; 
46    cout  < <  "func_addr:"  < <  hex  < <  func_addr  < <  endl ; 
47    a .inc ( ) ; 
48  
49    __asm  
50    { 51      lea  ecx , a 
52    } 53  #if 1 54    ( * ( void ( * ) ( ) ) ( func_addr )  ) ( ) ; 
55  
56    A  aa ; 
57    __asm  
58    { 59      lea  ecx , aa 
60    } 61    ( * ( void ( * ) ( ) ) ( func_addr )  ) ( ) ; 
62  
63    __asm  
64    { 65      lea  ecx , a 
66    } 67    ( * ( void ( * ) ( ) ) ( func_addr )  ) ( ) ; 
68  
69    __asm  
70    { 71      lea  ecx , aa 
72    } 73    ( * ( void ( * ) ( ) ) ( func_addr )  ) ( ) ; 
74  #endif 75    return  0 ; 
76  }  
C:\>cl  c.cpp
Microsoft (R) 32-bit C/C++ Optimizing Compiler Version 16.00.30319.01 for 80x86
Copyright (C) Microsoft Corporation.  All rights reserved.
c.cpp
C:\Program Files\Microsoft Visual Studio 10.0\VC\INCLUDE\xlocale(323) : warning
C4530: 已使用 C++ 例外處理常式,但沒有啟用回溯語意 (Unwind Semantics)。請指定 /E
Hsc
Microsoft (R) Incremental Linker Version 10.00.30319.01
Copyright (C) Microsoft Corporation.  All rights reserved.
/out:c.exe
c.obj
C:\>c
i: 10
vptr_addr:41a1bc
func_addr:4011a0
i: 11
i: 10
i: 11
i: 10
 
ref:
Member Function Pointers and the Fastest Possible C++ Delegates 深度探索 C++ 物件模型:virtual member function 這節 
Pointers to member functions are very strange animals (ptt purpose)   
沒有留言:
張貼留言
使用 google 的 reCAPTCHA 驗證碼, 總算可以輕鬆留言了。
我實在受不了 spam 了, 又不想讓大家的眼睛花掉, 只好放棄匿名留言。這是沒辦法中的辦法了。留言的朋友需要有 google 帳號。