# HG changeset patch # User lost@l-w.ca # Date 1279160123 21600 # Node ID a741d2e4869fa03fbd76b14c50b8a6785e029265 # Parent af5f2c51db76b7d74ff919849e835a71f0be18bc Various bugfixes; fixed lwobjdump to display symbols with unprintable characters more sensibly; start of a (nonfunctional for now) testing framework diff -r af5f2c51db76 -r a741d2e4869f lwasm/list.c --- a/lwasm/list.c Sun May 16 13:03:17 2010 -0600 +++ b/lwasm/list.c Wed Jul 14 20:15:23 2010 -0600 @@ -59,7 +59,13 @@ } else { - fprintf(of, "%04X ", lw_expr_intval(cl -> addr)); + lw_expr_t te; + te = lw_expr_copy(cl -> addr); + as -> exportcheck = 1; + lwasm_reduce_expr(as, te); + as -> exportcheck = 0; + fprintf(of, "%04X ", lw_expr_intval(te) & 0xffff); + lw_expr_destroy(te); for (i = 0; i < cl -> outputl && i < 8; i++) { fprintf(of, "%02X", cl -> output[i]); @@ -84,6 +90,8 @@ } fprintf(of, "%02X", cl -> output[i]); } + if (i % 8) + fprintf(of, "\n"); } } } diff -r af5f2c51db76 -r a741d2e4869f lwasm/lwasm.c --- a/lwasm/lwasm.c Sun May 16 13:03:17 2010 -0600 +++ b/lwasm/lwasm.c Wed Jul 14 20:15:23 2010 -0600 @@ -781,3 +781,57 @@ fprintf(stderr, " LINE: %s\n", cl -> ltext); } } + +/* +this does any passes and other gymnastics that might be useful +to see if an expression reduces early +*/ +extern void do_pass3(asmstate_t *as); +extern void do_pass4_aux(asmstate_t *as, int force); + +void lwasm_interim_reduce(asmstate_t *as) +{ + do_pass3(as); +// do_pass4_aux(as, 0); +} + +lw_expr_t lwasm_parse_cond(asmstate_t *as, char **p) +{ + lw_expr_t e; + + debug_message(as, 250, "Parsing condition"); + e = lwasm_parse_expr(as, p); + debug_message(as, 250, "COND EXPR: %s", lw_expr_print(e)); + + if (!e) + { + lwasm_register_error(as, as -> cl, "Bad expression"); + return NULL; + } + + /* we need to simplify the expression here */ + debug_message(as, 250, "Doing interim reductions"); + lwasm_interim_reduce(as); + debug_message(as, 250, "COND EXPR: %s", lw_expr_print(e)); + debug_message(as, 250, "Reducing expression"); + lwasm_reduce_expr(as, e); + debug_message(as, 250, "COND EXPR: %s", lw_expr_print(e)); +/* lwasm_reduce_expr(as, e); + debug_message(as, 250, "COND EXPR: %s", lw_expr_print(e)); + lwasm_reduce_expr(as, e); + debug_message(as, 250, "COND EXPR: %s", lw_expr_print(e)); + lwasm_reduce_expr(as, e); + debug_message(as, 250, "COND EXPR: %s", lw_expr_print(e)); +*/ + + lwasm_save_expr(as -> cl, 4242, e); + + if (!lw_expr_istype(e, lw_expr_type_int)) + { + debug_message(as, 250, "Non-constant expression"); + lwasm_register_error(as, as -> cl, "Conditions must be constant on pass 1"); + return NULL; + } + debug_message(as, 250, "Returning expression"); + return e; +} diff -r af5f2c51db76 -r a741d2e4869f lwasm/lwasm.h --- a/lwasm/lwasm.h Sun May 16 13:03:17 2010 -0600 +++ b/lwasm/lwasm.h Wed Jul 14 20:15:23 2010 -0600 @@ -275,6 +275,7 @@ extern void debug_message(asmstate_t *as, int level, const char *fmt, ...); extern void dump_state(asmstate_t *as); +extern lw_expr_t lwasm_parse_cond(asmstate_t *as, char **p); #endif diff -r af5f2c51db76 -r a741d2e4869f lwasm/main.c --- a/lwasm/main.c Sun May 16 13:03:17 2010 -0600 +++ b/lwasm/main.c Wed Jul 14 20:15:23 2010 -0600 @@ -260,4 +260,6 @@ debug_message(&asmstate, 50, "Done assembly"); do_list(&asmstate); + + exit(0); } diff -r af5f2c51db76 -r a741d2e4869f lwasm/output.c --- a/lwasm/output.c Sun May 16 13:03:17 2010 -0600 +++ b/lwasm/output.c Wed Jul 14 20:15:23 2010 -0600 @@ -243,7 +243,7 @@ { case lw_expr_type_oper: buf[0] = 0x04; - switch (lw_expr_intval(e)) + switch (lw_expr_whichop(e)) { case lw_expr_oper_plus: buf[1] = 0x01; @@ -301,7 +301,7 @@ buf[1] = 0xff; } writebytes(buf, 2, 1, of); - break; + return 0; case lw_expr_type_int: v = lw_expr_intval(e); @@ -309,7 +309,7 @@ buf[1] = (v >> 8) & 0xff; buf[2] = v & 0xff; writebytes(buf, 3, 1, of); - break; + return 0; case lw_expr_type_special: v = lw_expr_specint(e); @@ -321,9 +321,9 @@ sectiontab_t *se; se = lw_expr_specptr(e); - writebytes("\x03\x02", 1, 1, of); + writebytes("\x03\x02", 2, 1, of); writebytes(se -> name, strlen(se -> name) + 1, 1, of); - break; + return 0; } case lwasm_expr_import: { @@ -332,7 +332,7 @@ buf[0] = 0x02; writebytes(buf, 1, 1, of); writebytes(ie -> symbol, strlen(ie -> symbol) + 1, 1, of); - break; + return 0; } case lwasm_expr_syment: { @@ -347,13 +347,13 @@ writebytes(buf, strlen(buf), 1, of); } writebytes("", 1, 1, of); - break; + return 0; } - break; } default: // unrecognized term type - replace with integer 0 +// fprintf(stderr, "Unrecognized term type: %s\n", lw_expr_print(e)); buf[0] = 0x01; buf[1] = 0x00; buf[2] = 0x00; @@ -408,7 +408,7 @@ if (l -> outputl > 0) for (i = 0; i < l -> outputl; i++) write_code_obj_sbadd(l -> csect, l -> output[i]); - else if (l -> outputl == 0) + else if (l -> outputl == 0 || l -> outputl == -1) for (i = 0; i < l -> len; i++) write_code_obj_sbadd(l -> csect, 0); } @@ -432,6 +432,8 @@ // a symbol for section base address writebytes("\x02", 1, 1, of); writebytes(s -> name, strlen(s -> name) + 1, 1, of); + // address 0; "\0" is not an error + writebytes("\0", 2, 1, of); for (se = as -> symtab.head; se; se = se -> next) { // ignore symbols not in this section @@ -525,7 +527,7 @@ writebytes(buf, 2, 1, of); } - te = lw_expr_copy(ex -> se -> value); + te = lw_expr_copy(re -> offset); lwasm_reduce_expr(as, te); if (!lw_expr_istype(te, lw_expr_type_int)) { diff -r af5f2c51db76 -r a741d2e4869f lwasm/pass4.c --- a/lwasm/pass4.c Sun May 16 13:03:17 2010 -0600 +++ b/lwasm/pass4.c Wed Jul 14 20:15:23 2010 -0600 @@ -36,7 +36,7 @@ Force resolution of instruction sizes. */ -void do_pass4(asmstate_t *as) +void do_pass4_aux(asmstate_t *as, int force) { int rc; int cnt; @@ -76,7 +76,7 @@ if (sl -> len == -1 && sl -> insn >= 0 && instab[sl -> insn].resolve) { (instab[sl -> insn].resolve)(as, sl, 1); - if (sl -> len == -1) + if (force && sl -> len == -1) { lwasm_register_error(as, sl, "Instruction failed to resolve."); return; @@ -122,3 +122,8 @@ } while (rc > 0); } } + +void do_pass4(asmstate_t *as) +{ + do_pass4_aux(as, 1); +} diff -r af5f2c51db76 -r a741d2e4869f lwasm/pseudo.c --- a/lwasm/pseudo.c Sun May 16 13:03:17 2010 -0600 +++ b/lwasm/pseudo.c Wed Jul 14 20:15:23 2010 -0600 @@ -657,18 +657,8 @@ return; } - e = lwasm_parse_expr(as, p); - if (!e) - { - lwasm_register_error(as, l, "Bad expression"); - return; - } - if (!lw_expr_istype(e, lw_expr_type_int)) - { - lwasm_register_error(as, l, "Conditions must be constant on pass 1"); - return; - } - if (lw_expr_intval(e) != 0) + e = lwasm_parse_cond(as, p); + if (e && lw_expr_intval(e) != 0) { as -> skipcond = 1; as -> skipcount = 1; @@ -688,18 +678,8 @@ return; } - e = lwasm_parse_expr(as, p); - if (!e) - { - lwasm_register_error(as, l, "Bad expression"); - return; - } - if (!lw_expr_istype(e, lw_expr_type_int)) - { - lwasm_register_error(as, l, "Conditions must be constant on pass 1"); - return; - } - if (lw_expr_intval(e) == 0) + e = lwasm_parse_cond(as, p); + if (e && lw_expr_intval(e) == 0) { as -> skipcond = 1; as -> skipcount = 1; @@ -720,18 +700,8 @@ return; } - e = lwasm_parse_expr(as, p); - if (!e) - { - lwasm_register_error(as, l, "Bad expression"); - return; - } - if (!lw_expr_istype(e, lw_expr_type_int)) - { - lwasm_register_error(as, l, "Conditions must be constant on pass 1"); - return; - } - if (lw_expr_intval(e) <= 0) + e = lwasm_parse_cond(as, p); + if (e && lw_expr_intval(e) <= 0) { as -> skipcond = 1; as -> skipcount = 1; @@ -751,18 +721,8 @@ return; } - e = lwasm_parse_expr(as, p); - if (!e) - { - lwasm_register_error(as, l, "Bad expression"); - return; - } - if (!lw_expr_istype(e, lw_expr_type_int)) - { - lwasm_register_error(as, l, "Conditions must be constant on pass 1"); - return; - } - if (lw_expr_intval(e) < 0) + e = lwasm_parse_cond(as, p); + if (e && lw_expr_intval(e) < 0) { as -> skipcond = 1; as -> skipcount = 1; @@ -782,18 +742,8 @@ return; } - e = lwasm_parse_expr(as, p); - if (!e) - { - lwasm_register_error(as, l, "Bad expression"); - return; - } - if (!lw_expr_istype(e, lw_expr_type_int)) - { - lwasm_register_error(as, l, "Conditions must be constant on pass 1"); - return; - } - if (lw_expr_intval(e) >= 0) + e = lwasm_parse_cond(as, p); + if (e && lw_expr_intval(e) >= 0) { as -> skipcond = 1; as -> skipcount = 1; @@ -813,18 +763,8 @@ return; } - e = lwasm_parse_expr(as, p); - if (!e) - { - lwasm_register_error(as, l, "Bad expression"); - return; - } - if (!lw_expr_istype(e, lw_expr_type_int)) - { - lwasm_register_error(as, l, "Conditions must be constant on pass 1"); - return; - } - if (lw_expr_intval(e) > 0) + e = lwasm_parse_cond(as, p); + if (e && lw_expr_intval(e) > 0) { as -> skipcond = 1; as -> skipcount = 1; diff -r af5f2c51db76 -r a741d2e4869f lwasm/section.c --- a/lwasm/section.c Sun May 16 13:03:17 2010 -0600 +++ b/lwasm/section.c Wed Jul 14 20:15:23 2010 -0600 @@ -48,6 +48,8 @@ return; } + l -> len = 0; + if (as -> csect) { lw_expr_destroy(as -> csect -> offset); @@ -86,9 +88,13 @@ { // create section data structure s = lw_alloc(sizeof(sectiontab_t)); + s -> oblen = 0; + s -> obsize = 0; + s -> obytes = NULL; s -> name = lw_strdup(sn); s -> offset = lw_expr_build(lw_expr_type_special, lwasm_expr_secbase, s); s -> flags = section_flag_none; + s -> reloctab = NULL; if (!strcasecmp(sn, "bss") || !strcasecmp(sn, ".bss")) { s -> flags |= section_flag_bss; @@ -140,6 +146,8 @@ return; } + l -> len = 0; + if (!(as -> csect)) { lwasm_register_error(as, l, "ENDSECTION without SECTION"); @@ -171,6 +179,8 @@ lwasm_register_error(as, l, "EXPORT only supported for object target"); return; } + + l -> len = 0; if (l -> sym) { @@ -232,6 +242,8 @@ return; } + l -> len = 0; + if (l -> sym) { sym = lw_strdup(l -> sym); @@ -296,6 +308,8 @@ return; } + l -> len = 0; + if (l -> sym) sym = lw_strdup(l -> sym); diff -r af5f2c51db76 -r a741d2e4869f lwlib/lw_expr.c --- a/lwlib/lw_expr.c Sun May 16 13:03:17 2010 -0600 +++ b/lwlib/lw_expr.c Wed Jul 14 20:15:23 2010 -0600 @@ -49,6 +49,13 @@ return -1; } +int lw_expr_whichop(lw_expr_t e) +{ + if (e -> type == lw_expr_type_oper) + return e -> value; + return -1; +} + int lw_expr_specint(lw_expr_t e) { if (e -> type == lw_expr_type_special) @@ -198,7 +205,12 @@ struct lw_expr_opers *o; int c = 0; char buf[256]; - + + if (!E) + { + strcpy(buf, "(NULL)"); + return; + } for (o = E -> operands; o; o = o -> next) { c++; @@ -463,7 +475,9 @@ return 1; } -void lw_expr_simplify(lw_expr_t E, void *priv) +void lw_expr_simplify(lw_expr_t E, void *priv); + +void lw_expr_simplify_go(lw_expr_t E, void *priv) { struct lw_expr_opers *o; @@ -920,8 +934,80 @@ } return; } + + /* handle times - expand the terms - only with exactly two operands */ + if (E -> value == lw_expr_oper_times) + { + lw_expr_t t1; + lw_expr_t E2; + lw_expr_t E3; + if (E -> operands && E -> operands -> next && !(E -> operands -> next -> next)) + { + if (E -> operands -> p -> type == lw_expr_type_int) + { + /* TIMES */ + E2 = E -> operands -> next -> p; + E3 = E -> operands -> p; + if (E2 -> type == lw_expr_type_oper && E2 -> value == lw_expr_oper_plus) + { + lw_free(E -> operands -> next); + lw_free(E -> operands); + E -> operands = NULL; + E -> value = lw_expr_oper_plus; + + for (o = E2 -> operands; o; o = o -> next) + { + t1 = lw_expr_build(lw_expr_type_oper, lw_expr_oper_times, E3, o -> p); + lw_expr_add_operand(E, t1); + } + + lw_expr_destroy(E2); + lw_expr_destroy(E3); + } + } + else if (E -> operands -> next -> p -> type == lw_expr_type_int) + { + /* TIMES */ + E2 = E -> operands -> p; + E3 = E -> operands -> next -> p; + if (E2 -> type == lw_expr_type_oper && E2 -> value == lw_expr_oper_plus) + { + lw_free(E -> operands -> next); + lw_free(E -> operands); + E -> operands = NULL; + E -> value = lw_expr_oper_plus; + + for (o = E2 -> operands; o; o = o -> next) + { + t1 = lw_expr_build(lw_expr_type_oper, lw_expr_oper_times, E3, o -> p); + lw_expr_add_operand(E, t1); + } + + lw_expr_destroy(E2); + lw_expr_destroy(E3); + } + } + } + } } +void lw_expr_simplify(lw_expr_t E, void *priv) +{ + lw_expr_t te; + int c; + do + { + te = lw_expr_copy(E); + lw_expr_simplify_go(E, priv); + c = 0; + if (lw_expr_compare(te, E) == 0) + c = 1; + lw_expr_destroy(te); + } + while (c); +} + + /* The following two functions are co-routines which evaluate an infix diff -r af5f2c51db76 -r a741d2e4869f lwlib/lw_expr.h --- a/lwlib/lw_expr.h Sun May 16 13:03:17 2010 -0600 +++ b/lwlib/lw_expr.h Wed Jul 14 20:15:23 2010 -0600 @@ -99,6 +99,7 @@ extern int lw_expr_intval(lw_expr_t e); extern int lw_expr_specint(lw_expr_t e); extern void *lw_expr_specptr(lw_expr_t e); +extern int lw_expr_whichop(lw_expr_t e); extern int lw_expr_type(lw_expr_t e); diff -r af5f2c51db76 -r a741d2e4869f lwlink/objdump.c --- a/lwlink/objdump.c Sun May 16 13:03:17 2010 -0600 +++ b/lwlink/objdump.c Wed Jul 14 20:15:23 2010 -0600 @@ -34,6 +34,42 @@ void read_lwobj16v0(unsigned char *filedata, long filesize); char *program_name; +char *string_cleanup(char *sym) +{ + static char symbuf[4096]; + int optr = 0; + while (*sym) + { + if (*sym < 33 || *sym > 126) + { + int c; + symbuf[optr++] = '\\'; + c = *sym >> 4; + c+= 48; + if (c > 57) + c += 7; + symbuf[optr++] = c; + c = *sym & 15; + c += 48; + if (c > 57) + c += 7; + symbuf[optr++] = c; + } + else if (*sym == '\\') + { + symbuf[optr++] = '\\'; + symbuf[optr++] = '\\'; + } + else + { + symbuf[optr++] = *sym; + } + sym++; + } + symbuf[optr] = '\0'; + return symbuf; +} + /* The logic of reading the entire file into memory is simple. All the symbol names in the file are NUL terminated strings and can be used directly without @@ -185,7 +221,7 @@ NEXTBYTE(); // val is now the symbol value - printf(" %s=%04X\n", fp, val); + printf(" %s=%04X\n", string_cleanup(fp), val); } // skip terminating NUL @@ -205,7 +241,7 @@ NEXTBYTE(); // val is now the symbol value - printf(" %s=%04X\n", fp, val); + printf(" %s=%04X\n", string_cleanup(fp), val); } // skip terminating NUL NEXTBYTE(); @@ -237,12 +273,12 @@ case 0x02: // external symbol reference - printf(" ES=%s", CURSTR()); + printf(" ES=%s", string_cleanup(CURSTR())); break; case 0x03: // internal symbol reference - printf(" IS=%s", CURSTR()); + printf(" IS=%s", string_cleanup(CURSTR())); break; case 0x04: diff -r af5f2c51db76 -r a741d2e4869f m4/gnulib-cache.m4 --- a/m4/gnulib-cache.m4 Sun May 16 13:03:17 2010 -0600 +++ b/m4/gnulib-cache.m4 Wed Jul 14 20:15:23 2010 -0600 @@ -1,4 +1,4 @@ -# Copyright (C) 2002-2009 Free Software Foundation, Inc. +# Copyright (C) 2002-2010 Free Software Foundation, Inc. # # This file is free software, distributed under the terms of the GNU # General Public License. As a special exception to the GNU General diff -r af5f2c51db76 -r a741d2e4869f test/README --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/README Wed Jul 14 20:15:23 2010 -0600 @@ -0,0 +1,11 @@ +This folder contains various schemes for testing LWTOOLS. The tests are +undocumented and will remain so unless someone wishes to create +documentation for them. They are also specific to LWTOOLS. + +In general, a test should be created every time a bug is discovered; that +test should fail if the bug is found. No test need be created if another +test already covers the bug in question. + +Before any release is made, the test suite should be run to ensure there are +no regressions. This will not guarantee that there are no new bugs, but it +should prevent old bugs from creeping in again. diff -r af5f2c51db76 -r a741d2e4869f test/lwasm.t/README --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/lwasm.t/README Wed Jul 14 20:15:23 2010 -0600 @@ -0,0 +1,1 @@ +This directory contains various tests for the lwasm program itself. diff -r af5f2c51db76 -r a741d2e4869f test/runtests.sh --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/runtests.sh Wed Jul 14 20:15:23 2010 -0600 @@ -0,0 +1,50 @@ +#!/bin/bash +# +# run the various tests under the tests/ folder recursively + +function runtests() +{ + local fn + local base="$2" + local odir=`pwd` + local dir="$1" + + cd "$dir" + + for fn in *.t; do + if [ -d "$fn" ]; then + echo "Running tests in $base/$fn" + runtests "$fn" "$base/$fn" + elif [ -r "$fn" ]; then + echo "Running test $fn" + testcount=$(($testcount+1)) + TESTSTATE=failed + source "$fn" + if [ "$TESTSTATE" = ok ]; then + testpassed=$(($testpassed+1)) + else + testfailed=$(($testfailed+1)) + fi + fi + done + + cd "$odir" +} + +testcount=0 +testfailed=0 +testpassed=0 + +dir="$1" +if [ "x$dir" = "x" ]; then + dir=. +fi + +runtests "$dir" "$dir" + +echo "Passed $testpassed tests of $testcount" +if [ "$testfailed" -ne 0 ]; then + echo "Failed $testfailed of $testcount tests!" + exit 1 +fi +exit 0