start work on asm->c translation
[ia32rtools.git] / tools / mkbridge.c
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <string.h>
4
5 #include "my_assert.h"
6 #include "my_str.h"
7
8 #define ARRAY_SIZE(x) (sizeof(x) / sizeof(x[0]))
9 #define IS(w, y) !strcmp(w, y)
10
11 #include "protoparse.h"
12
13 static int is_x86_reg_saved(const char *reg)
14 {
15         static const char *nosave_regs[] = { "eax", "edx", "ecx" };
16         int nosave = 0;
17         int r;
18
19         for (r = 0; r < ARRAY_SIZE(nosave_regs); r++)
20                 if (strcmp(reg, nosave_regs[r]) == 0)
21                         nosave = 1;
22
23         return !nosave;
24 }
25
26 static void out_toasm_x86(FILE *f, char *sym, struct parsed_proto *pp)
27 {
28         int must_save = 0;
29         int sarg_ofs = 1; // stack offset to args, in DWORDs
30         int args_repushed = 0;
31         int i;
32
33         for (i = 0; i < pp->argc; i++) {
34                 if (pp->arg[i].reg != NULL)
35                         must_save |= is_x86_reg_saved(pp->arg[i].reg);
36         }
37
38         fprintf(f, ".global _%s\n", sym);
39         fprintf(f, "_%s:\n", sym);
40
41         if (pp->argc_reg == 0 && !pp->is_stdcall) {
42                 fprintf(f, "\tjmp %s\n\n", sym);
43                 return;
44         }
45
46         if (pp->argc_stack == 0 && !must_save && !pp->is_stdcall) {
47                 // load arg regs
48                 for (i = 0; i < pp->argc; i++) {
49                         fprintf(f, "\tmovl %d(%%esp), %%%s\n",
50                                 (i + sarg_ofs) * 4, pp->arg[i].reg);
51                 }
52                 fprintf(f, "\tjmp %s\n\n", sym);
53                 return;
54         }
55
56         // save the regs
57         for (i = 0; i < pp->argc; i++) {
58                 if (pp->arg[i].reg != NULL && is_x86_reg_saved(pp->arg[i].reg)) {
59                         fprintf(f, "\tpushl %%%s\n", pp->arg[i].reg);
60                         sarg_ofs++;
61                 }
62         }
63
64         // reconstruct arg stack
65         for (i = pp->argc - 1; i >= 0; i--) {
66                 if (pp->arg[i].reg == NULL) {
67                         fprintf(f, "\tmovl %d(%%esp), %%eax\n",
68                                 (i + sarg_ofs) * 4);
69                         fprintf(f, "\tpushl %%eax\n");
70                         sarg_ofs++;
71                         args_repushed++;
72                 }
73         }
74         my_assert(args_repushed, pp->argc_stack);
75
76         // load arg regs
77         for (i = 0; i < pp->argc; i++) {
78                 if (pp->arg[i].reg != NULL) {
79                         fprintf(f, "\tmovl %d(%%esp), %%%s\n",
80                                 (i + sarg_ofs) * 4, pp->arg[i].reg);
81                 }
82         }
83
84         fprintf(f, "\n\t# %s\n", pp->is_stdcall ? "__stdcall" : "__cdecl");
85         fprintf(f, "\tcall %s\n\n", sym);
86
87         if (args_repushed && !pp->is_stdcall)
88                 fprintf(f, "\tadd $%d,%%esp\n", args_repushed * 4);
89
90         // restore regs
91         for (i = pp->argc - 1; i >= 0; i--) {
92                 if (pp->arg[i].reg != NULL && is_x86_reg_saved(pp->arg[i].reg))
93                         fprintf(f, "\tpopl %%%s\n", pp->arg[i].reg);
94         }
95
96         fprintf(f, "\tret\n\n");
97 }
98
99 static void out_fromasm_x86(FILE *f, char *sym, struct parsed_proto *pp)
100 {
101         int sarg_ofs = 1; // stack offset to args, in DWORDs
102         int stack_args;
103         int i;
104
105         fprintf(f, "# %s\n", pp->is_stdcall ? "__stdcall" : "__cdecl");
106         fprintf(f, ".global %s\n", sym);
107         fprintf(f, "%s:\n", sym);
108
109         if (pp->argc_reg == 0 && !pp->is_stdcall) {
110                 fprintf(f, "\tjmp _%s\n\n", sym);
111                 return;
112         }
113
114         fprintf(f, "\tpushl %%edx\n"); // just in case..
115         sarg_ofs++;
116
117         // construct arg stack
118         stack_args = pp->argc_stack;
119         for (i = pp->argc - 1; i >= 0; i--) {
120                 if (pp->arg[i].reg == NULL) {
121                         fprintf(f, "\tmovl %d(%%esp), %%edx\n",
122                                 (sarg_ofs + stack_args - 1) * 4);
123                         fprintf(f, "\tpushl %%edx\n");
124                         stack_args--;
125                 }
126                 else {
127                         fprintf(f, "\tpushl %%%s\n", pp->arg[i].reg);
128                 }
129                 sarg_ofs++;
130         }
131
132         // no worries about calling conventions - always __cdecl
133         fprintf(f, "\n\tcall _%s\n\n", sym);
134
135         if (sarg_ofs > 2)
136                 fprintf(f, "\tadd $%d,%%esp\n", (sarg_ofs - 2) * 4);
137
138         fprintf(f, "\tpopl %%edx\n");
139
140         if (pp->is_stdcall && pp->argc_stack)
141                 fprintf(f, "\tret $%d\n\n", pp->argc_stack * 4);
142         else
143                 fprintf(f, "\tret\n\n");
144 }
145
146 int main(int argc, char *argv[])
147 {
148         FILE *fout, *fsyms_to, *fsyms_from, *fhdr;
149         struct parsed_proto pp;
150         char line[256];
151         char sym[256];
152         int ret;
153
154         if (argc != 5) {
155                 printf("usage:\n%s <bridge.s> <toasm_symf> <fromasm_symf> <hdrf>\n",
156                         argv[0]);
157                 return 1;
158         }
159
160         hdrfn = argv[4];
161         fhdr = fopen(hdrfn, "r");
162         my_assert_not(fhdr, NULL);
163
164         fsyms_from = fopen(argv[3], "r");
165         my_assert_not(fsyms_from, NULL);
166
167         fsyms_to = fopen(argv[2], "r");
168         my_assert_not(fsyms_to, NULL);
169
170         fout = fopen(argv[1], "w");
171         my_assert_not(fout, NULL);
172
173         fprintf(fout, ".text\n\n");
174         fprintf(fout, "# to asm\n\n");
175
176         while (fgets(line, sizeof(line), fsyms_to))
177         {
178                 next_word(sym, sizeof(sym), line);
179                 if (sym[0] == 0 || sym[0] == ';' || sym[0] == '#')
180                         continue;
181
182                 ret = proto_parse(fhdr, sym, &pp);
183                 if (ret)
184                         goto out;
185
186                 out_toasm_x86(fout, sym, &pp);
187                 proto_release(&pp);
188         }
189
190         fprintf(fout, "# from asm\n\n");
191
192         while (fgets(line, sizeof(line), fsyms_from))
193         {
194                 next_word(sym, sizeof(sym), line);
195                 if (sym[0] == 0 || sym[0] == ';' || sym[0] == '#')
196                         continue;
197
198                 ret = proto_parse(fhdr, sym, &pp);
199                 if (ret)
200                         goto out;
201
202                 out_fromasm_x86(fout, sym, &pp);
203                 proto_release(&pp);
204         }
205
206         ret = 0;
207 out:
208         fclose(fout);
209         fclose(fsyms_to);
210         fclose(fsyms_from);
211         fclose(fhdr);
212         if (ret)
213                 remove(argv[1]);
214
215         return ret;
216 }