--- /dev/null
+#ifndef lint
+static char rcsid[] = "$Header$";
+#endif
+
+/*
+ * led - linkage editor for ACK assemblers output format
+ */
+
+#include <stdio.h>
+#include "out.h"
+#include "const.h"
+#include "debug.h"
+#include "defs.h"
+#include "memory.h"
+#include "orig.h"
+
+extern bool incore;
+
+main(argc, argv)
+ int argc;
+ char **argv;
+{
+ initializations(argc, argv);
+ first_pass(argv);
+ freeze_core();
+ evaluate();
+ beginoutput();
+ second_pass(argv);
+ endoutput();
+ exit(0);
+}
+
+char *progname; /* Name this program was invoked with. */
+int passnumber; /* Pass we are in. */
+struct outhead outhead; /* Header of final output file. */
+struct outsect outsect[MAXSECT];/* Its section table. */
+
+/* ARGSUSED */
+static
+initializations(argc, argv)
+ int argc;
+ char *argv[];
+{
+ /*
+ * Avoid malloc()s.
+ */
+ setbuf(stdin, (char *)NULL);
+ setbuf(stdout, (char *)NULL);
+ setbuf(stderr, (char *)NULL);
+
+ progname = argv[0];
+ passnumber = FIRST;
+ determine_ordering();
+ init_core();
+ init_symboltable();
+ outhead.oh_magic = O_MAGIC;
+ outhead.oh_stamp = O_STAMP;
+}
+
+/* ------------------------ ROUTINES OF FIRST PASS ------------------------- */
+
+int flagword = 0; /* To store command-line options. */
+char *outputname = "a.out"; /* Name of the resulting object file. */
+
+/*
+ * Scan the arguments.
+ * If the argument starts with a '-', it's a flag, else it is either
+ * a plain file to be loaded, or an archive.
+ */
+static
+first_pass(argv)
+ register char **argv;
+{
+ register char *argp;
+ int sectno;
+ int h;
+ extern int atoi();
+ extern long number();
+ extern char *index();
+ extern int hash();
+ extern struct outname *searchname();
+ extern struct outname *makename();
+
+ while (*++argv) {
+ argp = *argv;
+ if (*argp != '-') {
+ pass1(argp);
+ continue;
+ }
+ /* It's a flag. */
+ switch (*++argp) {
+ case 'a':
+ /*
+ * The rest of the argument must be of the form
+ * `<section number>:<alignment>', where
+ * <section number> and <alignment> are numbers.
+ * <alignment> will be the alignment in the machine of
+ * section <section number>.
+ */
+ sectno = atoi(++argp);
+ if ((argp = index(argp, ':')) == (char *)0)
+ fatal("usage: -a<section number>:<alignment>");
+ setlign(sectno, number(++argp));
+ break;
+ case 'b':
+ /*
+ * The rest of the argument must be of the form
+ * `<section number>:<base>', where <section number>
+ * and base are decimal numbers. <base> will be
+ * the base address in the machine of section
+ * <section number>.
+ */
+ sectno = atoi(++argp);
+ if ((argp = index(argp, ':')) == (char *)0)
+ fatal("usage: -b<section number>:<base>");
+ setbase(sectno, number(++argp));
+ break;
+ case 'o':
+ /*
+ * The `name' argument after -o is used as name
+ * of the led output file, instead of "a.out".
+ */
+ if ((outputname = *++argv) == (char *)0)
+ fatal("-o needs filename");
+ break;
+ case 'r':
+ /*
+ * Generate relocation information in the output file
+ * so that it can be the subject of another led run.
+ * This flag also prevents final definitions from being
+ * given to common symbols, and suppresses the
+ * `Undefined:' diagnostic.
+ */
+ if (flagword & SFLAG)
+ warning("-r contradicts -s: -s ignored");
+ flagword |= RFLAG;
+ break;
+ case 's':
+ /*
+ * `Strip' the output, that is, remove the symbol table
+ * and relocation table to save space (but impair the
+ * usefullness of the debuggers). This information can
+ * also be removed by astrip(1).
+ */
+ if (flagword & RFLAG)
+ warning("-s contradicts -r: -s ignored");
+ else
+ flagword |= SFLAG;
+ break;
+ case 'u':
+ /*
+ * Take the following argument as a symbol and enter it
+ * as undefined in the symbol table. This is useful for
+ * loading wholly from a library, since initially the
+ * symbol table is empty and an unresolved reference is
+ * needed to force the loading of the first routine.
+ */
+ if (*++argv == (char *)0)
+ fatal("-u needs symbol name");
+ h = hash(*argv);
+ if (searchname(*argv, h) == (struct outname *)0)
+ entername(makename(*argv), h);
+ break;
+ default:
+ fatal("bad flag letter %c", *argp);
+ break;
+ }
+ }
+}
+
+/*
+ * If `s' starts with 0x/0X, it's hexadecimal,
+ * else if it starts with 0b/0B, it's binary,
+ * else if it starts with 0, it's octal,
+ * else it's decimal.
+ */
+static long
+number(s)
+ register char *s;
+{
+ register int digit;
+ register long value = 0;
+ register int radix = 10;
+
+ if (*s == '0') {
+ radix = 8;
+ s++;
+ if (*s == 'x' || *s == 'X') {
+ radix = 16;
+ s++;
+ } else if (*s == 'b' || *s == 'B') {
+ radix = 2;
+ s++;
+ }
+ }
+ while (digit = *s++) {
+ if (digit >= 'A' && digit <= 'F')
+ digit -= 'A' + 10;
+ else if (digit >= 'a' && digit <= 'f')
+ digit -= 'a' + 10;
+ else if (digit >= '0' && digit <= '9')
+ digit -= '0';
+ else
+ fatal("wrong digit %c", digit);
+ if (digit >= radix)
+ fatal("digit %c exceeds radix %d", digit, radix);
+ value = radix * value + digit;
+ }
+ return value;
+}
+
+/*
+ * We use one bit per section to indicate whether a base was already given or
+ * not. Only one base may be given. The same applies for alignments.
+ */
+static char basemap[MAXSECT / WIDTH];
+static long sect_base[MAXSECT];
+static char lignmap[MAXSECT / WIDTH];
+static long sect_lign[MAXSECT];
+
+/*
+/*
+ * Set the alignment of section `sectno' to `lign', if this doesn't
+ * conflict with earlier alignment.
+ */
+static
+setlign(sectno, lign)
+ register int sectno;
+ register long lign;
+{
+ extern bool setbit();
+
+ if (setbit(sectno, lignmap) && sect_lign[sectno] != lign)
+ fatal("section has different alignments");
+ if (lign == (long)0)
+ fatal("alignment cannot be zero");
+ sect_lign[sectno] = lign;
+}
+
+/*
+ * Set the base of section `sectno' to `base', if no other base has been
+ * given yet.
+ */
+static
+setbase(sectno, base)
+ register int sectno;
+ register long base;
+{
+ extern bool setbit();
+
+ if (setbit(sectno, basemap) && sect_base[sectno] != base)
+ fatal("section has different bases");
+ sect_base[sectno] = base;
+}
+
+static struct outname *
+makename(string)
+ char *string;
+{
+ static struct outname namebuf;
+
+ namebuf.on_mptr = string;
+ namebuf.on_type = S_UND + S_EXT;
+ namebuf.on_valu = (long)0;
+
+ return &namebuf;
+}
+
+/*
+ * If `file' is a plain file, symboltable information and section sizes are
+ * extracted. If it is an archive it is examined to see if it defines any
+ * undefined symbols.
+ */
+static
+pass1(file)
+ char *file;
+{
+ if (getfile(file) == PLAIN) {
+ debug("%s: plain file\n", file, 0, 0, 0);
+ extract();
+ } else {
+ /* It must be an archive. */
+ debug("%s: archive\n", file, 0, 0, 0);
+ arch();
+ }
+ closefile(file);
+}
+
+/* ---------------- ROUTINES BETWEEN FIRST AND SECOND PASS ----------------- */
+
+/*
+ * After pass 1 we know the sizes of all commons so we can give each common
+ * name an address within its section and we can compute the sizes of all
+ * sections in the machine. After this we can compute the bases of all
+ * sections. We then add the section bases to the values of names in
+ * corresponding sections.
+ */
+static
+evaluate()
+{
+ if (!(flagword & RFLAG))
+ norm_commons();
+ complete_sections();
+ if (!(flagword & RFLAG))
+ change_names();
+}
+
+extern ushort NGlobals, NLocals;
+
+/*
+ * Sect_comm[N] is the number of common bytes in section N.
+ * It is computed after pass 1.
+ */
+static long sect_comm[MAXSECT];
+
+/*
+ * If there are undefined names, we print them and we set a flag so that
+ * the output can be subject to another led run and we return.
+ * We now know how much space each common name needs. We change the value
+ * of the common name from the size to the address within its section,
+ * just like "normal" names. We also count the total size of common names
+ * within each section to be able to compute the final size in the machine.
+ */
+static
+norm_commons()
+{
+ register struct outname *name;
+ register int cnt;
+ register int und = FALSE;
+
+ name = (struct outname *)address(ALLOGLOB, (ind_t)0);
+ cnt = NGlobals;
+ while (cnt-- > 0) {
+ if (ISUNDEFINED(name)) {
+ if (!und) {
+ und = TRUE;
+ outhead.oh_flags |= HF_LINK;
+ flagword = (flagword & ~SFLAG) | RFLAG;
+ fprintf(stderr, "Undefined:\n");
+ }
+ fprintf(stderr, "\t%s\n",
+ address(ALLOGCHR, (ind_t)name->on_foff)
+ );
+ }
+ name++;
+ }
+ if (flagword & RFLAG) return;
+
+ /*
+ * RFLAG is off, so we need not produce relocatable output.
+ * We can now assign an address to common names.
+ * It also means that there are no undefined names.
+ */
+ name = (struct outname *)address(ALLOGLOB, (ind_t)0);
+ cnt = NGlobals;
+ while (cnt-- > 0) {
+ if (!ISABSOLUTE(name) && ISCOMMON(name)) {
+ register long size;
+ register int sectindex;
+
+ size = name->on_valu; /* XXX rounding? */
+ sectindex = (name->on_type & S_TYP) - S_MIN;
+ name->on_valu =
+ outsect[sectindex].os_size +
+ sect_comm[sectindex];
+ sect_comm[sectindex] += size;
+ name->on_type &= ~S_COM;
+ }
+ name++;
+ }
+}
+
+struct orig relorig[MAXSECT];
+
+/*
+ * Compute the offsets in file and machine that the sections will have.
+ * Also set the origins to 0.
+ */
+static
+complete_sections()
+{
+ register long base = 0;
+ register long foff;
+ register int sectindex;
+ extern bool tstbit();
+
+ foff = SZ_HEAD + outhead.oh_nsect * SZ_SECT;
+ for (sectindex = 0; sectindex < outhead.oh_nsect; sectindex++) {
+ relorig[sectindex].org_flen = (long)0;
+ relorig[sectindex].org_zero = (long)0;
+ outsect[sectindex].os_foff = foff;
+ foff += outsect[sectindex].os_flen;
+
+ if (flagword & RFLAG)
+ continue;
+
+ outsect[sectindex].os_size += sect_comm[sectindex];
+ outsect[sectindex].os_lign =
+ tstbit(sectindex, lignmap) ? sect_lign[sectindex] : 1;
+ if (tstbit(sectindex, basemap)) {
+ base = sect_base[sectindex];
+ if (base % outsect[sectindex].os_lign)
+ fatal("base not aligned");
+ } else {
+ base += outsect[sectindex].os_lign - 1;
+ base -= base % outsect[sectindex].os_lign;
+ }
+ outsect[sectindex].os_base = base;
+ base += outsect[sectindex].os_size;
+ }
+}
+
+/*
+ * For each name we add the base of its section to its value, unless
+ * the output has to be able to be linked again, as indicated by RFLAG.
+ */
+static
+change_names()
+{
+ register int cnt;
+ register struct outname *name;
+
+ name = (struct outname *)address(ALLOGLOB, (ind_t)0);
+ cnt = NGlobals;
+ while (cnt-- > 0) {
+ addbase(name);
+ name++;
+ }
+ if (!incore)
+ return;
+ /*
+ * Do the same with the local names.
+ */
+ name = (struct outname *)address(ALLOLOCL, (ind_t)0);
+ cnt = NLocals;
+ while (cnt-- > 0) {
+ addbase(name);
+ name++;
+ }
+}
+
+#define BIT 0x01
+
+/*
+ * This function sets a bit with index `indx' in string.
+ * It returns whether it was already set.
+ */
+bool
+setbit(indx, string)
+ int indx;
+ char string[];
+{
+ register int byte_index, bit_index;
+ register int byte;
+
+ byte_index = indx / WIDTH; /* Index of byte with bit we need. */
+ bit_index = indx % WIDTH; /* Index of bit we need. */
+ byte = string[byte_index];
+ byte >>= bit_index;
+ if (byte & BIT) return TRUE;
+
+ byte = BIT;
+ byte <<= bit_index;
+ string[byte_index] |= byte;
+ return FALSE;
+}
+
+/*
+ * This function returns whether the bit given by `indx' is set in `string'.
+ */
+static bool
+tstbit(indx, string)
+ int indx;
+ char string[];
+{
+ register int byte_index, bit_index;
+ register int byte;
+
+ byte_index = indx / WIDTH; /* Index of byte with bit we need. */
+ bit_index = indx % WIDTH; /* Index of bit we need. */
+ byte = string[byte_index];
+ byte >>= bit_index;
+
+ return byte & BIT;
+}
+
+/*
+ * Add the base of the section of a name to its value. For a name in the zero
+ * part, the size of the normal part is also a "base".
+ */
+addbase(name)
+ struct outname *name;
+{
+ register int type = name->on_type & S_TYP;
+ register int sectindex = type - S_MIN;
+
+ if (type == S_UND || type == S_ABS)
+ return;
+ if (name->on_type & S_COM)
+ return;
+
+ if (name->on_type & S_ZER) {
+ name->on_valu += outsect[sectindex].os_flen;
+ name->on_type &= ~S_ZER;
+ }
+ name->on_valu += outsect[sectindex].os_base;
+ debug( "%s: type 0x%x, value %ld\n",
+ address((name->on_type & S_EXT) ? ALLOGCHR : ALLOLCHR,
+ (ind_t)name->on_foff
+ ),
+ name->on_type, name->on_valu, 0
+ );
+}
+
+/* ------------------------ ROUTINES OF SECOND PASS ------------------------ */
+
+/*
+ * Flags have already been processed, so we ignore them here.
+ */
+static
+second_pass(argv)
+ char **argv;
+{
+ passnumber = SECOND;
+ while (*++argv) {
+ if ((*argv)[0] != '-') {
+ pass2(*argv);
+ continue;
+ }
+ switch ((*argv)[1]) {
+ case 'o':
+ case 'u':
+ ++argv;
+ break;
+ default:
+ break;
+ }
+ }
+}
+
+static
+pass2(file)
+ char *file;
+{
+ if (getfile(file) == PLAIN) {
+ debug("%s: plain file\n", file, 0, 0, 0);
+ finish();
+ } else {
+ /* It must be an archive. */
+ debug("%s: archive\n", file, 0, 0, 0);
+ arch2();
+ }
+ closefile(file);
+}