From 55017702e2049a25df869acc6985586ead610c58 Mon Sep 17 00:00:00 2001 From: duk Date: Thu, 10 Jan 1985 13:22:04 +0000 Subject: [PATCH] Header and section table now allocated statically. --- util/led/main.c | 554 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 554 insertions(+) create mode 100644 util/led/main.c diff --git a/util/led/main.c b/util/led/main.c new file mode 100644 index 000000000..9f47cd167 --- /dev/null +++ b/util/led/main.c @@ -0,0 +1,554 @@ +#ifndef lint +static char rcsid[] = "$Header$"; +#endif + +/* + * led - linkage editor for ACK assemblers output format + */ + +#include +#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 + * `
:', where + *
and are numbers. + * will be the alignment in the machine of + * section
. + */ + sectno = atoi(++argp); + if ((argp = index(argp, ':')) == (char *)0) + fatal("usage: -a
:"); + setlign(sectno, number(++argp)); + break; + case 'b': + /* + * The rest of the argument must be of the form + * `
:', where
+ * and base are decimal numbers. will be + * the base address in the machine of section + *
. + */ + sectno = atoi(++argp); + if ((argp = index(argp, ':')) == (char *)0) + fatal("usage: -b
:"); + 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); +} -- 2.34.1