X-Git-Url: https://notaz.gp2x.de/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=tools%2Fcvt_data.c;h=692fa1076ac351b0af52e5816009a4d31d8538f4;hb=7a7487bee79c16312270eb30275b095c92324348;hp=e21ff96e0b724cfc9b45ab01cd3ba0a0a3e6bb98;hpb=c0050df6e9d6eb81afacb0fa2d1910293dd2165e;p=ia32rtools.git diff --git a/tools/cvt_data.c b/tools/cvt_data.c index e21ff96..692fa10 100644 --- a/tools/cvt_data.c +++ b/tools/cvt_data.c @@ -1,14 +1,21 @@ +/* + * ia32rtools + * (C) notaz, 2013,2014 + * + * This work is licensed under the terms of 3-clause BSD license. + * See COPYING file in the top-level directory. + */ + #define _GNU_SOURCE #include #include #include +#include +#include #include "my_assert.h" #include "my_str.h" - -#define ARRAY_SIZE(x) (sizeof(x) / sizeof(x[0])) -#define IS(w, y) !strcmp(w, y) -#define IS_START(w, y) !strncmp(w, y, strlen(y)) +#include "common.h" #include "protoparse.h" @@ -18,6 +25,8 @@ static int asmln; static const struct parsed_proto *g_func_sym_pp; static char g_comment[256]; static int g_warn_cnt; +static int g_cconv_novalidate; +static int g_arm_mode; // note: must be in ascending order enum dx_type { @@ -77,7 +86,7 @@ static void next_section(FILE *fasm, char *name) name[0] = 0; - while (fgets(line, sizeof(line), fasm)) + while (my_fgets(line, sizeof(line), fasm)) { wordc = 0; asmln++; @@ -86,14 +95,8 @@ static void next_section(FILE *fasm, char *name) if (*p == 0) continue; - if (*p == ';') { - while (strlen(line) == sizeof(line) - 1) { - // one of those long comment lines.. - if (!fgets(line, sizeof(line), fasm)) - break; - } + if (*p == ';') continue; - } for (wordc = 0; wordc < ARRAY_SIZE(words); wordc++) { p = sskip(next_word(words[wordc], sizeof(words[0]), p)); @@ -136,7 +139,7 @@ static const char *type_name(enum dx_type type) case DXT_BYTE: return ".byte"; case DXT_WORD: - return ".word"; + return ".hword"; case DXT_DWORD: return ".long"; case DXT_QUAD: @@ -190,7 +193,7 @@ static char *escape_string(char *s) for (; *s != 0; s++) { if (*s == '"') { - strcpy(t, "\\22"); + strcpy(t, "\\\""); t += strlen(t); continue; } @@ -201,32 +204,12 @@ static char *escape_string(char *s) } *t++ = *s; } - *t = *s; + *t++ = *s; + if (t - buf > sizeof(buf)) + aerr("string is too long\n"); return strcpy(s, buf); } -static void sprint_pp(const struct parsed_proto *pp, char *buf, - size_t buf_size) -{ - size_t l; - int i; - - snprintf(buf, buf_size, "%s %s(", pp->ret_type.name, pp->name); - l = strlen(buf); - - for (i = 0; i < pp->argc_reg; i++) { - snprintf(buf + l, buf_size - l, "%s%s", - i == 0 ? "" : ", ", pp->arg[i].reg); - l = strlen(buf); - } - if (pp->argc_stack > 0) { - snprintf(buf + l, buf_size - l, "%s{%d stack}", - i == 0 ? "" : ", ", pp->argc_stack); - l = strlen(buf); - } - snprintf(buf + l, buf_size - l, ")"); -} - static void sprint_pp_short(const struct parsed_proto *pp, char *buf, size_t buf_size) { @@ -259,8 +242,8 @@ 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]; - int i, bad = 0; + char fp_sym[256], fp_var[256], *p; + int i; pp = proto_parse(fhdr, varname, 1); if (pp == NULL) { @@ -272,7 +255,7 @@ static const struct parsed_proto *check_var(FILE *fhdr, if (!pp->is_func && !pp->is_fptr) return NULL; - sprint_pp(pp, fp_var, sizeof(fp_var)); + pp_print(fp_var, sizeof(fp_var), pp); if (pp->argc_reg == 0) goto check_sym; @@ -281,14 +264,29 @@ static const struct parsed_proto *check_var(FILE *fhdr, { goto check_sym; } - if (pp->argc_reg != 2 - || !IS(pp->arg[0].reg, "ecx") - || !IS(pp->arg[1].reg, "edx")) + 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) { @@ -306,31 +304,43 @@ check_sym: return pp; } - if (pp->argc != pp_sym->argc || pp->argc_reg != pp_sym->argc_reg) - bad = 1; - else { - for (i = 0; i < pp->argc; i++) { - if ((pp->arg[i].reg != NULL) != (pp_sym->arg[i].reg != NULL)) { - bad = 1; - break; - } - if ((pp->arg[i].reg != NULL) - && !IS(pp->arg[i].reg, pp_sym->arg[i].reg)) - { - bad = 1; - break; - } + if (pp_cmp_func(pp, pp_sym)) { + if (pp_sym->argc_stack == 0 && pp_sym->is_fastcall + && pp->argc_stack == 0 + && (pp->is_fastcall || pp->argc_reg == 0) + && pp_sym->argc_reg > pp->argc_reg) + ; /* fascall compatible func doesn't use all args -> ok */ + else { + pp_print(fp_sym, sizeof(fp_sym), pp_sym); + anote("var: %s\n", fp_var); + anote("sym: %s\n", fp_sym); + awarn("^ mismatch\n"); } } - if (bad) { - sprint_pp(pp_sym, fp_sym, sizeof(fp_sym)); - anote("var: %s\n", fp_var); - anote("sym: %s\n", fp_sym); - awarn("^ mismatch\n"); + return pp; +} + +static void output_decorated_pp(FILE *fout, + const struct parsed_proto *pp) +{ + if (pp->name[0] != '_') + fprintf(fout, pp->is_fastcall ? "@" : "_"); + fprintf(fout, "%s", pp->name); + if (pp->is_stdcall && pp->argc > 0) + fprintf(fout, "@%d", pp->argc * 4); +} + +static int align_value(int src_val) +{ + if (src_val <= 0) { + awarn("bad align: %d\n", src_val); + src_val = 1; } + if (!g_arm_mode) + return src_val; - return pp; + return __builtin_ffs(src_val) - 1; } static int cmpstringp(const void *p1, const void *p2) @@ -338,15 +348,52 @@ static int cmpstringp(const void *p1, const void *p2) return strcmp(*(char * const *)p1, *(char * const *)p2); } +/* XXX: maybe move to external file? */ +static const char *unwanted_syms[] = { + "aRuntimeError", + "aTlossError", + "aSingError", + "aDomainError", + "aR6029ThisAppli", + "aR6028UnableToI", + "aR6027NotEnough", + "aR6026NotEnough", + "aR6025PureVirtu", + "aR6024NotEnough", + "aR6019UnableToO", + "aR6018Unexpecte", + "aR6017Unexpecte", + "aR6016NotEnough", + "aAbnormalProgra", + "aR6009NotEnough", + "aR6008NotEnough", + "aR6002FloatingP", + "aMicrosoftVisua", + "aRuntimeErrorPr", + "aThisApplicatio", + "aMicrosoftFindF", + "aMicrosoftOffic", +}; + +static int is_unwanted_sym(const char *sym) +{ + return bsearch(&sym, unwanted_syms, ARRAY_SIZE(unwanted_syms), + sizeof(unwanted_syms[0]), cmpstringp) != NULL; +} + int main(int argc, char *argv[]) { - FILE *fout, *fasm, *fhdr, *frlist; + 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; + uint64_t val64; const char *sym; enum dx_type type; char **pub_syms; @@ -355,6 +402,8 @@ int main(int argc, char *argv[]) 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; @@ -367,20 +416,39 @@ int main(int argc, char *argv[]) char *p2; if (argc < 4) { - printf("usage:\n%s <.s> <.asm> [rlist]*\n", - argv[0]); + // -nd: no symbol decorations + printf("usage:\n%s [-nd] [-i] [-a] <.s> <.asm> [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); - hdrfn = argv[arg++]; - fhdr = fopen(hdrfn, "r"); - my_assert_not(fhdr, 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); @@ -397,7 +465,7 @@ int main(int argc, char *argv[]) frlist = fopen(argv[arg], "r"); my_assert_not(frlist, NULL); - while (fgets(line, sizeof(line), frlist)) { + while (my_fgets(line, sizeof(line), frlist)) { p = sskip(line); if (*p == 0 || *p == ';') continue; @@ -421,6 +489,11 @@ int main(int argc, char *argv[]) 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)) @@ -428,23 +501,40 @@ int main(int argc, char *argv[]) if (IS(line + 1, "text")) continue; - if (IS(line + 1, "rdata")) - fprintf(fout, "\n.section .rodata\n"); - else if (IS(line + 1, "data")) - fprintf(fout, "\n.data\n"); + 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); - fprintf(fout, ".align 4\n"); + if (!header_mode) + fprintf(fout, ".align %d\n", align_value(4)); - while (fgets(line, sizeof(line), fasm)) + while (my_fgets(line, sizeof(line), fasm)) { sym = NULL; asmln++; p = sskip(line); - if (*p == 0 || *p == ';') + 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)); @@ -475,11 +565,19 @@ int main(int argc, char *argv[]) continue; if (IS(words[0], "align")) { - val = parse_number(words[1]); - fprintf(fout, "\t\t .align %ld", val); + if (header_mode) + continue; + + val = parse_number(words[1], 0); + fprintf(fout, "\t\t .align %d", align_value(val)); goto fin; } + if (IS(words[0], "public")) { + // skip, sym should appear in header anyway + continue; + } + w = 1; type = parse_dx_directive(words[0]); if (type == DXT_UNSPEC) { @@ -490,21 +588,59 @@ int main(int argc, char *argv[]) if (type == DXT_UNSPEC) aerr("unhandled decl: '%s %s'\n", words[0], words[1]); - if (sym != 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); + 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; } - pub_syms[pub_sym_cnt++] = strdup(sym); + + snprintf(last_sym, sizeof(last_sym), "%s", sym); pp = proto_parse(fhdr, sym, 1); - if (pp != NULL) + 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:", sym); + fprintf(fout, "%s%s:", no_decorations ? "" : "_", sym); len += 2; if (len < 8) @@ -517,10 +653,35 @@ int main(int argc, char *argv[]) fprintf(fout, " "); } else { + if (header_mode) + continue; + fprintf(fout, "\t\t "); } - if (type == DXT_BYTE && words[w][0] == '\'') { + // 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 \""); @@ -540,10 +701,12 @@ int main(int argc, char *argv[]) fprintf(fout, "%s", escape_string(word)); } else { - val = parse_number(words[w]); + val = parse_number(words[w], 0); if (val & ~0xff) aerr("bad string trailing byte?\n"); - fprintf(fout, "\\x%02lx", val); + // unfortunately \xHH is unusable - gas interprets + // things like \x27b as 0x7b, so have to use octal here + fprintf(fout, "\\%03lo", val); } } fprintf(fout, "\""); @@ -552,7 +715,7 @@ int main(int argc, char *argv[]) if (w == wordc - 2) { if (IS_START(words[w + 1], "dup(")) { - cnt = parse_number(words[w]); + cnt = parse_number(words[w], 0); p = words[w + 1] + 4; p2 = strchr(p, ')'); if (p2 == NULL) @@ -562,7 +725,7 @@ int main(int argc, char *argv[]) val = 0; if (!IS(word, "?")) - val = parse_number(word); + val = parse_number(word, 0); fprintf(fout, ".fill 0x%02lx,%d,0x%02lx", cnt, type_size(type), val); @@ -588,7 +751,13 @@ int main(int argc, char *argv[]) if (w != wordc - 1) aerr("TODO\n"); - fprintf(fout, "%s %s", type_name_float(type), words[w]); + 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; } @@ -629,19 +798,24 @@ int main(int argc, char *argv[]) } else { pp = check_var(fhdr, sym, p); - if (p[0] != '_') - fprintf(fout, (pp && pp->is_fastcall) ? "@" : "_"); - fprintf(fout, "%s", p); - if (pp && pp->is_stdcall && pp->argc > 0) - fprintf(fout, "@%d", pp->argc * 4); + 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); + val64 = parse_number(words[w], 1); + if (val64 < 10) + fprintf(fout, "%d", (int)val64); else - fprintf(fout, "0x%lx", val); + fprintf(fout, "0x%" PRIx64, val64); } first = 0; @@ -649,7 +823,7 @@ int main(int argc, char *argv[]) fin: if (g_comment[0] != 0) { - fprintf(fout, "\t\t# %s", g_comment); + fprintf(fout, "\t\t%c %s", comment_char, g_comment); g_comment[0] = 0; } fprintf(fout, "\n"); @@ -660,11 +834,13 @@ fin: // dump public syms for (i = 0; i < pub_sym_cnt; i++) - fprintf(fout, ".global _%s\n", pub_syms[i]); + fprintf(fout, ".global %s%s\n", + no_decorations ? "" : "_", pub_syms[i]); fclose(fout); fclose(fasm); - fclose(fhdr); + if (fhdr != NULL) + fclose(fhdr); return 0; }