Browse Source

Maybe some minor changes.

duk 39 years ago
parent
commit
2118ece784
20 changed files with 2251 additions and 112 deletions
  1. 120 0
      h/out.h
  2. 25 0
      h/ranlib.h
  3. 178 0
      util/led/archive.c
  4. 18 0
      util/led/assert.h
  5. 90 0
      util/led/byte_order.c
  6. 26 0
      util/led/const.h
  7. 11 0
      util/led/debug.h
  8. 10 0
      util/led/defs.h
  9. 182 0
      util/led/finish.c
  10. 24 0
      util/led/mach.c
  11. 66 112
      util/led/memory.c
  12. 35 0
      util/led/memory.h
  13. 6 0
      util/led/orig.h
  14. 134 0
      util/led/read.c
  15. 256 0
      util/led/relocate.c
  16. 104 0
      util/led/save.c
  17. 524 0
      util/led/scan.c
  18. 13 0
      util/led/scan.h
  19. 132 0
      util/led/sym.c
  20. 297 0
      util/led/write.c

+ 120 - 0
h/out.h

@@ -0,0 +1,120 @@
+/* $Header$ */
+/*
+ * output format for ACK assemblers
+ */
+#ifndef ushort
+#define ushort	unsigned short
+#endif ushort
+
+struct outhead {
+	ushort 	oh_magic;	/* magic number */
+	ushort 	oh_stamp;	/* version stamp */
+	ushort	oh_flags;	/* several format flags */
+	ushort	oh_nsect;	/* number of outsect structures */
+	ushort	oh_nrelo;	/* number of outrelo structures */
+	ushort	oh_nname;	/* number of outname structures */
+	long	oh_nemit;	/* sum of all os_flen */
+	long	oh_nchar;	/* size of string area */
+};
+
+#define O_MAGIC	0x0201		/* magic number of output file */
+#define	O_STAMP	0		/* version stamp */
+
+#ifdef JOHAN
+#define	HF_BREV	0x0001		/* high order byte lowest address */
+#define	HF_WREV	0x0002		/* high order word lowest address */
+#endif JOHAN
+#define	HF_LINK	0x0004		/* unresolved references left */
+#define	HF_8086	0x0008		/* os_base specially encoded */
+
+struct outsect {
+	long 	os_base;	/* startaddress in machine */
+	long	os_size;	/* section size in machine */
+	long	os_foff;	/* startaddress in file */
+	long	os_flen;	/* section size in file */
+	long	os_lign;	/* section alignment */
+};
+
+struct outrelo {
+	char	or_type;	/* type of reference */
+	char	or_sect;	/* referencing section */
+	ushort	or_nami;	/* referenced symbol index */
+	long	or_addr;	/* referencing address */
+};
+
+struct outname {
+	union {
+	  char	*on_ptr;	/* symbol name (in core) */
+	  long	on_off;		/* symbol name (in file) */
+	}	on_u;
+#define on_mptr	on_u.on_ptr
+#define on_foff	on_u.on_off
+	ushort	on_type;	/* symbol type */
+	ushort	on_desc;	/* debug info */
+	long	on_valu;	/* symbol value */
+};
+
+/*
+ * relocation type bits
+ */
+#define RELSZ	0x07		/* relocation length */
+#define RELO1	   1		/* 1 byte */
+#define RELO2	   2		/* 2 bytes */
+#define RELO4	   4		/* 4 bytes */
+#define RELPC	0x08		/* pc relative */
+#ifndef JOHAN
+#define RELBR	0x10		/* High order byte lowest address. */
+#define RELWR	0x20		/* High order word lowest address. */
+#endif JOHAN
+
+/*
+ * section type bits and fields
+ */
+#define S_TYP	0x007F		/* undefined, absolute or relative */
+#define S_EXT	0x0080		/* external flag */
+#define S_ETC	0x7F00		/* for symbolic debug, bypassing 'as' */
+
+/*
+ * S_TYP field values
+ */
+#define S_UND	0x0000		/* undefined item */
+#define S_ABS	0x0001		/* absolute item */
+#define S_MIN	0x0002		/* first user section */
+#define S_MAX	S_TYP		/* last user section */
+
+/*
+ * S_ETC field values
+ */
+#define S_SCT	0x0100		/* section names */
+#define S_LIN	0x0200		/* hll source line item */
+#define S_FIL	0x0300		/* hll source file item */
+#define S_MOD	0x0400		/* ass source file item */
+#ifndef JOHAN
+#define S_COM	0x1000		/* Common name. */
+#endif JOHAN
+
+/*
+ * structure format strings
+ */
+#define SF_HEAD		"22222244"
+#define SF_SECT		"44444"
+#define SF_RELO		"1124"
+#define SF_NAME		"4224"
+
+/*
+ * structure sizes (bytes in file; add digits in SF_*)
+ */
+#define SZ_HEAD		20
+#define SZ_SECT		20
+#define SZ_RELO		8
+#define SZ_NAME		12
+
+/*
+ * file access macros
+ */
+#define BADMAGIC(x)	((x).oh_magic!=O_MAGIC)
+#define OFF_SECT(x)	SZ_HEAD
+#define OFF_EMIT(x)	(OFF_SECT(x) + ((long)(x).oh_nsect * SZ_SECT))
+#define OFF_RELO(x)	(OFF_EMIT(x) + (x).oh_nemit)
+#define OFF_NAME(x)	(OFF_RELO(x) + ((long)(x).oh_nrelo * SZ_RELO))
+#define OFF_CHAR(x)	(OFF_NAME(x) + ((long)(x).oh_nname * SZ_NAME))

+ 25 - 0
h/ranlib.h

@@ -0,0 +1,25 @@
+/* $Header$ */
+
+#ifndef SYMDEF
+#	define SYMDEF	"__.SYMDEF"
+#endif SYMDEF
+
+/*
+ * Structure of the SYMDEF table of contents for an archive.
+ * SYMDEF begins with a long giving the number of ranlib
+ * structures that immediately follow, and then continues with a string
+ * table consisting of a long giving the number of bytes of
+ * strings that follow and then the strings themselves.
+ */
+struct ranlib {
+	union {
+	  char	*ran__ptr;	/* symbol name (in core) */
+	  long	ran__off;	/* symbol name (in file) */
+	}	ran_u;
+#define ran_ptr ran_u.ran__ptr
+#define ran_off ran_u.ran__off
+	long	ran_pos;	/* library member is at this position */
+};
+
+#define SZ_RAN	8
+#define SF_RAN	"44"

+ 178 - 0
util/led/archive.c

@@ -0,0 +1,178 @@
+#ifndef lint
+static char rcsid[] = "$Header$";
+#endif
+
+#include "arch.h"
+#include "out.h"
+#include "ranlib.h"
+#include "const.h"
+#include "debug.h"
+#include "defs.h"
+#include "memory.h"
+
+#define ENDLIB		((long)0)
+
+extern ind_t		hard_alloc();
+
+static struct ar_hdr	arhdr;
+
+/*
+ * First read a long telling how many ranlib structs there are, then
+ * the structs themselves. Second read a long telling how many chars there are
+ * in the string table, then the string table itself.
+ * We keep only one ranlib table in core, so this table always starts at offset
+ * (ind_t)0 from its base.
+ */
+static long
+getsymdeftable()
+{
+	register ind_t		off;
+	register struct ranlib	*ran;
+	register long		count;
+	register long		nran, nchar;
+	extern long		getlong();
+
+	count = nran = getlong();
+	debug("%ld ranlib structs, ", nran, 0, 0, 0);
+	off = hard_alloc(ALLORANL, nran * sizeof(struct ranlib));
+	if (off == BADOFF)
+		fatal("no space for ranlib structs");
+	ran = (struct ranlib *)address(ALLORANL, off);
+	read_table(ran, count);
+	nchar = getlong();
+	debug("%ld ranlib chars\n", nchar, 0, 0, 0);
+	if ((off = hard_alloc(ALLORANL, nchar)) == BADOFF)
+		fatal("no space for ranlib strings");
+	read_char(address(ALLORANL, off), nchar);
+	ran = (struct ranlib *)address(ALLORANL, (ind_t)0);
+	while (count--) {
+		/*
+		 * Adjust because names are now in core, not on file.
+		 * Note that `ran_off' is measured from the beginning of the
+		 * string area, NOT from the beginning of the file.
+		 */
+		if (ran->ran_off >= nchar)
+			fatal("bad ranlib string offset");
+		ran->ran_off += off;
+		ran++;
+	}
+	return nran;
+}
+
+extern char	*modulname;
+extern long	position;
+
+/*
+ * Process archive with table of contents. The table of contents tells
+ * of symbols in which module they are defined. We scan the table for
+ * symbols that are known but not yet defined. Then we extract all necessary
+ * information from the corresponding module. This module may need symbols that
+ * were defined in modules located before this one in the archive, so we
+ * scan the table again. We perform these actions as long as new symbols
+ * are defined.
+ */
+arch()
+{
+	long	nran;
+	bool	resolved;
+
+	nran = getsymdeftable();
+
+	savemagic();
+	do {
+		register ind_t	ranindex;
+		register long	count;
+
+		debug("(re)scan ranlib table\n", 0, 0, 0, 0);
+		ranindex = (ind_t)0;
+		count = nran;
+		resolved = FALSE;
+		while (count > 0) {
+			register struct ranlib	*ran;
+			register char		*string;
+			register struct outname	*name;
+			register long		pos;
+			extern int		hash();
+			extern struct outname	*searchname();
+
+			ran = (struct ranlib *)address(ALLORANL, ranindex);
+			string = address(ALLORANL, (ind_t)ran->ran_off);
+			name = searchname(string, hash(string));
+			if (name == (struct outname *)0 || !ISUNDEFINED(name)) {
+				ranindex += sizeof(struct ranlib);
+				count--;
+				continue;
+			}
+			seek(ran->ran_pos);
+			get_archive_header(&arhdr);
+			modulname = arhdr.ar_name;
+			debug("%s defines %s\n", modulname, string, 0, 0);
+			position = ran->ran_pos + SZ_ARCH;
+			resolved = TRUE;
+			/*
+			 * This archive member is going to be linked,
+			 * so we don't need to know what else it defines.
+			 * Note that we assume that all ranlib information of
+			 * one archive member is contiguous.
+			 */
+			pos = ran->ran_pos;
+			do {
+				count--; ran++;
+				ranindex += sizeof(struct ranlib);
+			} while (count > 0 && ran->ran_pos == pos);
+			notelib(pos);
+			savehdr(&arhdr);
+			extract();
+		}
+	} while (resolved);
+
+	dealloc(ALLORANL);
+	notelib(ENDLIB);
+}
+
+/*
+ * An archive member that will be loaded is remembered by storing its position
+ * in the archive into the table of positions.
+ */
+notelib(pos)
+	long		pos;
+{
+	register ind_t	off;
+
+	if ((off = hard_alloc(ALLOARCH, (long)sizeof(long))) == BADOFF)
+		fatal("no space for archive position");
+	*(long *)address(ALLOARCH, off) = pos;
+}
+
+/*
+ * Index of position of first archive member of next archive.
+ */
+static ind_t		posindex = (ind_t)0;
+
+/*
+ * Process the archive in pass 2.
+ * We walk through the table of positions telling at what byte offset the
+ * archive header + module is located, until this position is ENDLIB, meaning
+ * that we've processed all needed modules in this archive. Each group of
+ * positions of an archive is terminated with ENDLIB.
+ */
+arch2()
+{
+	register long	*pos;
+	register ind_t	localpos;
+
+	localpos = posindex;
+	for (	pos = (long *)address(ALLOARCH, localpos);
+		*pos != ENDLIB;
+		pos++, localpos += sizeof(long)
+	) {
+		seek(*pos);
+		get_archive_header(&arhdr);
+		modulname = arhdr.ar_name;
+		debug("%s: archive member\n", modulname, 0, 0, 0);
+		position = *pos + SZ_ARCH;
+		finish();
+	}
+	localpos += sizeof(long);	/* Skip ENDLIB. */
+	posindex = localpos;		/* Remember for next call. */
+}

