8 #define ARRAY_SIZE(x) (sizeof(x) / sizeof(x[0]))
10 static int find_protostr(char *dst, size_t dlen, FILE *fhdr,
11 const char *sym, int *pline)
18 while (fgets(dst, dlen, fhdr))
21 if (strstr(dst, sym) != NULL)
29 p = dst + strlen(dst);
30 for (p--; p > dst && my_isblank(*p); --p)
36 static int get_regparm(char *dst, size_t dlen, char *p)
43 for (o = 0, i = 1; o < dlen; i++) {
55 static const char *known_types[] = {
75 static int check_type(const char *name)
79 for (i = 0; i < ARRAY_SIZE(known_types); i++) {
80 l = strlen(known_types[i]);
81 if (strncmp(known_types[i], name, l) == 0)
88 static const char *hdrfn;
91 static int parse_protostr(char *protostr, char **reglist, int *cnt_out,
101 if (p[0] == '/' && p[1] == '/') {
102 //printf("warning: decl for sym '%s' is commented out\n", sym);
108 printf("%s:%d:%ld: unhandled return in '%s'\n",
109 hdrfn, pline, (p - protostr) + 1, protostr);
115 p = next_word(buf, sizeof(buf), p);
118 printf("%s:%d:%ld: cconv missing\n",
119 hdrfn, pline, (p - protostr) + 1);
122 if (strcmp(buf, "__cdecl") == 0)
124 else if (strcmp(buf, "__stdcall") == 0)
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?
131 // TODO: __thiscall needs special handling (arg1~ecx)
132 printf("%s:%d:%ld: unhandled cconv: '%s'\n",
133 hdrfn, pline, (p - protostr) + 1, buf);
137 p = next_idt(buf, sizeof(buf), p);
140 printf("%s:%d:%ld: func name missing\n",
141 hdrfn, pline, (p - protostr) + 1);
145 ret = get_regparm(regparm, sizeof(regparm), p);
147 if (strcmp(regparm, "eax") && strcmp(regparm, "ax")
148 && strcmp(regparm, "al"))
150 printf("%s:%d:%ld: bad regparm: %s\n",
151 hdrfn, pline, (p - protostr) + 1, regparm);
159 printf("%s:%d:%ld: '(' expected, got '%c'\n",
160 hdrfn, pline, (p - protostr) + 1, *p);
176 printf("%s:%d:%ld: unhandled type for arg%d\n",
177 hdrfn, pline, (p - protostr) + 1, xarg);
183 p = next_idt(buf, sizeof(buf), p);
187 printf("%s:%d:%ld: idt missing for arg%d\n",
188 hdrfn, pline, (p - protostr) + 1, xarg);
192 reglist[xarg - 1] = NULL;
194 ret = get_regparm(regparm, sizeof(regparm), p);
199 reglist[xarg - 1] = strdup(regparm);
208 static int is_x86_reg_saved(const char *reg)
210 static const char *nosave_regs[] = { "eax", "edx", "ecx" };
214 for (r = 0; r < ARRAY_SIZE(nosave_regs); r++)
215 if (strcmp(reg, nosave_regs[r]) == 0)
221 static void out_toasm_x86(FILE *f, char *sym, char *reg_list[], int reg_cnt,
224 int have_normal = 0; // normal args
227 int sarg_ofs = 1; // stack offset to args, in DWORDs
228 int args_repushed = 0;
231 for (i = 0; i < reg_cnt; i++) {
232 if (reg_list[i] == NULL) {
238 must_save |= is_x86_reg_saved(reg_list[i]);
241 fprintf(f, ".global _%s\n", sym);
242 fprintf(f, "_%s:\n", sym);
244 if (!have_regs && !is_stdcall) {
245 fprintf(f, "\tjmp %s\n\n", sym);
249 if (!have_normal && !must_save && !is_stdcall) {
251 for (i = 0; i < reg_cnt; i++) {
252 fprintf(f, "\tmovl %d(%%esp), %%%s\n",
253 (i + sarg_ofs) * 4, reg_list[i]);
255 fprintf(f, "\tjmp %s\n\n", sym);
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]);
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",
272 fprintf(f, "\tpushl %%eax\n");
277 my_assert(args_repushed, have_normal);
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]);
287 fprintf(f, "\n\t# %s\n", is_stdcall ? "__stdcall" : "__cdecl");
288 fprintf(f, "\tcall %s\n\n", sym);
290 if (args_repushed && !is_stdcall)
291 fprintf(f, "\tadd $%d,%%esp\n", args_repushed * 4);
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]);
299 fprintf(f, "\tret\n\n");
302 static void out_fromasm_x86(FILE *f, char *sym, char *reg_list[], int reg_cnt,
305 int have_normal = 0; // normal args
307 int sarg_ofs = 1; // stack offset to args, in DWORDs
311 for (i = 0; i < reg_cnt; i++) {
312 if (reg_list[i] == NULL) {
320 fprintf(f, "# %s\n", is_stdcall ? "__stdcall" : "__cdecl");
321 fprintf(f, ".global %s\n", sym);
322 fprintf(f, "%s:\n", sym);
325 fprintf(f, "\tjmp _%s\n\n", sym);
329 fprintf(f, "\tpushl %%edx\n"); // just in case..
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");
342 fprintf(f, "\tpushl %%%s\n", reg_list[i]);
347 // no worries about calling conventions - always __cdecl
348 fprintf(f, "\n\tcall _%s\n\n", sym);
351 fprintf(f, "\tadd $%d,%%esp\n", (sarg_ofs - 2) * 4);
353 fprintf(f, "\tpopl %%edx\n");
355 if (is_stdcall && have_normal)
356 fprintf(f, "\tret $%d\n\n", have_normal * 4);
358 fprintf(f, "\tret\n\n");
361 int main(int argc, char *argv[])
363 FILE *fout, *fsyms_to, *fsyms_from, *fhdr;
373 printf("usage:\n%s <bridge.s> <toasm_symf> <fromasm_symf> <hdrf>\n",
379 fhdr = fopen(hdrfn, "r");
380 my_assert_not(fhdr, NULL);
382 fsyms_from = fopen(argv[3], "r");
383 my_assert_not(fsyms_from, NULL);
385 fsyms_to = fopen(argv[2], "r");
386 my_assert_not(fsyms_to, NULL);
388 fout = fopen(argv[1], "w");
389 my_assert_not(fout, NULL);
391 fprintf(fout, ".text\n\n");
392 fprintf(fout, "# to asm\n\n");
394 while (fgets(line, sizeof(line), fsyms_to))
396 next_word(sym, sizeof(sym), line);
397 if (sym[0] == 0 || sym[0] == ';' || sym[0] == '#')
400 ret = find_protostr(protostr, sizeof(protostr), fhdr,
403 printf("%s: sym '%s' is missing\n",
408 ret = parse_protostr(protostr, reg_list, ®_cnt, &is_stdcall);
412 out_toasm_x86(fout, sym, reg_list, reg_cnt, is_stdcall);
415 fprintf(fout, "# from asm\n\n");
417 while (fgets(line, sizeof(line), fsyms_from))
419 next_word(sym, sizeof(sym), line);
420 if (sym[0] == 0 || sym[0] == ';' || sym[0] == '#')
423 ret = find_protostr(protostr, sizeof(protostr), fhdr,
426 printf("%s: sym '%s' is missing\n",
431 ret = parse_protostr(protostr, reg_list, ®_cnt, &is_stdcall);
435 out_fromasm_x86(fout, sym, reg_list, reg_cnt, is_stdcall);