|
1 |
|
2 #include <stdio.h> |
|
3 |
|
4 typedef unsigned nsresult; |
|
5 typedef unsigned uint32_t; |
|
6 typedef unsigned nsXPCVariant; |
|
7 |
|
8 |
|
9 #if defined(WIN32) |
|
10 #define NS_IMETHOD virtual nsresult __stdcall |
|
11 #define NS_IMETHODIMP nsresult __stdcall |
|
12 #else |
|
13 #define NS_IMETHOD virtual nsresult |
|
14 #define NS_IMETHODIMP nsresult |
|
15 #endif |
|
16 |
|
17 |
|
18 class base{ |
|
19 public: |
|
20 NS_IMETHOD ignored() = 0; |
|
21 }; |
|
22 |
|
23 class foo : public base { |
|
24 public: |
|
25 NS_IMETHOD callme1(int i, int j) = 0; |
|
26 NS_IMETHOD callme2(int i, int j) = 0; |
|
27 NS_IMETHOD callme3(int i, int j) = 0; |
|
28 }; |
|
29 |
|
30 class bar : public foo{ |
|
31 public: |
|
32 NS_IMETHOD ignored(); |
|
33 NS_IMETHOD callme1(int i, int j); |
|
34 NS_IMETHOD callme2(int i, int j); |
|
35 NS_IMETHOD callme3(int i, int j); |
|
36 }; |
|
37 |
|
38 class baz : public base { |
|
39 public: |
|
40 NS_IMETHOD ignored(); |
|
41 NS_IMETHOD callme1(); |
|
42 NS_IMETHOD callme2(); |
|
43 NS_IMETHOD callme3(); |
|
44 void setfoo(foo* f) {other = f;} |
|
45 |
|
46 foo* other; |
|
47 }; |
|
48 NS_IMETHODIMP baz::ignored(){return 0;} |
|
49 |
|
50 NS_IMETHODIMP bar::ignored(){return 0;} |
|
51 |
|
52 NS_IMETHODIMP bar::callme1(int i, int j) |
|
53 { |
|
54 printf("called bar::callme1 with: %d %d\n", i, j); |
|
55 return 15; |
|
56 } |
|
57 |
|
58 NS_IMETHODIMP bar::callme2(int i, int j) |
|
59 { |
|
60 printf("called bar::callme2 with: %d %d\n", i, j); |
|
61 return 25; |
|
62 } |
|
63 |
|
64 NS_IMETHODIMP bar::callme3(int i, int j) |
|
65 { |
|
66 printf("called bar::callme3 with: %d %d\n", i, j); |
|
67 return 35; |
|
68 } |
|
69 |
|
70 void docall(foo* f, int i, int j){ |
|
71 f->callme1(i, j); |
|
72 } |
|
73 |
|
74 /***************************************************************************/ |
|
75 #if defined(WIN32) |
|
76 |
|
77 static int __stdcall |
|
78 PrepareAndDispatch(baz* self, uint32_t methodIndex, |
|
79 uint32_t* args, uint32_t* stackBytesToPop) |
|
80 { |
|
81 fprintf(stdout, "PrepareAndDispatch (%p, %d, %p)\n", |
|
82 (void*)self, methodIndex, (void*)args); |
|
83 foo* a = self->other; |
|
84 int p1 = (int) *args; |
|
85 int p2 = (int) *(args+1); |
|
86 int out = 0; |
|
87 switch(methodIndex) |
|
88 { |
|
89 case 1: out = a->callme1(p1, p2); break; |
|
90 case 2: out = a->callme2(p1, p2); break; |
|
91 case 3: out = a->callme3(p1, p2); break; |
|
92 } |
|
93 *stackBytesToPop = 2*4; |
|
94 return out; |
|
95 } |
|
96 |
|
97 #ifndef __GNUC__ |
|
98 static __declspec(naked) void SharedStub(void) |
|
99 { |
|
100 __asm { |
|
101 push ebp // set up simple stack frame |
|
102 mov ebp, esp // stack has: ebp/vtbl_index/retaddr/this/args |
|
103 push ecx // make room for a ptr |
|
104 lea eax, [ebp-4] // pointer to stackBytesToPop |
|
105 push eax |
|
106 lea ecx, [ebp+16] // pointer to args |
|
107 push ecx |
|
108 mov edx, [ebp+4] // vtbl_index |
|
109 push edx |
|
110 mov eax, [ebp+12] // this |
|
111 push eax |
|
112 call PrepareAndDispatch |
|
113 mov edx, [ebp+8] // return address |
|
114 mov ecx, [ebp-4] // stackBytesToPop |
|
115 add ecx, 12 // for this, the index, and ret address |
|
116 mov esp, ebp |
|
117 pop ebp |
|
118 add esp, ecx // fix up stack pointer |
|
119 jmp edx // simulate __stdcall return |
|
120 } |
|
121 } |
|
122 |
|
123 // these macros get expanded (many times) in the file #included below |
|
124 #define STUB_ENTRY(n) \ |
|
125 __declspec(naked) nsresult __stdcall baz::callme##n() \ |
|
126 { __asm push n __asm jmp SharedStub } |
|
127 |
|
128 #else /* __GNUC__ */ |
|
129 |
|
130 #define STUB_ENTRY(n) \ |
|
131 nsresult __stdcall baz::callme##n() \ |
|
132 { \ |
|
133 uint32_t *args, stackBytesToPop; \ |
|
134 int result = 0; \ |
|
135 baz *obj; \ |
|
136 __asm__ __volatile__ ( \ |
|
137 "leal 0x0c(%%ebp), %0\n\t" /* args */ \ |
|
138 "movl 0x08(%%ebp), %1\n\t" /* this */ \ |
|
139 : "=r" (args), \ |
|
140 "=r" (obj)); \ |
|
141 result = PrepareAndDispatch(obj, n, args,&stackBytesToPop); \ |
|
142 fprintf(stdout, "stub returning: %d\n", result); \ |
|
143 fprintf(stdout, "bytes to pop: %d\n", stackBytesToPop); \ |
|
144 return result; \ |
|
145 } |
|
146 |
|
147 #endif /* ! __GNUC__ */ |
|
148 |
|
149 #else |
|
150 /***************************************************************************/ |
|
151 // just Linux_x86 now. Add other later... |
|
152 |
|
153 static int |
|
154 PrepareAndDispatch(baz* self, uint32_t methodIndex, uint32_t* args) |
|
155 { |
|
156 foo* a = self->other; |
|
157 int p1 = (int) *args; |
|
158 int p2 = (int) *(args+1); |
|
159 switch(methodIndex) |
|
160 { |
|
161 case 1: a->callme1(p1, p2); break; |
|
162 case 2: a->callme2(p1, p2); break; |
|
163 case 3: a->callme3(p1, p2); break; |
|
164 } |
|
165 return 1; |
|
166 } |
|
167 |
|
168 #define STUB_ENTRY(n) \ |
|
169 nsresult baz::callme##n() \ |
|
170 { \ |
|
171 void* method = PrepareAndDispatch; \ |
|
172 nsresult result; \ |
|
173 __asm__ __volatile__( \ |
|
174 "leal 0x0c(%%ebp), %%ecx\n\t" /* args */ \ |
|
175 "pushl %%ecx\n\t" \ |
|
176 "pushl $"#n"\n\t" /* method index */ \ |
|
177 "movl 0x08(%%ebp), %%ecx\n\t" /* this */ \ |
|
178 "pushl %%ecx\n\t" \ |
|
179 "call *%%edx" /* PrepareAndDispatch */ \ |
|
180 : "=a" (result) /* %0 */ \ |
|
181 : "d" (method) /* %1 */ \ |
|
182 : "memory" ); \ |
|
183 return result; \ |
|
184 } |
|
185 |
|
186 #endif |
|
187 /***************************************************************************/ |
|
188 |
|
189 STUB_ENTRY(1) |
|
190 STUB_ENTRY(2) |
|
191 STUB_ENTRY(3) |
|
192 |
|
193 int main() |
|
194 { |
|
195 foo* a = new bar(); |
|
196 baz* b = new baz(); |
|
197 |
|
198 /* here we make the global 'check for alloc failure' checker happy */ |
|
199 if(!a || !b) |
|
200 return 1; |
|
201 |
|
202 foo* c = (foo*)b; |
|
203 |
|
204 b->setfoo(a); |
|
205 c->callme1(1,2); |
|
206 c->callme2(2,4); |
|
207 c->callme3(3,6); |
|
208 |
|
209 return 0; |
|
210 } |