cvt_data: allow fastcall compatible funcs
[ia32rtools.git] / tools / cvt_data.c
CommitLineData
7637b6cc 1/*
2 * ia32rtools
3 * (C) notaz, 2013,2014
4 *
5 * This work is licensed under the terms of 3-clause BSD license.
6 * See COPYING file in the top-level directory.
7 */
8
054f95b2 9#define _GNU_SOURCE
10#include <stdio.h>
11#include <stdlib.h>
12#include <string.h>
e27467d0 13#include <stdint.h>
14#include <inttypes.h>
054f95b2 15
16#include "my_assert.h"
17#include "my_str.h"
9ea60b8d 18#include "common.h"
054f95b2 19
054f95b2 20#include "protoparse.h"
21
22static const char *asmfn;
23static int asmln;
054f95b2 24
b545ba7c 25static const struct parsed_proto *g_func_sym_pp;
26static char g_comment[256];
27static int g_warn_cnt;
77f3a833 28static int g_cconv_novalidate;
f0be238a 29static int g_arm_mode;
b545ba7c 30
36595fd2 31// note: must be in ascending order
054f95b2 32enum dx_type {
33 DXT_UNSPEC,
34 DXT_BYTE,
35 DXT_WORD,
36 DXT_DWORD,
37 DXT_QUAD,
38 DXT_TEN,
39};
40
36595fd2 41#define anote(fmt, ...) \
42 printf("%s:%d: note: " fmt, asmfn, asmln, ##__VA_ARGS__)
b545ba7c 43#define awarn(fmt, ...) do { \
44 printf("%s:%d: warning: " fmt, asmfn, asmln, ##__VA_ARGS__); \
45 if (++g_warn_cnt == 10) { \
46 fcloseall(); \
47 exit(1); \
48 } \
49} while (0)
054f95b2 50#define aerr(fmt, ...) do { \
51 printf("%s:%d: error: " fmt, asmfn, asmln, ##__VA_ARGS__); \
52 fcloseall(); \
53 exit(1); \
54} while (0)
55
56#include "masm_tools.h"
57
58static char *next_word_s(char *w, size_t wsize, char *s)
59{
60 int quote = 0;
61 size_t i;
62
63 s = sskip(s);
64
65 for (i = 0; i < wsize - 1; i++) {
66 if (s[i] == '\'')
67 quote ^= 1;
68 if (s[i] == 0 || (!quote && (my_isblank(s[i]) || s[i] == ',')))
69 break;
70 w[i] = s[i];
71 }
72 w[i] = 0;
73
74 if (s[i] != 0 && !my_isblank(s[i]) && s[i] != ',')
75 printf("warning: '%s' truncated\n", w);
76
77 return s + i;
78}
79
80static void next_section(FILE *fasm, char *name)
81{
82 char words[2][256];
83 char line[256];
84 int wordc;
85 char *p;
86
87 name[0] = 0;
88
9ea60b8d 89 while (my_fgets(line, sizeof(line), fasm))
054f95b2 90 {
91 wordc = 0;
92 asmln++;
93
94 p = sskip(line);
95 if (*p == 0)
96 continue;
97
9ea60b8d 98 if (*p == ';')
054f95b2 99 continue;
054f95b2 100
101 for (wordc = 0; wordc < ARRAY_SIZE(words); wordc++) {
102 p = sskip(next_word(words[wordc], sizeof(words[0]), p));
103 if (*p == 0 || *p == ';') {
104 wordc++;
105 break;
106 }
107 }
108
109 if (wordc < 2)
110 continue;
111
112 if (!IS(words[1], "segment"))
113 continue;
114
115 strcpy(name, words[0]);
116 break;
117 }
118}
119
120static enum dx_type parse_dx_directive(const char *name)
121{
122 if (IS(name, "dd"))
123 return DXT_DWORD;
124 if (IS(name, "dw"))
125 return DXT_WORD;
126 if (IS(name, "db"))
127 return DXT_BYTE;
128 if (IS(name, "dq"))
129 return DXT_QUAD;
130 if (IS(name, "dt"))
131 return DXT_TEN;
132
133 return DXT_UNSPEC;
134}
135
136static const char *type_name(enum dx_type type)
137{
138 switch (type) {
139 case DXT_BYTE:
140 return ".byte";
141 case DXT_WORD:
b0d802b2 142 return ".hword";
054f95b2 143 case DXT_DWORD:
144 return ".long";
145 case DXT_QUAD:
146 return ".quad";
147 case DXT_TEN:
148 return ".tfloat";
149 case DXT_UNSPEC:
150 break;
151 }
152 return "<bad>";
153}
154
36595fd2 155static const char *type_name_float(enum dx_type type)
156{
157 switch (type) {
158 case DXT_DWORD:
159 return ".float";
160 case DXT_QUAD:
161 return ".double";
162 case DXT_TEN:
163 return ".tfloat";
164 default:
165 break;
166 }
167 return "<bad_float>";
168}
169
054f95b2 170static int type_size(enum dx_type type)
171{
172 switch (type) {
173 case DXT_BYTE:
174 return 1;
175 case DXT_WORD:
176 return 2;
177 case DXT_DWORD:
178 return 4;
179 case DXT_QUAD:
180 return 8;
181 case DXT_TEN:
182 return 10;
183 case DXT_UNSPEC:
184 break;
185 }
186 return -1;
187}
188
189static char *escape_string(char *s)
190{
191 char buf[256];
192 char *t = buf;
193
194 for (; *s != 0; s++) {
195 if (*s == '"') {
206c0727 196 strcpy(t, "\\\"");
054f95b2 197 t += strlen(t);
198 continue;
199 }
200 if (*s == '\\') {
201 strcpy(t, "\\\\");
202 t += strlen(t);
203 continue;
204 }
205 *t++ = *s;
206 }
206c0727 207 *t++ = *s;
208 if (t - buf > sizeof(buf))
209 aerr("string is too long\n");
054f95b2 210 return strcpy(s, buf);
211}
212
b545ba7c 213static void sprint_pp_short(const struct parsed_proto *pp, char *buf,
214 size_t buf_size)
215{
216 char *p = buf;
217 size_t l;
218 int i;
219
220 if (pp->ret_type.is_ptr)
221 *p++ = 'p';
222 else if (IS(pp->ret_type.name, "void"))
223 *p++ = 'v';
224 else
225 *p++ = 'i';
226 *p++ = '(';
227 l = 2;
228
229 for (i = 0; i < pp->argc; i++) {
230 if (pp->arg[i].reg != NULL)
231 snprintf(buf + l, buf_size - l, "%s%s",
232 i == 0 ? "" : ",", pp->arg[i].reg);
233 else
234 snprintf(buf + l, buf_size - l, "%sa%d",
235 i == 0 ? "" : ",", i + 1);
236 l = strlen(buf);
237 }
238 snprintf(buf + l, buf_size - l, ")");
239}
240
c0050df6 241static const struct parsed_proto *check_var(FILE *fhdr,
242 const char *sym, const char *varname)
b545ba7c 243{
244 const struct parsed_proto *pp, *pp_sym;
179b79a9 245 char fp_sym[256], fp_var[256], *p;
246 int i;
b545ba7c 247
248 pp = proto_parse(fhdr, varname, 1);
36595fd2 249 if (pp == NULL) {
b545ba7c 250 if (IS_START(varname, "sub_"))
251 awarn("sub_ sym missing proto: '%s'\n", varname);
c0050df6 252 return NULL;
36595fd2 253 }
254
255 if (!pp->is_func && !pp->is_fptr)
c0050df6 256 return NULL;
b545ba7c 257
b74c31e3 258 pp_print(fp_var, sizeof(fp_var), pp);
b545ba7c 259
36595fd2 260 if (pp->argc_reg == 0)
b545ba7c 261 goto check_sym;
36595fd2 262 if (pp->argc_reg == 1 && pp->argc_stack == 0
263 && IS(pp->arg[0].reg, "ecx"))
264 {
b545ba7c 265 goto check_sym;
36595fd2 266 }
77f3a833 267 if (!g_cconv_novalidate
268 && (pp->argc_reg != 2
269 || !IS(pp->arg[0].reg, "ecx")
270 || !IS(pp->arg[1].reg, "edx")))
36595fd2 271 {
b545ba7c 272 awarn("unhandled reg call: %s\n", fp_var);
36595fd2 273 }
36595fd2 274
b545ba7c 275check_sym:
179b79a9 276 // fptrs must use 32bit args, callsite might have no information and
277 // lack a cast to smaller types, which results in incorrectly masked
278 // args passed (callee may assume masked args, it does on ARM)
279 for (i = 0; i < pp->argc; i++) {
280 if (pp->arg[i].type.is_ptr)
281 continue;
282 p = pp->arg[i].type.name;
283 if (strstr(p, "int8") || strstr(p, "int16")
284 || strstr(p, "char") || strstr(p, "short"))
285 {
286 awarn("reference to %s with arg%d '%s'\n", pp->name, i + 1, p);
287 }
288 }
289
b545ba7c 290 sprint_pp_short(pp, g_comment, sizeof(g_comment));
291
292 if (sym != NULL) {
293 g_func_sym_pp = NULL;
294 pp_sym = proto_parse(fhdr, sym, 1);
295 if (pp_sym == NULL)
c0050df6 296 return pp;
b545ba7c 297 if (!pp_sym->is_fptr)
298 aerr("func ptr data, but label '%s' !is_fptr\n", pp_sym->name);
299 g_func_sym_pp = pp_sym;
36595fd2 300 }
b545ba7c 301 else {
302 pp_sym = g_func_sym_pp;
303 if (pp_sym == NULL)
c0050df6 304 return pp;
b545ba7c 305 }
306
27ebfaed 307 if (pp_cmp_func(pp, pp_sym)) {
7a7487be 308 if (pp_sym->argc_stack == 0 && pp_sym->is_fastcall
309 && pp->argc_stack == 0
310 && (pp->is_fastcall || pp->argc_reg == 0)
311 && pp_sym->argc_reg > pp->argc_reg)
312 ; /* fascall compatible func doesn't use all args -> ok */
313 else {
314 pp_print(fp_sym, sizeof(fp_sym), pp_sym);
315 anote("var: %s\n", fp_var);
316 anote("sym: %s\n", fp_sym);
317 awarn("^ mismatch\n");
318 }
36595fd2 319 }
c0050df6 320
321 return pp;
36595fd2 322}
323
aa1aa2c2 324static void output_decorated_pp(FILE *fout,
325 const struct parsed_proto *pp)
326{
327 if (pp->name[0] != '_')
328 fprintf(fout, pp->is_fastcall ? "@" : "_");
329 fprintf(fout, "%s", pp->name);
330 if (pp->is_stdcall && pp->argc > 0)
331 fprintf(fout, "@%d", pp->argc * 4);
332}
333
f0be238a 334static int align_value(int src_val)
335{
336 if (src_val <= 0) {
337 awarn("bad align: %d\n", src_val);
338 src_val = 1;
339 }
340 if (!g_arm_mode)
341 return src_val;
342
343 return __builtin_ffs(src_val) - 1;
344}
345
36595fd2 346static int cmpstringp(const void *p1, const void *p2)
347{
348 return strcmp(*(char * const *)p1, *(char * const *)p2);
349}
350
c87eb470 351/* XXX: maybe move to external file? */
352static const char *unwanted_syms[] = {
353 "aRuntimeError",
354 "aTlossError",
355 "aSingError",
356 "aDomainError",
357 "aR6029ThisAppli",
358 "aR6028UnableToI",
359 "aR6027NotEnough",
360 "aR6026NotEnough",
361 "aR6025PureVirtu",
362 "aR6024NotEnough",
363 "aR6019UnableToO",
364 "aR6018Unexpecte",
365 "aR6017Unexpecte",
366 "aR6016NotEnough",
367 "aAbnormalProgra",
368 "aR6009NotEnough",
369 "aR6008NotEnough",
370 "aR6002FloatingP",
371 "aMicrosoftVisua",
372 "aRuntimeErrorPr",
373 "aThisApplicatio",
374 "aMicrosoftFindF",
375 "aMicrosoftOffic",
376};
377
378static int is_unwanted_sym(const char *sym)
379{
380 return bsearch(&sym, unwanted_syms, ARRAY_SIZE(unwanted_syms),
381 sizeof(unwanted_syms[0]), cmpstringp) != NULL;
382}
383
054f95b2 384int main(int argc, char *argv[])
385{
afdd4566 386 FILE *fout, *fasm, *fhdr = NULL, *frlist;
b545ba7c 387 const struct parsed_proto *pp;
aa1aa2c2 388 int no_decorations = 0;
f0be238a 389 char comment_char = '#';
054f95b2 390 char words[20][256];
054f95b2 391 char word[256];
392 char line[256];
c87eb470 393 char last_sym[32];
054f95b2 394 unsigned long val;
395 unsigned long cnt;
e27467d0 396 uint64_t val64;
054f95b2 397 const char *sym;
398 enum dx_type type;
36595fd2 399 char **pub_syms;
400 int pub_sym_cnt = 0;
401 int pub_sym_alloc;
402 char **rlist;
403 int rlist_cnt = 0;
404 int rlist_alloc;
afdd4566 405 int header_mode = 0;
406 int is_ro = 0;
054f95b2 407 int is_label;
36595fd2 408 int is_bss;
054f95b2 409 int wordc;
410 int first;
411 int arg_out;
412 int arg = 1;
413 int len;
36595fd2 414 int w, i;
054f95b2 415 char *p;
416 char *p2;
417
36595fd2 418 if (argc < 4) {
aa1aa2c2 419 // -nd: no symbol decorations
afdd4566 420 printf("usage:\n%s [-nd] [-i] [-a] <.s> <.asm> <hdrf> [rlist]*\n"
421 "%s -hdr <.h> <.asm>\n",
422 argv[0], argv[0]);
054f95b2 423 return 1;
424 }
425
aa1aa2c2 426 for (arg = 1; arg < argc; arg++) {
427 if (IS(argv[arg], "-nd"))
428 no_decorations = 1;
77f3a833 429 else if (IS(argv[arg], "-i"))
430 g_cconv_novalidate = 1;
f0be238a 431 else if (IS(argv[arg], "-a")) {
432 comment_char = '@';
433 g_arm_mode = 1;
434 }
afdd4566 435 else if (IS(argv[arg], "-hdr"))
436 header_mode = 1;
aa1aa2c2 437 else
438 break;
439 }
440
054f95b2 441 arg_out = arg++;
442
443 asmfn = argv[arg++];
444 fasm = fopen(asmfn, "r");
445 my_assert_not(fasm, NULL);
446
afdd4566 447 if (!header_mode) {
448 hdrfn = argv[arg++];
449 fhdr = fopen(hdrfn, "r");
450 my_assert_not(fhdr, NULL);
451 }
054f95b2 452
453 fout = fopen(argv[arg_out], "w");
454 my_assert_not(fout, NULL);
455
36595fd2 456 pub_sym_alloc = 64;
457 pub_syms = malloc(pub_sym_alloc * sizeof(pub_syms[0]));
458 my_assert_not(pub_syms, NULL);
459
460 rlist_alloc = 64;
461 rlist = malloc(rlist_alloc * sizeof(rlist[0]));
462 my_assert_not(rlist, NULL);
463
464 for (; arg < argc; arg++) {
465 frlist = fopen(argv[arg], "r");
466 my_assert_not(frlist, NULL);
467
9ea60b8d 468 while (my_fgets(line, sizeof(line), frlist)) {
36595fd2 469 p = sskip(line);
470 if (*p == 0 || *p == ';')
471 continue;
472
473 p = next_word(words[0], sizeof(words[0]), p);
474 if (words[0][0] == 0)
475 continue;
476
477 if (rlist_cnt >= rlist_alloc) {
478 rlist_alloc = rlist_alloc * 2 + 64;
479 rlist = realloc(rlist, rlist_alloc * sizeof(rlist[0]));
480 my_assert_not(rlist, NULL);
481 }
482 rlist[rlist_cnt++] = strdup(words[0]);
483 }
484
485 fclose(frlist);
486 frlist = NULL;
487 }
488
489 if (rlist_cnt > 0)
490 qsort(rlist, rlist_cnt, sizeof(rlist[0]), cmpstringp);
491
c87eb470 492 qsort(unwanted_syms, ARRAY_SIZE(unwanted_syms),
493 sizeof(unwanted_syms[0]), cmpstringp);
494
495 last_sym[0] = 0;
496
36595fd2 497 while (1) {
054f95b2 498 next_section(fasm, line);
36595fd2 499 if (feof(fasm))
500 break;
054f95b2 501 if (IS(line + 1, "text"))
502 continue;
503
afdd4566 504 if (IS(line + 1, "rdata")) {
505 is_ro = 1;
506 if (!header_mode)
507 fprintf(fout, "\n.section .rodata\n");
508 }
509 else if (IS(line + 1, "data")) {
510 is_ro = 0;
511 if (!header_mode)
512 fprintf(fout, "\n.data\n");
513 }
054f95b2 514 else
515 aerr("unhandled section: '%s'\n", line);
516
afdd4566 517 if (!header_mode)
518 fprintf(fout, ".align %d\n", align_value(4));
054f95b2 519
9ea60b8d 520 while (my_fgets(line, sizeof(line), fasm))
054f95b2 521 {
522 sym = NULL;
523 asmln++;
524
525 p = sskip(line);
b0d802b2 526 if (*p == 0)
527 continue;
528
529 if (*p == ';') {
530 if (IS_START(p, ";org") && sscanf(p + 5, "%Xh", &i) == 1) {
531 // ;org is only seen at section start, so assume . addr 0
532 i &= 0xfff;
afdd4566 533 if (i != 0 && !header_mode)
b0d802b2 534 fprintf(fout, "\t\t .skip 0x%x\n", i);
535 }
054f95b2 536 continue;
b0d802b2 537 }
054f95b2 538
539 for (wordc = 0; wordc < ARRAY_SIZE(words); wordc++) {
054f95b2 540 p = sskip(next_word_s(words[wordc], sizeof(words[0]), p));
541 if (*p == 0 || *p == ';') {
542 wordc++;
543 break;
544 }
545 if (*p == ',') {
054f95b2 546 p = sskip(p + 1);
547 }
548 }
549
b545ba7c 550 if (*p == ';') {
551 p = sskip(p + 1);
552 if (IS_START(p, "sctclrtype"))
553 g_func_sym_pp = NULL;
554 }
555
054f95b2 556 if (wordc == 2 && IS(words[1], "ends"))
557 break;
36595fd2 558 if (wordc <= 2 && IS(words[0], "end"))
559 break;
054f95b2 560 if (wordc < 2)
561 aerr("unhandled: '%s'\n", words[0]);
562
563 // don't cares
564 if (IS(words[0], "assume"))
565 continue;
566
567 if (IS(words[0], "align")) {
afdd4566 568 if (header_mode)
569 continue;
570
e27467d0 571 val = parse_number(words[1], 0);
f0be238a 572 fprintf(fout, "\t\t .align %d", align_value(val));
054f95b2 573 goto fin;
574 }
575
c1fbaecc 576 if (IS(words[0], "public")) {
577 // skip, sym should appear in header anyway
578 continue;
579 }
580
054f95b2 581 w = 1;
582 type = parse_dx_directive(words[0]);
583 if (type == DXT_UNSPEC) {
584 type = parse_dx_directive(words[1]);
585 sym = words[0];
586 w = 2;
587 }
588 if (type == DXT_UNSPEC)
589 aerr("unhandled decl: '%s %s'\n", words[0], words[1]);
590
afdd4566 591 if (sym != NULL)
592 {
593 if (header_mode) {
594 int is_str = 0;
595
596 fprintf(fout, "extern ");
597 if (is_ro)
598 fprintf(fout, "const ");
599
600 switch (type) {
601 case DXT_BYTE:
602 for (i = w; i < wordc; i++)
603 if (words[i][0] == '\'')
604 is_str = 1;
605 if (is_str)
606 fprintf(fout, "char %s[];\n", sym);
607 else
608 fprintf(fout, "uint8_t %s;\n", sym);
609 break;
610
611 case DXT_WORD:
612 fprintf(fout, "uint16_t %s;\n", sym);
613 break;
614
615 case DXT_DWORD:
616 fprintf(fout, "uint32_t %s;\n", sym);
617 break;
618
619 default:
620 fprintf(fout, "_UNKNOWN %s;\n", sym);
621 break;
622 }
623
624 continue;
625 }
626
c87eb470 627 snprintf(last_sym, sizeof(last_sym), "%s", sym);
36595fd2 628
b545ba7c 629 pp = proto_parse(fhdr, sym, 1);
c87eb470 630 if (pp != NULL) {
b545ba7c 631 g_func_sym_pp = NULL;
632
c87eb470 633 // public/global name
634 if (pub_sym_cnt >= pub_sym_alloc) {
635 pub_sym_alloc *= 2;
636 pub_syms = realloc(pub_syms, pub_sym_alloc * sizeof(pub_syms[0]));
637 my_assert_not(pub_syms, NULL);
638 }
639 pub_syms[pub_sym_cnt++] = strdup(sym);
640 }
641
054f95b2 642 len = strlen(sym);
aa1aa2c2 643 fprintf(fout, "%s%s:", no_decorations ? "" : "_", sym);
054f95b2 644
645 len += 2;
646 if (len < 8)
647 fprintf(fout, "\t");
648 if (len < 16)
649 fprintf(fout, "\t");
650 if (len <= 16)
651 fprintf(fout, " ");
652 else
653 fprintf(fout, " ");
654 }
655 else {
afdd4566 656 if (header_mode)
657 continue;
658
054f95b2 659 fprintf(fout, "\t\t ");
660 }
661
c87eb470 662 // fill out some unwanted strings with zeroes..
663 if (type == DXT_BYTE && words[w][0] == '\''
664 && is_unwanted_sym(last_sym))
665 {
666 len = 0;
667 for (; w < wordc; w++) {
668 if (words[w][0] == '\'') {
669 p = words[w] + 1;
670 for (; *p && *p != '\''; p++)
671 len++;
672 }
673 else {
674 // assume encoded byte
675 len++;
676 }
677 }
678 fprintf(fout, ".skip %d", len);
679 goto fin;
680 }
681 else if (type == DXT_BYTE
efea2951 682 && (words[w][0] == '\''
683 || (w + 1 < wordc && words[w + 1][0] == '\'')))
684 {
054f95b2 685 // string; use asciz for most common case
686 if (w == wordc - 2 && IS(words[w + 1], "0")) {
687 fprintf(fout, ".asciz \"");
688 wordc--;
689 }
690 else
691 fprintf(fout, ".ascii \"");
692
693 for (; w < wordc; w++) {
694 if (words[w][0] == '\'') {
695 p = words[w] + 1;
696 p2 = strchr(p, '\'');
697 if (p2 == NULL)
698 aerr("unterminated string? '%s'\n", p);
699 memcpy(word, p, p2 - p);
700 word[p2 - p] = 0;
701 fprintf(fout, "%s", escape_string(word));
702 }
703 else {
e27467d0 704 val = parse_number(words[w], 0);
054f95b2 705 if (val & ~0xff)
706 aerr("bad string trailing byte?\n");
206c0727 707 // unfortunately \xHH is unusable - gas interprets
708 // things like \x27b as 0x7b, so have to use octal here
709 fprintf(fout, "\\%03lo", val);
054f95b2 710 }
711 }
712 fprintf(fout, "\"");
713 goto fin;
714 }
715
716 if (w == wordc - 2) {
717 if (IS_START(words[w + 1], "dup(")) {
e27467d0 718 cnt = parse_number(words[w], 0);
054f95b2 719 p = words[w + 1] + 4;
720 p2 = strchr(p, ')');
721 if (p2 == NULL)
722 aerr("bad dup?\n");
723 memmove(word, p, p2 - p);
724 word[p2 - p] = 0;
36595fd2 725
726 val = 0;
727 if (!IS(word, "?"))
e27467d0 728 val = parse_number(word, 0);
054f95b2 729
730 fprintf(fout, ".fill 0x%02lx,%d,0x%02lx",
731 cnt, type_size(type), val);
732 goto fin;
733 }
734 }
735
736 if (type == DXT_DWORD && words[w][0] == '\''
737 && words[w][5] == '\'' && strlen(words[w]) == 6)
738 {
739 if (w != wordc - 1)
740 aerr("TODO\n");
741
742 p = words[w];
743 val = (p[1] << 24) | (p[2] << 16) | (p[3] << 8) | p[4];
744 fprintf(fout, ".long 0x%lx", val);
b545ba7c 745 snprintf(g_comment, sizeof(g_comment), "%s", words[w]);
054f95b2 746 goto fin;
747 }
748
36595fd2 749 if (type >= DXT_DWORD && strchr(words[w], '.'))
054f95b2 750 {
751 if (w != wordc - 1)
752 aerr("TODO\n");
753
f0be238a 754 if (g_arm_mode && type == DXT_TEN) {
755 fprintf(fout, ".fill 10");
756 snprintf(g_comment, sizeof(g_comment), "%s %s",
757 type_name_float(type), words[w]);
758 }
759 else
760 fprintf(fout, "%s %s", type_name_float(type), words[w]);
054f95b2 761 goto fin;
762 }
763
764 first = 1;
765 fprintf(fout, "%s ", type_name(type));
766 for (; w < wordc; w++)
767 {
768 if (!first)
769 fprintf(fout, ", ");
770
36595fd2 771 is_label = is_bss = 0;
772 if (w <= wordc - 2 && IS(words[w], "offset")) {
054f95b2 773 is_label = 1;
774 w++;
775 }
36595fd2 776 else if (IS(words[w], "?")) {
777 is_bss = 1;
778 }
054f95b2 779 else if (type == DXT_DWORD
780 && !('0' <= words[w][0] && words[w][0] <= '9'))
781 {
782 // assume label
783 is_label = 1;
784 }
785
36595fd2 786 if (is_bss) {
787 fprintf(fout, "0");
788 }
789 else if (is_label) {
054f95b2 790 p = words[w];
ddaf8bd7 791 if (IS_START(p, "loc_") || IS_START(p, "__imp")
792 || strchr(p, '?') || strchr(p, '@')
36595fd2 793 || bsearch(&p, rlist, rlist_cnt, sizeof(rlist[0]),
794 cmpstringp))
054f95b2 795 {
796 fprintf(fout, "0");
b545ba7c 797 snprintf(g_comment, sizeof(g_comment), "%s", p);
36595fd2 798 }
799 else {
c0050df6 800 pp = check_var(fhdr, sym, p);
aa1aa2c2 801 if (pp == NULL) {
802 fprintf(fout, "%s%s",
803 (no_decorations || p[0] == '_') ? "" : "_", p);
804 }
805 else {
806 if (no_decorations)
807 fprintf(fout, "%s", pp->name);
808 else
809 output_decorated_pp(fout, pp);
810 }
054f95b2 811 }
054f95b2 812 }
813 else {
e27467d0 814 val64 = parse_number(words[w], 1);
815 if (val64 < 10)
816 fprintf(fout, "%d", (int)val64);
054f95b2 817 else
e27467d0 818 fprintf(fout, "0x%" PRIx64, val64);
054f95b2 819 }
820
821 first = 0;
822 }
823
824fin:
b545ba7c 825 if (g_comment[0] != 0) {
f0be238a 826 fprintf(fout, "\t\t%c %s", comment_char, g_comment);
b545ba7c 827 g_comment[0] = 0;
054f95b2 828 }
829 fprintf(fout, "\n");
054f95b2 830 }
831 }
832
36595fd2 833 fprintf(fout, "\n");
834
835 // dump public syms
836 for (i = 0; i < pub_sym_cnt; i++)
aa1aa2c2 837 fprintf(fout, ".global %s%s\n",
838 no_decorations ? "" : "_", pub_syms[i]);
36595fd2 839
054f95b2 840 fclose(fout);
841 fclose(fasm);
afdd4566 842 if (fhdr != NULL)
843 fclose(fhdr);
054f95b2 844
845 return 0;
846}
847
848// vim:ts=2:shiftwidth=2:expandtab