# HG changeset patch # User lost@l-w.ca # Date 1314422760 21600 # Node ID 08fb11004df908cf026d339acbc44678c7e3c648 # Parent 9cf1796259b246062dc54db8cc199683b6aba3e1 Initial pass at OS9 module support for lwlink diff -r 9cf1796259b2 -r 08fb11004df9 lwlink/link.c --- a/lwlink/link.c Thu Aug 25 22:29:58 2011 -0600 +++ b/lwlink/link.c Fri Aug 26 23:26:00 2011 -0600 @@ -30,6 +30,8 @@ #include "expr.h" #include "lwlink.h" +void check_os9(void); + struct section_list *sectlist = NULL; int nsects = 0; static int nforced = 0; @@ -390,6 +392,9 @@ if (symerr) exit(1); + + if (outformat == OUTPUT_OS9) + check_os9(); } /* @@ -460,3 +465,106 @@ fprintf(stderr, "Warning: %s (%d) does not resolve any symbols\n", inputfiles[fn] -> filename, fn); } } +void find_section_by_name_once_aux(char *name, fileinfo_t *fn, section_t **rval, int *found); +void find_section_by_name_once_aux(char *name, fileinfo_t *fn, section_t **rval, int *found) +{ + int sn; + + if (fn -> forced == 0) + return; + + for (sn = 0; sn < fn -> nsections; sn++) + { + if (!strcmp(name, (char *)(fn -> sections[sn].name))) + { + (*found)++; + *rval = &(fn -> sections[sn]); + } + } + for (sn = 0; sn < fn -> nsubs; sn++) + { + find_section_by_name_once_aux(name, fn -> subs[sn], rval, found); + } +} + +section_t *find_section_by_name_once(char *name) +{ + int fn; + int found = 0; + section_t *rval = NULL; + + for (fn = 0; fn < ninputfiles; fn++) + { + find_section_by_name_once_aux(name, inputfiles[fn], &rval, &found); + } + if (found != 1) + { + rval = NULL; + fprintf(stderr, "Warning: multiple instances of section %s found; ignoring all of them which is probably not what you want\n", name); + } + return rval; +} + +void check_os9(void) +{ + section_t *s; + symtab_t *sym; + + s = find_section_by_name_once("__os9"); + linkscript.name = outfile; + + if (!s) + { + // use defaults if not found + return; + } + + // this section is special + // several symbols may be defined as LOCAL symbols: + // type: module type + // lang: module language + // attr: module attributes + // rev: module revision + // + // the symbols are not case sensitive + // + // any unrecognized symbols are ignored + + // the contents of the actual data to the first NUL + // is assumed to be the module name unless it is an empty string + if (s -> codesize > 0 && (s -> flags & SECTION_BSS) == 0 && s -> code[0] != 0) + { + linkscript.name = (char *)(s -> code); + } + + for (sym = s -> localsyms; s; sym = sym -> next) + { + char *sm = (char *)(sym -> sym); + if (!strcasecmp(sm, "type")) + { + linkscript.modtype = sym -> offset; + } + else if (!strcasecmp(sm, "lang")) + { + linkscript.modlang = sym -> offset; + } + else if (!strcasecmp(sm, "attr")) + { + linkscript.modlang = sym -> offset; + } + else if (!strcasecmp(sm, "rev")) + { + linkscript.modrev = sym -> offset; + } + } + if (linkscript.modtype > 15) + linkscript.modtype = linkscript.modtype >> 4; + + if (linkscript.modattr > 15) + linkscript.modattr = linkscript.modattr >> 4; + + linkscript.modlang &= 15; + linkscript.modtype &= 15; + linkscript.modrev &= 15; + linkscript.modattr &= 15; +} diff -r 9cf1796259b2 -r 08fb11004df9 lwlink/lwlink.h --- a/lwlink/lwlink.h Thu Aug 25 22:29:58 2011 -0600 +++ b/lwlink/lwlink.h Fri Aug 26 23:26:00 2011 -0600 @@ -29,6 +29,7 @@ #define OUTPUT_DECB 0 // DECB multirecord format #define OUTPUT_RAW 1 // raw sequence of bytes #define OUTPUT_LWEX0 2 // LWOS LWEX binary version 0 +#define OUTPUT_OS9 3 // OS9 object code module typedef struct symtab_s symtab_t; struct symtab_s @@ -147,6 +148,11 @@ char *execsym; // entry point symbol int execaddr; // execution address (entry point) int stacksize; // stack size + int modtype; // module type + int modlang; // module language + int modattr; // module attributes + int modrev; // module revision + char *name; // module name } linkscript_t; #ifndef __script_c_seen__ diff -r 9cf1796259b2 -r 08fb11004df9 lwlink/main.c --- a/lwlink/main.c Thu Aug 25 22:29:58 2011 -0600 +++ b/lwlink/main.c Fri Aug 26 23:26:00 2011 -0600 @@ -74,6 +74,8 @@ outformat = OUTPUT_RAW; else if (!strcasecmp(arg, "lwex0") || !strcasecmp(arg, "lwex")) outformat = OUTPUT_LWEX0; + else if (!strcasecmp(arg, "os9")) + outformat = OUTPUT_OS9; else { fprintf(stderr, "Invalid output format: %s\n", arg); @@ -119,7 +121,7 @@ { "debug", 'd', 0, 0, "Set debug mode"}, { "format", 'f', "TYPE", 0, - "Select output format: decb, raw, lwex"}, + "Select output format: decb, raw, lwex, os9"}, { "decb", 'b', 0, 0, "Generate DECB .bin format output, equivalent of --format=decb"}, { "raw", 'r', 0, 0, diff -r 9cf1796259b2 -r 08fb11004df9 lwlink/output.c --- a/lwlink/output.c Thu Aug 25 22:29:58 2011 -0600 +++ b/lwlink/output.c Fri Aug 26 23:26:00 2011 -0600 @@ -32,6 +32,7 @@ // better in the future #define writebytes(s, l, c, f) do { int r; r = fwrite((s), (l), (c), (f)); } while (0) +void do_output_os9(FILE *of); void do_output_decb(FILE *of); void do_output_raw(FILE *of); void do_output_lwex0(FILE *of); @@ -62,6 +63,10 @@ do_output_lwex0(of); break; + case OUTPUT_OS9: + do_output_os9(of); + break; + default: fprintf(stderr, "Unknown output format doing output!\n"); exit(111); @@ -213,3 +218,118 @@ writebytes(sectlist[sn].ptr -> code, 1, sectlist[sn].ptr -> codesize, of); } } + +void os9crc(unsigned char crc[3], unsigned char b) +{ + b ^= crc[0]; + crc[0] = crc[1]; + crc[1] = crc[2]; + crc[1] ^= b >> 7; + crc[2] = b << 1; + crc[1] ^= b >> 2; + crc[2] ^= b << 6; + b ^= b << 1; + b ^= b << 2; + b ^= b << 4; + if (b & 0x80) + { + crc[0] ^= 0x80; + crc[2] ^= 0x21; + } +} + + +void do_output_os9(FILE *of) +{ + int sn; + int codedatasize = 0; + int bsssize = 0; + int i; + + unsigned char buf[16]; + unsigned char crc[3]; + + // calculate items for the file header + for (sn = 0; sn < nsects; sn++) + { + if (sectlist[sn].ptr -> flags & SECTION_BSS) + { + // no output for a BSS section + bsssize += sectlist[sn].ptr -> codesize; + continue; + } + codedatasize += sectlist[sn].ptr -> codesize; + } + + // now bss size is the data size for the module + // and codesize is the length of the module minus the module header + // and CRC + + codedatasize += 16; // add in headers + codedatasize += strlen(linkscript.name); // add in name length + + // output the file header + buf[0] = 0x87; + buf[1] = 0xCD; + buf[2] = (codedatasize >> 8) & 0xff; + buf[3] = codedatasize & 0xff; + buf[4] = 0; + buf[5] = 13; + buf[6] = (linkscript.modtype << 4) | (linkscript.modlang); + buf[7] = (linkscript.modattr << 4) | (linkscript.modrev); + buf[8] = (~(buf[0] ^ buf[1] ^ buf[2] ^ buf[3] ^ buf[4] ^ buf[5] ^ buf[6] ^ buf[7])) & 0xff; + buf[9] = (linkscript.execaddr >> 8) & 0xff; + buf[10] = linkscript.execaddr & 0xff; + buf[11] = (bsssize >> 8) & 0xff; + buf[12] = bsssize & 0xff; + + crc[0] = 0xff; + crc[1] = 0xff; + crc[2] = 0xff; + + os9crc(crc, buf[0]); + os9crc(crc, buf[1]); + os9crc(crc, buf[2]); + os9crc(crc, buf[3]); + os9crc(crc, buf[4]); + os9crc(crc, buf[5]); + os9crc(crc, buf[6]); + os9crc(crc, buf[7]); + os9crc(crc, buf[8]); + os9crc(crc, buf[9]); + os9crc(crc, buf[10]); + os9crc(crc, buf[11]); + os9crc(crc, buf[12]); + + + writebytes(buf, 1, 13, of); + + // output the name + for (i = 0; linkscript.name[i + 1]; i++) + { + writebytes(linkscript.name + i, 1, 1, of); + os9crc(crc, linkscript.name[i]); + } + buf[0] = linkscript.name[i] | 0x80; + writebytes(buf, 1, 1, of); + os9crc(crc, buf[0]); + + // output the data + // NOTE: disjoint load addresses will not work correctly!!!!! + for (sn = 0; sn < nsects; sn++) + { + if (sectlist[sn].ptr -> flags & SECTION_BSS) + { + // no output for a BSS section + continue; + } + writebytes(sectlist[sn].ptr -> code, 1, sectlist[sn].ptr -> codesize, of); + for (i = 0; i < sectlist[sn].ptr -> codesize; i++) + os9crc(crc, sectlist[sn].ptr -> code[i]); + } + + crc[0] ^= 0xff; + crc[1] ^= 0xff; + crc[2] ^= 0xff; + writebytes(crc, 1, 3, of); +} diff -r 9cf1796259b2 -r 08fb11004df9 lwlink/script.c --- a/lwlink/script.c Thu Aug 25 22:29:58 2011 -0600 +++ b/lwlink/script.c Fri Aug 26 23:26:00 2011 -0600 @@ -32,6 +32,16 @@ #include "lwlink.h" +// the built-in OS9 script +static char *os9_script = + "section code load 0000\n" + "section .text\n" + "section data\n" + "section .data\n" + "section bss,bss load 0000\n" + "section .bss,bss\n" + ; + // the built-in DECB target linker script static char *decb_script = "section init load 2000\n" @@ -125,6 +135,10 @@ case OUTPUT_LWEX0: script = lwex0_script; break; + + case OUTPUT_OS9: + script = os9_script; + break; default: script = simple_script; @@ -154,6 +168,15 @@ if (outformat == OUTPUT_LWEX0) linkscript.stacksize = 0x100; + if (outformat == OUTPUT_OS9) + { + linkscript.modtype = 0x01; + linkscript.modlang = 0x01; + linkscript.modattr = 0x08; + linkscript.modrev = 0x00; + linkscript.name = NULL; + } + oscript = script; // now parse the script file while (*script)