# HG changeset patch # User lost # Date 1231474980 0 # Node ID a338d496350eccb1329158e1ae60544e6c7e98e1 # Parent 2fe5fd7d65a38e25454944888bb85a2671d91b72 Checkpointing conversion to allow object target diff -r 2fe5fd7d65a3 -r a338d496350e src/insn_gen.c --- a/src/insn_gen.c Thu Jan 08 02:57:24 2009 +0000 +++ b/src/insn_gen.c Fri Jan 09 04:23:00 2009 +0000 @@ -39,7 +39,7 @@ int f8 = 0; int f16 = 0; int isdp = 0; - + optr2 = *optr; while (*optr2 && !isspace(*optr2) && *optr2 != ',') optr2++ /* do nothing */ ; @@ -62,24 +62,21 @@ (*optr)++; f16 = 1; } - s = lwasm_evaluate_expr(as, l, *optr, NULL); - if (!s) - { - register_error(as, l, 1, "Bad expression"); - return; - } - if (!lwasm_expr_is_constant(s) && as -> passnum == 1) + rval = lwasm_expr_result2(as, l, optr, 0, &v1, 0); + if (rval != 0) { f16 = 1; + v1 = 0; l -> fsize = 2; - register_error(as, l, 2, "Incomplete reference"); } - v1 = lwasm_expr_get_value(s); - lwasm_expr_stack_free(s); if (((v1 >> 8) & 0xff) == (as -> dpval & 0xff)) isdp = 1; + // disallow non-explicit DP in obj target + if (as -> outformat == OUTPUT_OBJ && !f8) + f16 = 1; + if (f8 || (!f16 && isdp)) { v1 = v1 & 0xffff; @@ -101,6 +98,7 @@ lwasm_emitop(as, l, instab[opnum].ops[2]); if (extra != -1) lwasm_emit(as, l, extra); + l -> relocoff = as -> addr - l -> codeaddr; lwasm_emit(as, l, v1 >> 8); lwasm_emit(as, l, v1 & 0xff); return; @@ -136,13 +134,17 @@ OPFUNC(insn_gen8) { int rval; + int r; if (**p == '#') { lwasm_emitop(as, l, instab[opnum].ops[3]); (*p)++; - if (lwasm_expr_result(as, l, p, EXPR_PASS2CONST | EXPR_BYTE, &rval) < 0) + r = lwasm_expr_result2(as, l, p, EXPR_PASS2CONST | EXPR_BYTE, &rval, 0); + if (r != 0) rval = 0; + if (r == 1 && as -> passnum == 2) + register_error(as, l, 2, "Illegal external or intersegment reference"); lwasm_emit(as, l, rval & 0xff); return; } @@ -152,25 +154,19 @@ OPFUNC(insn_gen16) { - lwasm_expr_stack_t *s; - int rval; + int rval, r; if (**p == '#') { lwasm_emitop(as, l, instab[opnum].ops[3]); (*p)++; - s = lwasm_evaluate_expr(as, l, *p, NULL); - if (!s) - { - register_error(as, l, 1, "Bad expression"); + + r = lwasm_expr_result2(as, l, p, 0, &rval, 0); + if (r != 0) rval = 0; - } - else + if (r == 1 && as -> passnum == 2) { - if (!lwasm_expr_is_constant(s)) - register_error(as, l, 2, "Incomplete reference"); - rval = lwasm_expr_get_value(s); - lwasm_expr_stack_free(s); + l -> relocoff = as -> addr - l -> codeaddr; } lwasm_emit(as, l, (rval >> 8) & 0xff); lwasm_emit(as, l, rval & 0xff); @@ -182,26 +178,21 @@ OPFUNC(insn_gen32) { - lwasm_expr_stack_t *s; - int rval; + int r, rval; if (**p == '#') { lwasm_emitop(as, l, instab[opnum].ops[3]); (*p)++; - s = lwasm_evaluate_expr(as, l, *p, NULL); - if (!s) + + r = lwasm_expr_result2(as, l, p, 0, &rval, 0); + if (r != 0) + rval = 0; + if (r == 1 && as -> passnum == 2) { - register_error(as, l, 1, "Bad expression"); - rval = 0; + register_error(as, l, 2, "Illegal external or intersegment reference"); } - else - { - if (!lwasm_expr_is_constant(s)) - register_error(as, l, 2, "Incomplete reference"); - rval = lwasm_expr_get_value(s); - lwasm_expr_stack_free(s); - } + lwasm_emit(as, l, (rval >> 24) & 0xff); lwasm_emit(as, l, (rval >> 16) & 0xff); lwasm_emit(as, l, (rval >> 8) & 0xff); @@ -214,26 +205,19 @@ OPFUNC(insn_imm8) { - lwasm_expr_stack_t *s; - int rval; + int r, rval; if (**p == '#') { lwasm_emitop(as, l, instab[opnum].ops[0]); (*p)++; - s = lwasm_evaluate_expr(as, l, *p, NULL); - if (!s) - { - register_error(as, l, 1, "Bad expression"); + + r = lwasm_expr_result2(as, l, p, EXPR_PASS2CONST | EXPR_BYTE, &rval, 0); + if (r != 0) rval = 0; - } - else - { - if (!lwasm_expr_is_constant(s)) - register_error(as, l, 2, "Incomplete reference"); - rval = lwasm_expr_get_value(s); - lwasm_expr_stack_free(s); - } + if (r == 1 && as -> passnum == 2) + register_error(as, l, 2, "Illegal external or intersegment reference"); + if (rval < -128 || rval > 255) register_error(as, l, 2, "Byte overflow"); lwasm_emit(as, l, rval & 0xff); diff -r 2fe5fd7d65a3 -r a338d496350e src/insn_rel.c --- a/src/insn_rel.c Thu Jan 08 02:57:24 2009 +0000 +++ b/src/insn_rel.c Fri Jan 09 04:23:00 2009 +0000 @@ -33,28 +33,81 @@ OPFUNC(insn_rel8) { int v; + lwasm_expr_term_t *t; + int r; lwasm_emitop(as, l, instab[opnum].ops[0]); - - if (lwasm_expr_result(as, l, p, EXPR_PASS2CONST, &v) < 0) + + if ((r = lwasm_expr_result2(as, l, p, EXPR_PASS2CONST | EXPR_NOINTERSECT, &v, 0)) != 0) + v = 0; + else { - v = 0; + if (as -> passnum == 1) + { + // need to adjust the expression + v -= as -> addr + 1; + if (l -> exprs[0]) + { + t = lwasm_expr_term_create_int(as -> addr + 1); + lwasm_expr_stack_push(l -> exprs[0], t); + lwasm_expr_term_free(t); + t = lwasm_expr_term_create_oper(LWASM_OPER_MINUS); + lwasm_expr_stack_push(l -> exprs[0], t); + lwasm_expr_term_free(t); + } + else + { + l -> exprvals[0] -= as -> addr + 1; + } + } } - v -= as -> addr + 1; + if (r == 1 && as -> passnum == 2) + { + register_error(as, l, 2, "Illegal external or intersegment reference"); + } if (v < -128 || v > 127) register_error(as, l, 2, "Byte overflow"); lwasm_emit(as, l, v & 0xff); } +/* +External and intersegment references are adjusted for the relative addressing mode +by adjusting the expression on pass 1 and then treated as absolute references later +*/ OPFUNC(insn_rel16) { int v; + int r; + lwasm_expr_term_t *t; lwasm_emitop(as, l, instab[opnum].ops[0]); - if (lwasm_expr_result(as, l, p, EXPR_PASS2CONST, &v) < 0) + r = lwasm_expr_result2(as, l, p, EXPR_PASS2CONST, &v, 0); + if (r != 0) v = 0; - v -= as -> addr + 2; + else + { + if (as -> passnum == 1) + { + // need to adjust the expression + v -= as -> addr + 1; + if (l -> exprs[0]) + { + t = lwasm_expr_term_create_int(as -> addr + 1); + lwasm_expr_stack_push(l -> exprs[0], t); + lwasm_expr_term_free(t); + t = lwasm_expr_term_create_oper(LWASM_OPER_MINUS); + lwasm_expr_stack_push(l -> exprs[0], t); + lwasm_expr_term_free(t); + } + else + { + l -> exprvals[0] -= as -> addr + 2; + } + } + } + if (as -> passnum == 2 && r == 1) + l -> relocoff = as -> addr - l -> codeaddr; lwasm_emit(as, l, (v >> 8) & 0xff); lwasm_emit(as, l, v & 0xff); } diff -r 2fe5fd7d65a3 -r a338d496350e src/lwasm.c --- a/src/lwasm.c Thu Jan 08 02:57:24 2009 +0000 +++ b/src/lwasm.c Fri Jan 09 04:23:00 2009 +0000 @@ -216,7 +216,10 @@ se = lwasm_find_symbol(st -> as, sym, -1); debug_message(3, "lwasm_expr_lookup_symbol(): got '%p'", se); if (!se) + { + register_error(st -> as, st -> l, 2, "Undefined symbol '%s'", sym); return NULL; + } if (st -> as -> outformat != OUTPUT_OBJ || se -> sect == NULL || se -> sect == st -> as -> csect) { // global symbol, intrasegment reference, or not an object target @@ -258,6 +261,17 @@ return(lwasm_expr_eval(inp, outp, lwasm_expr_lookup_symbol, &st)); } + +int lwasm_reevaluate_expr(asmstate_t *as, lwasm_line_t *l, lwasm_expr_stack_t *s) +{ + struct symstateinfo st; + + st.as = as; + st.l = l; + + return(lwasm_expr_reval(s, lwasm_expr_lookup_symbol, &st)); +} + // return 1 if no undefined symbols (externals and incompletes are okay) // return 0 if there are undefined symbols int lwasm_expr_result_ckconst(asmstate_t *as, lwasm_expr_stack_t *s) @@ -265,6 +279,14 @@ lwasm_expr_stack_node_t *n; lwasm_symbol_ent_t *se; + if (as -> outformat != OUTPUT_OBJ) + { + if (lwasm_expr_is_constant(s)) + return 1; + else + return 0; + } + for (n = s -> head; n; n = n -> next) { if (n -> term -> term_type == LWASM_TERM_SYM) @@ -289,7 +311,13 @@ - a symbol defined in another section will remain unresolved - external references will also remain unresolved +EXPR_PASS2PASS will cause the result from pass 1 along with the offset to +the end of the expression to be stored in the line data. There can only be +one such expression per source line. In this case, the expression is parsed +and evaluated on pass 1 but the intermediate representation is re-evaluated +on pass 2. */ +/* int lwasm_expr_result(asmstate_t *as, lwasm_line_t *l, char **inp, int flag, int *val) { lwasm_expr_stack_t *s; @@ -305,22 +333,40 @@ } *inp = (char *)ep; - if (flag & EXPR_PASS1CONST && as -> passnum == 1 && !lwasm_expr_is_constant(s)) + if (flag & EXPR_PASS1CONST && as -> passnum == 1 && !lwasm_expr_result_ckconst(as, s)) { - register_error(as, l, 1, "Illegal incomplete reference (pass 1)"); + register_error(as, l, 1, "Undefined reference (pass 1)"); + *val = 0; + lwasm_expr_stack_free(s); + return -1; + } + if (flag & EXPR_PASS2CONST && as -> passnum == 2 && !lwasm_expr_result_ckconst(as, s)) + { + register_error(as, l, 2, "Undefined reference (pass 2)"); *val = 0; lwasm_expr_stack_free(s); return -1; } - if (flag & EXPR_PASS2CONST && as -> passnum == 2 && !lwasm_expr_is_constant(s)) + if (flag & EXPR_NOINTERSECT && !lwasm_expr_is_constant(s)) { - register_error(as, l, 2, "Incomplete reference (pass 2)"); - *val = 0; - lwasm_expr_stack_free(s); - return -1; + register_error(as, l, 2, "Invalid inter-section reference"); } *val = lwasm_expr_get_value(s); - lwasm_expr_stack_free(s); + if (l -> expr) + { + lwasm_expr_stack_free(l -> expr); + l -> expr = NULL; + } + if (lwasm_is_constant(s)) + { + // fully resolved value here + lwasm_expr_stack_free(s); + } + else + { + // incomplete reference here + l -> expr = s; + } if (flag & EXPR_BYTE && as -> passnum == 2 && (*val < -128 || *val > 255)) { @@ -335,6 +381,50 @@ return 0; } +*/ +int lwasm_expr_result2(asmstate_t *as, lwasm_line_t *l, char **inp, int flag, int *val, int slot) +{ + lwasm_expr_stack_t *s; + const char *ep; + int rval; + + if (as -> passnum == 1) + { + s = lwasm_evaluate_expr(as, l, *inp, &ep); + l -> exprs[slot] = s; + if (!s) + { + register_error(as, l, 1, "Bad expression"); + *val = 0; + return -1; + } + *inp = (char *)ep; + l -> exprends[slot] = *inp; + l -> exprvals[slot] = lwasm_expr_get_value(s); + } + else if (l -> exprs[slot]) + { + s = l -> exprs[slot]; + *inp = l -> exprends[slot]; + lwasm_reevaluate_expr(as, l, s); + l -> exprvals[slot] = lwasm_expr_get_value(s); + } + + if (s && lwasm_expr_is_constant(s)) + { + lwasm_expr_stack_free(s); + l -> exprs[slot] = NULL; + s = NULL; + } + + if (!s) + { + *val = l -> exprvals[slot]; + return 0; + } + + return 1; +} void debug_message(int level, const char *fmt, ...) { diff -r 2fe5fd7d65a3 -r a338d496350e src/lwasm.h --- a/src/lwasm.h Thu Jan 08 02:57:24 2009 +0000 +++ b/src/lwasm.h Fri Jan 09 04:23:00 2009 +0000 @@ -62,6 +62,10 @@ }; // structure for keeping track of lines +// it also as space for 4 expressions which is enough for all known +// instructions and addressing modes +// on pass 1, the expressions are parsed, on pass 2 they are re-evaluated +// to determine constancy typedef struct lwasm_line_s lwasm_line_t; struct lwasm_line_s { char *text; // the actual text of the line @@ -84,8 +88,9 @@ // the following are used for obj format - for external references, inter-section // references, and intrasection relocations int relocoff; // offset into insn where relocation value goes - // the incomplete reference expression - lwasm_expr_stack_t *expr; + lwasm_expr_stack_t *exprs[4]; // non-constant expression values + int exprvals[4]; // constant expression values + char *exprends[4]; // pointer to character after end of expression }; // for keeping track of symbols @@ -175,8 +180,10 @@ #define EXPR_PASS2CONST 2 // no undefined references on pass 2 #define EXPR_BYTE 4 // the result must fit within 8 bits #define EXPR_COMPLEX 8 // a non-constant result is permitted (stored in l -> expr) +#define EXPR_NOINTERSECT 16 // only allow intra-section values (pass 2) __lwasm_E__ int lwasm_expr_result(asmstate_t *as, lwasm_line_t *l, char **inp, int flag, int *val); +__lwasm_E__ int lwasm_expr_result2(asmstate_t *as, lwasm_line_t *l, char **inp, int flag, int *val, int slot); #undef __lwasm_E__ diff -r 2fe5fd7d65a3 -r a338d496350e src/symbol.c --- a/src/symbol.c Thu Jan 08 02:57:24 2009 +0000 +++ b/src/symbol.c Fri Jan 09 04:23:00 2009 +0000 @@ -35,6 +35,11 @@ recognize because the expression evaluator must avoid all ambiguity in order to achieve predictable results. The checks here are simply a fuzz check. */ + +/* +NOTE: complex symbols always take their value from slot 0 on the expression placeholders +for a line! +*/ int lwasm_register_symbol(asmstate_t *as, lwasm_line_t *l, char *sym, int val, int flags) { lwasm_symbol_ent_t *se, *se2; @@ -45,9 +50,9 @@ // if the symbol is constant, fall back to simple registration! if (flags & SYMBOL_COMPLEX) { - if (lwasm_expr_is_constant(l -> expr)) + if (l -> exprs[0] == NULL) { - val = lwasm_expr_get_value(l -> expr); + val = l -> exprvals[0]; flags &= ~SYMBOL_COMPLEX; } } @@ -98,7 +103,7 @@ se -> value = val; if (flags & SYMBOL_COMPLEX) { - se -> expr = l -> expr; + se -> expr = l -> exprs[0]; } return; } @@ -121,7 +126,7 @@ } se -> value = val; if (flags & SYMBOL_COMPLEX) - se -> expr = l -> expr; + se -> expr = l -> exprs[0]; se -> sym = lwasm_strdup(sym); se -> context = scontext; se -> sect = as -> csect;