2013年8月30日 星期五

c++ member function pointer

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   *%eax
208 
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:
    1. Member Function Pointers and the Fastest Possible C++ Delegates
    2. 深度探索 C++ 物件模型:virtual member function 這節
    3. Pointers to member functions are very strange animals (ptt purpose)

      沒有留言:

      張貼留言

      使用 google 的 reCAPTCHA 驗證碼, 總算可以輕鬆留言了。

      我實在受不了 spam 了, 又不想讓大家的眼睛花掉, 只好放棄匿名留言。這是沒辦法中的辦法了。留言的朋友需要有 google 帳號。