begin pulling in disassembly, fix stuff
[ia32rtools.git] / tools / mkbridge.c
CommitLineData
57e4efe9 1#include <stdio.h>
2#include <stdlib.h>
3#include <string.h>
4
5#include "my_assert.h"
6#include "my_str.h"
7
232aca37 8#define ARRAY_SIZE(x) (sizeof(x) / sizeof(x[0]))
9
57e4efe9 10static int find_protostr(char *dst, size_t dlen, FILE *fhdr,
11 const char *sym, int *pline)
12{
13 int line = 0;
14 char *p;
15
232aca37 16 rewind(fhdr);
17
57e4efe9 18 while (fgets(dst, dlen, fhdr))
19 {
20 line++;
21 if (strstr(dst, sym) != NULL)
22 break;
23 }
24 *pline = line;
25
26 if (feof(fhdr))
27 return -1;
28
29 p = dst + strlen(dst);
30 for (p--; p > dst && my_isblank(*p); --p)
31 *p = 0;
32
33 return 0;
34}
35
36static int get_regparm(char *dst, size_t dlen, char *p)
37{
38 int i, o;
39
40 if (*p != '<')
41 return 0;
42
43 for (o = 0, i = 1; o < dlen; i++) {
44 if (p[i] == 0)
45 return 0;
46 if (p[i] == '>')
47 break;
48 dst[o++] = p[i];
49 }
50 dst[o] = 0;
51 return i + 1;
52}
53
232aca37 54// hmh..
57e4efe9 55static const char *known_types[] = {
232aca37 56 "char",
57 "unsigned __int8",
57e4efe9 58 "int",
232aca37 59 "signed int",
60 "unsigned int",
57e4efe9 61 "void",
232aca37 62 "BYTE",
63 "WORD",
57e4efe9 64 "DWORD",
65 "HMODULE",
66 "HANDLE",
67 "HWND",
232aca37 68 "LPCSTR",
69 "size_t",
70 "void *",
71 "const void *",
72 "FILE *",
57e4efe9 73};
74
75static int check_type(const char *name)
76{
77 int i, l;
78
232aca37 79 for (i = 0; i < ARRAY_SIZE(known_types); i++) {
57e4efe9 80 l = strlen(known_types[i]);
81 if (strncmp(known_types[i], name, l) == 0)
82 return l;
83 }
84
85 return 0;
86}
87
232aca37 88static const char *hdrfn;
89static int pline = 0;
90
91static int parse_protostr(char *protostr, char **reglist, int *cnt_out,
92 int *is_stdcall)
93{
94 char regparm[16];
95 char buf[256];
96 int xarg = 0;
97 int ret;
98 char *p;
99
100 p = protostr;
101 if (p[0] == '/' && p[1] == '/') {
102 //printf("warning: decl for sym '%s' is commented out\n", sym);
103 p = sskip(p + 2);
104 }
105
106 ret = check_type(p);
107 if (ret <= 0) {
108 printf("%s:%d:%ld: unhandled return in '%s'\n",
109 hdrfn, pline, (p - protostr) + 1, protostr);
110 return 1;
111 }
112 p += ret;
113 p = sskip(p);
114
115 p = next_word(buf, sizeof(buf), p);
116 p = sskip(p);
117 if (buf[0] == 0) {
118 printf("%s:%d:%ld: cconv missing\n",
119 hdrfn, pline, (p - protostr) + 1);
120 return 1;
121 }
122 if (strcmp(buf, "__cdecl") == 0)
123 *is_stdcall = 0;
124 else if (strcmp(buf, "__stdcall") == 0)
125 *is_stdcall = 1;
126 else if (strcmp(buf, "__userpurge") == 0)
127 *is_stdcall = 1; // in all cases seen..
128 else if (strcmp(buf, "__usercall") == 0)
129 *is_stdcall = 0; // ..or is it?
130 else {
131 // TODO: __thiscall needs special handling (arg1~ecx)
132 printf("%s:%d:%ld: unhandled cconv: '%s'\n",
133 hdrfn, pline, (p - protostr) + 1, buf);
134 return 1;
135 }
136
137 p = next_idt(buf, sizeof(buf), p);
138 p = sskip(p);
139 if (buf[0] == 0) {
140 printf("%s:%d:%ld: func name missing\n",
141 hdrfn, pline, (p - protostr) + 1);
142 return 1;
143 }
144
145 ret = get_regparm(regparm, sizeof(regparm), p);
146 if (ret > 0) {
147 if (strcmp(regparm, "eax") && strcmp(regparm, "ax")
148 && strcmp(regparm, "al"))
149 {
150 printf("%s:%d:%ld: bad regparm: %s\n",
151 hdrfn, pline, (p - protostr) + 1, regparm);
152 return 1;
153 }
154 p += ret;
155 p = sskip(p);
156 }
157
158 if (*p != '(') {
159 printf("%s:%d:%ld: '(' expected, got '%c'\n",
160 hdrfn, pline, (p - protostr) + 1, *p);
161 return 1;
162 }
163 p++;
164
165 while (1) {
166 p = sskip(p);
167 if (*p == ')')
168 break;
169 if (*p == ',')
170 p = sskip(p + 1);
171
172 xarg++;
173
174 ret = check_type(p);
175 if (ret <= 0) {
176 printf("%s:%d:%ld: unhandled type for arg%d\n",
177 hdrfn, pline, (p - protostr) + 1, xarg);
178 return 1;
179 }
180 p += ret;
181 p = sskip(p);
182
183 p = next_idt(buf, sizeof(buf), p);
184 p = sskip(p);
185#if 0
186 if (buf[0] == 0) {
187 printf("%s:%d:%ld: idt missing for arg%d\n",
188 hdrfn, pline, (p - protostr) + 1, xarg);
189 return 1;
190 }
191#endif
192 reglist[xarg - 1] = NULL;
193
194 ret = get_regparm(regparm, sizeof(regparm), p);
195 if (ret > 0) {
196 p += ret;
197 p = sskip(p);
198
199 reglist[xarg - 1] = strdup(regparm);
200 }
201 }
202
203 *cnt_out = xarg;
204
205 return 0;
206}
207
208static int is_x86_reg_saved(const char *reg)
209{
210 static const char *nosave_regs[] = { "eax", "edx", "ecx" };
211 int nosave = 0;
212 int r;
213
214 for (r = 0; r < ARRAY_SIZE(nosave_regs); r++)
215 if (strcmp(reg, nosave_regs[r]) == 0)
216 nosave = 1;
217
218 return !nosave;
219}
220
221static void out_toasm_x86(FILE *f, char *sym, char *reg_list[], int reg_cnt,
222 int is_stdcall)
223{
224 int have_normal = 0; // normal args
225 int have_regs = 0;
226 int must_save = 0;
227 int sarg_ofs = 1; // stack offset to args, in DWORDs
228 int args_repushed = 0;
229 int i;
230
231 for (i = 0; i < reg_cnt; i++) {
232 if (reg_list[i] == NULL) {
233 have_normal++;
234 continue;
235 }
236
237 have_regs++;
238 must_save |= is_x86_reg_saved(reg_list[i]);
239 }
240
a51421fa 241 fprintf(f, ".global _%s\n", sym);
242 fprintf(f, "_%s:\n", sym);
232aca37 243
244 if (!have_regs && !is_stdcall) {
245 fprintf(f, "\tjmp %s\n\n", sym);
246 return;
247 }
248
249 if (!have_normal && !must_save && !is_stdcall) {
250 // load arg regs
251 for (i = 0; i < reg_cnt; i++) {
252 fprintf(f, "\tmovl %d(%%esp), %%%s\n",
253 (i + sarg_ofs) * 4, reg_list[i]);
254 }
255 fprintf(f, "\tjmp %s\n\n", sym);
256 return;
257 }
258
259 // save the regs
260 for (i = 0; i < reg_cnt; i++) {
261 if (reg_list[i] != NULL && is_x86_reg_saved(reg_list[i])) {
262 fprintf(f, "\tpushl %%%s\n", reg_list[i]);
263 sarg_ofs++;
264 }
265 }
266
267 // reconstruct arg stack
268 for (i = reg_cnt - 1; i >= 0; i--) {
269 if (reg_list[i] == NULL) {
270 fprintf(f, "\tmovl %d(%%esp), %%eax\n",
271 (i + sarg_ofs) * 4);
272 fprintf(f, "\tpushl %%eax\n");
273 sarg_ofs++;
274 args_repushed++;
275 }
276 }
277 my_assert(args_repushed, have_normal);
278
279 // load arg regs
280 for (i = 0; i < reg_cnt; i++) {
281 if (reg_list[i] != NULL) {
282 fprintf(f, "\tmovl %d(%%esp), %%%s\n",
283 (i + sarg_ofs) * 4, reg_list[i]);
284 }
285 }
286
287 fprintf(f, "\n\t# %s\n", is_stdcall ? "__stdcall" : "__cdecl");
288 fprintf(f, "\tcall %s\n\n", sym);
289
290 if (args_repushed && !is_stdcall)
a51421fa 291 fprintf(f, "\tadd $%d,%%esp\n", args_repushed * 4);
232aca37 292
293 // restore regs
294 for (i = reg_cnt - 1; i >= 0; i--) {
295 if (reg_list[i] != NULL && is_x86_reg_saved(reg_list[i]))
296 fprintf(f, "\tpopl %%%s\n", reg_list[i]);
297 }
298
299 fprintf(f, "\tret\n\n");
300}
301
302static void out_fromasm_x86(FILE *f, char *sym, char *reg_list[], int reg_cnt,
303 int is_stdcall)
304{
305 int have_normal = 0; // normal args
306 int have_regs = 0;
307 int sarg_ofs = 1; // stack offset to args, in DWORDs
308 int stack_args;
309 int i;
310
311 for (i = 0; i < reg_cnt; i++) {
312 if (reg_list[i] == NULL) {
313 have_normal++;
314 continue;
315 }
316
317 have_regs++;
318 }
319
320 fprintf(f, "# %s\n", is_stdcall ? "__stdcall" : "__cdecl");
321 fprintf(f, ".global %s\n", sym);
322 fprintf(f, "%s:\n", sym);
323
324 if (!have_regs) {
325 fprintf(f, "\tjmp _%s\n\n", sym);
326 return;
327 }
328
329 fprintf(f, "\tpushl %%edx\n"); // just in case..
330 sarg_ofs++;
331
332 // construct arg stack
333 stack_args = have_normal;
334 for (i = reg_cnt - 1; i >= 0; i--) {
335 if (reg_list[i] == NULL) {
336 fprintf(f, "\tmovl %d(%%esp), %%edx\n",
337 (sarg_ofs + stack_args - 1) * 4);
338 fprintf(f, "\tpushl %%edx\n");
339 stack_args--;
340 }
341 else {
342 fprintf(f, "\tpushl %%%s\n", reg_list[i]);
343 }
344 sarg_ofs++;
345 }
346
347 // no worries about calling conventions - always __cdecl
348 fprintf(f, "\n\tcall _%s\n\n", sym);
349
350 if (sarg_ofs > 2)
a51421fa 351 fprintf(f, "\tadd $%d,%%esp\n", (sarg_ofs - 2) * 4);
232aca37 352
353 fprintf(f, "\tpopl %%edx\n");
354
355 if (is_stdcall && have_normal)
356 fprintf(f, "\tret $%d\n\n", have_normal * 4);
357 else
358 fprintf(f, "\tret\n\n");
359}
360
57e4efe9 361int main(int argc, char *argv[])
362{
232aca37 363 FILE *fout, *fsyms_to, *fsyms_from, *fhdr;
57e4efe9 364 char protostr[256];
365 char line[256];
366 char sym[256];
232aca37 367 char *reg_list[16];
368 int is_stdcall = 0;
369 int reg_cnt = 0;
57e4efe9 370 int ret;
371
232aca37 372 if (argc != 5) {
373 printf("usage:\n%s <bridge.s> <toasm_symf> <fromasm_symf> <hdrf>\n",
57e4efe9 374 argv[0]);
375 return 1;
376 }
377
232aca37 378 hdrfn = argv[4];
57e4efe9 379 fhdr = fopen(hdrfn, "r");
380 my_assert_not(fhdr, NULL);
381
232aca37 382 fsyms_from = fopen(argv[3], "r");
383 my_assert_not(fsyms_from, NULL);
384
385 fsyms_to = fopen(argv[2], "r");
386 my_assert_not(fsyms_to, NULL);
57e4efe9 387
388 fout = fopen(argv[1], "w");
389 my_assert_not(fout, NULL);
390
391 fprintf(fout, ".text\n\n");
232aca37 392 fprintf(fout, "# to asm\n\n");
57e4efe9 393
232aca37 394 while (fgets(line, sizeof(line), fsyms_to))
57e4efe9 395 {
396 next_word(sym, sizeof(sym), line);
397 if (sym[0] == 0 || sym[0] == ';' || sym[0] == '#')
398 continue;
399
400 ret = find_protostr(protostr, sizeof(protostr), fhdr,
401 sym, &pline);
402 if (ret != 0) {
403 printf("%s: sym '%s' is missing\n",
404 hdrfn, sym);
232aca37 405 goto out;
57e4efe9 406 }
407
232aca37 408 ret = parse_protostr(protostr, reg_list, &reg_cnt, &is_stdcall);
409 if (ret)
410 goto out;
57e4efe9 411
232aca37 412 out_toasm_x86(fout, sym, reg_list, reg_cnt, is_stdcall);
413 }
57e4efe9 414
232aca37 415 fprintf(fout, "# from asm\n\n");
57e4efe9 416
232aca37 417 while (fgets(line, sizeof(line), fsyms_from))
418 {
419 next_word(sym, sizeof(sym), line);
420 if (sym[0] == 0 || sym[0] == ';' || sym[0] == '#')
421 continue;
57e4efe9 422
232aca37 423 ret = find_protostr(protostr, sizeof(protostr), fhdr,
424 sym, &pline);
425 if (ret != 0) {
426 printf("%s: sym '%s' is missing\n",
427 hdrfn, sym);
428 goto out;
57e4efe9 429 }
57e4efe9 430
232aca37 431 ret = parse_protostr(protostr, reg_list, &reg_cnt, &is_stdcall);
432 if (ret)
433 goto out;
57e4efe9 434
232aca37 435 out_fromasm_x86(fout, sym, reg_list, reg_cnt, is_stdcall);
57e4efe9 436 }
437
232aca37 438 ret = 0;
439out:
57e4efe9 440 fclose(fout);
232aca37 441 fclose(fsyms_to);
442 fclose(fsyms_from);
443 fclose(fhdr);
444 if (ret)
445 remove(argv[1]);
446
447 return ret;
57e4efe9 448}