123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627 |
- /*
- * (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
- * See the copyright notice in the ACK home directory, in the file "Copyright".
- */
- #ifndef lint
- static char rcsid[] = "$Id$";
- #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;
- #ifndef NOSTATISTICS
- int statistics;
- #endif
- #ifndef NDEBUG
- int DEB = 0;
- #endif
- int Verbose = 0;
- static initializations();
- static first_pass();
- static long number();
- static setlign();
- static setbase();
- static struct outname *makename();
- static pass1();
- static evaluate();
- static norm_commons();
- static complete_sections();
- static change_names();
- static bool tstbit();
- static second_pass();
- static pass2();
- #ifndef NOSTATISTICS
- static do_statistics();
- #endif
- main(argc, argv)
- int argc;
- char **argv;
- {
- initializations(argc, argv);
- first_pass(argv);
- #ifndef NOSTATISTICS
- if (statistics) do_statistics();
- #endif
- freeze_core();
- evaluate();
- beginoutput();
- second_pass(argv);
- endoutput();
- stop();
- }
- #ifndef NOSTATISTICS
- static
- do_statistics()
- {
- register struct memory *m = mems;
- while (m <= &mems[NMEMS-1]) {
- fprintf(stderr, "mem %d: full %lx, free %lx\n",
- (int)(m - mems),
- (long) m->mem_full,
- (long) m->mem_left);
- m++;
- }
- }
- #endif
- 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;
- 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. */
- int exitstatus = 0;
- /*
- * 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 char *strchr();
- extern int hash();
- extern struct outname *searchname();
- 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 = strchr(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 = strchr(argp, ':')) == (char *)0)
- fatal("usage: -b<section number>:<base>");
- setbase(sectno, number(++argp));
- break;
- case 'c':
- /*
- * Leave relocation information in the output, so that
- * a next pass can see where relocation was done. The
- * resulting output however is no longer relocatable.
- */
- flagword &= ~RFLAG;
- flagword |= CFLAG;
- break;
- #ifndef NDEBUG
- case 'd':
- DEB = 1;
- break;
- #endif
- case 'n':
- /* In the resulting name list, leave offsets with
- respect to the beginning of the section instead
- of absolute addresses.
- */
- flagword |= NFLAG;
- 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 & CFLAG) break;
- 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;
- case 'v':
- Verbose = 1;
- break;
- case 'S':
- statistics = 1;
- break;
- default:
- warning("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 = digit - 'A' + 10;
- else if (digit >= 'a' && digit <= 'f')
- digit = digit - 'a' + 10;
- else if (digit >= '0' && digit <= '9')
- digit = 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()
- {
- norm_commons();
- complete_sections();
- if (!(flagword&(RFLAG|NFLAG)))
- change_names();
- }
- extern unsigned short NGlobals, NLocals;
- /*
- * Sect_comm[N] is the number of common bytes in section N.
- * It is computed after pass 1.
- */
- 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;
- if (!(flagword & RFLAG)) {
- exitstatus = 1;
- fprintf(stderr, "Undefined:\n");
- }
- outhead.oh_flags |= HF_LINK;
- if (flagword & RFLAG) break;
- flagword = (flagword & ~SFLAG) | RFLAG;
- }
- 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 struct outsect *sc;
- register int sectindex;
- foff = SZ_HEAD + outhead.oh_nsect * SZ_SECT;
- for (sectindex = 0; sectindex < outhead.oh_nsect; sectindex++) {
- relorig[sectindex].org_size = (long)0;
- sc = &outsect[sectindex];
- sc->os_foff = foff;
- foff += sc->os_flen;
- if (flagword & RFLAG)
- continue;
- sc->os_size += sect_comm[sectindex];
- sc->os_lign =
- tstbit(sectindex, lignmap) ? sect_lign[sectindex] : 1;
- if (tstbit(sectindex, basemap)) {
- base = sect_base[sectindex];
- if (sc->os_lign && base % sc->os_lign)
- fatal("base not aligned");
- } else if (sc->os_lign) {
- base += sc->os_lign - 1;
- base -= base % sc->os_lign;
- }
- sc->os_base = base;
- base += sc->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.
- */
- 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 || type == S_CRS)
- return;
- if (name->on_type & S_COM)
- return;
- 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);
- }
|