start bridge gen tool
[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 static int find_protostr(char *dst, size_t dlen, FILE *fhdr,
9         const char *sym, int *pline)
10 {
11         int line = 0;
12         char *p;
13
14         while (fgets(dst, dlen, fhdr))
15         {
16                 line++;
17                 if (strstr(dst, sym) != NULL)
18                         break;
19         }
20         *pline = line;
21
22         if (feof(fhdr))
23                 return -1;
24
25         p = dst + strlen(dst);
26         for (p--; p > dst && my_isblank(*p); --p)
27                 *p = 0;
28
29         return 0;
30 }
31
32 static int get_regparm(char *dst, size_t dlen, char *p)
33 {
34         int i, o;
35
36         if (*p != '<')
37                 return 0;
38
39         for (o = 0, i = 1; o < dlen; i++) {
40                 if (p[i] == 0)
41                         return 0;
42                 if (p[i] == '>')
43                         break;
44                 dst[o++] = p[i];
45         }
46         dst[o] = 0;
47         return i + 1;
48 }
49
50 static const char *known_types[] = {
51         "unsigned int",
52         "signed int",
53         "int",
54         "void",
55         "DWORD",
56         "HMODULE",
57         "HANDLE",
58         "HWND",
59 };
60
61 static int check_type(const char *name)
62 {
63         int i, l;
64
65         for (i = 0; i < sizeof(known_types) / sizeof(known_types[0]); i++) {
66                 l = strlen(known_types[i]);
67                 if (strncmp(known_types[i], name, l) == 0)
68                         return l;
69         }
70
71         return 0;
72 }
73
74 int main(int argc, char *argv[])
75 {
76         FILE *fout, *fsyms, *fhdr;
77         const char *hdrfn;
78         char protostr[256];
79         char line[256];
80         char sym[256];
81         char buf[256];
82         char regparm[16];
83         char *p;
84         int first_regparm = 0;
85         int have_regparm;
86         int pline = 0;
87         int xarg;
88         int ret;
89
90         if (argc != 4) {
91                 // -c - patch callsites
92                 printf("usage:\n%s <bridge.s> <symf> <hdrf>\n",
93                         argv[0]);
94                 return 1;
95         }
96
97         hdrfn = argv[3];
98         fhdr = fopen(hdrfn, "r");
99         my_assert_not(fhdr, NULL);
100
101         fsyms = fopen(argv[2], "r");
102         my_assert_not(fsyms, NULL);
103
104         fout = fopen(argv[1], "w");
105         my_assert_not(fout, NULL);
106
107         fprintf(fout, ".text\n\n");
108
109         while (fgets(line, sizeof(line), fsyms))
110         {
111                 next_word(sym, sizeof(sym), line);
112                 if (sym[0] == 0 || sym[0] == ';' || sym[0] == '#')
113                         continue;
114
115                 ret = find_protostr(protostr, sizeof(protostr), fhdr,
116                         sym, &pline);
117                 if (ret != 0) {
118                         printf("%s: sym '%s' is missing\n",
119                                 hdrfn, sym);
120                         return 1;
121                 }
122
123                 p = protostr;
124                 if (p[0] == '/' && p[1] == '/') {
125                         printf("warning: decl for sym '%s' is commented out\n", sym);
126                         p = sskip(p + 2);
127                 }
128
129                 ret = check_type(p);
130                 if (ret <= 0) {
131                         printf("%s:%d:%ld: unhandled return in '%s'\n",
132                                 hdrfn, pline, (p - protostr) + 1, protostr);
133                         return 1;
134                 }
135                 p += ret;
136                 p = sskip(p);
137
138                 // ignore calling convention specifier, for now
139                 p = next_word(buf, sizeof(buf), p);
140                 p = sskip(p);
141                 if (buf[0] == 0) {
142                         printf("%s:%d:%ld: cconv missing\n",
143                                 hdrfn, pline, (p - protostr) + 1);
144                         return 1;
145                 }
146
147                 p = next_idt(buf, sizeof(buf), p);
148                 p = sskip(p);
149                 if (buf[0] == 0) {
150                         printf("%s:%d:%ld: func name missing\n",
151                                 hdrfn, pline, (p - protostr) + 1);
152                         return 1;
153                 }
154
155                 ret = get_regparm(regparm, sizeof(regparm), p);
156                 if (ret > 0) {
157                         if (strcmp(regparm, "eax") && strcmp(regparm, "ax")) {
158                                 printf("%s:%d:%ld: bad regparm: %s\n",
159                                         hdrfn, pline, (p - protostr) + 1, regparm);
160                                 return 1;
161                         }
162                         p += ret;
163                         p = sskip(p);
164                 }
165
166                 if (*p != '(') {
167                         printf("%s:%d:%ld: '(' expected, got '%c'\n",
168                                 hdrfn, pline, (p - protostr) + 1, *p);
169                         return 1;
170                 }
171                 p++;
172
173                 fprintf(fout, ".global _asm_%s\n", sym);
174                 fprintf(fout, "_asm_%s:\n", sym);
175
176                 xarg = 1;
177                 while (1) {
178                         p = sskip(p);
179                         if (*p == ')')
180                                 break;
181                         if (*p == ',')
182                                 p = sskip(p + 1);
183
184                         ret = check_type(p);
185                         if (ret <= 0) {
186                                 printf("%s:%d:%ld: unhandled type for arg%d\n",
187                                         hdrfn, pline, (p - protostr) + 1, xarg);
188                                 return 1;
189                         }
190                         p += ret;
191                         p = sskip(p);
192
193                         p = next_idt(buf, sizeof(buf), p);
194                         p = sskip(p);
195                         if (buf[0] == 0) {
196                                 printf("%s:%d:%ld: idt missing for arg%d\n",
197                                         hdrfn, pline, (p - protostr) + 1, xarg);
198                                 return 1;
199                         }
200
201                         have_regparm = 0;
202                         ret = get_regparm(regparm, sizeof(regparm), p);
203                         if (ret > 0) {
204                                 p += ret;
205                                 p = sskip(p);
206
207                                 have_regparm = 1;
208                                 fprintf(fout, "\t movl %d(%%esp), %%%s\n",
209                                         xarg * 4, regparm);
210                         }
211                         if (xarg == 1)
212                                 first_regparm = have_regparm;
213                         else if (have_regparm != first_regparm) {
214                                 printf("%s:%d:%ld: mixed regparm is unhandled\n",
215                                         hdrfn, pline, (p - protostr) + 1);
216                                 return 1;
217                         }
218                 }
219
220                 fprintf(fout, "\t jmp %s\n\n", sym);
221         }
222
223         fclose(fout);
224         return 0;
225 }