/* File: main.c * * Main entry to the linker. */ #include "link.h" #include extern unsigned char sourcename[]; extern unsigned char filename[]; extern unsigned char logname[]; extern unsigned char mapname[]; extern unsigned char objname[]; extern unsigned char gblname[]; extern unsigned char cmdline[]; extern unsigned char cname1[]; extern unsigned char cname2[]; extern unsigned char dateb[]; extern unsigned char timeb[]; extern unsigned char sdate[]; extern unsigned char sxtime[]; extern unsigned char line[]; extern unsigned char *who; extern unsigned char cmdflag; extern unsigned char passno; extern unsigned char mode; extern unsigned int log; extern unsigned int noref; extern unsigned int nosym; extern unsigned int nopsect; extern unsigned int noload; extern unsigned int ltruncate; extern unsigned int hex_value; extern unsigned int cmdaddress; extern unsigned int fullflag; extern unsigned int cvalue1; extern unsigned int cvalue2; extern unsigned int relo[]; extern unsigned int adrefc[]; extern unsigned int ofset1; extern unsigned int errcnt; extern unsigned int warning; extern unsigned int fatal; extern unsigned int dataflag; extern unsigned int lflag; extern unsigned int slenth; extern FILE *cmdfile; extern FILE *logfile; extern FILE *objfile; extern FILE *mapfile; extern FILE *infile; extern FILE *datafile; extern char *optarg; extern int optind; int data_flag; int had_data; unsigned char *search(); unsigned char *look(); unsigned char *skipsp(); unsigned char *move(); int onintr(); int Orecord = MAXOBJ; static unsigned char *org_hold; static unsigned char *org_save; static unsigned char ctoken; static unsigned char printbuff[100]; static unsigned char whoami[30]; static unsigned int deleteflag; static unsigned int errorflag; static unsigned int printflag; static unsigned int mailflag; static unsigned int ofirst; static unsigned int dfirst; static unsigned int parenflag; static unsigned int expression; FILE *tryopen(); SYM *locate(); main(argc, argv) int argc; char **argv; { register unsigned char *sp; register SYM *xp; register int c; unsigned short hold; unsigned char xbuff[50]; slenth = 14; while((c = getopt(argc, argv, "lxsmafdepito:")) != EOF) { switch(c) { case 'l': log = 1; break; case 'x': noref = 1; break; case 's': nosym = 1; break; case 'm': nopsect = 1; break; case 'd': deleteflag = 1; break; case 'e': errorflag = 1; break; case 'p': printflag = 1; break; case 'i': mailflag = 1; break; case 't': ltruncate = 1; break; case 'S': slenth = atoi(optarg); break; case 'o': Orecord = atoi(optarg); if(Orecord < 8) { fprintf(stderr, "Illegal hex output length. Defaulting to 8\n"); Orecord = 8; } else if(Orecord > MAXOBJ) { fprintf(stderr, "Illegal hex output length. Defaulting to %d\n", MAXOBJ); Orecord = MAXOBJ; } break; default: (void) fprintf(stderr, "Unknown option %c\n", c); break; } } if(deleteflag || errorflag) printflag = 1; if(signal(SIGINT, SIG_IGN) != SIG_IGN) { (void) signal(SIGINT, onintr); (void) signal(SIGQUIT, onintr); (void) signal(SIGHUP, onintr); (void) signal(SIGKILL, onintr); } gettime(); (void) strcpy(sdate, dateb); (void) strcpy(sxtime, timeb); (void) strcpy(whoami, getenv("USER")); (void) strcpy(filename, argv[optind]); (void) strcpy(sourcename, look(filename)); makelower(sourcename); if(sp = search(sourcename)) *sp = 0; force_extension(sourcename, mapname, ".map"); force_extension(sourcename, objname, ".hex"); force_extension(sourcename, logname, ".log"); force_extension(sourcename, gblname, ".gbl"); objfile = fopen(objname, "w+"); if(noref || nosym || nopsect) mapfile = fopen(mapname, "w+"); if(log) logfile = fopen(logname, "w+"); if(sp = search(filename)) cmdflag = equal(++sp, "cmd"); else { cmdflag = 1; addext(filename, ".cmd"); } hold = 0; data_flag = -1; for(passno = 1; passno < 3; passno++) { adrefc[CSEG] = BASE_ADDRESS; relo[CSEG] = BASE_ADDRESS; adrefc[DSEG] = hold; relo[DSEG] = hold; mode = CSEG; ofset1 = 0; lflag = 0; ofirst = 0; dfirst = 0; errcnt = 0; fatal = 0; warning = 0; openr(); clsrec(); if(cmdflag) { if((cmdfile = tryopen(filename)) == 0) { printl("Can't open command file: %s\n", filename); xdone(1); } while(parse()) { switch(ctoken) { case ORG_TOKEN: printl("CODE:\t%04.4X", cvalue1); if(expression) { org_hold[strlen(org_hold) - 1] = 0; printl("\t\t;%s", org_hold); } printl("\n"); if(ofirst && (cvalue1 < adrefc[CSEG])) printl("Warning: new code segment overlaps old code segment\n"); else ++ofirst; adrefc[CSEG] = cvalue1; relo[CSEG] = cvalue1; lflag |= LADIS; break; case DATA_TOKEN: if(cvalue1 == 0) cvalue1 = adrefc[CSEG]; printl("DATA:\t%04.4X", cvalue1); if(expression) { org_hold[strlen(org_hold) - 1] = 0; printl("\t\t;%s", org_hold); } printl("\n"); if(dfirst && (cvalue1 < adrefc[DSEG])) printl("Warning: new data segment overlaps old data segment\n"); else ++dfirst; adrefc[DSEG] = cvalue1; relo[DSEG] = cvalue1; hold = cvalue1; data_flag = 0; break; case DUMMY: case LIST_TOKEN: case NAME_TOKEN: case FILL_TOKEN: continue; case INCLUDE_TOKEN: glink(); break; case LOAD_TOKEN: include(); break; case DPAGE_TOKEN: linkset(cvalue1); break; case END_TOKEN: if(passno == 2) traout(cvalue1, 0); goto done; case GLOBAL_TOKEN: printl("command file GLOBAL is NOT supported\n"); printl("GLOBAL whatever labels you need in the source file(s)\n"); continue; case DEFINE_TOKEN: if(passno == 1) { if(equal(cname1, "$")) { printl("Can't redefine the pc\n"); continue; } else if(xp = locate(cname2)) { if(xp->flag & LNKENT) printl("WARNING: value of %s being redefined\n", cname2); xp->value = cvalue2; xp->flag |= LNKENT; } else insert(cname2, cvalue2, LNKENT); printl("%s defined with value of %04.4X\n", cname2, cvalue2); } continue; default: printl("unknown operation: %s", cmdline); continue; } } done: fclose(cmdfile); } else { addext(filename, ".rel"); if((infile = tryopen(filename, "r")) == 0) { printl("Can't open main link file: %s\n", filename); xdone(1); } else { who = filename; fgetc(infile); /* get the 'more' header */ fgetc(infile); /* and throw it away */ xlink(); } fclose(infile); } if(had_data && data_flag) { cvalue1 = adrefc[CSEG]; adrefc[DSEG] = cvalue1; relo[DSEG] = cvalue1; hold = cvalue1; data_flag = 0; } printl("Pass %d complete", passno); if(log) { gettime(); printl(" at %s", timeb); } printl("\n"); } dspmap(); dspsym(); dspref(); if(errcnt) sprintf(xbuff, "%d", errcnt); else sprintf(xbuff, "No"); strcpy(line, mapfile ? "\n" : ""); strcat(line, xbuff); strcat(line, " Link Error"); if(errcnt != 1) strcat(line, "s"); if(errcnt) { sprintf(xbuff, "\t%d Warnings, %d Fatal", warning, fatal); strcat(line, xbuff); } if(mapfile) { list(line); fclose(mapfile); } printl("%s\n", line); if (printflag && mapfile) { if (errorflag && errcnt) { printl("link: Listing NOT printed due to errors\n"); } else { sprintf(printbuff, "lpr -X %s %s\n", deleteflag ? "-r" : "", mapname); system(printbuff); } } xdone(errcnt ? 1 : 0); } parse() { register unsigned char *pnt; if(fgets(cmdline, 100, cmdfile) == 0) { printl("Unexpected EOF from command file\n"); return(0); } cname1[0] = 0; cname2[0] = 0; cvalue1 = 0; cvalue2 = 0; ctoken = 0; expression = 0; pnt = move(skipsp(cmdline), cname1); if(*pnt == '\'') pnt = skipsp(++pnt); org_save = pnt; org_hold = pnt; if(isdigit(*pnt)) cvalue1 = eval(pnt); else { pnt = move(pnt, cname2); strip(cname2); } if(equal(cname1, "org") || equal(cname1, "code")) { ctoken = ORG_TOKEN; cvalue1 = evaluate(); } else if(equal(cname1, "data")) { ctoken = DATA_TOKEN; cvalue1 = evaluate(); } else if(equal(cname1, "list")) ctoken = LIST_TOKEN; else if(equal(cname1, "name")) ctoken = NAME_TOKEN; else if((equal(cname1, "include")) || (equal(cname1, "includ"))) ctoken = INCLUDE_TOKEN; else if(equal(cname1, "load")) ctoken = LOAD_TOKEN; else if(equal(cname1, "dpage")) { ctoken = DPAGE_TOKEN; if(equal(cname2, "P")) cvalue1 = 256; else cvalue1 = evaluate(); } else if(equal(cname1, "end")) { ctoken = END_TOKEN; cvalue1 = evaluate(org_save); } else if(equal(cname1, "global")) ctoken = GLOBAL_TOKEN; else if(!cname1[0]) ctoken = DUMMY; else if(cname1[0] == '*' || cname1[0] == '#') ctoken = DUMMY; else if(equal(cname1, "define")) { org_save = pnt; ctoken = DEFINE_TOKEN; cvalue2 = evaluate(); } else if(equal(cname1, "fill")) { ctoken = FILL_TOKEN; noload = 1; hex_value = evaluate(); } return(1); } unsigned char *move(from, to) register unsigned char *from, *to; { while(*from > ' ') *to++ = *from++; *to = 0; return(skipsp(from)); } eval(pointer) register unsigned char *pointer; { unsigned char c; register unsigned int value = 0; while(ishex(c = *pointer)) { value *= 16; value += c > '9' ? c - '7' : c - '0'; ++pointer; } if(tolower(*pointer) == 'h') ++pointer; return(value); } evaluate() { register unsigned int value, value1; register unsigned char *bp, *xp; register SYM *sp; unsigned char sbuff[100]; value = 0; for(;;) { if(*org_save <= ' ' || *org_save == '\'' || *org_save > 'z') return(value); if(*org_save == ')') { if(!parenflag) { eprintf("No matching paren", org_save); ++org_save; continue; } return(value); } if(isdigit(*org_save)) { bp = sbuff; while(ishex(*org_save)) *bp++ = *org_save++; if(tolower(*org_save) == 'h') ++org_save; *bp = 0; value = eval(sbuff); } else if(an(*org_save)) { if((org_save[0] == '$') && (!an(org_save[1]))) goto current; bp = sbuff; xp = org_save; while(an(*org_save)) *bp++ = *org_save++; *bp = 0; if(sp = locate(sbuff)) value = sp->value; else eprintf("Undefined GLOBAL symbol", xp); } else { current: switch(*org_save++) { case '(': ++parenflag; value = evaluate(); --parenflag; if(*org_save != ')') eprintf("Unbalanced parens", org_save); else ++org_save; break; case '+': value += evaluate(); break; case '-': value -= evaluate(); break; case '/': value1 = evaluate(); if(value1) value /= evaluate(); else eprintf("Division by zero error", org_save); break; case '*': value *= evaluate(); break; case '<': value <<= evaluate(); break; case '>': value >>= evaluate(); break; case '^': value ^= evaluate(); break; case '|': value |= evaluate(); break; case '&': value &= evaluate(); break; case '$': value = adrefc[mode]; break; default: eprintf("Unknown math operation", &org_save[-1]); continue; } expression = 1; } } } static eprintf(msg, pnt) register unsigned char *msg, *pnt; { register unsigned int i; unsigned char xbuff[200]; i = 0; while(cmdline[i] && strcmp(&cmdline[i], pnt)) { xbuff[i] = (cmdline[i] == '\t') ? '\t' : ' '; ++i; } xbuff[i++] = '^'; xbuff[i] = 0; printl("\n%s", cmdline); printl("%s\n", xbuff); printl("*** %s ***\n\n", msg); if(passno == 2) { ++errcnt; ++fatal; } } xdone(number) { gettime(); if (mailflag) { if (number) sprintf(printbuff, "Link of %s aborting abnormally during pass %u on: %s at: %s", filename, passno, dateb, timeb); else sprintf(printbuff, "Link of %s complete with %u errors on: %s at: %s", filename, errcnt, dateb, timeb); mailit(); } exit(number); } onintr(signo) int signo; { if (signo == SIGQUIT) (void) signal(SIGQUIT, onintr); gettime(); printl("\nLink interrupted on: %s at: %s\n", dateb, timeb); if (mailflag) { (void) sprintf(printbuff, "Link of %s interrupted on: %s at: %s\n", filename, dateb, timeb); mailit(); } exit(1); } static mailit() { char mailbuf[200]; (void) sprintf(mailbuf, "mail %s <