+ 18 - 0
util/led/assert.h

@@ -0,0 +1,18 @@
+/* $Header$ */
+
+#ifndef lint
+#ifdef NASSERT
+
+#define assert(ex)
+
+#else NASSERT
+
+#define assert(ex) \
+{if (!(ex)) fatal("Assertion failed: file %s, line %d", __FILE__, __LINE__);}
+
+#endif NASSERT
+#else lint
+
+#define assert(ex)
+
+#endif lint

+ 90 - 0
util/led/byte_order.c

@@ -0,0 +1,90 @@
+#ifndef lint
+static char rcsid[] = "$Header$";
+#endif lint
+
+#include "const.h"
+#include "assert.h"
+
+bool	bytes_reversed = FALSE;
+bool	words_reversed = FALSE;
+
+/*
+ * Determine the byte/word order in shorts/longs, assuming the size of a short
+ * is 2 chars, and the size of a long is 4 chars. Not all theoretical
+ * possibilities are tested; only bytes reversed and/or words reversed.
+ */
+determine_ordering()
+{
+	short	s;
+	long	l;
+	register char	*cp;
+	register short	*sp;
+
+	cp = (char *)&s;
+	cp[0] = 0x01; cp[1] = 0x02;
+	if (s != 0x01 + (0x02 << 8))
+		bytes_reversed = TRUE;
+	sp = (short *)&l;
+	sp[0] = 0x0001; sp[1] = 0x0002;
+	if (l != 0x0001 + (0x0002 << 16))
+		words_reversed = TRUE;
+}
+
+/*
+ * `Format' is a string of digits indicating how many bytes must be taken
+ * from `buf' to form an integer of some type. E.g. if the digit is '2', two
+ * bytes are taken to form a short.
+ */
+swap(buf, format)
+	register char	*buf;
+	register char	*format;
+{
+	register char	savebyte;
+
+	while (*format) {
+		switch (*format++) {
+		case '1':
+			buf += 1;
+			break;
+		case '2':
+			if (bytes_reversed) {
+				savebyte = buf[0];
+				buf[0] = buf[1];
+				buf[1] = savebyte;
+			}
+			buf += 2;
+			break;
+		case '4':
+			/*
+			 * Written out to save recursive calls.
+			 */
+			if (bytes_reversed && words_reversed) {
+				savebyte = buf[0];
+				buf[0] = buf[3];
+				buf[3] = savebyte;
+				savebyte = buf[1];
+				buf[1] = buf[2];
+				buf[2] = savebyte;
+			} else if (bytes_reversed) {
+				savebyte = buf[0];
+				buf[0] = buf[1];
+				buf[1] = savebyte;
+				savebyte = buf[2];
+				buf[2] = buf[3];
+				buf[3] = savebyte;
+			} else if (words_reversed) {
+				savebyte = buf[0];
+				buf[0] = buf[2];
+				buf[2] = savebyte;
+				savebyte = buf[1];
+				buf[1] = buf[3];
+				buf[3] = savebyte;
+			}
+			buf += 4;
+			break;
+		default:
+			assert(FALSE);
+			break;
+		}
+	}
+}

+ 26 - 0
util/led/const.h

@@ -0,0 +1,26 @@
+/* $Header$ */
+
+typedef int		bool;
+
+#define FALSE		0
+#define TRUE		1
+
+#define S_ZER		0x2000		/* Internal use only.		*/
+
+#define WIDTH		8		/* Number of bits in a byte.	*/
+#define BYTEMASK	0xFF		/* Mask to get low order byte.	*/
+#define MININT		(1 << (sizeof(int) * WIDTH - 1))
+#define MAXCHUNK	(-(MININT + 1))	/* Highest count we write(2).	*/
+
+#define RFLAG		0x01		/* -r flag given.		*/
+#define SFLAG		0x02		/* -s flag given.		*/
+
+#define MAXSECT		64		/* Maximum number of sections.	*/
+
+#define PLAIN		0		/* Input file is a normal file.	*/
+#define ARCHIVE		1		/* Input file is an archive.	*/
+
+#define FIRST		1		/* Pass number.			*/
+#define SECOND		2		/* Idem.			*/
+
+#define BADOFF		((ind_t)-1)

+ 11 - 0
util/led/debug.h

@@ -0,0 +1,11 @@
+/* $Header$ */
+
+#ifdef NDEBUG
+
+#define debug(s, a1, a2, a3, a4)
+
+#else
+
+#define debug(s, a1, a2, a3, a4)	printf(s, a1, a2, a3, a4)
+
+#endif

+ 10 - 0
util/led/defs.h

@@ -0,0 +1,10 @@
+/* $Header$ */
+
+/*
+ * We need the S_EXT because we leave locals alone.
+ */
+#define ISUNDEFINED(n)	(((n)->on_type & (S_TYP | S_EXT)) == (S_UND | S_EXT))
+#define ISABSOLUTE(n)	(((n)->on_type & (S_TYP | S_EXT)) == (S_ABS | S_EXT))
+#define ISCOMMON(n)	(((n)->on_type & (S_COM | S_EXT)) == (S_COM | S_EXT))
+
+#define mustsavelocal(name)	(!((name)->on_type & S_SCT))

+ 182 - 0
util/led/finish.c

@@ -0,0 +1,182 @@
+#ifndef lint
+static char rcsid[] = "$Header$";
+#endif
+
+#include "out.h"
+#include "const.h"
+#include "defs.h"
+#include "memory.h"
+#include "orig.h"
+#include "scan.h"
+
+extern bool	incore;
+extern int	flagword;
+
+/*
+ * We know all there is to know about the current module.
+ * Now we relocate the values in the emitted bytes and write
+ * those to the final output file. Then we compute the relative origins
+ * for the next module.
+ */
+finish()
+{
+	struct outhead	*head;
+	struct outsect	*sects;
+	struct outname	*names;
+	char		*chars;
+
+	get_modul();
+	head = (struct outhead *)modulptr(IND_HEAD);
+	sects = (struct outsect *)modulptr(IND_SECT(*head));
+	names = (struct outname *)modulptr(IND_NAME(*head));
+	chars = (char *)modulptr(IND_CHAR(*head));
+	adjust_names(names, head, chars);
+	handle_relos(head, sects, names);
+	if (!incore && !(flagword & SFLAG)) {
+		put_locals(names, head->oh_nname, sects);
+#ifdef SYMDBUG
+		put_dbug(OFF_DBUG(*head));
+#endif SYMDBUG
+	}
+	compute_origins(sects, head->oh_nsect);
+	skip_modul(head);
+}
+
+/*
+ * Adjust all local names for the move into core.
+ */
+static
+adjust_names(name, head, chars)
+	register struct outname	*name;
+	struct outhead		*head;
+	register char		*chars;
+{
+	register int		cnt;
+	register ind_t		charoff;
+
+	cnt = head->oh_nname;
+	charoff = OFF_CHAR(*head);
+	while (cnt--) {
+		if (name->on_foff != (long)0)
+			name->on_mptr = chars + name->on_foff - charoff;
+		name++;
+	}
+}
+
+/*
+ * If all sections are in core, we can access them randomly, so we need only
+ * scan the relocation table once. Otherwise we must for each section scan
+ * the relocation table again, because the relocation entries of one section
+ * need not be consecutive.
+ */
+static
+handle_relos(head, sects, names)
+	struct outhead		*head;
+	struct outsect		*sects;
+	struct outname		*names;
+{
+	register struct outrelo	*relo;
+	register int		sectindex;
+	register int		nrelo;
+	register char		*emit;
+	extern char		*getemit();
+	extern struct outrelo	*nextrelo();
+
+	if (incore) {
+		nrelo = head->oh_nrelo; sectindex = -1;
+		startrelo(head); relo = nextrelo();
+		while (nrelo--) {
+			if (sectindex != relo->or_sect - S_MIN) {
+				sectindex = relo->or_sect - S_MIN;
+				emit = getemit(head, sects, sectindex);
+			}
+			relocate(head, emit, names, relo, sects);
+			relo++;
+		}
+	} else {
+		for (sectindex = 0; sectindex < head->oh_nsect; sectindex++) {
+			emit = getemit(head, sects, sectindex);
+			nrelo = head->oh_nrelo; startrelo(head);
+			while (nrelo--) {
+				relo = nextrelo();
+				if (relo->or_sect - S_MIN == sectindex) {
+					relocate(head,emit,names,relo,sects);
+					/*
+					 * Write out the (probably changed)
+					 * relocation information.
+					 */
+					if (flagword & RFLAG)
+						wrt_relo(relo);
+				}
+			}
+			wrt_emit(emit, sectindex, sects[sectindex].os_flen);
+			/*
+			 * XXX We should be able to free the emitted bytes.
+			 */
+		}
+	}
+}
+
+/*
+ * Write out the local names that must be saved.
+ */
+static
+put_locals(name, nnames, sects)
+	register struct outname	*name;
+	register ushort		nnames;
+	register struct outsect	*sects;
+{
+	while (nnames--) {
+		if ((name->on_type & S_EXT) == 0 && mustsavelocal(name)) {
+			namerelocate(name, sects);
+			addbase(name);
+			wrt_name(name);
+		}
+		name++;
+	}
+}
+
+/*
+ * Add all flen's and all (size - flen == zero)'s of preceding sections
+ * with the same number.
+ */
+static
+compute_origins(sect, nsect)
+	register struct outsect	*sect;
+	register ushort		nsect;
+{
+	extern struct orig	relorig[];
+	register struct orig	*orig = relorig;
+
+	while (nsect--) {
+		orig->org_flen += sect->os_flen;
+		orig->org_zero += sect->os_size - sect->os_flen;
+		orig++; sect++;
+	}
+}
+#ifdef SYMDBUG
+
+/*
+ * Write out what is after the string area. This is likely to be
+ * debugging information.
+ */
+static
+put_dbug(offdbug)
+	long		offdbug;
+{
+	char		buf[512];
+	register int	nbytes;
+	register long	dbugsize;
+	extern long	objectsize;
+	extern long	position;
+
+	dbugsize = objectsize - offdbug;
+	seek(position + offdbug);
+	while (dbugsize) {
+		nbytes = dbugsize > 512 ? 512 : dbugsize;
+		read_char(buf, (long)nbytes);
+		wrt_dbug(buf, nbytes);
+		dbugsize -= nbytes;
+	}
+}
+#endif SYMDBUG

