Mercurial > hg-old > index.cgi
view old-trunk/lwasm/old/lwasm.c @ 377:55ed7d06b136
Fixed intersection internal references in object target
author | lost@starbug |
---|---|
date | Mon, 26 Apr 2010 18:37:06 -0600 |
parents | eb230fa7d28e |
children |
line wrap: on
line source
/* lwasm.c Copyright © 2009 William Astle This file is part of LWASM. LWASM is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses/>. Contains random functions used by the assembler */ #define __lwasm_c_seen__ #include <config.h> #include <stdarg.h> #include <stdlib.h> #include <stdio.h> #include "lwasm.h" #include "util.h" #include "expr.h" int debug_level = 0; int register_error(asmstate_t *as, lwasm_line_t *l, int pass, const char *fmt, ...) { lwasm_error_t *e; va_list args; char errbuff[1024]; int r; if (!l) return; if (as -> passnum != pass) return; va_start(args, fmt); e = lwasm_alloc(sizeof(lwasm_error_t)); e -> next = l -> err; l -> err = e; as -> errorcount++; r = vsnprintf(errbuff, 1024, fmt, args); e -> mess = lwasm_strdup(errbuff); va_end(args); return r; } void lwasm_emit(asmstate_t *as, lwasm_line_t *l, int b) { as -> addr += 1; as -> addr &= 0xffff; if (as -> outformat == OUTPUT_OBJ && !(as -> csect)) { register_error(as, l, 1, "Output not allowed outside sections with obj target"); return; } if (as -> outformat == OUTPUT_OBJ && as -> csect -> flags & SECTION_BSS) { register_error(as, l, 1, "Output not allowed inside BSS sections"); return; } if (as -> outformat == OUTPUT_OS9 && as -> inmod == 0) { register_error(as, l, 1, "Output not allowed outside of module in OS9 mode"); return; } if (as -> passnum == 1) return; if (l -> codelen >= l -> codesize) { l -> bytes = realloc(l -> bytes, l -> codesize + 16); l -> codesize += 16; } l -> bytes[l -> codelen] = b & 0xff; l -> codelen += 1; if (as -> outformat == OUTPUT_OS9 && as -> inmod) { // calc the CRC // this is a direct transliteration from the nitros9 asm source // to C; it can, no doubt, be optimized for 32 bit processing b &= 0xff; b ^= (as -> crc)[0]; (as -> crc)[0] = (as -> crc)[1]; (as -> crc)[1] = (as -> crc)[2]; (as -> crc)[1] ^= (b >> 7); (as -> crc)[2] = (b << 1); (as -> crc)[1] ^= (b >> 2); (as -> crc)[2] ^= (b << 6); b ^= (b << 1); b ^= (b << 2); b ^= (b << 4); if (b & 0x80) { (as -> crc)[0] ^= 0x80; (as -> crc)[2] ^= 0x21; } } } void lwasm_emitop(asmstate_t *as, lwasm_line_t *l, int o) { if (o >= 0x100) lwasm_emit(as, l, o >> 8); lwasm_emit(as, l, o & 0xff); } int lwasm_lookupreg2(const char *reglist, char **str) { int rval = 0; while (*reglist) { if (toupper(**str) == *reglist) { // first char matches if (reglist[1] == ' ' && !isalpha(*(*str + 1))) break; if (toupper(*(*str + 1)) == reglist[1]) break; } reglist += 2; rval++; } if (!*reglist) return -1; if (reglist[1] == ' ') (*str)++; else (*str) += 2; return rval; } int lwasm_lookupreg3(const char *rlist, const char **str) { int rval = 0; int f = 0; const char *reglist = rlist; while (*reglist) { if (toupper(**str) == *reglist) { // first char matches if (reglist[1] == ' ') { f = 1; break; } if (toupper(*(*str + 1)) == reglist[1]) { // second char matches if (reglist[2] == ' ') { f = 1; break; } if (toupper(*(*str + 2)) == reglist[2]) { f = 1; break; } } } reglist += 3; rval++; } if (f == 0) return -1; reglist = rval * 3 + rlist; if (reglist[1] == ' ') (*str) += 1; else if (reglist[2] == ' ') (*str) += 2; else (*str)+=3; return rval; } struct symstateinfo { asmstate_t *as; lwasm_line_t *l; int flags; }; lwasm_expr_stack_t *lwasm_expr_lookup_symbol(char *sym, void *state) { lwasm_symbol_ent_t *se; struct symstateinfo *st; lwasm_expr_stack_t *rs; lwasm_expr_term_t *t; lwasm_expr_stack_node_t *n; int val; st = state; debug_message(3, "lwasm_expr_lookup_symbol(): find '%s' (context=%d)", sym, st -> as -> context); // check for special symbols first... if (sym[1] == '\0') { switch (sym[0]) { // current line address case '*': case '.': val = st -> l -> codeaddr; goto retconst; case '<': // previous branch point // not implemented break; case '>': // next branch point // not implemented break; } } // look for local symbol first then global symbol se = lwasm_find_symbol(st -> as, sym, st -> as -> context); if (!se) 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; } // external reference - can not resolve it if (se -> flags & SYMBOL_EXTERN) { return NULL; } if (st -> flags & EXPR_SECTCONST) { if (se -> sect == st -> l -> sect) { if (se -> expr) goto retsym; val = se -> value; goto retconst; } } if (st -> as -> outformat == OUTPUT_OBJ && se -> sect != NULL) { return NULL; } if (st -> as -> outformat != OUTPUT_OBJ || se -> sect == NULL) { // global symbol, intrasegment reference, or not an object target val = se -> value; goto retconst; } // an intersegment reference will return as NULL (to be resolved at output/link time) // if se -> expr is NULL, it has to be an intersegment reference here if (se -> expr == NULL) { return NULL; } retsym: // duplicate the expression for return rs = lwasm_expr_stack_create(); for (n = se -> expr -> head; n; n = n -> next) { lwasm_expr_stack_push(rs, n -> term); } return rs; retconst: rs = lwasm_expr_stack_create(); t = lwasm_expr_term_create_int(val); lwasm_expr_stack_push(rs, t); lwasm_expr_term_free(t); return rs; } lwasm_expr_stack_t *lwasm_evaluate_expr(asmstate_t *as, lwasm_line_t *l, const char *inp, const char **outp, int flags) { struct symstateinfo st; st.as = as; st.l = l; st.flags = flags; debug_message(2, "Evaluate expression: %s", inp); 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, int flags) { struct symstateinfo st; st.as = as; st.l = l; st.flags = flags; 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) { 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) { se = lwasm_find_symbol(as, n -> term -> symbol, as -> context); if (!se) se = lwasm_find_symbol(as, n -> term -> symbol, -1); if (!se) return 0; } } return 1; } /* Evaluate an expression according to the flag value. Return 0 if a constant result was obtained, 1 if an incomplete result was obtained, and -1 if an error was flagged. */ int lwasm_expr_result2(asmstate_t *as, lwasm_line_t *l, char **inp, int flag, int *val, int slot) { lwasm_expr_stack_t *s = NULL; const char *ep; int rval; if ((as -> passnum == 1 && !(flag & EXPR_REEVAL)) || slot < 0) { s = lwasm_evaluate_expr(as, l, *inp, &ep, flag); if (slot >= 0) { l -> exprs[slot] = s; l -> exprends[slot] = ep; } if (!s) { register_error(as, l, 1, "Bad expression"); *val = 0; return -1; } *inp = (char *)ep; if (slot >= 0) { // l -> exprends[slot] = (char *)ep; l -> exprvals[slot] = lwasm_expr_get_value(s); } } else if (l -> exprs[slot]) { s = l -> exprs[slot]; lwasm_reevaluate_expr(as, l, s, flag); l -> exprvals[slot] = lwasm_expr_get_value(s); } if (as -> passnum == 2 && slot >= 0) *inp = l -> exprends[slot]; if (s && lwasm_expr_is_constant(s)) { *val = lwasm_expr_get_value(s); lwasm_expr_stack_free(s); l -> exprs[slot] = NULL; s = NULL; return 0; } if (!s && slot >= 0) { *val = l -> exprvals[slot]; return 0; } else if (!s) { *val = 0; return 0; } // was a constant result on pass 1 requested? // that means we must have a constant on either pass if (flag & EXPR_PASS1CONST) { *val = 0; if (slot >= 0) l -> exprvals[slot] = 0; register_error(as, l, 1, "Illegal forward, external, or inter-section reference"); lwasm_expr_stack_free(s); if (slot >= 0) l -> exprs[slot] = NULL; return -1; } return 1; } void debug_message(int level, const char *fmt, ...) { va_list args; va_start(args, fmt); if (debug_level >= level) { if (level > 0) fprintf(stderr, "DEBUG %d: ", level); vfprintf(stderr, fmt, args); fputc('\n', stderr); } va_end(args); } int lwasm_next_context(asmstate_t *as) { int r; r = as -> nextcontext; as -> nextcontext += 1; debug_message(3, "lwasm_next_context(): %d (%d) pass %d", r, as -> nextcontext, as -> passnum); return r; }