Header and section table now allocated statically.
authorduk <none@none>
Thu, 10 Jan 1985 13:22:04 +0000 (13:22 +0000)
committerduk <none@none>
Thu, 10 Jan 1985 13:22:04 +0000 (13:22 +0000)
util/led/main.c [new file with mode: 0644]

diff --git a/util/led/main.c b/util/led/main.c
new file mode 100644 (file)
index 0000000..9f47cd1
--- /dev/null
@@ -0,0 +1,554 @@
+#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);
+}