+ 24 - 0
util/led/mach.c

@@ -0,0 +1,24 @@
+/*
+ * $Header$
+ */
+/*
+ * Values depend on the machine on which this program should run.
+ * Now for Vax 11/750.
+ */
+
+#define K 1024
+
+	mems[ALLOEMIT + 0].mem_left = 64 * K;
+	mems[ALLOEMIT + 1].mem_left = 64 * K;
+	mems[ALLORELO].mem_left = 64 * K;
+	mems[ALLOLOCL].mem_left = 64 * K;
+	mems[ALLOGLOB].mem_left = 64 * K;
+	mems[ALLOLCHR].mem_left = 64 * K;
+	mems[ALLOGCHR].mem_left = 64 * K;
+#ifdef SYMDBUG
+	mems[ALLODBUG].mem_left = 64 * K;
+#endif SYMDBUG
+	mems[ALLOSYMB].mem_left = 4 * K;
+	mems[ALLOARCH].mem_left = 1 * K;
+	mems[ALLOMODL].mem_left = 3 * 64 * K;
+	mems[ALLORANL].mem_left = 4 * K;

+ 66 - 112
util/led/memory.c

@@ -9,7 +9,6 @@ static char rcsid[] = "$Header$";
  * is done and pieces after the one that requested the growth are moved up.
  */
 
-#include <stdio.h>
 #include "out.h"
 #include "const.h"
 #include "assert.h"
@@ -19,7 +18,7 @@ static char rcsid[] = "$Header$";
 struct memory	mems[NMEMS];
 
 bool	incore = TRUE;	/* TRUE while everything can be kept in core. */
-off_t	core_position = (off_t)0;	/* Index of current module. */
+ind_t	core_position = (ind_t)0;	/* Index of current module. */
 
 #define AT_LEAST	2	/* See comment about string areas. */
 
@@ -29,51 +28,18 @@ off_t	core_position = (off_t)0;	/* Index of current module. */
  */
 init_core()
 {
-	FILE			*ledrc;
-	int			piece;
-	off_t			left;
 	register char		*base;
-	register off_t		total_size;
+	register ind_t		total_size;
 	register struct memory	*mem;
 	extern char		*sbrk();
 
-#ifndef TJALK
-	/*
-	 * Read in what should be allocated for each piece initially.
-	 * This facilitates testing, but is slower and should not
-	 * be done in the final version. XXX
-	 */
-	incore = (ledrc = fopen(".ledrc", "r")) != (FILE *)0;
-
-	if (incore) {
-		while (fscanf(ledrc, "%d %d", &piece, &left) == 2)
-			mems[piece].mem_left = left;
-		fclose(ledrc);
-	}
-#else TJALK
-	mems[ALLOHEAD].mem_left = 20;	/*XXX*/
-	mems[ALLOSECT].mem_left = 60;	/*XXX*/
-	mems[ALLOEMIT + 0].mem_left = 65536;
-	mems[ALLOEMIT + 1].mem_left = 65536;
-	mems[ALLORELO].mem_left = 65536;
-	mems[ALLOLOCL].mem_left = 65536;
-	mems[ALLOGLOB].mem_left = 65536;
-	mems[ALLOLCHR].mem_left = 65536;
-	mems[ALLOGCHR].mem_left = 65536;
-#ifdef SYMDBUG
-	mems[ALLODBUG].mem_left = 65536;
-#endif SYMDBUG
-	mems[ALLOSYMB].mem_left = 4096;
-	mems[ALLOARCH].mem_left = 512;
-	mems[ALLOMODL].mem_left = 196608;
-	mems[ALLORANL].mem_left = 4096;
-#endif TJALK
+#include "mach.c"
 
-	total_size = (off_t)0;/* Will accumulate the sizes. */
+	total_size = (ind_t)0;	/* Will accumulate the sizes. */
 	base = sbrk(0);		/* First free. */
 	for (mem = mems; mem < &mems[NMEMS]; mem++) {
 		mem->mem_base = base;
-		mem->mem_full = (off_t)0;
+		mem->mem_full = (ind_t)0;
 		base += mem->mem_left;	/* Each piece will start after prev. */
 		total_size += mem->mem_left;
 	}
@@ -93,12 +59,11 @@ init_core()
 	mems[ALLOLCHR].mem_full = 1;
 	mems[ALLOGCHR].mem_full = 1;
 
-	if ((int)sbrk(total_size) == -1) {
+	if (total_size != (int)total_size || (int)sbrk((int)total_size) == -1) {
 		incore = FALSE;	/* In core strategy failed. */
 		if ((int)sbrk(AT_LEAST) == -1)
 			fatal("no core at all");
 	}
-
 }
 
 /*
@@ -109,13 +74,13 @@ init_core()
 static bool
 move_up(piece, incr)
 	register int		piece;
-	register off_t		incr;
+	register ind_t		incr;
 {
 	register struct memory	*mem;
 	extern char		*sbrk();
 
 	debug("move_up(%d, %d)\n", piece, (int)incr, 0, 0);
-	if ((int)sbrk(incr) == -1)
+	if (incr != (int)incr || (int)sbrk((int)incr) == -1)
 		return FALSE;
 
 	for (mem = &mems[NMEMS - 1]; mem > &mems[piece]; mem--)
@@ -137,33 +102,33 @@ extern int	passnumber;
 static bool
 compact(piece, incr)
 	register int		piece;
-	register off_t		incr;
+	register ind_t		incr;
 {
-	register off_t		gain;
+	register ind_t		gain;
 	register struct memory	*mem;
 
 	debug("compact(%d, %d)\n", piece, (int)incr, 0, 0);
 	gain = mems[0].mem_left;
-	mems[0].mem_left = (off_t)0;
+	mems[0].mem_left = (ind_t)0;
 	for (mem = &mems[1]; mem <= &mems[piece]; mem++) {
 		/* Here memory is inserted before a piece. */
-		assert(passnumber == FIRST || gain == (off_t)0);
+		assert(passnumber == FIRST || gain == (ind_t)0);
 		copy_down(mem, gain);
 		gain += mem->mem_left;
-		mem->mem_left = (off_t)0;
+		mem->mem_left = (ind_t)0;
 	}
 	/*
 	 * Note that we already added the left bytes of the piece we want to
 	 * enlarge to `gain'.
 	 */
 	if (gain < incr) {
-		register off_t	up = (off_t)0;
+		register ind_t	up = (ind_t)0;
 
 		for (mem = &mems[NMEMS - 1]; mem > &mems[piece]; mem--) {
 			/* Here memory is appended after a piece. */
 			up += mem->mem_left;
 			copy_up(mem, up);
-			mem->mem_left = (off_t)0;
+			mem->mem_left = (ind_t)0;
 		}
 		gain += up;
 	}
@@ -180,11 +145,11 @@ compact(piece, incr)
 static
 copy_down(mem, dist)
 	register struct memory	*mem;
