# HG changeset patch
# User lost@starbug
# Date 1272140118 21600
# Node ID d99322ef6f217e147e5cfb32ec95c1913df39728
# Parent 8f9d72cfb897955da79854a441c4b82539cf2214
Stage 1: actually do output
diff -r 8f9d72cfb897 -r d99322ef6f21 lwasm/Makefile.am
--- a/lwasm/Makefile.am Thu Apr 22 18:30:30 2010 -0600
+++ b/lwasm/Makefile.am Sat Apr 24 14:15:18 2010 -0600
@@ -4,6 +4,6 @@
instab.c symbol.c macro.c pass2.c pass3.c pass4.c pass5.c pass6.c \
insn_inh.c insn_rtor.c insn_tfm.c insn_rlist.c insn_rel.c \
insn_bitbit.c insn_indexed.c insn_gen.c insn_logicmem.c \
- pseudo.c section.c os9.c pass7.c debug.c
+ pseudo.c section.c os9.c pass7.c debug.c output.c
lwasm_LDADD = -L$(top_builddir)/lib -L$(top_srcdir)/lib -L$(top_builddir)/lwlib -L$(top_srcdir)/lwlib -lgnu -llw
EXTRA_DIST = lwasm.h input.h instab.h
diff -r 8f9d72cfb897 -r d99322ef6f21 lwasm/lwasm.c
--- a/lwasm/lwasm.c Thu Apr 22 18:30:30 2010 -0600
+++ b/lwasm/lwasm.c Sat Apr 24 14:15:18 2010 -0600
@@ -189,6 +189,9 @@
void lwasm_emit(line_t *cl, int byte)
{
+ if (cl -> outputl < 0)
+ cl -> outputl = 0;
+
if (cl -> outputl == cl -> outputbl)
{
cl -> output = lw_realloc(cl -> output, cl -> outputbl + 8);
@@ -605,6 +608,23 @@
// handle external/cross-section/incomplete references here
else
{
+ if (l -> as -> output_format == OUTPUT_OBJ)
+ {
+ reloctab_t *re;
+
+ // add "expression" record to section table
+ v = lw_expr_intval(l -> addr) + l -> outputl;
+ re = lw_alloc(sizeof(reloctab_t));
+ re -> next = l -> csect -> reloctab;
+ l -> csect -> reloctab = re;
+ re -> offset = v;
+ re -> size = size;
+ re -> expr = lw_expr_copy(expr);
+
+ for (v = 0; v < size; v++)
+ lwasm_emit(l, 0);
+ return 0;
+ }
lwasm_register_error(l -> as, l, "Expression not fully resolved");
return -1;
}
diff -r 8f9d72cfb897 -r d99322ef6f21 lwasm/lwasm.h
--- a/lwasm/lwasm.h Thu Apr 22 18:30:30 2010 -0600
+++ b/lwasm/lwasm.h Sat Apr 24 14:15:18 2010 -0600
@@ -84,12 +84,25 @@
section_flag_none = 0 // no flags
};
+typedef struct reloctab_s reloctab_t;
+struct reloctab_s
+{
+ int offset; // offset of relocation
+ int size; // size of relocation
+ lw_expr_t *expr; // relocation expression
+ reloctab_t *next;
+};
+
typedef struct sectiontab_s sectiontab_t;
struct sectiontab_s
{
char *name; // section name
int flags; // section flags;
lw_expr_t offset; // offset for next instance
+ int oblen; // size of section output
+ int obsize; // size of output buffer
+ unsigned char *obytes; // output buffer
+ reloctab_t *reloctab; // table of relocations
sectiontab_t *next;
};
@@ -113,6 +126,7 @@
struct exportlist_s
{
char *symbol; // symbol to export
+ struct symtabe *se; // symbol table entry
line_t *line; // line the export is on
exportlist_t *next; // next in the export list
};
@@ -163,6 +177,7 @@
int context; // symbol context (-1 for global)
int version; // version of the symbol (for "set")
int flags; // flags for the symbol
+ sectiontab_t *section; // section the symbol is defined in
lw_expr_t value; // symbol value
struct symtabe *next; // next symbol in the table
};
diff -r 8f9d72cfb897 -r d99322ef6f21 lwasm/main.c
--- a/lwasm/main.c Thu Apr 22 18:30:30 2010 -0600
+++ b/lwasm/main.c Sat Apr 24 14:15:18 2010 -0600
@@ -174,6 +174,7 @@
extern void do_pass5(asmstate_t *as);
extern void do_pass6(asmstate_t *as);
extern void do_pass7(asmstate_t *as);
+extern void do_output(asmstate_t *as);
extern lw_expr_t lwasm_evaluate_special(int t, void *ptr, void *priv);
extern lw_expr_t lwasm_evaluate_var(char *var, void *priv);
extern lw_expr_t lwasm_parse_term(char **p, void *priv);
@@ -234,4 +235,9 @@
exit(1);
}
}
+
+ debug_message(&asmstate, 50, "Doing output");
+ do_output(&asmstate);
+
+ debug_message(&asmstate, 50, "Done assembly");
}
diff -r 8f9d72cfb897 -r d99322ef6f21 lwasm/output.c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/lwasm/output.c Sat Apr 24 14:15:18 2010 -0600
@@ -0,0 +1,450 @@
+/*
+output.c
+Copyright © 2009, 2010 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 .
+
+
+Contains the code for actually outputting the assembled code
+*/
+#include
+#include
+#include
+#include
+#include
+
+#include
+#include
+
+#include "lwasm.h"
+
+void write_code_raw(asmstate_t *as, FILE *of);
+void write_code_decb(asmstate_t *as, FILE *of);
+void write_code_rawrel(asmstate_t *as, FILE *of);
+void write_code_obj(asmstate_t *as, FILE *of);
+void write_code_os9(asmstate_t *as, FILE *of);
+
+// this prevents warnings about not using the return value of fwrite()
+#define writebytes(s, l, c, f) do { int r; r = fwrite((s), (l), (c), (f)); } while (0)
+
+void do_output(asmstate_t *as)
+{
+ FILE *of;
+
+ if (as -> errorcount > 0)
+ {
+ fprintf(stderr, "Not doing output due to assembly errors.\n");
+ return;
+ }
+
+ of = fopen(as -> output_file, "wb");
+ if (!of)
+ {
+ fprintf(stderr, "Cannot open '%s' for output", as -> output_file);
+ perror("");
+ return;
+ }
+
+ switch (as -> output_format)
+ {
+ case OUTPUT_RAW:
+ write_code_raw(as, of);
+ break;
+
+ case OUTPUT_DECB:
+ write_code_decb(as, of);
+ break;
+
+ case OUTPUT_RAWREL:
+ write_code_rawrel(as, of);
+ break;
+
+ case OUTPUT_OBJ:
+ write_code_obj(as, of);
+ break;
+
+ case OUTPUT_OS9:
+ write_code_os9(as, of);
+ break;
+
+ default:
+ fprintf(stderr, "BUG: unrecognized output format when generating output file\n");
+ fclose(of);
+ unlink(as -> output_file);
+ return;
+ }
+
+ fclose(of);
+}
+
+/*
+rawrel output treats an ORG directive as an offset from the start of the
+file. Undefined results will occur if an ORG directive moves the output
+pointer backward. This particular implementation uses "fseek" to handle
+ORG requests and to skip over RMBs.
+
+This simple brain damanged method simply does an fseek before outputting
+each instruction.
+*/
+void write_code_rawrel(asmstate_t *as, FILE *of)
+{
+ line_t *cl;
+
+ for (cl = as -> line_head; cl; cl = cl -> next)
+ {
+ if (cl -> outputl <= 0)
+ continue;
+
+ fseek(of, lw_expr_intval(cl -> addr), SEEK_SET);
+ writebytes(cl -> output, cl -> outputl, 1, of);
+ }
+}
+
+/*
+raw merely writes all the bytes directly to the file as is. ORG is just a
+reference for the assembler to handle absolute references. Multiple ORG
+statements will produce mostly useless results
+*/
+void write_code_raw(asmstate_t *as, FILE *of)
+{
+ line_t *cl;
+
+ for (cl = as -> line_head; cl; cl = cl -> next)
+ {
+ if (cl -> len > 0 && cl -> outputl == 0)
+ {
+ int i;
+ for (i = 0; i < cl -> len; i++)
+ writebytes("\0", 1, 1, of);
+ continue;
+ }
+ else if (cl -> outputl > 0)
+ writebytes(cl -> output, cl -> outputl, 1, of);
+ }
+}
+
+
+/*
+OS9 target also just writes all the bytes in order. No need for anything
+else.
+*/
+void write_code_os9(asmstate_t *as, FILE *of)
+{
+ line_t *cl;
+
+ for (cl = as -> line_head; cl; cl = cl -> next)
+ {
+ if (cl -> inmod == 0)
+ continue;
+ if (cl -> len > 0 && cl -> outputl == 0)
+ {
+ int i;
+ for (i = 0; i < cl -> len; i++)
+ writebytes("\0", 1, 1, of);
+ continue;
+ }
+ else if (cl -> outputl > 0)
+ writebytes(cl -> output, cl -> outputl, 1, of);
+ }
+}
+
+void write_code_decb(asmstate_t *as, FILE *of)
+{
+ long preambloc;
+ line_t *cl;
+ int blocklen = -1;
+ int nextcalc = -1;
+ unsigned char outbuf[5];
+ int caddr;
+
+ for (cl = as -> line_head; cl; cl = cl -> next)
+ {
+ if (cl -> outputl < 0)
+ continue;
+ caddr = lw_expr_intval(cl -> addr);
+ if (caddr != nextcalc && cl -> outputl > 0)
+ {
+ // need preamble here
+ if (blocklen > 0)
+ {
+ // update previous preamble if needed
+ fseek(of, preambloc, SEEK_SET);
+ outbuf[0] = (blocklen >> 8) & 0xFF;
+ outbuf[1] = blocklen & 0xFF;
+ writebytes(outbuf, 2, 1, of);
+ fseek(of, 0, SEEK_END);
+ }
+ blocklen = 0;
+ nextcalc = caddr;
+ outbuf[0] = 0x00;
+ outbuf[1] = 0x00;
+ outbuf[2] = 0x00;
+ outbuf[3] = (nextcalc >> 8) & 0xFF;
+ outbuf[4] = nextcalc & 0xFF;
+ preambloc = ftell(of) + 1;
+ writebytes(outbuf, 5, 1, of);
+ }
+ nextcalc += cl -> outputl;
+ writebytes(cl -> output, cl -> outputl, 1, of);
+ blocklen += cl -> outputl;
+ }
+ if (blocklen > 0)
+ {
+ fseek(of, preambloc, SEEK_SET);
+ outbuf[0] = (blocklen >> 8) & 0xFF;
+ outbuf[1] = blocklen & 0xFF;
+ writebytes(outbuf, 2, 1, of);
+ fseek(of, 0, SEEK_END);
+ }
+
+ // now write postamble
+ outbuf[0] = 0xFF;
+ outbuf[1] = 0x00;
+ outbuf[2] = 0x00;
+ outbuf[3] = (as -> execaddr >> 8) & 0xFF;
+ outbuf[4] = (as -> execaddr) & 0xFF;
+ writebytes(outbuf, 5, 1, of);
+}
+
+void write_code_obj_sbadd(sectiontab_t *s, unsigned char b)
+{
+ if (s -> oblen >= s -> obsize)
+ {
+ s -> obytes = lw_realloc(s -> obytes, s -> obsize + 128);
+ s -> obsize += 128;
+ }
+ s -> obytes[s -> oblen] = b;
+ s -> oblen += 1;
+}
+
+void write_code_obj(asmstate_t *as, FILE *of)
+{
+ line_t *l;
+ sectiontab_t *s;
+ reloctab_t *re;
+ struct symtabe *se;
+
+ int i;
+ unsigned char buf[16];
+
+ // output the magic number and file header
+ // the 8 is NOT an error
+ writebytes("LWOBJ16", 8, 1, of);
+
+ // run through the entire system and build the byte streams for each
+ // section; at the same time, generate a list of "local" symbols to
+ // output for each section
+ // NOTE: for "local" symbols, we will append \x01 and the ascii string
+ // of the context identifier (so sym in context 1 would be "sym\x011"
+ // we can do this because the linker can handle symbols with any
+ // character other than NUL.
+ // also we will generate a list of incomplete references for each
+ // section along with the actual definition that will be output
+
+ // once all this information is generated, we will output each section
+ // to the file
+
+ // NOTE: we build everything in memory then output it because the
+ // assembler accepts multiple instances of the same section but the
+ // linker expects only one instance of each section in the object file
+ // so we need to collect all the various pieces of a section together
+ // (also, the assembler treated multiple instances of the same section
+ // as continuations of previous sections so we would need to collect
+ // them together anyway.
+
+ for (l = as -> line_head; l; l = l -> next)
+ {
+ if (l -> csect)
+ {
+ // we're in a section - need to output some bytes
+ 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)
+ for (i = 0; i < l -> len; i++)
+ write_code_obj_sbadd(l -> csect, 0);
+ }
+ }
+
+ // run through the sections
+ for (s = as -> sections; s; s = s -> next)
+ {
+ // write the name
+ writebytes(s -> name, strlen(s -> name) + 1, 1, of);
+
+ // write the flags
+ if (s -> flags & section_flag_bss)
+ writebytes("\x01", 1, 1, of);
+
+ // indicate end of flags - the "" is NOT an error
+ writebytes("", 1, 1, of);
+
+ // now the local symbols
+ for (se = as -> symtab.head; se; se = se -> next)
+ {
+ // ignore symbols not in this section
+ if (se -> section != s)
+ continue;
+
+ if (se -> flags & symbol_flag_set)
+ continue;
+
+ // don't output non-constant symbols
+ if (!lw_expr_istype(se -> value, lw_expr_type_int))
+ continue;
+
+ writebytes(se -> symbol, strlen(se -> symbol), 1, of);
+ if (se -> context >= 0)
+ {
+ writebytes("\x01", 1, 1, of);
+ sprintf(buf, "%d", se -> context);
+ writebytes(buf, strlen(buf), 1, of);
+ }
+ // the "" is NOT an error
+ writebytes("", 1, 1, of);
+
+ // write the address
+ buf[0] = (lw_expr_intval(se -> value) >> 8) & 0xff;
+ buf[1] = lw_expr_intval(se -> value) & 0xff;
+ writebytes(buf, 2, 1, of);
+ }
+ // flag end of local symbol table - "" is NOT an error
+ writebytes("", 1, 1, of);
+
+ // now the exports -- FIXME
+/* for (ex = as -> exportlist; ex; ex = ex -> next)
+ {
+ int eval;
+ ex -> se -> section != s)
+ continue;
+ if (!lwasm_expr_exportable(ex -> se -> value))
+ continue;
+ eval = lwasm_expr_exportval(ex -> se -> value);
+ writebytes(ex -> symbol, strlen(ex -> symbol) + 1, 1, of);
+ buf[0] = (eval >> 8) & 0xff;
+ buf[1] = eval & 0xff;
+ writebytes(buf, 2, 1, of);
+ }
+*/
+ // flag end of exported symbols - "" is NOT an error
+ writebytes("", 1, 1, of);
+
+ // FIXME - relocation table
+/* for (re = s -> rl; re; re = re -> next)
+ {
+ if (re -> expr == NULL)
+ {
+ // this is an error but we'll simply ignore it
+ // and not output this expression
+ continue;
+ }
+
+ // work through each term in the expression and output
+ // the proper equivalent to the object file
+ if (re -> relocsize == 1)
+ {
+ // flag an 8 bit relocation (low 8 bits will be used)
+ buf[0] = 0xFF;
+ buf[1] = 0x01;
+ writebytes(buf, 2, 1, of);
+ }
+ for (sn = re -> expr -> head; sn; sn = sn -> next)
+ {
+ switch (sn -> term -> term_type)
+ {
+ case LWASM_TERM_OPER:
+ buf[0] = 0x04;
+ buf[1] = sn -> term -> value;
+ writebytes(buf, 2, 1, of);
+ break;
+
+ case LWASM_TERM_INT:
+ buf[0] = 0x01;
+ buf[1] = (sn -> term -> value >> 8) & 0xff;
+ buf[2] = sn -> term -> value & 0xff;
+ writebytes(buf, 3, 1, of);
+ break;
+
+ case LWASM_TERM_SECBASE:
+ writebytes("\x05", 1, 1, of);
+ break;
+
+ case LWASM_TERM_SYM:
+ // now for the ugly part - resolve a symbol reference
+ // and determine whether it's internal, external, or
+ // a section base
+ se = lwasm_find_symbol(as, sn -> term -> symbol, re -> context);
+ if (!se)
+ se = lwasm_find_symbol(as, sn -> term -> symbol, -1);
+ if (!se || se -> flags & SYMBOL_EXTERN)
+ {
+ // not found - assume external reference
+ // found but flagged external - handle it
+ writebytes("\x02", 1, 1, of);
+ writebytes(se -> sym, strlen(se -> sym) + 1, 1, of);
+ break;
+ }
+ // a local symbol reference here
+ writebytes("\x03", 1, 1, of);
+ writebytes(se -> sym, strlen(se -> sym), 1, of);
+ if (se -> context >= 0)
+ {
+ writebytes("\x01", 1, 1, of);
+ sprintf(buf, "%d", se -> context);
+ writebytes(buf, strlen(buf), 1, of);
+ }
+ writebytes("", 1, 1, of);
+ break;
+
+ default:
+ // unrecognized term type - replace with integer 0
+ buf[0] = 0x01;
+ buf[1] = 0x00;
+ buf[2] = 0x00;
+ writebytes(buf, 3, 1, of);
+ break;
+ }
+ }
+
+ // flag end of expressions
+ writebytes("", 1, 1, of);
+
+ // write the offset
+ buf[0] = (re -> offset >> 8) & 0xff;
+ buf[1] = re -> offset & 0xff;
+ writebytes(buf, 2, 1, of);
+ }
+*/
+ // flag end of incomplete references list
+ writebytes("", 1, 1, of);
+
+ // now blast out the code
+
+ // length
+ buf[0] = s -> oblen >> 8 & 0xff;
+ buf[1] = s -> oblen & 0xff;
+ writebytes(buf, 2, 1, of);
+
+ if (!(s -> flags & section_flag_bss))
+ {
+ writebytes(s -> obytes, s -> oblen, 1, of);
+ }
+ }
+
+ // flag no more sections
+ // the "" is NOT an error
+ writebytes("", 1, 1, of);
+}
diff -r 8f9d72cfb897 -r d99322ef6f21 lwasm/pass1.c
--- a/lwasm/pass1.c Thu Apr 22 18:30:30 2010 -0600
+++ b/lwasm/pass1.c Sat Apr 24 14:15:18 2010 -0600
@@ -80,6 +80,7 @@
cl = lw_alloc(sizeof(line_t));
memset(cl, 0, sizeof(line_t));
+ cl -> outputl = -1;
cl -> prev = as -> line_tail;
cl -> insn = -1;
cl -> as = as;
diff -r 8f9d72cfb897 -r d99322ef6f21 lwasm/pass2.c
--- a/lwasm/pass2.c Thu Apr 22 18:30:30 2010 -0600
+++ b/lwasm/pass2.c Sat Apr 24 14:15:18 2010 -0600
@@ -72,6 +72,7 @@
lwasm_register_error(as, ex -> line, "Undefined exported symbol");
}
}
+ ex -> se = s;
}
if (as -> errorcount > 0)
return;
diff -r 8f9d72cfb897 -r d99322ef6f21 lwasm/section.c
--- a/lwasm/section.c Thu Apr 22 18:30:30 2010 -0600
+++ b/lwasm/section.c Sat Apr 24 14:15:18 2010 -0600
@@ -203,6 +203,7 @@
e -> next = as -> exportlist;
e -> symbol = lw_strdup(sym);
e -> line = l;
+ e -> se = NULL;
as -> exportlist = e;
lw_free(sym);
diff -r 8f9d72cfb897 -r d99322ef6f21 lwasm/symbol.c
--- a/lwasm/symbol.c Thu Apr 22 18:30:30 2010 -0600
+++ b/lwasm/symbol.c Sat Apr 24 14:15:18 2010 -0600
@@ -108,6 +108,7 @@
se -> flags = flags;
se -> value = lw_expr_copy(val);
se -> symbol = lw_strdup(sym);
+ se -> section = cl -> csect;
return se;
}