int main(int argc, char *argv[]) { FILE *fout, *fasm, *fhdr = NULL, *frlist; const struct parsed_proto *pp; int no_decorations = 0; char comment_char = '#'; char words[20][256]; char word[256]; char line[256]; char last_sym[32]; unsigned long val; unsigned long cnt; const char *sym; enum dx_type type; char **pub_syms; int pub_sym_cnt = 0; int pub_sym_alloc; char **rlist; int rlist_cnt = 0; int rlist_alloc; int header_mode = 0; int is_ro = 0; int is_label; int is_bss; int wordc; int first; int arg_out; int arg = 1; int len; int w, i; char *p; char *p2; if (argc < 4) { // -nd: no symbol decorations printf("usage:\n%s [-nd] [-i] [-a] <.s> <.asm> <hdrf> [rlist]*\n" "%s -hdr <.h> <.asm>\n", argv[0], argv[0]); return 1; } for (arg = 1; arg < argc; arg++) { if (IS(argv[arg], "-nd")) no_decorations = 1; else if (IS(argv[arg], "-i")) g_cconv_novalidate = 1; else if (IS(argv[arg], "-a")) { comment_char = '@'; g_arm_mode = 1; } else if (IS(argv[arg], "-hdr")) header_mode = 1; else break; } arg_out = arg++; asmfn = argv[arg++]; fasm = fopen(asmfn, "r"); my_assert_not(fasm, NULL); if (!header_mode) { hdrfn = argv[arg++]; fhdr = fopen(hdrfn, "r"); my_assert_not(fhdr, NULL); } fout = fopen(argv[arg_out], "w"); my_assert_not(fout, NULL); pub_sym_alloc = 64; pub_syms = malloc(pub_sym_alloc * sizeof(pub_syms[0])); my_assert_not(pub_syms, NULL); rlist_alloc = 64; rlist = malloc(rlist_alloc * sizeof(rlist[0])); my_assert_not(rlist, NULL); for (; arg < argc; arg++) { frlist = fopen(argv[arg], "r"); my_assert_not(frlist, NULL); while (my_fgets(line, sizeof(line), frlist)) { p = sskip(line); if (*p == 0 || *p == ';') continue; p = next_word(words[0], sizeof(words[0]), p); if (words[0][0] == 0) continue; if (rlist_cnt >= rlist_alloc) { rlist_alloc = rlist_alloc * 2 + 64; rlist = realloc(rlist, rlist_alloc * sizeof(rlist[0])); my_assert_not(rlist, NULL); } rlist[rlist_cnt++] = strdup(words[0]); } fclose(frlist); frlist = NULL; } if (rlist_cnt > 0) qsort(rlist, rlist_cnt, sizeof(rlist[0]), cmpstringp); qsort(unwanted_syms, ARRAY_SIZE(unwanted_syms), sizeof(unwanted_syms[0]), cmpstringp); last_sym[0] = 0; while (1) { next_section(fasm, line); if (feof(fasm)) break; if (IS(line + 1, "text")) continue; if (IS(line + 1, "rdata")) { is_ro = 1; if (!header_mode) fprintf(fout, "\n.section .rodata\n"); } else if (IS(line + 1, "data")) { is_ro = 0; if (!header_mode) fprintf(fout, "\n.data\n"); } else aerr("unhandled section: '%s'\n", line); if (!header_mode) fprintf(fout, ".align %d\n", align_value(4)); while (my_fgets(line, sizeof(line), fasm)) { sym = NULL; asmln++; p = sskip(line); if (*p == 0) continue; if (*p == ';') { if (IS_START(p, ";org") && sscanf(p + 5, "%Xh", &i) == 1) { // ;org is only seen at section start, so assume . addr 0 i &= 0xfff; if (i != 0 && !header_mode) fprintf(fout, "\t\t .skip 0x%x\n", i); } continue; } for (wordc = 0; wordc < ARRAY_SIZE(words); wordc++) { p = sskip(next_word_s(words[wordc], sizeof(words[0]), p)); if (*p == 0 || *p == ';') { wordc++; break; } if (*p == ',') { p = sskip(p + 1); } } if (*p == ';') { p = sskip(p + 1); if (IS_START(p, "sctclrtype")) g_func_sym_pp = NULL; } if (wordc == 2 && IS(words[1], "ends")) break; if (wordc <= 2 && IS(words[0], "end")) break; if (wordc < 2) aerr("unhandled: '%s'\n", words[0]); // don't cares if (IS(words[0], "assume")) continue; if (IS(words[0], "align")) { if (header_mode) continue; val = parse_number(words[1]); fprintf(fout, "\t\t .align %d", align_value(val)); goto fin; } w = 1; type = parse_dx_directive(words[0]); if (type == DXT_UNSPEC) { type = parse_dx_directive(words[1]); sym = words[0]; w = 2; } if (type == DXT_UNSPEC) aerr("unhandled decl: '%s %s'\n", words[0], words[1]); if (sym != NULL) { if (header_mode) { int is_str = 0; fprintf(fout, "extern "); if (is_ro) fprintf(fout, "const "); switch (type) { case DXT_BYTE: for (i = w; i < wordc; i++) if (words[i][0] == '\'') is_str = 1; if (is_str) fprintf(fout, "char %s[];\n", sym); else fprintf(fout, "uint8_t %s;\n", sym); break; case DXT_WORD: fprintf(fout, "uint16_t %s;\n", sym); break; case DXT_DWORD: fprintf(fout, "uint32_t %s;\n", sym); break; default: fprintf(fout, "_UNKNOWN %s;\n", sym); break; } continue; } snprintf(last_sym, sizeof(last_sym), "%s", sym); pp = proto_parse(fhdr, sym, 1); if (pp != NULL) { g_func_sym_pp = NULL; // public/global name if (pub_sym_cnt >= pub_sym_alloc) { pub_sym_alloc *= 2; pub_syms = realloc(pub_syms, pub_sym_alloc * sizeof(pub_syms[0])); my_assert_not(pub_syms, NULL); } pub_syms[pub_sym_cnt++] = strdup(sym); } len = strlen(sym); fprintf(fout, "%s%s:", no_decorations ? "" : "_", sym); len += 2; if (len < 8) fprintf(fout, "\t"); if (len < 16) fprintf(fout, "\t"); if (len <= 16) fprintf(fout, " "); else fprintf(fout, " "); } else { if (header_mode) continue; fprintf(fout, "\t\t "); } // fill out some unwanted strings with zeroes.. if (type == DXT_BYTE && words[w][0] == '\'' && is_unwanted_sym(last_sym)) { len = 0; for (; w < wordc; w++) { if (words[w][0] == '\'') { p = words[w] + 1; for (; *p && *p != '\''; p++) len++; } else { // assume encoded byte len++; } } fprintf(fout, ".skip %d", len); goto fin; } else if (type == DXT_BYTE && (words[w][0] == '\'' || (w + 1 < wordc && words[w + 1][0] == '\''))) { // string; use asciz for most common case if (w == wordc - 2 && IS(words[w + 1], "0")) { fprintf(fout, ".asciz \""); wordc--; } else fprintf(fout, ".ascii \""); for (; w < wordc; w++) { if (words[w][0] == '\'') { p = words[w] + 1; p2 = strchr(p, '\''); if (p2 == NULL) aerr("unterminated string? '%s'\n", p); memcpy(word, p, p2 - p); word[p2 - p] = 0; fprintf(fout, "%s", escape_string(word)); } else { val = parse_number(words[w]); if (val & ~0xff) aerr("bad string trailing byte?\n"); // unfortunately \xHH is unusable - gas interprets // things like \x27b as 0x7b, so have to use octal here fprintf(fout, "\\%03lo", val); } } fprintf(fout, "\""); goto fin; } if (w == wordc - 2) { if (IS_START(words[w + 1], "dup(")) { cnt = parse_number(words[w]); p = words[w + 1] + 4; p2 = strchr(p, ')'); if (p2 == NULL) aerr("bad dup?\n"); memmove(word, p, p2 - p); word[p2 - p] = 0; val = 0; if (!IS(word, "?")) val = parse_number(word); fprintf(fout, ".fill 0x%02lx,%d,0x%02lx", cnt, type_size(type), val); goto fin; } } if (type == DXT_DWORD && words[w][0] == '\'' && words[w][5] == '\'' && strlen(words[w]) == 6) { if (w != wordc - 1) aerr("TODO\n"); p = words[w]; val = (p[1] << 24) | (p[2] << 16) | (p[3] << 8) | p[4]; fprintf(fout, ".long 0x%lx", val); snprintf(g_comment, sizeof(g_comment), "%s", words[w]); goto fin; } if (type >= DXT_DWORD && strchr(words[w], '.')) { if (w != wordc - 1) aerr("TODO\n"); if (g_arm_mode && type == DXT_TEN) { fprintf(fout, ".fill 10"); snprintf(g_comment, sizeof(g_comment), "%s %s", type_name_float(type), words[w]); } else fprintf(fout, "%s %s", type_name_float(type), words[w]); goto fin; } first = 1; fprintf(fout, "%s ", type_name(type)); for (; w < wordc; w++) { if (!first) fprintf(fout, ", "); is_label = is_bss = 0; if (w <= wordc - 2 && IS(words[w], "offset")) { is_label = 1; w++; } else if (IS(words[w], "?")) { is_bss = 1; } else if (type == DXT_DWORD && !('0' <= words[w][0] && words[w][0] <= '9')) { // assume label is_label = 1; } if (is_bss) { fprintf(fout, "0"); } else if (is_label) { p = words[w]; if (IS_START(p, "loc_") || IS_START(p, "__imp") || strchr(p, '?') || strchr(p, '@') || bsearch(&p, rlist, rlist_cnt, sizeof(rlist[0]), cmpstringp)) { fprintf(fout, "0"); snprintf(g_comment, sizeof(g_comment), "%s", p); } else { pp = check_var(fhdr, sym, p); if (pp == NULL) { fprintf(fout, "%s%s", (no_decorations || p[0] == '_') ? "" : "_", p); } else { if (no_decorations) fprintf(fout, "%s", pp->name); else output_decorated_pp(fout, pp); } } } else { val = parse_number(words[w]); if (val < 10) fprintf(fout, "%ld", val); else fprintf(fout, "0x%lx", val); } first = 0; } fin: if (g_comment[0] != 0) { fprintf(fout, "\t\t%c %s", comment_char, g_comment); g_comment[0] = 0; } fprintf(fout, "\n"); } } fprintf(fout, "\n"); // dump public syms for (i = 0; i < pub_sym_cnt; i++) fprintf(fout, ".global %s%s\n", no_decorations ? "" : "_", pub_syms[i]); fclose(fout); fclose(fasm); if (fhdr != NULL) fclose(fhdr); return 0; }
int main(int argc, char *argv[]) { const struct parsed_proto *pp; FILE *fout, *fhdr; char basename[256] = { 0, }; char line[256]; char fmt[256]; char word[256]; int noname = 0; const char *p2; char *p; int arg; int ret, ord; int l; for (arg = 1; arg < argc; arg++) { if (IS(argv[arg], "-n")) noname = 1; else if (IS(argv[arg], "-b") && arg < argc - 1) snprintf(basename, sizeof(basename), "%s", argv[++arg]); else break; } if (argc != arg + 2) { printf("usage:\n%s [-n] [-b <basename>] <.h> <.def>\n", argv[0]); return 1; } hdrfn = argv[arg++]; fhdr = fopen(hdrfn, "r"); my_assert_not(fhdr, NULL); fout = fopen(argv[arg++], "w"); my_assert_not(fout, NULL); if (basename[0] == 0) { p = strrchr(hdrfn, '.'); my_assert_not(p, NULL); p2 = strrchr(hdrfn, '/'); if (p2++ == NULL) p2 = hdrfn; l = p - p2; my_assert((unsigned int)l < 256, 1); memcpy(basename, p2, l); basename[l] = 0; } snprintf(fmt, sizeof(fmt), "%s_%%d", basename); fprintf(fout, "LIBRARY %s\n", basename); fprintf(fout, "EXPORTS\n"); while (fgets(line, sizeof(line), fhdr)) { p = sskip(line); if (*p == 0) continue; if (IS_START(p, "//")) continue; ret = 0; while (p != NULL && *p != 0) { p = next_word(word, sizeof(word), p); ret = sscanf(word, fmt, &ord); if (ret == 1) break; } if (ret != 1) { printf("scan for '%s' failed for '%s'\n", fmt, line); return 1; } snprintf(word, sizeof(word), fmt, ord); pp = proto_parse(fhdr, word, 0); if (pp == NULL) return 1; fputc(' ', fout); fputc(pp->is_fastcall ? '@' : ' ', fout); fprintf(fout, "%s", word); if (pp->is_stdcall) fprintf(fout, "@%-2d", pp->argc * 4); else fprintf(fout, " "); fprintf(fout, " @%d", ord); if (noname) fprintf(fout, " NONAME"); fprintf(fout, "\n"); } fclose(fhdr); fclose(fout); return 0; }
static const struct parsed_proto *check_var(FILE *fhdr, const char *sym, const char *varname) { const struct parsed_proto *pp, *pp_sym; char fp_sym[256], fp_var[256], *p; int i; pp = proto_parse(fhdr, varname, 1); if (pp == NULL) { if (IS_START(varname, "sub_")) awarn("sub_ sym missing proto: '%s'\n", varname); return NULL; } if (!pp->is_func && !pp->is_fptr) return NULL; pp_print(fp_var, sizeof(fp_var), pp); if (pp->argc_reg == 0) goto check_sym; if (pp->argc_reg == 1 && pp->argc_stack == 0 && IS(pp->arg[0].reg, "ecx")) { goto check_sym; } if (!g_cconv_novalidate && (pp->argc_reg != 2 || !IS(pp->arg[0].reg, "ecx") || !IS(pp->arg[1].reg, "edx"))) { awarn("unhandled reg call: %s\n", fp_var); } check_sym: // fptrs must use 32bit args, callsite might have no information and // lack a cast to smaller types, which results in incorrectly masked // args passed (callee may assume masked args, it does on ARM) for (i = 0; i < pp->argc; i++) { if (pp->arg[i].type.is_ptr) continue; p = pp->arg[i].type.name; if (strstr(p, "int8") || strstr(p, "int16") || strstr(p, "char") || strstr(p, "short")) { awarn("reference to %s with arg%d '%s'\n", pp->name, i + 1, p); } } sprint_pp_short(pp, g_comment, sizeof(g_comment)); if (sym != NULL) { g_func_sym_pp = NULL; pp_sym = proto_parse(fhdr, sym, 1); if (pp_sym == NULL) return pp; if (!pp_sym->is_fptr) aerr("func ptr data, but label '%s' !is_fptr\n", pp_sym->name); g_func_sym_pp = pp_sym; } else { pp_sym = g_func_sym_pp; if (pp_sym == NULL) return pp; } if (pp_cmp_func(pp, pp_sym)) { pp_print(fp_sym, sizeof(fp_sym), pp_sym); anote("var: %s\n", fp_var); anote("sym: %s\n", fp_sym); awarn("^ mismatch\n"); } return pp; }