-	off_t			dist;
+	ind_t			dist;
 {
 	register char		*old;
 	register char		*new;
-	register off_t		size;
+	register ind_t		size;
 
 	size = mem->mem_full;
 	old = mem->mem_base;
@@ -203,11 +168,11 @@ copy_down(mem, dist)
 static
 copy_up(mem, dist)
 	register struct memory	*mem;
-	off_t			dist;
+	ind_t			dist;
 {
 	register char		*old;
 	register char		*new;
-	register off_t		size;
+	register ind_t		size;
 
 	size = mem->mem_full;
 	old = mem->mem_base + size;
@@ -224,18 +189,20 @@ copy_up(mem, dist)
  * how many times the area is moved, because of another allocate, this offset
  * remains valid.
  */
-off_t
+ind_t
 alloc(piece, size)
 	register int		piece;
-	register off_t		size;
+	register long		size;
 {
-	register off_t		incr = 0;
-	register off_t		left = mems[piece].mem_left;
-	register off_t		full = mems[piece].mem_full;
+	register ind_t		incr = 0;
+	register ind_t		left = mems[piece].mem_left;
+	register ind_t		full = mems[piece].mem_full;
 
 	assert(passnumber == FIRST || (!incore && piece == ALLOMODL));
-	if (size == (off_t)0)
+	if (size == (long)0)
 		return full;
+	if (size != (ind_t)size)
+		return BADOFF;
 
 	while (left + incr < size)
 		incr += INCRSIZE;
@@ -254,14 +221,16 @@ alloc(piece, size)
  * Same as alloc() but for a piece which really needs it. If the first
  * attempt fails, release the space occupied by other pieces and try again.
  */
-off_t
+ind_t
 hard_alloc(piece, size)
-	int		piece;
-	off_t		size;
+	register int	piece;
+	register long	size;
 {
-	off_t		ret;
+	register ind_t	ret;
 	register int	i;
 
+	if (size != (ind_t)size)
+		return BADOFF;
 	if ((ret = alloc(piece, size)) != BADOFF)
 		return ret;
 
@@ -270,8 +239,6 @@ hard_alloc(piece, size)
 	 */
 	for (i = 0; i < NMEMS; i++) {
 		switch (i) {
-		case ALLOHEAD:
-		case ALLOSECT:
 		case ALLOGLOB:
 		case ALLOGCHR:
 		case ALLOSYMB:
@@ -296,7 +263,7 @@ hard_alloc(piece, size)
 static
 free_saved_moduls()
 {
-	register off_t		size;
+	register ind_t		size;
 	register char		*old, *new;
 	register struct memory	*mem = &mems[ALLOMODL];
 
@@ -307,7 +274,7 @@ free_saved_moduls()
 		*new++ = *old++;
 	mem->mem_full -= core_position;
 	mem->mem_left += core_position;
-	core_position = (off_t)0;
+	core_position = (ind_t)0;
 }
 
 /*
@@ -320,22 +287,20 @@ dealloc(piece)
 	/*
 	 * Some pieces need their memory throughout the program.
 	 */
-	assert(piece != ALLOHEAD);
-	assert(piece != ALLOSECT);
 	assert(piece != ALLOGLOB);
 	assert(piece != ALLOGCHR);
 	assert(piece != ALLOSYMB);
 	assert(piece != ALLOARCH);
 	mems[piece].mem_left += mems[piece].mem_full;
-	mems[piece].mem_full = (off_t)0;
+	mems[piece].mem_full = (ind_t)0;
 }
 
 char *
 core_alloc(piece, size)
 	register int	piece;
-	register off_t	size;
+	register long	size;
 {
-	register off_t	off;
+	register ind_t	off;
 
 	if ((off = alloc(piece, size)) == BADOFF)
 		return (char *)0;
@@ -350,15 +315,13 @@ freeze_core()
 {
 	register int	i;
 
-	core_position = (off_t)0;
+	core_position = (ind_t)0;
 
 	if (incore)
 		return;
 
 	for (i = 0; i < NMEMS; i++) {
 		switch (i) {
-		case ALLOHEAD:
-		case ALLOSECT:
 		case ALLOGLOB:
 		case ALLOGCHR:
 		case ALLOSYMB:
@@ -369,7 +332,7 @@ freeze_core()
 			break;
 		}
 	}
-	compact(NMEMS - 1, (off_t)0);
+	compact(NMEMS - 1, (ind_t)0);
 }
 
 /* ------------------------------------------------------------------------- */
@@ -383,24 +346,24 @@ extern bool	words_reversed;
  */
 write_bytes()
 {
-	register struct outhead	*head;
-	ushort		nsect, nrelo;
-	long		offchar;
-	int		fd;
-	register int	piece;
-	extern ushort	NLocals, NGlobals;
-	extern long	NLChars, NGChars;
-	extern int	flagword;
-	extern char	*outputname;
+	ushort			nsect, nrelo;
+	long			offchar;
+	int			fd;
+	register struct memory	*mem;
+	extern ushort		NLocals, NGlobals;
+	extern long		NLChars, NGChars;
+	extern int		flagword;
+	extern struct outhead	outhead;
+	extern struct outsect	outsect[];
+	extern char		*outputname;
 
-	head = (struct outhead *)mems[ALLOHEAD].mem_base;
-	nsect = head->oh_nsect;
-	nrelo = head->oh_nrelo;
-	offchar = OFF_CHAR(*head);
+	nsect = outhead.oh_nsect;
+	nrelo = outhead.oh_nrelo;
+	offchar = OFF_CHAR(outhead);
 
 	if (bytes_reversed || words_reversed) {
-		headswap();
-		sectswap(nsect);
+		swap((char *)&outhead, SF_HEAD);
+		sectswap(outsect, nsect);
 		reloswap(nrelo);
 	}
 	/*
@@ -423,8 +386,10 @@ write_bytes()
 	/*
 	 * These pieces must always be written.
 	 */
-	for (piece = ALLOHEAD; piece < ALLORELO; piece++)
-		writelong(fd, mems[piece].mem_base, mems[piece].mem_full);
+	writelong(fd, (char *)&outhead, (ind_t)SZ_HEAD);
+	writelong(fd, (char *)outsect, (ind_t)nsect * SZ_SECT);
+	for (mem = &mems[ALLOEMIT]; mem < &mems[ALLORELO]; mem++)
+		writelong(fd, mem->mem_base, mem->mem_full);
 	/*
 	 * The rest depends on the flags.
 	 */
@@ -433,10 +398,10 @@ write_bytes()
 	if (!(flagword & SFLAG)) {
 		writelong(fd, mems[ALLOLOCL].mem_base, mems[ALLOLOCL].mem_full);
 		writelong(fd, mems[ALLOGLOB].mem_base, mems[ALLOGLOB].mem_full);
-		writelong(fd, mems[ALLOLCHR].mem_base + 1, NLChars);
-		writelong(fd, mems[ALLOGCHR].mem_base + 1, NGChars);
+		writelong(fd, mems[ALLOLCHR].mem_base + 1, (ind_t)NLChars);
+		writelong(fd, mems[ALLOGCHR].mem_base + 1, (ind_t)NGChars);
 #ifdef SYMDBUG
-		writelong(fd, mems[ALLODBUG].mem_base, mems[ALLODBUG].mem_size);
+		writelong(fd, mems[ALLODBUG].mem_base, mems[ALLODBUG].mem_full);
 #endif SYMDBUG
 	}
 	close(fd);
@@ -446,12 +411,12 @@ static
 writelong(fd, base, size)
 	register int	fd;
 	register char	*base;
-	register off_t	size;
+	register ind_t	size;
 {
 	register int	chunk;
 
 	while (size) {
-		chunk = size > (off_t)MAXCHUNK ? MAXCHUNK : size;
+		chunk = size > (ind_t)MAXCHUNK ? MAXCHUNK : size;
 		write(fd, base, chunk);
 		size -= chunk;
 		base += chunk;
@@ -459,21 +424,10 @@ writelong(fd, base, size)
 }
 
 static
-headswap()
-{
-	register struct outhead	*head;
-
-	head = (struct outhead *)mems[ALLOHEAD].mem_base;
-	swap((char *)head, SF_HEAD);
-}
-
-static
-sectswap(nsect)
+sectswap(sect, nsect)
+	register struct outsect	*sect;
 	register ushort		nsect;
 {
-	register struct outsect	*sect;
-
-	sect = (struct outsect *)mems[ALLOSECT].mem_base;
 	while (nsect--)
 		swap((char *)sect++, SF_SECT);
 }

+ 35 - 0
util/led/memory.h

@@ -0,0 +1,35 @@
+/* $Header$ */
+
+#define ALLOEMIT	0			/* Section contents. */
+#define ALLORELO	(ALLOEMIT + MAXSECT)	/* Relocation table. */
+#define ALLOLOCL	(ALLORELO + 1)		/* Saved local names. */
+#define ALLOGLOB	(ALLOLOCL + 1)		/* Saved global names. */
+#define ALLOLCHR	(ALLOGLOB + 1)		/* Strings of local names. */
+#define ALLOGCHR	(ALLOLCHR + 1)		/* Strings of global names. */
+#ifdef SYMDEBUG
+#define ALLODBUG	(ALLOGCHR + 1)		/* Symbolic debugging info. */
+#else SYMDEBUG
+#define ALLODBUG	ALLOGCHR
+#endif SYMDEBUG
+#define ALLOSYMB	(ALLODBUG + 1)		/* Symbol table. */
+#define ALLOARCH	(ALLOSYMB + 1)		/* Archive positions. */
+#define ALLOMODL	(ALLOARCH + 1)		/* Modules. */
+#define ALLORANL	(ALLOMODL + 1)		/* Ranlib information. */
+#define NMEMS		(ALLORANL + 1)
+
+#define INCRSIZE	1024
+
+typedef unsigned int	ind_t;
+#define BADOFF		((ind_t)-1)
+
+struct memory {
+	char	*mem_base;
+	ind_t	mem_full;
+	ind_t	mem_left;
+};
+extern struct memory	mems[];
+
+#define address(piece,offset)	(mems[(piece)].mem_base+(offset))
+#define modulptr(offset)	(mems[ALLOMODL].mem_base+core_position+(offset))
+
+extern ind_t		core_position;

+ 6 - 0
util/led/orig.h

@@ -0,0 +1,6 @@
+/* $Header$ */
+
+struct orig {
+	long	org_flen;	/* Accumulated length of preceding sections. */
+	long	org_zero;	/* 	"	  "	     "	  zeroparts. */
+};

+ 134 - 0
util/led/read.c

@@ -0,0 +1,134 @@
+#ifndef lint
+static char rcsid[] = "$Header$";
+#endif
+
+/*
+ * Routines to read in the various parts of the object file.
+ */
+
+#include "arch.h"
+#include "out.h"
+#include "ranlib.h"
+#include "const.h"
+#include "assert.h"
+
+int	infile;	/* The current input file. */
+
+extern bool	bytes_reversed;
+extern bool	words_reversed;
+
+ushort
+getushort()
+{
+	ushort	ubuf;
+
+	if (read(infile, (char *)&ubuf, 2) != 2)
+		fatal("premature EOF");
+	if (bytes_reversed)
+		swap((char *)&ubuf, "2");
+	return ubuf;
+}
+
+long
+getlong()
+{
+	long	lbuf;
+
+	if (read(infile, (char *)&lbuf, 4) != 4)
+		fatal("premature EOF");
+	if (bytes_reversed || words_reversed)
+		swap((char *)&lbuf, "4");
+	return lbuf;
+}
+
+read_head(head)
+	register struct outhead	*head;
+{
+	if (read(infile, (char *)head, SZ_HEAD) != SZ_HEAD)
+		fatal("premature EOF");
+	if (bytes_reversed || words_reversed)
+		swap((char *)head, SF_HEAD);
+	if (BADMAGIC(*head))
+		fatal("bad magic number");
+}
+
+/*
+ * Someone inadvertently misaligned a long, thereby creating a hole.
+ * Therefore we can't read the header in one chunk.
+ */
+read_arhdr(arhdr)
+	register struct ar_hdr	*arhdr;
+{
+	if (read(infile, (char *)arhdr, 14) != 14)
+		fatal("premature EOF");
+	if (read(infile, (char *)&arhdr->ar_date, SZ_ARCH - 14) != SZ_ARCH - 14)
+		fatal("premature EOF");
+	if (bytes_reversed || words_reversed)
+		swap((char *)&arhdr->ar_date, SF_ARCH);
+}
+
+read_table(ran, cnt)
+	register struct ranlib	*ran;
+	register long		cnt;
+{
+	read_char((char *)ran, cnt * SZ_RAN);
+	if (bytes_reversed || words_reversed)
+		while (cnt--)
+			swap((char *)ran++, SF_RAN);
+}
+
+read_sect(sect, cnt)
+	register struct outsect	*sect;
+	register ushort		cnt;
+{
+	if (read(infile, (char *)sect, cnt * SZ_SECT) != cnt * SZ_SECT)
+		fatal("premature EOF");
+	if (bytes_reversed || words_reversed)
+		while (cnt--)
+			swap((char *)sect++, SF_SECT);
+}
+
+read_emit(emit, cnt)
+	register char		*emit;
+	register long		cnt;
+{
+	read_char(emit, cnt);
+}
+
+read_relo(relo, cnt)
+	register struct outrelo	*relo;
+	register ushort		cnt;
+{
+	read_char((char *)relo, (long)cnt * SZ_RELO);
+	if (bytes_reversed || words_reversed)
+		while (cnt--)
+			swap((char *)relo++, SF_RELO);
+}
+
+read_name(name, cnt)
+	register struct outname	*name;
+	register ushort		cnt;
+{
+	read_char((char *)name, (long)cnt * SZ_NAME);
+	if (bytes_reversed || words_reversed)
+		while (cnt--)
+			swap((char *)name++, SF_NAME);
+}
+
+/*
+ * We don't have to worry about byte order here.
+ */
+read_char(string, cnt)
+	register char	*string;
+	register long	cnt;
+{
+	register int	n;
+
+	while (cnt) {
+		n = cnt >= MAXCHUNK ? MAXCHUNK : cnt;
+		if (read(infile, string, n) != n)
+			fatal("premature EOF");
+		string += n;
+		cnt -= n;
+	}
+}

+ 256 - 0
util/led/relocate.c

@@ -0,0 +1,256 @@
+#ifndef lint
+static char rcsid[] = "$Header$";
+#endif
+
+#include "out.h"
+#include "const.h"
+#include "debug.h"
+#include "defs.h"
+#include "orig.h"
+
+#define UBYTE(x)	((x) & BYTEMASK)
+
+/*
+ * The bits in type indicate how many bytes the value occupies and what
+ * significance should be attributed to each byte.
+ */
+static long
+getvalu(addr, type)
+	char	addr[];
+	char	type;
+{
+	ushort	word0, word1;
+
+	switch (type & RELSZ) {
+	case RELO1:
+		return UBYTE(addr[0]);
+	case RELO2:
+		if (type & RELBR)
+			return (UBYTE(addr[0]) << WIDTH) + UBYTE(addr[1]);
+		else
+			return (UBYTE(addr[1]) << WIDTH) + UBYTE(addr[0]);
+	case RELO4:
+		if (type & RELBR) {
+			word0 = (UBYTE(addr[0]) << WIDTH) + UBYTE(addr[1]);
+			word1 = (UBYTE(addr[2]) << WIDTH) + UBYTE(addr[3]);
+		} else {
+			word0 = (UBYTE(addr[1]) << WIDTH) + UBYTE(addr[0]);
+			word1 = (UBYTE(addr[3]) << WIDTH) + UBYTE(addr[2]);
+		}
+		if (type & RELWR)
+			return ((long)word0 << (2 * WIDTH)) + word1;
+		else
+			return ((long)word1 << (2 * WIDTH)) + word0;
+	default:
+		fatal("bad relocation size");
+	}
+	/* NOTREACHED */
+}
+
+/*
+ * The bits in type indicate how many bytes the value occupies and what
+ * significance should be attributed to each byte.
+ * We do not check for overflow.
+ */
+static
+putvalu(valu, addr, type)
+	long	valu;
+	char	addr[];
+	char	type;
+{
+	ushort	word0, word1;
+
+	switch (type & RELSZ) {
+	case RELO1:
+		addr[0] = valu;
+		break;
+	case RELO2:
+		if (type & RELBR) {
+			addr[0] = valu >> WIDTH;
+			addr[1] = valu;
+		} else {
+			addr[0] = valu;
+			addr[1] = valu >> WIDTH;
+		}
+		break;
+	case RELO4:
+		if (type & RELWR) {
+			word0 = valu >> (2 * WIDTH);
+			word1 = valu;
+		} else {
+			word0 = valu;
+			word1 = valu >> (2 * WIDTH);
+		}
+		if (type & RELBR) {
+			addr[0] = word0 >> WIDTH;
+			addr[1] = word0;
+			addr[2] = word1 >> WIDTH;
+			addr[3] = word1;
+		} else {
+			addr[0] = word0;
+			addr[1] = word0 >> WIDTH;
+			addr[2] = word1;
+			addr[3] = word1 >> WIDTH;
+		}
+		break;
+	default:
+		fatal("bad relocation size");
+	}
+}
+
+/*
+ * Returns whether `valu' refers to the zero part of its section.
+ * The address of its zero part (relative to the beginning of the section)
+ * is in `zero_addr'. If `valu' is used in a pc-relative address computation,
+ * we have to do that computation ourselves. A pc-relative address is the
+ * difference between the address of the byte after the value and the "real"
+ * address:
+ * referencing address + its size + pc-relative address == "real" address.
+ */
+static bool
+refers_zero(valu, relo, zero_addr)
+	register long	valu;
+	struct outrelo	*relo;
+	long		zero_addr;
+{
+	if (relo->or_type & RELPC) {
+		valu += relo->or_addr;
+		/*
+		 * Below is a dirty switch-statement. But an even dirtier
+		 * statement would be: valu += (relo->or_type & RELSZ),
+		 * because in that case you would have to know the values
+		 * of the RELO[124] symbols.
+		 */
+		switch (relo->or_type & RELSZ) {
+		case RELO4:	valu += 1;
+				valu += 1;
+		case RELO2:	valu += 1;
+		case RELO1:	valu += 1;
+		}
+	}
+	return valu >= zero_addr;
+}
+
+extern ushort		NLocals, NGlobals;
+extern struct outsect	outsect[];
+extern struct orig	relorig[];
+
+/*
+ * There are two cases: `local' is an undefined external or common name,
+ * or `local' is a section name.
+ * First case: if the name has been defined in another module,
+ * its value is known and can be added. Or_nami will be the
+ * index of the name of the section in which this name was
+ * defined. Otherwise we must change or_nami to the index of
+ * this name in the name table of the output file and leave
+ * its value unchanged.
+ * Second case: we must update the value by the change
+ * in position of the section of local.
+ */
+static ushort
+addrelo(relo, names, sects, valu_out)
+	struct outrelo		*relo;
+	struct outname		*names;
+	struct outsect		*sects;
+	long			*valu_out;	/* Out variable. */
+{
+	register struct outname	*local = &names[relo->or_nami];
+	register ushort		index = NLocals;
+	register long		valu = *valu_out;
+
+	if (ISUNDEFINED(local) || ISCOMMON(local)) {
+		register struct outname	*name;
+		extern int		hash();
+		extern struct outname	*searchname();
+		extern ushort		indexof();
+
+		name = searchname(local->on_mptr, hash(local->on_mptr));
+		if (name == (struct outname *)0)
+			fatal("name %s not found in pass 2", local->on_mptr);
+		if (ISCOMMON(name) || ISUNDEFINED(name)) {
+			debug("can't relocate from %s\n",local->on_mptr,0,0,0);
+			index += indexof(name);
+		} else {
+			valu += name->on_valu;
+			index += NGlobals + (name->on_type & S_TYP) - S_MIN;
+		}
+	} else {
+		register int	sectindex = (local->on_type & S_TYP) - S_MIN;
+
+		if (!(local->on_type & S_SCT))
+			fatal("bad relocation index");
+		if (refers_zero(valu, relo, sects[sectindex].os_flen)) {
+			valu -= sects[sectindex].os_flen;
+			valu += outsect[sectindex].os_flen;
+			valu += relorig[sectindex].org_zero;
+		} else {
+			valu += relorig[sectindex].org_flen;
+		}
+		valu += outsect[sectindex].os_base;
+		index += NGlobals + sectindex;
+	}
+	*valu_out = valu;
+	return index;
+}
+
+/*
+ * This routine relocates a value in a section pointed to by `emit', of
+ * which the header is pointed to by `head'. Relocation is relative to the
+ * names in `names'; `relo' tells how to relocate.
+ */
+relocate(head, emit, names, relo, sects)
+	struct outhead	*head;
+	char		*emit;
+	struct outname	names[];
+	struct outrelo	*relo;
+	struct outsect	*sects;
+{
+	long		valu;
+	int		sectindex = relo->or_sect - S_MIN;
+	extern struct outhead	outhead;
+
+	/*
+	 * Pick up previous value at location to be relocated.
+	 */
+	valu = getvalu(emit + relo->or_addr, relo->or_type);
+	/*
+	 * Or_nami is an index in the name table of the considered module.
+	 * The name of which it is an index can be:
+	 *	- an undefined external or a common name
+	 *	- a section name
+	 *	- the first name outside! the name table (argh)
+	 */
+	if (relo->or_nami < head->oh_nname) {
+		/* First two cases. */
+		relo->or_nami = addrelo(relo, names, sects, &valu);
+	} else {
+		/*
+		 * Third case: it is absolute. The relocation of absolute
+		 * names is always 0. We only need to change the index.
+		 */
+		relo->or_nami = NLocals + NGlobals + outhead.oh_nsect;
+	}
+
+	/*
+	 * If relocation is pc-relative, we had to update the value by
+	 * the change in distance between the referencING and referencED
+	 * section. We already added the origin of the referencED section;
+	 * now we subtract the origin of the referencING section.
+	 * Note that the the value to be relocated cannot lie within the
+	 * zero part.
+	 */
+	if (relo->or_type & RELPC)
+		valu -=	relorig[sectindex].org_flen+outsect[sectindex].os_base;
+
+	/*
+	 * Now put the value back.
+	 */
+	putvalu(valu, emit + relo->or_addr, relo->or_type);
+
+	/*
+	 * We must change the offset within the section of the value to be
+	 * relocated to its offset in the new section. `Or_addr' must again be
+	 * in the normal part, of course.
+	 */
+	relo->or_addr += relorig[sectindex].org_flen;
+}

+ 104 - 0
util/led/save.c

@@ -0,0 +1,104 @@
+#ifndef lint
+static char rcsid[] = "$Header$";
+#endif
+
+/*
+ * If everything is kept in core, we must save some things for the second pass.
+ */
+
+#include "arch.h"
+#include "out.h"
+#include "const.h"
+#include "assert.h"
+#include "memory.h"
+
+extern bool	incore;
+extern char	*core_alloc();
+
+savemagic()
+{
+	register char	*p;
+
+	if (!incore)
+		return;
+
+	if ((p = core_alloc(ALLOMODL, (long)sizeof(ushort))) != (char *)0) {
+		*(ushort *)p = ARMAG;
+		core_position += sizeof(ushort);
+	}
+}
+
+savehdr(hdr)
+	struct ar_hdr	*hdr;
+{
+	register char	*p;
+
+	if (!incore)
+		return;
+
+	if ((p=core_alloc(ALLOMODL,(long)sizeof(struct ar_hdr)))!=(char *)0) {
+		*(struct ar_hdr *)p = *hdr;
+		core_position += sizeof(struct ar_hdr);
+	}
+}
+
+long	NLChars = 0;	/* Size of string area for local names. */
+long	NGChars = 0;	/* Idem for global names. */
+
+/*
+ * Put the string in cp into the block allocated for the string area.
+ * Return its offset in this area. We don't use the first char of the string
+ * area, so that empty strings can be distinguished from the first string.
+ */
+ind_t
+savechar(piece, off)
+	register int	piece;
+	register ind_t	off;
+{
+	register long	len;
+	register ind_t	newoff;
+	extern int	strlen();
+	extern ind_t	alloc();
+	extern ind_t	hard_alloc();
+	extern char	*strcpy();
+
+	if (off == (ind_t)0)
+		return 0;
+
+	len = strlen(modulptr(off)) + 1;
+	if (piece == ALLOLCHR) {
+		NLChars += len;
+		if (!incore || (newoff = alloc(piece, len)) == BADOFF)
+			return BADOFF;
+	} else {
+		assert(piece == ALLOGCHR);
+		NGChars += len;
+		if ((newoff = hard_alloc(piece, len)) == BADOFF)
+			return BADOFF;
+	}
+	strcpy(address(piece, newoff), modulptr(off));
+	return newoff;
+}
+
+/*
+ * Put the local in `name' in the piece allocated for local names that must
+ * be saved. `Name' points to a private copy, so will not become invalid after
+ * allocation, but the string of which name->on_foff is the offset may be
+ * destroyed, so we save that first.
+ */
+savelocal(name)
+	struct outname	*name;
+{
+	ind_t		savindex;
+	struct outname	*new;
+
+	if ((savindex = savechar(ALLOLCHR, (ind_t)name->on_foff)) == BADOFF)
+		return;
+
+	new = (struct outname *)
+			core_alloc(ALLOLOCL, (long)sizeof(struct outname));
+	if (new != (struct outname *)0) {
+		*new = *name;
+		new->on_foff = savindex;
+	}
+}

+ 524 - 0
util/led/scan.c

@@ -0,0 +1,524 @@
+#ifndef lint
+static char rcsid[] = "$Header$";
+#endif
+
+#ifdef SYMDBUG
+#include <sys/types.h>
+#include <sys/stat.h>
+#endif SYMDBUG
+#include "arch.h"
+#include "out.h"
+#include "ranlib.h"
+#include "const.h"
+#include "assert.h"
+#include "memory.h"
+#include "scan.h"
+
+#define READ	0
+
+#define IND_EMIT(x)	(IND_CHAR(x) + (ind_t)align((x).oh_nchar))
+#define IND_RELO(x)	(IND_EMIT(x) + (x).oh_nsect * sizeof(ind_t))
+#ifdef SYMDBUG
+#define IND_DBUG(x)	(IND_RELO(x) + sizeof(ind_t))
+#endif SYMDBUG
+
+extern long	lseek();
+extern bool	incore;
+extern int	infile;
+extern int	passnumber;
+
+char		*archname;	/* Name of archive, if reading from archive. */
+char		*modulname;	/* Name of object module. */
+long		position;	/* Byte offset within cuurent input file. */
+#ifdef SYMDBUG
+long		objectsize;
+#endif SYMDBUG
+
+static long	align();
+static char	*modulbase;
+static long	modulsize();
+
+/*
+ * Open the file with name `filename' (if necessary) and examine the first
+ * few bytes to see if it's a plain file or an archive.
+ * In case of a plain file, the file pointer is repositioned after the
+ * examination. Otherwise it is at the beginning of the table of contents.
+ */
+int
+getfile(filename)
+	char		*filename;
+{
+	struct ar_hdr	archive_header;
+	ushort		magic_number;
+#ifdef SYMDBUG
+	struct stat	statbuf;
+	extern int	fstat();
+#endif SYMDBUG
+	extern ushort	getushort();
+
+	archname = (char *)0;
+	modulname = (char *)0;
+
+	if (passnumber == FIRST || !incore) {
+		if ((infile = open(filename, READ)) < 0)
+			fatal("can't read %s", filename);
+		magic_number = getushort();
+	} else {
+		modulbase = modulptr((ind_t)0);
+		magic_number = *(ushort *)modulbase;
+	}
+
+	switch (magic_number) {
+	case O_MAGIC:
+#ifdef SYMDBUG
+		if (passnumber == FIRST || !incore) {
+			if (fstat(infile, &statbuf) < 0)
+				fatal("cannot stat");
+			objectsize = statbuf.st_size;
+		}
+#endif SYMDBUG
+		position = (long)0;
+		seek((long)0);
+		modulname = filename;
+		return PLAIN;
+	case ARMAG:
+		archname = filename;
+		if (passnumber == FIRST) {
+			read_arhdr(&archive_header);
+			if (strcmp(archive_header.ar_name, SYMDEF))
+				fatal("no table of contents");
+		} else if (incore) {
+			modulbase += sizeof(ushort);
+			core_position += sizeof(ushort);
+		}
+		return ARCHIVE;
+	default:
+		fatal("wrong magic number");
+	}
+	/* NOTREACHED */
+}
+
+/* ARGSUSED */
+closefile(filename)
+	char	*filename;
+{
+	if (passnumber == FIRST || !incore)
+		close(infile);
+}
+
+get_archive_header(archive_header)
+	register struct ar_hdr	*archive_header;
+{
+	if (passnumber == FIRST || !incore) {
+		read_arhdr(archive_header);
+	} else {
+		/* Copy structs. */
+		*archive_header = *(struct ar_hdr *)modulbase;
+		modulbase += sizeof(struct ar_hdr);
+		core_position += sizeof(struct ar_hdr);
+	}
+#ifdef SYMDBUG
+	objectsize = archive_header.ar_size;
+#endif SYMDBUG
+}
+
+get_modul()
+{
+	if (passnumber == FIRST) {
+		scan_modul();
+	} else if (!incore) {
+		read_modul();
+	}
+}
+
+/*
+ * Read module from the current file. If it doesn't fit into core, the strategy
+ * to keep everything in core is abandoned, but we will always put the header,
+ * the section table, and the name and string table into core.
+ */
+static
+scan_modul()
+{
+	bool		space;
+	struct outhead	*head;
+	struct outsect	*sect;
+
+	space = all_alloc();
+	head = (struct outhead *)modulptr(IND_HEAD);
+	if (space) {
+		sect = (struct outsect *)modulptr(IND_SECT(*head));
+		get_indirect(head, sect);
+	} else {
+		lseek(infile, OFF_NAME(*head) - OFF_EMIT(*head), 1);
+	}
+	read_name((struct outname *)modulptr(IND_NAME(*head)), head->oh_nname);
+	read_char((char *)modulptr(IND_CHAR(*head)), head->oh_nchar);
+#ifdef SYMDBUG
+	if (space) {
+		get_dbug(*(ind_t *)modulptr(IND_DBUG(*head)),
+			 ojectsize - OFF_DBUG(*head)
+		);
+	}
+#endif SYMDBUG
+}
+
+/*
+ * Allocate space for and read in the header and section table.
+ * First get the header. With this we can determine what to allocate
+ * for the rest of the module, and with the rest we can determine what
+ * to allocate for the section contents.
+ * If possible, allocate space for the rest of the module. Return whether
+ * this was possible.
+ */
+static bool
+all_alloc()
+{
+	struct outhead	head;
+	extern ind_t	hard_alloc();
+
+	if (hard_alloc(ALLOMODL, (long)sizeof(struct outhead)) == BADOFF)
+		fatal("no space for module header");
+	read_head((struct outhead *)modulptr(IND_HEAD));
+	/*
+	 * Copy the header because we need it so often.
+	 */
+	head = *(struct outhead *)modulptr(IND_HEAD);
+	return direct_alloc(&head) && indirect_alloc(&head);
+}
+
+/*
+ * Allocate space for the rest of the direct bytes.
+ * First allocate the section table and read it in, then allocate the rest
+ * and return whether this succeeded.
+ */
+static bool
+direct_alloc(head)
+	struct outhead	*head;
+{
+	ind_t		sectindex = IND_SECT(*head);
+	ushort		nsect = head->oh_nsect;
+	long		size, rest;
+	extern ind_t	hard_alloc();
+	extern ind_t	alloc();
+
+#ifdef SYMDBUG
+	rest = nsect * sizeof(ind_t) + sizeof(ind_t) + sizeof(ind_t);
+#else SYMDBUG
+	rest = nsect * sizeof(ind_t) + sizeof(ind_t);
+#endif SYMDBUG
+	/*
+	 * We already allocated space for the header, we now need
+	 * the section, name an string table.
+	 */
+	size = modulsize(head) - sizeof(struct outhead) - rest;
+	if (hard_alloc(ALLOMODL, size) == BADOFF)
+		fatal("no space for module");
+	read_sect((struct outsect *)modulptr(sectindex), nsect);
+
+	return incore && alloc(ALLOMODL, rest) != BADOFF;
+}
+
+/*
+ * Allocate space for the indirectly accessed pieces: the section contents and
+ * the relocation table, and put their indices in the right place.
+ */
+static bool
+indirect_alloc(head)
+	struct outhead	*head;
+{
+	register int	allopiece;
+	ushort		nsect = head->oh_nsect;
+	ushort		nrelo = head->oh_nrelo;
+	ind_t		sectindex = IND_SECT(*head);
+	ind_t		emitoff = IND_EMIT(*head);
+	ind_t		relooff = IND_RELO(*head);
+#ifdef SYMDBUG
+	ind_t		dbugoff = IND_DBUG(*head);
+	extern long	objectsize;
+	long		dbugsize = objectsize - OFF_DBUG(*head);
+#endif SYMDBUG
+
+	assert(incore);
+	for (allopiece = ALLOEMIT; allopiece < ALLOEMIT + nsect; allopiece++) {
+		if (!putemitindex(sectindex, emitoff, allopiece))
+			return FALSE;
+		sectindex += sizeof(struct outsect);
+		emitoff += sizeof(ind_t);
+	}
+#ifdef SYMDBUG
+	return	putreloindex(relooff, (long)nrelo * sizeof(struct outrelo))
+		&&
+		putdbugindex(dbugoff, dbugsize);
+#else SYMDBUG
+	return putreloindex(relooff, (long)nrelo * sizeof(struct outrelo));
+#endif SYMDBUG
+}
+
+/*
+ * Allocate space for the contents of the section of which the table entry is
+ * at offset `sectindex'. Put the offset of the allocated piece at offset
+ * `emitoff'.
+ */
+static bool
+putemitindex(sectindex, emitoff, allopiece)
+	ind_t		sectindex;
+	ind_t		emitoff;
+	int		allopiece;
+{
+	long		flen;
+	ind_t		emitindex;
+	extern ind_t	alloc();
+
+	flen = ((struct outsect *)modulptr(sectindex))->os_flen;
+	if ((emitindex = alloc(allopiece, flen)) != BADOFF) {
+		*(ind_t *)modulptr(emitoff) = emitindex;
+		return TRUE;
+	}
+	return FALSE;
+}
+
+/*
+ * Allocate space for a relocation table with `nrelobytes' bytes, and put the
+ * offset at `relooff'.
+ */
+static bool
+putreloindex(relooff, nrelobytes)
+	ind_t		relooff;
+	long		nrelobytes;
+{
+	ind_t		reloindex;
+	extern ind_t	alloc();
+
+	if ((reloindex = alloc(ALLORELO, nrelobytes)) != BADOFF) {
+		*(ind_t *)modulptr(relooff) = reloindex;
+		return TRUE;
+	}
+	return FALSE;
+}
+#ifdef SYMDBUG
+/*
+ * Allocate space for debugging information and put the offset at `dbugoff'.
+ */
+static bool
+putdbugindex(dbugoff, ndbugbytes)
+	ind_t		relooff;
+	long		ndbugbytes;
+{
+	ind_t		dbugindex;
+	extern ind_t	alloc();
+
+	if ((dbugindex = alloc(ALLORELO, ndbugbytes)) != BADOFF) {
+		*(ind_t *)modulptr(dbugoff) = dbugindex;
+		return TRUE;
+	}
+	return FALSE;
+}
+#endif SYMDBUG
+
+/*
+ * Compute addresses and read in. Remember that the contents of the sections
+ * and also the relocation table are accessed indirectly.
+ */
+static
+get_indirect(head, sect)
+	register struct outhead	*head;
+	register struct outsect	*sect;
+{
+	register ind_t		*emitindex;
+	register int		nsect;
+	register int		piece;
+	ind_t			*reloindex;
+
+	emitindex = (ind_t *)modulptr(IND_EMIT(*head));
+	nsect = head->oh_nsect; piece = ALLOEMIT;
+	while (nsect--) {
+		read_emit(address(piece, *emitindex), sect->os_flen);
+		piece++; emitindex++; sect++;
+	}
+	reloindex = (ind_t *)modulptr(IND_RELO(*head));
+	read_relo((struct outrelo *)address(ALLORELO, *reloindex),
+		head->oh_nrelo
+	);
+}
+
+/*
+ * Set the file pointer at `pos'.
+ */
+seek(pos)
+	long		pos;
+{
+	if (passnumber == FIRST || !incore)
+		lseek(infile, pos, 0);
+}
+
+/*
+ * A file pointer is advanced automatically when reading, a char pointer
+ * is not. That's why we do it here. If we don't keep everything in core,
+ * we give the space allocated for a module back.
+ */
+skip_modul(head)
+	struct outhead	*head;
+{
+	register ind_t	skip = modulsize(head);
+
+	if (incore) {
+		core_position += skip;
+		if (passnumber == SECOND)
+			modulbase += skip;
+	} else {
+		dealloc(ALLOMODL);
+		core_position = (ind_t)0;
+	}
+}
+
+/*
+ * Read in what we need in pass 2, because we couldn't keep it in core.
+ */
+static
+read_modul()
+{
+	struct outhead	*head;
+	struct outsect	*sects;
+	struct outname	*names;
+	char		*chars;
+	ind_t		sectindex, nameindex, charindex;
+	ushort		nsect, nname;
+	long		size;
+	long		nchar;
+	long		skip;
+	extern ind_t	hard_alloc();
+
+	assert(passnumber == SECOND);
+	assert(!incore);
+	if (hard_alloc(ALLOMODL, (long)sizeof(struct outhead)) == BADOFF)
+		fatal("no space for module header");
+	head = (struct outhead *)modulptr(IND_HEAD);
+	read_head(head);
+	nsect = head->oh_nsect; sectindex = IND_SECT(*head);
+	nname = head->oh_nname; nameindex = IND_NAME(*head);
+	nchar = head->oh_nchar; charindex = IND_CHAR(*head);
+	skip = OFF_NAME(*head) - OFF_EMIT(*head);
+#ifdef SYMDBUG
+	size = modulsize(head) - (nsect * sizeof(ind_t) + 2 * sizeof(ind_t));
+#else SYMDBUG
+	size = modulsize(head) - (nsect * sizeof(ind_t) + sizeof(ind_t));
+#endif SYMDBUG
+	if (hard_alloc(ALLOMODL, size) == BADOFF)
+		fatal("no space for module");
+
+	sects = (struct outsect *)modulptr(sectindex);
+	names = (struct outname *)modulptr(nameindex);
+	chars = modulptr(charindex);
+
+	read_sect(sects, nsect);
+	lseek(infile, skip, 1);
+	read_name(names, nname);
+	read_char(chars, nchar);
+}
+
+/*
+ * Align `size' to a multiple of the size of a double.
+ * This is assumed to be a power of 2.
+ */
+static long
+align(size)
+	register long	size;
+{
+	size += sizeof(double) - 1;
+	return size - (size & (sizeof(double) - 1));
+}
+
+/*
+ * Compute how many DIRECT bytes must be allocated for a module of which the
+ * header is pointed to by `head':
+ *	0. the header,
+ * 	1. the section table,
+ *	2. the name table,
+ *	3. the string table,
+ *	4. for each section the offset of its contents,
+ *	5. the offset of the relocation table.
+#ifdef SYMDBUG
+ *	6. the offset of the debugging information.
+#endif SYMDBUG
+ */
+static long
+modulsize(head)
+	register struct outhead	*head;
+{
+	return	sizeof(struct outhead) +			/* 0 */
+		head->oh_nsect * sizeof(struct outsect) +	/* 1 */
+		head->oh_nname * sizeof(struct outname) +	/* 2 */
+		align(head->oh_nchar) +				/* 3 */
+		head->oh_nsect * sizeof(ind_t) +		/* 4 */
+#ifdef SYMDBUG
+		sizeof(ind_t) +					/* 5 */
+		sizeof(ind_t);					/* 6 */
+#else SYMDBUG
+		sizeof(ind_t);					/* 5 */
+#endif SYMDBUG
+}
+
+/* ------------------------------------------------------------------------- */
+
+/*
+ * Walk through the relocation table of the current module. We must either walk
+ * through core or through file. Startrelo() should be called first.
+ */
+
+static struct outrelo	*walkrelo;
+
+startrelo(head)
+	struct outhead	*head;
+{
+	ind_t		reloindex;
+
+	if (incore) {
+		reloindex = *(ind_t *)(modulbase + IND_RELO(*head));
+		walkrelo = (struct outrelo *)address(ALLORELO, reloindex);
+	} else
+		lseek(infile, position + OFF_RELO(*head), 0);
+}
+
+struct outrelo *
+nextrelo()
+{
+	static struct outrelo	relobuf;
+
+	if (incore)
+		return walkrelo++;
+
+	read_relo(&relobuf, (ushort)1);
+	return &relobuf;
+}
+
+/* ------------------------------------------------------------------------- */
+
+/*
+ * Get the section contents in core of which the describing struct has index
+ * `sectindex'. `Head' points to the header of the module.
+ */
+char *
+getemit(head, sects, sectindex)
+	struct outhead	*head;
+	struct outsect	*sects;
+	int		sectindex;
+{
+	char		*ret;
+	ind_t		off;
+	extern char	*core_alloc();
+
+	if (!incore) {
+		ret = core_alloc(ALLOMODL, sects[sectindex].os_flen);
+		if (ret == (char *)0)
+			fatal("no space for section contents");
+		lseek(infile, position + sects[sectindex].os_foff, 0);
+		read_emit(ret, sects[sectindex].os_flen);
+		return ret;
+	}
+	/*
+	 * We have an offset in the contents of the final output
+	 * "file" where normally the contents would be.
+	 */
+	off = *((ind_t *)(modulbase + IND_EMIT(*head)) + sectindex);
+	return address(ALLOEMIT + sectindex, off);
+}

+ 13 - 0
util/led/scan.h

@@ -0,0 +1,13 @@
+/* $Header$ */
+
+/*
+ * Offsets of the pieces of the input module in core.
+ */
+
+#define IND_HEAD	((ind_t)0)
+#define IND_SECT(x)	(IND_HEAD    +		      sizeof(struct outhead))
+#define IND_NAME(x)	(IND_SECT(x) + (x).oh_nsect * sizeof(struct outsect))
+#define IND_CHAR(x)	(IND_NAME(x) + (x).oh_nname * sizeof(struct outname))
+#ifdef SYMDBUG
+#define OFF_DBUG(x)	(OFF_CHAR(x) + (x).oh_nchar)
+#endif SYMDBUG

+ 132 - 0
util/led/sym.c

@@ -0,0 +1,132 @@
+#ifndef lint
+static char rcsid[] = "$Header$";
+#endif
+
+/*
+ * Symbol table management.
+ */
+
+#include "out.h"
+#include "const.h"
+#include "memory.h"
+
+/*
+ * Symbol table types. Each hash table entry contains the offset of a symbol
+ * struct. `Sy_name' contains the offset the name in the piece of global
+ * names. `Sy_next' contains the offset of the next symbol of which the
+ * corresponding name has the same hash value.
+ */
+struct symbol {
+	ind_t	sy_name;
+	ind_t	sy_next;
+};
+
+#define NHASH	256		/* Size of hash table. Should be even. */
+
+static ind_t	hashtable[NHASH];
+
+/*
+ * Initialize the symbol table. All indices should be noticeably invalid.
+ */
+init_symboltable()
+{
+	register ind_t	*rap;
+
+	for (rap = hashtable; rap < &hashtable[NHASH]; rap++)
+		*rap = BADOFF;
+}
+
+/*
+ * Search for `string' in the symboltable. The hash value of `string' is in
+ * `hashval'. The linked list belonging to the entry of hashval
+ * in the hash table is followed. If the names match, a pointer to the outname
+ * in this element of the list is returned. When a match cannot be found,
+ * NIL is returned.
+ */ 
+struct outname *
+searchname(string, hashval)
+	char			*string;
+	int			hashval;
+{
+	register char		*rcp;
+	register char		*namestring;
+	register ind_t		symindex;
+	register struct outname	*name;
+	register struct symbol	*sym;
+
+	symindex = hashtable[hashval];
+	while (symindex != BADOFF) {
+		sym = (struct symbol *)address(ALLOSYMB, symindex);
+		name = (struct outname *)address(ALLOGLOB, sym->sy_name);
+		namestring = address(ALLOGCHR, (ind_t)name->on_foff);
+		rcp = string;
+		while (*rcp == *namestring++)
+			if (*rcp++ == '\0')
+				return name;
+		symindex = sym->sy_next;
+	}
+	/* Not found. */
+	return (struct outname *)0;
+}
+
+/*
+ * Enter a new name in the symbol table. We must copy everything to a
+ * new entry. `Name' is a private copy, i.e. the pointer to it will not be
+ * destroyed by allocation. However, the string of which name->on_foff is the
+ * offset can be destroyed, so we save it first.
+ */
+entername(name, hashval)
+	struct outname	*name;
+	int		hashval;
+{
+	ind_t		savindex;
+	ind_t		symindex;
+	ind_t		namindex;
+	struct symbol	*sym;
+	struct outname	*newname;
+	extern ind_t	savechar();
+	extern ind_t	hard_alloc();
+
+	savindex = savechar(ALLOGCHR, (ind_t)name->on_foff);
+	symindex = hard_alloc(ALLOSYMB, (long)sizeof(struct symbol));
+	namindex = hard_alloc(ALLOGLOB, (long)sizeof(struct outname));
+	if (savindex == BADOFF || symindex == BADOFF || namindex == BADOFF)
+		fatal("symbol table overflow");
+	sym = (struct symbol *)address(ALLOSYMB, symindex);
+	sym->sy_name = namindex;
+	newname = (struct outname *)address(ALLOGLOB, namindex);
+	*newname = *name;
+	newname->on_foff = savindex;
+	sym->sy_next = hashtable[hashval];
+	hashtable[hashval] = symindex;
+}
+
+/*
+ * Return the index of `name' in the symbol table in the order in which
+ * it was entered. We need a REAL index, not a byte offset.
+ */
+ushort
+indexof(name)
+	struct outname	*name;
+{
+	return name - (struct outname *)address(ALLOGLOB, (ind_t)0);
+}
+
+/*
+ * Assign an integer to the string in p.
+ * 0 <= hash(p) < NHASH, so it can - and will - be used
+ * as index in a hash table.
+ */
+int
+hash(p)
+	register char		*p;
+{
+	register unsigned int	h = 0;
+	register int		c;
+
+	while (c = *p++) {
+		h <<= 2;
+		h += c;
+	}
+	return h & (NHASH - 1);
+}

+ 297 - 0
util/led/write.c

@@ -0,0 +1,297 @@
+#ifndef lint
+static char rcsid[] = "$Header$";
+#endif
+
+/*
+ * You can choose between two strategies:
+ *	- Open the output file several times, once for each logical part, and
+ *	write to it in multiple places.
+ *	- Open the output file once and seek back and forth to each logical
+ *	part. In this case #define OUTSEEK.
+ */
+
+#include <stdio.h>
+#include "out.h"
+#include "const.h"
+#include "assert.h"
+#include "memory.h"
+#include "orig.h"
+
+extern long		lseek();
+
+#define WRITE		1	/* Argument to open(). */
+
+/*
+ * Parts of the output file.
+ */
+#define	PARTEMIT	0
+#define	PARTRELO	1
+#define	PARTNAME	2
+#define	PARTCHAR	3
+#ifdef SYMDBUG
+#define PARTDBUG	4
+#else SYMDBUG
+#define PARTDBUG	PARTCHAR
+#endif SYMDBUG
+#define	NPARTS		(PARTDBUG + 1)
+
+/*
+ * Call OUTPART() with the part you want to write on as argument, before
+ * you call OUTWRITE().
+ */
+static int		outpart = NPARTS;
+
+#ifdef OUTSEEK
+
+static int		outfile;
+static long		outseek[NPARTS];
+
+#define	OUTPART(p) \
+	{	if (outpart != (p)) {\
+			outpart = (p);\
+			lseek(outfile, outseek[(p)], 0);\
+		}\
+	}
+#define OUTSECT(i) \
+	{	outpart = NPARTS;\
+		outseek[PARTEMIT] =\
+			outsect[(i)].os_foff + relorig[(i)].org_flen;\
+	}
+#define OUTWRITE(b, n) \
+	{	if (write(outfile, (b), (n)) != (n))\
+			fatal("write error");\
+		outseek[outpart] += (n);\
+	}
+#define BEGINSEEK(p, o) \
+	{	outseek[(p)] = (o);\
+	}
+
+#else OUTSEEK
+
+static int	outfile[NPARTS];
+
+#define	OUTPART(p) \
+	{	outpart = (p);\
+	}
+#define OUTSECT(i) \
+	{	lseek(	outfile[PARTEMIT],\
+			outsect[(i)].os_foff + relorig[(i)].org_flen,\
+			0\
+		);\
+	}
+#define OUTWRITE(b, n) \
+	{	if (write(outfile[outpart], (b), (n)) != (n))\
+			fatal("write error");\
+	}
+#define	BEGINSEEK(p, o) \
+	{	lseek(outfile[(p)], (o), 0);\
+	}
+
+#endif OUTSEEK
+
+extern struct outhead	outhead;
+extern struct outsect	outsect[];
+extern int		flagword;
+extern struct orig	relorig[];
+extern bool		bytes_reversed, words_reversed;
+extern bool		incore;
+
+
+static long		offchar;
+
+/*
+ * Open the output file according to the chosen strategy.
+ * Write away the header and section table: they will not change anymore.
+ */
+begin_write()
+{
+	register long	off;
+
+	openoutput();
+	BEGINSEEK(PARTEMIT, (long)0);
+	wrt_head(&outhead);
+	wrt_sect(outsect, outhead.oh_nsect);
+
+	off = SZ_HEAD + (long)outhead.oh_nsect * SZ_SECT + outhead.oh_nemit;
+	
+	if (flagword & RFLAG) {
+		/* A relocation table will be produced. */
+		BEGINSEEK(PARTRELO, off);
+		off += (long)outhead.oh_nrelo * SZ_RELO;
+	}
+
+	if (flagword & SFLAG)
+		return;
+
+	/* A name table will be produced. */
+	BEGINSEEK(PARTNAME, off);
+	off += (long)outhead.oh_nname * SZ_NAME;
+	BEGINSEEK(PARTCHAR, off);
+	offchar = off; /* See wrt_name(). */
+#ifdef SYMDBUG
+	off += outhead.oh_nchar;
+	BEGINSEEK(PARTDBUG, off);
+#endif SYMDBUG
+}
+
+static
+openoutput()
+{
+#ifndef OUTSEEK
+	register int	*fdp;
+#endif OUTSEEK
+	extern char	*outputname;
+
+	close(creat(outputname, 0666));
+#ifdef OUTSEEK
+	if ((outfile = open(outputname, WRITE)) < 0)
+		fatal("can't write %s", outputname);
+#else OUTSEEK
+	for (fdp = &outfile[PARTEMIT]; fdp < &outfile[NPARTS]; fdp++)
+		if ((*fdp = open(outputname, WRITE)) < 0)
+			fatal("can't write %s", outputname);
+#endif OUTSEEK
+}
+
+static struct outname *
+sectname(sectindex)
+	int			sectindex;
+{
+	static struct outname	namebuf;
+
+	namebuf.on_foff = (long)0;	/* No string name. */
+	namebuf.on_type = (S_MIN + sectindex) | S_SCT;
+	namebuf.on_desc = 0;
+	namebuf.on_valu = outsect[sectindex].os_base;
+
+	return &namebuf;
+}
+
+/*
+ * Write out the symbol table and the section names.
+ */
+end_write()
+{
+	register ushort		cnt;
+	register struct outname	*name;
+	register int		sectindex;
+	extern ushort		NGlobals;
+
+	assert(!incore);
+	assert(!(flagword & SFLAG));
+	cnt = NGlobals;
+	name = (struct outname *)address(ALLOGLOB, (ind_t)0);
+	while (cnt--) {
+		if (name->on_foff != (long)0) {
+			name->on_mptr = address(ALLOGCHR, (ind_t)name->on_foff);
+		} else {
+			name->on_mptr = (char *)0;
+		}
+		wrt_name(name);
+		name++;
+	}
+
+	for (sectindex = 0; sectindex < outhead.oh_nsect; sectindex++)
+		wrt_name(sectname(sectindex));
+}
+	
+static
+wrt_head(head)
+	register struct outhead	*head;
+{
+	assert(!incore);
+	OUTPART(PARTEMIT);
+	if (bytes_reversed || words_reversed)
+		swap((char *)head, SF_HEAD);
+	OUTWRITE((char *)head, SZ_HEAD);
+	/*
+	 * Swap back because we will need it again.
+	 */
+	if (bytes_reversed || words_reversed)
+		swap((char *)head, SF_HEAD);
+}
+
+static
+wrt_sect(sect, cnt)
+	register struct outsect	*sect;
+	register ushort		cnt;
+{
+	assert(!incore);
+	OUTPART(PARTEMIT);
+	while (cnt--) {
+		if (bytes_reversed || words_reversed)
+			swap((char *)sect, SF_SECT);
+		OUTWRITE((char *)sect, SZ_SECT);
+		/*
+		 * Swap back because we will need it again.
+		 */
+		if (bytes_reversed || words_reversed)
+			swap((char *)sect, SF_SECT);
+		sect++;
+	}
+}
+
+/*
+ * We don't have to worry about byte order here.
+ */
+wrt_emit(emit, sectindex, cnt)
+	register char		*emit;
+	int			sectindex;
+	register long		cnt;
+{
+	register int		n;
+
+	assert(!incore);
+	OUTPART(PARTEMIT);
+	OUTSECT(sectindex);
+	while (cnt) {
+		n = cnt >= BUFSIZ ? BUFSIZ : cnt;
+		OUTWRITE(emit, n);
+		emit += n;
+		cnt -= n;
+	}
+}
+
+wrt_relo(relo)
+	register struct outrelo	*relo;
+{
+	assert(!incore);
+	assert(flagword & RFLAG);
+	OUTPART(PARTRELO);
+	if (bytes_reversed || words_reversed)
+		swap((char *)relo, SF_RELO);
+	OUTWRITE((char *)relo, SZ_RELO);
+}		
+
+wrt_name(name)
+	register struct outname	*name;
+{
+	assert(!incore);
+	assert(!(flagword & SFLAG));
+	if (name->on_mptr != (char *)0) {
+		register int	len = strlen(name->on_mptr) + 1;
+
+		OUTPART(PARTCHAR);
+		OUTWRITE(name->on_mptr, len);
+		name->on_foff = offchar;
+		offchar += len;
+	} else {
+		name->on_foff = (long)0;
+	}
+	OUTPART(PARTNAME);
+	if (bytes_reversed || words_reversed)
+		swap((char *)name, SF_NAME);
+	OUTWRITE((char *)name, SZ_NAME);
+}
+#ifdef SYMDBUG
+
+wrt_dbug(buf, size)
+	char		*buf;
+	int		size;
+{
+	assert(!incore);
+	assert(!(flagword & SFLAG));
+	OUTPART(PARTDBUG);
+	OUTWRITE((char *)buf, size);
+}
+#endif SYMDBUG