summaryrefslogtreecommitdiff
path: root/ld
diff options
context:
space:
mode:
authorRobert de Bath <rdebath@poboxes.com>2002-07-27 09:23:57 +0200
committerLubomir Rintel <lkundrak@v3.sk>2013-10-23 23:16:11 +0200
commita7aba15e8efffb1c5d3097656f1a93955a64f01f (patch)
tree4bb9d6d1d1528bc5647670d510aca6cc5fb300a8 /ld
downloaddev86-a7aba15e8efffb1c5d3097656f1a93955a64f01f.tar.gz
Import origs.tar.gzorigs
Diffstat (limited to 'ld')
-rw-r--r--ld/6809/config.h28
-rw-r--r--ld/Makefile18
-rw-r--r--ld/Makefile.minix20
-rw-r--r--ld/README.199417
-rw-r--r--ld/align.h10
-rw-r--r--ld/bugs17
-rw-r--r--ld/byteord.h20
-rw-r--r--ld/config.h28
-rw-r--r--ld/const.h14
-rw-r--r--ld/dumps.c68
-rw-r--r--ld/globvar.h14
-rw-r--r--ld/io.c606
-rw-r--r--ld/ld.c187
-rw-r--r--ld/obj.h54
-rw-r--r--ld/readobj.c374
-rw-r--r--ld/table.c205
-rw-r--r--ld/type.h163
-rw-r--r--ld/typeconv.c536
-rw-r--r--ld/writebin.c989
19 files changed, 3368 insertions, 0 deletions
diff --git a/ld/6809/config.h b/ld/6809/config.h
new file mode 100644
index 0000000..dc5fed4
--- /dev/null
+++ b/ld/6809/config.h
@@ -0,0 +1,28 @@
+/* config.h - configuration for linker */
+
+/* Copyright (C) 1994 Bruce Evans */
+
+/* one of these target processors must be defined */
+
+#undef I8086 /* Intel 8086 */
+#undef I80386 /* Intel 80386 */
+#define MC6809 /* Motorola 6809 */
+
+/* one of these target operating systems must be defined */
+
+#define EDOS /* generate EDOS executable */
+#undef MINIX /* generate Minix executable */
+
+/* these may need to be defined to suit the source processor */
+
+#define HOST_8BIT /* enable some 8-bit optimizations */
+
+/* #define S_ALIGNMENT 4 */ /* source memory alignment, power of 2 */
+ /* don't use for 8 bit processors */
+ /* don't use even for 80386 - overhead for */
+ /* alignment cancels improved access */
+
+/* these must be defined to suit the source libraries */
+
+#define CREAT_PERMS 0666 /* permissions for creat() */
+#define EXEC_PERMS 0111 /* extra permissions to set for executable */
diff --git a/ld/Makefile b/ld/Makefile
new file mode 100644
index 0000000..756a25c
--- /dev/null
+++ b/ld/Makefile
@@ -0,0 +1,18 @@
+CFLAGS =-O -DBSD_A_OUT -DSTANDARD_GNU_A_OUT
+LDFLAGS =-N -s
+
+OBJS =dumps.o io.o ld.o readobj.o table.o typeconv.o writebin.o
+
+ld: $(OBJS)
+ $(CC) $(LDFLAGS) $(OBJS) -o $@
+
+clean:
+ rm -f $(OBJS) ld
+
+dumps.o: dumps.c const.h config.h obj.h type.h globvar.h
+io.o: io.c const.h config.h obj.h type.h globvar.h
+ld.o: ld.c const.h config.h byteord.h type.h globvar.h
+readobj.o: readobj.c const.h config.h byteord.h obj.h type.h globvar.h
+table.o: table.c const.h config.h align.h obj.h type.h globvar.h
+typeconv.o: typeconv.c const.h config.h type.h globvar.h
+writebin.o: writebin.c const.h config.h obj.h type.h globvar.h
diff --git a/ld/Makefile.minix b/ld/Makefile.minix
new file mode 100644
index 0000000..7f819fa
--- /dev/null
+++ b/ld/Makefile.minix
@@ -0,0 +1,20 @@
+CFLAGS =-O -DBSD_A_OUT
+LDFLAGS =
+
+OBJS =dumps.o io.o ld.o readobj.o table.o typeconv.o writebin.o
+
+ld: $(OBJS)
+ $(CC) $(LDFLAGS) $(OBJS) -o $@
+ chmem =232000 $@
+
+clean:
+ rm -f $(OBJS) ld
+
+dumps.o: dumps.c const.h config.h obj.h type.h globvar.h
+io.o: io.c const.h config.h obj.h type.h globvar.h
+ld.o: ld.c const.h config.h byteord.h type.h globvar.h
+readobj.o: readobj.c ar.h const.h config.h byteord.h obj.h type.h globvar.h
+table.o: table.c const.h config.h align.h obj.h type.h globvar.h
+typeconv.o: typeconv.c const.h config.h type.h globvar.h
+writebin.o: writebin.c bsd-a.out.h a.out.gnu.h const.h config.h obj.h type.h \
+ globvar.h
diff --git a/ld/README.1994 b/ld/README.1994
new file mode 100644
index 0000000..669c8a8
--- /dev/null
+++ b/ld/README.1994
@@ -0,0 +1,17 @@
+The `bcc' and `ld' parts of the bin86 distribution are now covered by the
+GNU GPL. The next release of the `as' part will be covered by the GPL.
+The `a.out.h' part is no longer used and should be deleted. The `bccfp'
+belongs in another package and may be deleted.
+
+`ld' is now correctly ported to linux. It now defaults to the target
+a.out format for output. However, it still requires its own special
+format for input. It is best used as a post-processor for `as' to
+produce objects in a.out format. Then the target ld can be used to
+link the objects. The post-processing step is:
+
+ ld86 -r -o tmpfile.o file.o && mv tmpfile.o file.o
+
+This can be handled more simply by using the `bcc' compiler driver as
+the assembler and never calling as86 or ld86 directly:
+
+ AS86="bcc -G -0 -c"
diff --git a/ld/align.h b/ld/align.h
new file mode 100644
index 0000000..ba33fb8
--- /dev/null
+++ b/ld/align.h
@@ -0,0 +1,10 @@
+/* align.h - memory alignment requirements for linker */
+
+/* Copyright (C) 1994 Bruce Evans */
+
+#ifndef S_ALIGNMENT
+# define align(x)
+#else
+# define align(x) ((x) = ((int) (x) + (S_ALIGNMENT-1)) & ~(S_ALIGNMENT-1))
+ /* assumes sizeof(int) == sizeof(char *) */
+#endif
diff --git a/ld/bugs b/ld/bugs
new file mode 100644
index 0000000..b671f30
--- /dev/null
+++ b/ld/bugs
@@ -0,0 +1,17 @@
+1. Should cause error when an address which requires > 16 bits is referenced
+ using 16 bits.
+
+TODO:
+ integrate byteord.h with compiler as well as assembler
+
+TODO:
+ integrate align.h with compiler and assembler
+ use alignment for *86 like compiler - use more portable macro
+ ((x) + (-(int) (x) & MASK)) when it is either necessary or
+ faster
+
+TODO:
+ do malloc stuff better, as in compiler
+
+2. Error message about "foo.a is not an object file" is confusing - should
+ name archive member.
diff --git a/ld/byteord.h b/ld/byteord.h
new file mode 100644
index 0000000..57d17b9
--- /dev/null
+++ b/ld/byteord.h
@@ -0,0 +1,20 @@
+/* byteord.h - byte order dependencies for C compiler, assembler, linker */
+
+/* Copyright (C) 1994 Bruce Evans */
+
+/* These are for the targets of everything and for linker source too. */
+
+#ifdef I8086
+# define BIG_ENDIAN 0
+# define LONG_BIG_ENDIAN 0 /* except longs are back to front for Xenix */
+#endif
+
+#ifdef I80386
+# define BIG_ENDIAN 0
+# define LONG_BIG_ENDIAN 0
+#endif
+
+#ifdef MC6809
+# define BIG_ENDIAN 1 /* byte order in words is high-low */
+# define LONG_BIG_ENDIAN 1 /* byte order in longs is high-low */
+#endif
diff --git a/ld/config.h b/ld/config.h
new file mode 100644
index 0000000..201c153
--- /dev/null
+++ b/ld/config.h
@@ -0,0 +1,28 @@
+/* config.h - configuration for linker */
+
+/* Copyright (C) 1994 Bruce Evans */
+
+/* one of these target processors must be defined */
+
+#undef I8086 /* Intel 8086 */
+#define I80386 /* Intel 80386 */
+#undef MC6809 /* Motorola 6809 */
+
+/* one of these target operating systems must be defined */
+
+#undef EDOS /* generate EDOS executable */
+#define MINIX /* generate Minix executable */
+
+/* these may need to be defined to suit the source processor */
+
+#undef HOST_8BIT /* enable some 8-bit optimizations */
+
+/* #define S_ALIGNMENT 4 */ /* source memory alignment, power of 2 */
+ /* don't use for 8 bit processors */
+ /* don't use even for 80386 - overhead for */
+ /* alignment cancels improved access */
+
+/* these must be defined to suit the source libraries */
+
+#define CREAT_PERMS 0666 /* permissions for creat() */
+#define EXEC_PERMS 0111 /* extra permissions to set for executable */
diff --git a/ld/const.h b/ld/const.h
new file mode 100644
index 0000000..7705e15
--- /dev/null
+++ b/ld/const.h
@@ -0,0 +1,14 @@
+/* const.h - constants for linker */
+
+/* Copyright (C) 1994 Bruce Evans */
+
+#define FALSE 0
+#define NULL 0
+#define TRUE 1
+
+#define EXTERN extern
+#define FORWARD static
+#define PRIVATE static
+#define PUBLIC
+
+#include "config.h"
diff --git a/ld/dumps.c b/ld/dumps.c
new file mode 100644
index 0000000..5027fac
--- /dev/null
+++ b/ld/dumps.c
@@ -0,0 +1,68 @@
+/* dumps.c - print data about symbols and modules for linker */
+
+/* Copyright (C) 1994 Bruce Evans */
+
+#include "const.h"
+#include "obj.h"
+#include "type.h"
+#include "globvar.h"
+
+/* print list of modules and whether they are loaded */
+
+PUBLIC void dumpmods()
+{
+ struct modstruct *modptr;
+
+ for (modptr = modfirst; modptr != NULL; modptr = modptr->modnext)
+ {
+ putstr(modptr->loadflag ? "L " : " ");
+ putbstr(20, modptr->modname);
+ putbyte('\n');
+ }
+}
+
+/* print data about symbols (in loaded modules only) */
+
+PUBLIC void dumpsyms()
+{
+ flags_t flags;
+ struct modstruct *modptr;
+ struct symstruct **symparray;
+ struct symstruct *symptr;
+ char uflag;
+
+ for (modptr = modfirst; modptr != NULL; modptr = modptr->modnext)
+ if (modptr->loadflag)
+ {
+ for (symparray = modptr->symparray;
+ (symptr = *symparray) != NULL; ++symparray)
+ if (symptr->modptr == modptr)
+ {
+ uflag = FALSE;
+ if (((flags = symptr->flags) & (C_MASK | I_MASK)) == I_MASK)
+ uflag = TRUE;
+ putbstr(20, uflag ? "" : modptr->modname);
+ putstr(" ");
+ putbstr(20, symptr->name);
+ putstr(" ");
+ putbyte(hexdigit[flags & SEGM_MASK]);
+ putstr(" ");
+ if (uflag)
+ putstr(" ");
+ else
+#ifdef LONG_OFFSETS
+ put08lx(symptr->value);
+#else
+ put08x(symptr->value);
+#endif
+ putstr(flags & A_MASK ? " A" : " R");
+ if (uflag)
+ putstr(" U");
+ if (flags & C_MASK)
+ putstr(" C");
+ if (flags & N_MASK)
+ putstr(" N");
+ putbyte('\n');
+ }
+ }
+}
diff --git a/ld/globvar.h b/ld/globvar.h
new file mode 100644
index 0000000..0351a6b
--- /dev/null
+++ b/ld/globvar.h
@@ -0,0 +1,14 @@
+/* globvar.h - global variables for linker */
+
+/* Copyright (C) 1994 Bruce Evans */
+
+#ifdef EXTERN
+EXTERN char hexdigit[];
+#else
+#define EXTERN
+PUBLIC char hexdigit[] = "0123456789abcdef";
+#endif
+EXTERN unsigned errcount; /* count of errors */
+EXTERN struct entrylist *entryfirst; /* first on list of entry symbols */
+EXTERN struct modstruct *modfirst; /* data for 1st module */
+EXTERN struct redlist *redfirst; /* first on list of redefined symbols */
diff --git a/ld/io.c b/ld/io.c
new file mode 100644
index 0000000..aef49d0
--- /dev/null
+++ b/ld/io.c
@@ -0,0 +1,606 @@
+/* io.c - input/output and error modules for linker */
+
+/* Copyright (C) 1994 Bruce Evans */
+
+#include "const.h"
+#include "obj.h" /* needed for LONG_OFFSETS and offset_t */
+#include "type.h"
+#include "globvar.h"
+
+#ifdef STDC_HEADERS_MISSING
+void exit P((int status));
+void *malloc P((unsigned size));
+#else
+#undef NULL
+#include <stdlib.h>
+#endif
+
+#ifdef POSIX_HEADERS_MISSING
+#define O_RDONLY 0
+#define O_WRONLY 1
+#define SEEK_SET 0
+#define STDOUT_FILENO 0
+#include <sys/stat.h>
+#define mode_t unsigned short
+#define off_t long
+int chmod P((const char *path, int mode));
+int close P((int fd));
+int creat P((const char *path, int mode));
+int fstat P((int fd, struct stat *statbuf));
+off_t lseek P((int fd, off_t offset, int whence));
+int open P((const char *path, int oflag, ...));
+int read P((int fd, void *buf, unsigned nbytes));
+mode_t umask P((int oldmask));
+int write P((int fd, const void *buf, unsigned nbytes));
+#else
+#undef NULL
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+#endif
+
+#define DRELBUFSIZE 3072
+#define ERR (-1)
+#define ERRBUFSIZE 1024
+#define INBUFSIZE 1024
+#define OUTBUFSIZE 2048
+#define TRELBUFSIZE 1024
+
+#ifdef BSD_A_OUT
+PRIVATE char *drelbuf; /* extra output buffer for data relocations */
+PRIVATE char *drelbufptr; /* data relocation output buffer ptr */
+PRIVATE char *drelbuftop; /* data relocation output buffer top */
+#endif
+PRIVATE char *errbuf; /* error buffer (actually uses STDOUT) */
+PRIVATE char *errbufptr; /* error buffer ptr */
+PRIVATE char *errbuftop; /* error buffer top */
+PRIVATE char *inbuf; /* input buffer */
+PRIVATE char *inbufend; /* input buffer top */
+PRIVATE char *inbufptr; /* end of input in input buffer */
+PRIVATE int infd; /* input file descriptor */
+PRIVATE char *inputname; /* name of current input file */
+PRIVATE char *outbuf; /* output buffer */
+PRIVATE char *outbufptr; /* output buffer ptr */
+PRIVATE char *outbuftop; /* output buffer top */
+PRIVATE int outfd; /* output file descriptor */
+PRIVATE mode_t outputperms; /* permissions of output file */
+PRIVATE char *outputname; /* name of output file */
+PRIVATE char *refname; /* name of program for error reference */
+#ifdef BSD_A_OUT
+PRIVATE char *trelbuf; /* extra output buffer for text relocations */
+PRIVATE char *trelbufptr; /* text relocation output buffer ptr */
+PRIVATE char *trelbuftop; /* text relocation output buffer top */
+PRIVATE int trelfd; /* text relocation output file descriptor */
+#endif
+PRIVATE unsigned warncount; /* count of warnings */
+
+FORWARD void errexit P((char *message));
+FORWARD void flushout P((void));
+#ifdef BSD_A_OUT
+FORWARD void flushtrel P((void));
+#endif
+FORWARD void outhexdigs P((offset_t num));
+FORWARD void outputerror P((char *message));
+FORWARD void put04x P((unsigned num));
+FORWARD void putstrn P((char *message));
+FORWARD void refer P((void));
+
+PUBLIC void ioinit(progname)
+char *progname;
+{
+ infd = ERR;
+ if (*progname)
+ refname = progname; /* name must be static (is argv[0]) */
+ else
+ refname = "link";
+#ifdef BSD_A_OUT
+ drelbuf = malloc(DRELBUFSIZE);
+ drelbuftop = drelbuf + DRELBUFSIZE;
+#endif
+ errbuf = malloc(ERRBUFSIZE);
+ errbufptr = errbuf;
+ errbuftop = errbuf + ERRBUFSIZE;
+ inbuf = malloc(INBUFSIZE);
+ outbuf = malloc(OUTBUFSIZE);/* outbuf invalid if this fails but then */
+ /* will not be used - tableinit() aborts */
+ outbuftop = outbuf + OUTBUFSIZE;
+#ifdef BSD_A_OUT
+ trelbuf = malloc(TRELBUFSIZE);
+ trelbuftop = trelbuf + TRELBUFSIZE;
+#endif
+}
+
+PUBLIC void closein()
+{
+ if (infd != ERR && close(infd) < 0)
+ inputerror("cannot close");
+ infd = ERR;
+}
+
+PUBLIC void closeout()
+{
+#ifdef BSD_A_OUT
+ unsigned nbytes;
+#endif
+
+ flushout();
+#ifdef BSD_A_OUT
+ flushtrel();
+ nbytes = drelbufptr - drelbuf;
+ if (write(trelfd, drelbuf, nbytes) != nbytes)
+ outputerror("cannot write");
+#endif
+ if (close(outfd) == ERR)
+ outputerror("cannot close");
+#ifdef BSD_A_OUT
+ if (close(trelfd) == ERR)
+ outputerror("cannot close");
+#endif
+}
+
+PUBLIC void errtrace(name, level)
+char *name;
+int level;
+{
+ while (level-- > 0)
+ putbyte(' ');
+ putstrn(name);
+}
+
+PUBLIC void executable()
+{
+ mode_t oldmask;
+
+ if (errcount == 0)
+ {
+ oldmask = umask(0);
+ umask(oldmask);
+ chmod(outputname, outputperms | (EXEC_PERMS & ~oldmask));
+ }
+}
+
+PUBLIC void flusherr()
+{
+ write(STDOUT_FILENO, errbuf, (unsigned) (errbufptr - errbuf));
+ errbufptr = errbuf;
+}
+
+PRIVATE void flushout()
+{
+ unsigned nbytes;
+
+ nbytes = outbufptr - outbuf;
+ if (write(outfd, outbuf, nbytes) != nbytes)
+ outputerror("cannot write");
+ outbufptr = outbuf;
+}
+
+#ifdef BSD_A_OUT
+PRIVATE void flushtrel()
+{
+ unsigned nbytes;
+
+ nbytes = trelbufptr - trelbuf;
+ if (write(trelfd, trelbuf, nbytes) != nbytes)
+ outputerror("cannot write");
+ trelbufptr = trelbuf;
+}
+#endif
+
+PUBLIC void openin(filename)
+char *filename;
+{
+#if 0 /* XXX - this probably won't work with constructed lib names? */
+ if (infd == ERR || strcmp(inputname, filename) != 0)
+#endif
+ {
+ closein();
+ inputname = filename; /* this relies on filename being static */
+ if ((infd = open(filename, O_RDONLY)) < 0)
+ inputerror("cannot open");
+ inbufptr = inbufend = inbuf;
+ }
+}
+
+PUBLIC void openout(filename)
+char *filename;
+{
+ struct stat statbuf;
+
+ outputname = filename;
+ if ((outfd = creat(filename, CREAT_PERMS)) == ERR)
+ outputerror("cannot open");
+ if (fstat(outfd, &statbuf) != 0)
+ outputerror("cannot stat");
+ outputperms = statbuf.st_mode;
+ chmod(filename, outputperms & ~EXEC_PERMS);
+#ifdef BSD_A_OUT
+ drelbufptr = drelbuf;
+#endif
+ outbufptr = outbuf;
+#ifdef BSD_A_OUT
+ if ((trelfd = open(filename, O_WRONLY)) == ERR)
+ outputerror("cannot reopen");
+ trelbufptr = trelbuf;
+#endif
+}
+
+PRIVATE void outhexdigs(num)
+register offset_t num;
+{
+ if (num >= 0x10)
+ {
+ outhexdigs(num / 0x10);
+ num %= 0x10;
+ }
+ putbyte(hexdigit[num]);
+}
+
+PRIVATE void put04x(num)
+register unsigned num;
+{
+ putbyte(hexdigit[num / 0x1000]);
+ putbyte(hexdigit[(num / 0x100) & 0x0F]);
+ putbyte(hexdigit[(num / 0x10) & 0x0F]);
+ putbyte(hexdigit[num & 0x0F]);
+}
+
+#ifdef LONG_OFFSETS
+
+PUBLIC void put08lx(num)
+register offset_t num;
+{
+ put04x(num / 0x10000);
+ put04x(num % 0x10000);
+}
+
+#else /* not LONG_OFFSETS */
+
+PUBLIC void put08x(num)
+register offset_t num;
+{
+ putstr("0000");
+ put04x(num);
+}
+
+#endif /* not LONG_OFFSETS */
+
+PUBLIC void putbstr(width, str)
+unsigned width;
+char *str;
+{
+ unsigned length;
+
+ for (length = strlen(str); length < width; ++length)
+ putbyte(' ');
+ putstr(str);
+}
+
+PUBLIC void putbyte(ch)
+int ch;
+{
+ register char *ebuf;
+
+ ebuf = errbufptr;
+ if (ebuf >= errbuftop)
+ {
+ flusherr();
+ ebuf = errbufptr;
+ }
+ *ebuf++ = ch;
+ errbufptr = ebuf;
+}
+
+PUBLIC void putstr(message)
+char *message;
+{
+ while (*message != 0)
+ putbyte(*message++);
+}
+
+PRIVATE void putstrn(message)
+char *message;
+{
+ putstr(message);
+ putbyte('\n');
+ flusherr();
+}
+
+PUBLIC int readchar()
+{
+ int ch;
+
+ register char *ibuf;
+ int nread;
+
+ ibuf = inbufptr;
+ if (ibuf >= inbufend)
+ {
+ ibuf = inbufptr = inbuf;
+ nread = read(infd, ibuf, INBUFSIZE);
+ if (nread <= 0)
+ {
+ inbufend = ibuf;
+ return ERR;
+ }
+ inbufend = ibuf + nread;
+ }
+ ch = (unsigned char) *ibuf++;
+ inbufptr = ibuf;
+ return ch;
+}
+
+PUBLIC void readin(buf, count)
+char *buf;
+unsigned count;
+{
+ int ch;
+
+ while (count--)
+ {
+ if ((ch = readchar()) < 0)
+ prematureeof();
+ *buf++ = ch;
+ }
+}
+
+PUBLIC bool_pt readineofok(buf, count)
+char *buf;
+unsigned count;
+{
+ int ch;
+
+ while (count--)
+ {
+ if ((ch = readchar()) < 0)
+ return TRUE;
+ *buf++ = ch;
+ }
+ return FALSE;
+}
+
+PUBLIC void seekin(offset)
+unsigned long offset;
+{
+ inbufptr = inbufend = inbuf;
+ if (lseek(infd, (off_t) offset, SEEK_SET) != offset)
+ prematureeof();
+}
+
+PUBLIC void seekout(offset)
+unsigned long offset;
+{
+ flushout();
+ if (lseek(outfd, (off_t) offset, SEEK_SET) != offset)
+ outputerror("cannot seek in");
+}
+
+#ifdef BSD_A_OUT
+PUBLIC void seektrel(offset)
+unsigned long offset;
+{
+ flushtrel();
+ if (lseek(trelfd, (off_t) offset, SEEK_SET) != offset)
+ outputerror("cannot seek in");
+}
+#endif
+
+PUBLIC void writechar(ch)
+int ch;
+{
+ register char *obuf;
+
+ obuf = outbufptr;
+ if (obuf >= outbuftop)
+ {
+ flushout();
+ obuf = outbufptr;
+ }
+ *obuf++ = ch;
+ outbufptr = obuf;
+}
+
+#ifdef BSD_A_OUT
+PUBLIC void writedrel(buf, count)
+register char *buf;
+unsigned count;
+{
+ register char *rbuf;
+
+ rbuf = drelbufptr;
+ while (count--)
+ {
+ if (rbuf >= drelbuftop)
+ inputerror("data relocation buffer full while processing");
+ *rbuf++ = *buf++;
+ }
+ drelbufptr = rbuf;
+}
+#endif
+
+PUBLIC void writeout(buf, count)
+register char *buf;
+unsigned count;
+{
+ register char *obuf;
+
+ obuf = outbufptr;
+ while (count--)
+ {
+ if (obuf >= outbuftop)
+ {
+ outbufptr = obuf;
+ flushout();
+ obuf = outbufptr;
+ }
+ *obuf++ = *buf++;
+ }
+ outbufptr = obuf;
+}
+
+#ifdef BSD_A_OUT
+PUBLIC void writetrel(buf, count)
+register char *buf;
+unsigned count;
+{
+ register char *rbuf;
+
+ rbuf = trelbufptr;
+ while (count--)
+ {
+ if (rbuf >= trelbuftop)
+ {
+ trelbufptr = rbuf;
+ flushtrel();
+ rbuf = trelbufptr;
+ }
+ *rbuf++ = *buf++;
+ }
+ trelbufptr = rbuf;
+}
+#endif
+
+/* error module */
+
+PRIVATE void errexit(message)
+char *message;
+{
+ putstrn(message);
+ exit(2);
+}
+
+PUBLIC void fatalerror(message)
+char *message;
+{
+ refer();
+ errexit(message);
+}
+
+PUBLIC void inputerror(message)
+char *message;
+{
+ refer();
+ putstr(message);
+ putstr(" input file ");
+ errexit(inputname);
+}
+
+PUBLIC void input1error(message)
+char *message;
+{
+ refer();
+ putstr(inputname);
+ errexit(message);
+}
+
+PRIVATE void outputerror(message)
+char *message;
+{
+ refer();
+ putstr(message);
+ putstr(" output file ");
+ errexit(outputname);
+}
+
+PUBLIC void outofmemory()
+{
+ inputerror("out of memory while processing");
+}
+
+PUBLIC void prematureeof()
+{
+ inputerror("premature end of");
+}
+
+PUBLIC void redefined(name, message, archentry, deffilename, defarchentry)
+char *name;
+char *message;
+char *archentry;
+char *deffilename;
+char *defarchentry;
+{
+ ++warncount;
+ refer();
+ putstr("warning: ");
+ putstr(name);
+ putstr(" redefined");
+ putstr(message);
+ putstr(" in file ");
+ putstr(inputname);
+ if (archentry != NULL)
+ {
+ putbyte('(');
+ putstr(archentry);
+ putbyte(')');
+ }
+ putstr("; using definition in ");
+ putstr(deffilename);
+ if (defarchentry != NULL)
+ {
+ putbyte('(');
+ putstr(defarchentry);
+ putbyte(')');
+ }
+ putbyte('\n');
+}
+
+PRIVATE void refer()
+{
+ putstr(refname);
+ putstr(": ");
+}
+
+PUBLIC void reserved(name)
+char *name;
+{
+ ++errcount;
+ putstr("incorrect use of reserved symbol: ");
+ putstrn(name);
+}
+
+PUBLIC void size_error(seg, count, size)
+char seg;
+offset_t count;
+offset_t size;
+{
+ refer();
+ putstr("seg ");
+ outhexdigs((offset_t) seg);
+ putstr(" has wrong size ");
+ outhexdigs(count);
+ putstr(", supposed to be ");
+ outhexdigs(size);
+ errexit("\n");
+}
+
+PUBLIC void undefined(name)
+char *name;
+{
+ ++errcount;
+ putstr("undefined symbol: ");
+ putstrn(name);
+}
+
+PUBLIC void usage()
+{
+ putstr("usage: ");
+ putstr(refname);
+#ifdef BSD_A_OUT
+ errexit("\
+ [-03Mimrstz[-]] [-llib_extension] [-o outfile] [-Ccrtfile]\n\
+ [-Llibdir] [-Olibfile] [-T textaddr] infile...");
+#else
+ errexit("\
+ [-03Mimstz[-]] [-llib_extension] [-o outfile] [-Ccrtfile]\n\
+ [-Llibdir] [-Olibfile] [-T textaddr] infile...");
+#endif
+}
+
+PUBLIC void use_error(message)
+char *message;
+{
+ refer();
+ putstrn(message);
+ usage();
+}
diff --git a/ld/ld.c b/ld/ld.c
new file mode 100644
index 0000000..c19b98d
--- /dev/null
+++ b/ld/ld.c
@@ -0,0 +1,187 @@
+/* ld.c - linker for Introl format (6809 C) object files 6809/8086/80386 */
+
+/* Copyright (C) 1994 Bruce Evans */
+
+#include "const.h"
+#include "byteord.h"
+#include "type.h"
+#include "globvar.h"
+
+#ifdef STDC_HEADERS_MISSING
+extern int errno;
+char *strcat P((char *dest, const char *src));
+unsigned long strtoul P((const char *s, char **endptr, int base));
+#else
+#undef NULL
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+#endif
+
+#ifdef POSIX_HEADERS_MISSING
+#define R_OK 0
+int access P((const char *path, int amode));
+#else
+#undef NULL
+#include <unistd.h>
+#endif
+
+#define MAX_LIBS (NR_STDLIBS + 5)
+#define NR_STDLIBS 1
+
+PUBLIC long text_base_address; /* XXX */
+
+PRIVATE bool_t flag[128];
+PRIVATE char *libs[MAX_LIBS] = {
+#ifdef MC6809
+ "/usr/local/lib/m09/",
+#else
+ /* One of the following values will be inserted at run time. */
+# define std386lib "/usr/local/lib/i386/"
+# define std86lib "/usr/local/lib/i86/"
+#endif
+ 0
+};
+PRIVATE int lastlib = NR_STDLIBS;
+
+FORWARD char *buildname P((char *pre, char *mid, char *suf));
+FORWARD char *expandlib P((char *fn));
+
+PRIVATE char *buildname(pre, mid, suf)
+char *pre;
+char *mid;
+char *suf;
+{
+ char *name;
+
+ name = ourmalloc(strlen(pre) + strlen(mid) + strlen(suf) + 1);
+ strcpy(name, pre);
+ strcat(name, mid);
+ strcat(name, suf);
+ return name;
+}
+
+PRIVATE char *expandlib(fn)
+char *fn;
+{
+ char *path;
+ int i;
+
+#ifndef MC6809
+ libs[0] = flag['3'] ? std386lib : std86lib;
+#endif
+
+ for (i = lastlib - 1; i >= 0; --i)
+ {
+ path = ourmalloc(strlen(libs[i]) + strlen(fn) + 1);
+ strcpy(path, libs[i]);
+ strcat(path, fn);
+ if (access(path, R_OK) == 0)
+ return path;
+ ourfree(path);
+ }
+ return NULL;
+}
+
+PUBLIC int main(argc, argv)
+int argc;
+char **argv;
+{
+ register char *arg;
+ int argn;
+ static char crtprefix[] = "crt";
+ static char crtsuffix[] = ".o";
+ char *infilename;
+ static char libprefix[] = "lib";
+ static char libsuffix[] = ".a";
+ char *outfilename;
+ char *tfn;
+
+ ioinit(argv[0]);
+ objinit();
+ syminit();
+ typeconv_init(BIG_ENDIAN, LONG_BIG_ENDIAN);
+#ifndef MC6809
+ flag['z'] = flag['3'] = sizeof(char *) >= 4;
+#endif
+ outfilename = NULL;
+ for (argn = 1; argn < argc; ++argn)
+ {
+ arg = argv[argn];
+ if (*arg != '-')
+ readsyms(arg, flag['t']);
+ else
+ switch (arg[1])
+ {
+ case '0': /* use 16-bit libraries */
+ case '3': /* use 32-bit libraries */
+ case 'M': /* print symbols linked */
+ case 'i': /* separate I & D output */
+ case 'm': /* print modules linked */
+#ifdef BSD_A_OUT
+ case 'r': /* relocatable output */
+#endif
+ case 's': /* strip symbols */
+ case 't': /* trace modules linked */
+ case 'z': /* unmapped zero page */
+ if (arg[2] == 0)
+ flag[(int) arg[1]] = TRUE;
+ else if (arg[2] == '-' && arg[3] == 0)
+ flag[(int) arg[1]] = FALSE;
+ else
+ usage();
+ if (arg[1] == '0') /* flag 0 is negative logic flag 3 */
+ flag['3'] = !flag['0'];
+ break;
+ case 'C': /* startfile name */
+ tfn = buildname(crtprefix, arg + 2, crtsuffix);
+ if ((infilename = expandlib(tfn)) == NULL)
+ fatalerror(tfn); /* XXX - need to describe failure */
+ readsyms(infilename, flag['t']);
+ break;
+ case 'L': /* library path */
+ if (lastlib < MAX_LIBS)
+ libs[lastlib++] = arg + 2;
+ else
+ fatalerror("too many library paths");
+ break;
+ case 'O': /* library file name */
+ if ((infilename = expandlib(arg + 2)) == NULL)
+ fatalerror(arg); /* XXX */
+ readsyms(infilename, flag['t']);
+ break;
+ case 'T': /* text base address */
+ if (arg[2] != 0 || ++argn >= argc)
+ usage();
+ errno = 0;
+ text_base_address = strtoul(argv[argn], (char **) NULL, 16);
+ if (errno != 0)
+ use_error("invalid text address");
+ break;
+ case 'l': /* library name */
+ tfn = buildname(libprefix, arg + 2, libsuffix);
+ if ((infilename = expandlib(tfn)) == NULL)
+ fatalerror(tfn); /* XXX */
+ readsyms(infilename, flag['t']);
+ break;
+ case 'o': /* output file name */
+ if (arg[2] != 0 || ++argn >= argc || outfilename != NULL)
+ usage();
+ outfilename = argv[argn];
+ break;
+ default:
+ usage();
+ }
+ }
+ linksyms(flag['r']);
+ if (outfilename == NULL)
+ outfilename = "a.out";
+ writebin(outfilename, flag['i'], flag['3'], flag['s'],
+ flag['z'] & flag['3']);
+ if (flag['m'])
+ dumpmods();
+ if (flag['M'])
+ dumpsyms();
+ flusherr();
+ return errcount ? 1 : 0;
+}
diff --git a/ld/obj.h b/ld/obj.h
new file mode 100644
index 0000000..e0a52dc
--- /dev/null
+++ b/ld/obj.h
@@ -0,0 +1,54 @@
+/* obj.h - constants for Introl object modules */
+
+/* Copyright (C) 1994 Bruce Evans */
+
+#define OBJ_H
+
+#ifdef I80386
+# define LONG_OFFSETS /* others can use this, but wasteful */
+#endif
+
+#ifndef OMAGIC
+# ifdef I80386
+# define OMAGIC 0x86A3
+# endif
+
+# ifdef I8086
+# define OMAGIC 0x86A0
+# endif
+
+# ifdef MC6809
+# define OMAGIC 0x5331
+# endif
+#endif
+
+#ifdef LONG_OFFSETS
+# define cntooffset cnu4
+# define offtocn u4cn
+#else
+# define cntooffset cnu2
+# define offtocn u2cn
+#endif
+
+#ifdef MC6809 /* temp don't support alignment at all */
+# define roundup( num, boundary, type ) (num)
+#else
+# define roundup( num, boundary, type ) \
+ (((num) + ((boundary) - 1)) & (type) ~((boundary) - 1))
+#endif
+
+#define MAX_OFFSET_SIZE 4
+#define NSEG 16
+
+/* flag values |SZ|LXXXX|N|E|I|R|A|SEGM|, X not used */
+
+#define A_MASK 0x0010 /* absolute */
+#define C_MASK 0x0020 /* common (internal only) */
+#define E_MASK 0x0080 /* exported */
+#define I_MASK 0x0040 /* imported */
+#define N_MASK 0x0100 /* entry point */
+#define R_MASK 0x0020 /* relative (in text only) */
+#define SEGM_MASK 0x000F /* segment (if not absolute) */
+#define SA_MASK 0x2000 /* offset is storage allocation */
+#define SZ_MASK 0xC000 /* size descriptor for value */
+#define SZ_SHIFT 14
diff --git a/ld/readobj.c b/ld/readobj.c
new file mode 100644
index 0000000..791436f
--- /dev/null
+++ b/ld/readobj.c
@@ -0,0 +1,374 @@
+/* readobj.c - read object file for linker */
+
+/* Copyright (C) 1994 Bruce Evans */
+
+#include "ar.h" /* maybe local copy of <ar.h> for cross-link */
+#include "const.h"
+#include "byteord.h"
+#include "obj.h"
+#include "type.h"
+#include "globvar.h"
+
+#ifdef STDC_HEADERS_MISSING
+int strncmp P((const char *s1, const char *s2, unsigned n));
+char *strncpy P((char *dest, const char *src, unsigned n));
+unsigned long strtoul P((const char *s, char **endptr, int base));
+#else
+#undef NULL
+#include <stdlib.h>
+#include <string.h>
+#endif
+
+/*
+ Linking takes 2 passes. The 1st pass reads through all files specified
+in the command line, and all libraries. All public symbols are extracted
+and stored in a chained hash table. For each module, its file and header
+data recorded, and the resulting structures are chained together
+(interleaved with the symbols).
+
+ The symbol descriptors are separated from the symbol names, so we must
+record all the descriptors of a module before putting the symbols in the
+symbol table (poor design). The descriptors are stored in the symbol
+table, then moved to the top of the table to make room for the symols.
+The symbols referred to in a given module are linked together by a chain
+beginning in the module descriptor.
+*/
+
+PRIVATE unsigned convertsize[NSEG / 4] = {0, 1, 2, 4};
+PRIVATE struct entrylist *entrylast; /* last on list of entry symbols */
+PRIVATE struct redlist *redlast; /* last on list of redefined symbols */
+PRIVATE struct modstruct *modlast; /* data for last module */
+
+FORWARD long readarheader P((char **parchentry));
+FORWARD unsigned readfileheader P((void));
+FORWARD void readmodule P((char *filename, char *archentry));
+FORWARD void reedmodheader P((void));
+FORWARD bool_pt redsym P((struct symstruct *symptr, offset_t value));
+FORWARD unsigned checksum P((char *string, unsigned length));
+FORWARD unsigned segbits P((unsigned seg, char *sizedesc));
+
+/* initialise object file handler */
+
+PUBLIC void objinit()
+{
+ modfirst = modlast = NULL;
+ entryfirst = entrylast = NULL;
+ redfirst = redlast = NULL;
+}
+
+/* read all symbol definitions in an object file */
+
+PUBLIC void readsyms(filename, trace)
+char *filename;
+bool_pt trace;
+{
+ char *archentry;
+ long filelength;
+ char filemagic[SARMAG];
+ unsigned long filepos;
+ unsigned modcount;
+
+ if (trace)
+ errtrace(filename, 0);
+ openin(filename); /* input is not open, so position is start */
+ switch ((unsigned) readsize(2))
+ {
+ case OMAGIC:
+ seekin((unsigned long) 0);
+ for (modcount = readfileheader(); modcount-- != 0;)
+ readmodule(filename, (char *) NULL);
+ break;
+ default:
+ seekin((unsigned long) 0);
+ readin(filemagic, sizeof filemagic);
+ if (strncmp(filemagic, ARMAG, sizeof filemagic) != 0)
+ input1error(" has bad magic number");
+ filepos = SARMAG;
+ while ((filelength = readarheader(&archentry)) > 0)
+ {
+ if (trace)
+ errtrace(archentry, 2);
+ filepos += sizeof(struct ar_hdr);
+ for (modcount = readfileheader(); modcount-- != 0;)
+ {
+ readmodule(stralloc(filename), archentry);
+ modlast->textoffset += filepos;
+ }
+ seekin(filepos += roundup(filelength, 2, long));
+ }
+ break;
+ }
+ closein();
+}
+
+/* read archive header and return length */
+
+PRIVATE long readarheader(parchentry)
+char **parchentry;
+{
+ struct ar_hdr arheader;
+ char *endptr;
+ char *nameptr;
+
+ if (readineofok((char *) &arheader, sizeof arheader))
+ return 0;
+ strncpy (*parchentry = nameptr = ourmalloc(sizeof arheader.ar_name + 1),
+ arheader.ar_name, sizeof arheader.ar_name);
+ endptr = nameptr + sizeof arheader.ar_name;
+ do
+ *endptr = 0;
+ while (endptr > nameptr && *--endptr == ' ');
+ return strtoul(arheader.ar_size, (char **) NULL, 0);
+}
+
+/* read and check file header of the object file just opened */
+
+PRIVATE unsigned readfileheader()
+{
+ struct
+ {
+ char magic[2];
+ char count[2]; /* really an int */
+ }
+ fileheader;
+ char filechecksum; /* part of fileheader but would unalign */
+
+ readin((char *) &fileheader, sizeof fileheader);
+ readin(&filechecksum, sizeof filechecksum);
+ if (filechecksum != checksum((char *) &fileheader, sizeof fileheader))
+ input1error(" is not an object file");
+ return c2u2(fileheader.count);
+}
+
+/* read the next module */
+
+PRIVATE void readmodule(filename, archentry)
+char *filename;
+char *archentry;
+{
+ struct symdstruct /* to save parts of symbol before name known */
+ {
+ offset_t dvalue;
+ flags_t dflags;
+ };
+ struct symdstruct *endsymdptr;
+ flags_t flags;
+ unsigned nsymbol;
+ struct symdstruct *symdptr;
+ char *symname;
+ struct symstruct **symparray;
+ struct symstruct *symptr;
+
+ reedmodheader();
+ modlast->filename = filename;
+ modlast->archentry = archentry;
+ nsymbol = readsize(2);
+ symdptr = (struct symdstruct *)
+ ourmalloc(nsymbol * sizeof(struct symdstruct));
+ for (endsymdptr = symdptr + nsymbol; symdptr < endsymdptr; ++symdptr)
+ {
+ readsize(2); /* discard string offset, assume strings seq */
+ symdptr->dflags = flags = readsize(2);
+ symdptr->dvalue = readconvsize((flags & SZ_MASK) >> SZ_SHIFT);
+ /* NB unsigned flags to give logical shift */
+ /* bug in Xenix 2.5 cc causes (int) of the */
+ /* argument to turn flags into an int */
+ }
+ symdptr = (struct symdstruct *)
+ moveup(nsymbol * sizeof(struct symdstruct));
+ modlast->symparray = symparray = (struct symstruct **)
+ ourmalloc((nsymbol + 1) * sizeof(struct symstruct *));
+ symname = readstring(); /* module name */
+ modlast->modname = stralloc(symname); /* likely OK overlapped copy */
+ for (endsymdptr = symdptr + nsymbol; symdptr < endsymdptr;
+ *symparray++ = symptr, release((char *) ++symdptr))
+ {
+ symname = readstring();
+ if ((flags = symdptr->dflags) & (E_MASK | I_MASK) &&
+ (symptr = findsym(symname)) != NULL)
+ {
+ /*
+ weaken segment-checking by letting the maximum segment
+ (SEGM_MASK) mean any segment
+ */
+ if ((symptr->flags & SEGM_MASK) == SEGM_MASK)
+ symptr->flags &= ~(flags_t) SEGM_MASK | (flags & SEGM_MASK);
+ else if ((flags & SEGM_MASK) == SEGM_MASK)
+ flags &= ~(flags_t) SEGM_MASK | (symptr->flags & SEGM_MASK);
+ if ((flags ^ symptr->flags) & (N_MASK | A_MASK | SEGM_MASK))
+ {
+ redefined(symname, " with different segment or relocatability",
+ archentry, symptr->modptr->filename,
+ symptr->modptr->archentry);
+ continue;
+ }
+ if (symptr->flags & E_MASK)
+ {
+ if (flags & E_MASK && redsym(symptr, symdptr->dvalue))
+ redefined(symname, "", archentry, symptr->modptr->filename,
+ symptr->modptr->archentry);
+ continue;
+ }
+ if (flags & I_MASK && symdptr->dvalue <= symptr->value)
+ continue;
+ }
+ else
+ symptr = addsym(symname);
+ symptr->modptr = modlast;
+ symptr->value = symdptr->dvalue;
+ symptr->flags = flags;
+ if (flags & N_MASK)
+ entrysym(symptr);
+ }
+ *symparray = NULL;
+}
+
+/* put symbol on entry symbol list if it is not already */
+
+PUBLIC void entrysym(symptr)
+struct symstruct *symptr;
+{
+ register struct entrylist *elptr;
+
+ for (elptr = entryfirst; elptr != NULL; elptr = elptr->elnext)
+ if (symptr == elptr->elsymptr)
+ return;
+ elptr = (struct entrylist *) ourmalloc(sizeof(struct entrylist));
+ elptr->elnext = NULL;
+ elptr->elsymptr = symptr;
+ if (entryfirst == NULL)
+ entryfirst = elptr;
+ else
+ entrylast->elnext = elptr;
+ entrylast = elptr;
+}
+
+/* read the header of the next module */
+
+PRIVATE void reedmodheader()
+{
+ struct
+ {
+ char htextoffset[4]; /* offset to module text in file */
+ char htextsize[4]; /* size of text (may be 0 for last mod) */
+ char stringssize[2]; /* size of string area */
+ char hclass; /* module class */
+ char revision; /* module revision */
+ }
+ modheader;
+ unsigned seg;
+ unsigned count;
+ char *cptr;
+ struct modstruct *modptr;
+
+ readin((char *) &modheader, sizeof modheader);
+ modptr = (struct modstruct *) ourmalloc(sizeof(struct modstruct));
+ modptr->modnext = NULL;
+ modptr->textoffset = c4u4(modheader.htextoffset);
+ modptr->class = modheader.hclass;
+ readin(modptr->segmaxsize, sizeof modptr->segmaxsize);
+ readin(modptr->segsizedesc, sizeof modptr->segsizedesc);
+ cptr = modptr->segsize;
+ for (seg = 0; seg < NSEG; ++seg)
+ {
+ if ((count = segsizecount(seg, modptr)) != 0)
+ {
+ if (cptr == modptr->segsize)
+ ourmalloc(count - 1); /* 1st byte reserved in struct */
+ else
+ ourmalloc(count);
+ readin(cptr, count);
+ cptr += count;
+ }
+ }
+ if (modfirst == NULL)
+ modfirst = modptr;
+ else
+ modlast->modnext = modptr;
+ modlast = modptr;
+}
+
+PRIVATE bool_pt redsym(symptr, value)
+register struct symstruct *symptr;
+offset_t value;
+{
+ register struct redlist *rlptr;
+ char class;
+
+ if (symptr->modptr->class != (class = modlast->class))
+ for (rlptr = redfirst;; rlptr = rlptr->rlnext)
+ {
+ if (rlptr == NULL)
+ {
+ rlptr = (struct redlist *)
+ ourmalloc(sizeof(struct redlist));
+ rlptr->rlnext = NULL;
+ rlptr->rlsymptr = symptr;
+ if (symptr->modptr->class < class)
+ /* prefer lower class - put other on redlist */
+ {
+ rlptr->rlmodptr = modlast;
+ rlptr->rlvalue = value;
+ }
+ else
+ {
+ rlptr->rlmodptr = symptr->modptr;
+ symptr->modptr = modlast;
+ rlptr->rlvalue = symptr->value;
+ symptr->value = value;
+ }
+ if (redfirst == NULL)
+ redfirst = rlptr;
+ else
+ redlast->rlnext = rlptr;
+ redlast = rlptr;
+ return FALSE;
+ }
+ if (symptr == rlptr->rlsymptr && class == rlptr->rlmodptr->class)
+ break;
+ }
+ return TRUE;
+}
+
+PRIVATE unsigned checksum(string, length)
+char *string;
+unsigned length;
+{
+ unsigned char sum; /* this is a 1-byte checksum */
+
+ for (sum = 0; length-- != 0;)
+ sum += *string++ & 0xFF;
+ return sum;
+}
+
+PUBLIC offset_t readconvsize(countindex)
+unsigned countindex;
+{
+ return readsize(convertsize[countindex]);
+}
+
+PUBLIC offset_t readsize(count)
+unsigned count;
+{
+ char buf[MAX_OFFSET_SIZE];
+
+ if (count == 0)
+ return 0;
+ readin(buf, count);
+ return cntooffset(buf, count);
+}
+
+PRIVATE unsigned segbits(seg, sizedesc)
+unsigned seg;
+char *sizedesc;
+{
+ return 3 & ((unsigned) sizedesc[((NSEG - 1) - seg) / 4] >> (2 * (seg % 4)));
+ /* unsigned to give logical shift */
+}
+
+PUBLIC unsigned segsizecount(seg, modptr)
+unsigned seg;
+struct modstruct *modptr;
+{
+ return convertsize[segbits(seg, modptr->segsizedesc)];
+}
diff --git a/ld/table.c b/ld/table.c
new file mode 100644
index 0000000..5260741
--- /dev/null
+++ b/ld/table.c
@@ -0,0 +1,205 @@
+/* table.c - table-handler module for linker */
+
+/* Copyright (C) 1994 Bruce Evans */
+
+#include "const.h"
+#include "align.h"
+#include "obj.h"
+#include "type.h"
+#include "globvar.h"
+
+#ifdef STDC_HEADERS_MISSING
+void *malloc P((unsigned size));
+#else
+#undef NULL
+#include <stdlib.h>
+#endif
+
+#define GOLDEN 157 /* GOLDEN/HASHTABSIZE approx golden ratio */
+#define HASHTABSIZE 256
+
+PRIVATE struct symstruct *hashtab[HASHTABSIZE]; /* hash table */
+PRIVATE char *tableptr; /* next free spot in catchall table */
+PRIVATE char *tableend; /* ptr to spot after last in table */
+
+FORWARD struct symstruct **gethashptr P((char *name));
+
+/* initialise symbol table */
+
+PUBLIC void syminit()
+{
+ unsigned i;
+
+ for (i = sizeof(int) <= 2 ? 0xE000 : (unsigned) 0x38000;
+ i != 0; i -= 512)
+ if ((tableptr = malloc(i)) != NULL)
+ break;
+ if (tableptr == NULL)
+ outofmemory();
+ tableend = tableptr + i;
+ for (i = 0; i < HASHTABSIZE; i++)
+ hashtab[i] = NULL;
+}
+
+/* add named symbol to end of table - initialise only name and next fields */
+/* caller must not duplicate names of externals for findsym() to work */
+
+PUBLIC struct symstruct *addsym(name)
+char *name;
+{
+ struct symstruct **hashptr;
+ struct symstruct *oldsymptr;
+ struct symstruct *symptr;
+
+ hashptr = gethashptr(name);
+ symptr = *hashptr;
+ while (symptr != NULL)
+ {
+ oldsymptr = symptr;
+ symptr = symptr->next;
+ }
+ align(tableptr);
+ symptr = (struct symstruct *) tableptr;
+ if ((tableptr = symptr->name + (strlen(name) + 1)) > tableend)
+ outofmemory();
+ symptr->modptr = NULL;
+ symptr->next = NULL;
+ if (name != symptr->name)
+ strcpy(symptr->name, name); /* should't happen */
+ if (*hashptr == NULL)
+ *hashptr = symptr;
+ else
+ oldsymptr->next = symptr;
+ return symptr;
+}
+
+/* lookup named symbol */
+
+PUBLIC struct symstruct *findsym(name)
+char *name;
+{
+ struct symstruct *symptr;
+
+ symptr = *gethashptr(name);
+ while (symptr != NULL && (!(symptr->flags & (E_MASK | I_MASK)) ||
+ strcmp(symptr->name, name) != 0))
+ symptr = symptr->next;
+ return symptr;
+}
+
+/* convert name to a hash table ptr */
+
+PRIVATE struct symstruct **gethashptr(name)
+register char *name;
+{
+ register unsigned hashval;
+
+ hashval = 0;
+ while (*name)
+ hashval = hashval * 2 + *name++;
+ return hashtab + ((hashval * GOLDEN) & (HASHTABSIZE - 1));
+
+/*
+
+#asm
+
+GOLDEN EQU 157
+HASHTABSIZE EQU 256
+
+ CLRB can build value here since HASHTABSIZE <= 256
+ LDA ,X
+ BEQ HASHVAL.EXIT
+HASHVAL.LOOP
+ ADDB ,X+
+ LSLB
+ LDA ,X
+ BNE HASHVAL.LOOP
+ RORB
+ LDA #GOLDEN
+ MUL
+HASHVAL.EXIT
+HASHVAL.EXIT
+ LDX #_hashtab
+ ABX discard A - same as taking mod HASHTABSIZE
+ ABX
+#endasm
+
+*/
+
+}
+
+/* move symbol descriptor entries to top of table (no error checking) */
+
+PUBLIC char *moveup(nbytes)
+unsigned nbytes;
+{
+ register char *source;
+ register char *target;
+
+ source = tableptr;
+ target = tableend;
+ while (nbytes--)
+ *--target = *--source;
+ tableptr = source;
+ return tableend = target;
+}
+
+/* our version of malloc */
+
+PUBLIC char *ourmalloc(nbytes)
+unsigned nbytes;
+{
+ char *allocptr;
+
+ align(tableptr);
+ allocptr = tableptr;
+ if ((tableptr += nbytes) > tableend)
+ outofmemory();
+ return allocptr;
+}
+
+/* our version of free (release from bottom of table) */
+
+PUBLIC void ourfree(cptr)
+char *cptr;
+{
+ tableptr = cptr;
+}
+
+/* read string from file into table at offset suitable for next symbol */
+
+PUBLIC char *readstring()
+{
+ int c;
+ char *s;
+ char *start;
+
+ align(tableptr);
+ start = s = ((struct symstruct *) tableptr)->name;
+ while (TRUE)
+ {
+ if (s >= tableend)
+ outofmemory();
+ if ((c = readchar()) < 0)
+ prematureeof();
+ if ((*s++ = c) == 0)
+ return start;
+ }
+ /* NOTREACHED */
+}
+
+/* release from top of table */
+
+PUBLIC void release(cptr)
+char *cptr;
+{
+ tableend = cptr;
+}
+
+/* allocate space for string */
+
+PUBLIC char *stralloc(s)
+char *s;
+{
+ return strcpy(ourmalloc((unsigned) strlen(s) + 1), s);
+}
diff --git a/ld/type.h b/ld/type.h
new file mode 100644
index 0000000..142ea53
--- /dev/null
+++ b/ld/type.h
@@ -0,0 +1,163 @@
+/* type.h - types for linker */
+
+/* Copyright (C) 1994 Bruce Evans */
+
+typedef int bool_pt;
+typedef unsigned char bool_t;
+
+typedef unsigned short u2_t;
+typedef unsigned u2_pt;
+typedef unsigned long u4_t;
+typedef unsigned long u4_pt;
+
+#ifdef HOST_8BIT
+typedef char fastin_t;
+#else
+typedef int fastin_t;
+#endif
+typedef int fastin_pt;
+
+#ifdef OBJ_H /* obj.h is included */
+
+typedef unsigned flags_t; /* unsigned makes shifts logical */
+
+#ifdef LONG_OFFSETS
+typedef unsigned long offset_t;
+#else
+typedef unsigned offset_t;
+#endif
+
+struct entrylist /* list of entry symbols */
+{
+ struct entrylist *elnext; /* next on list */
+ struct symstruct *elsymptr; /* entry on list */
+};
+
+struct modstruct /* module table entry format */
+{
+ char *filename; /* file containing this module */
+ char *archentry; /* name of component file for archives */
+ char *modname; /* name of module */
+ unsigned long textoffset; /* offset to module text in file */
+ char class; /* class of module */
+ char loadflag; /* set if module to be loaded */
+ char segmaxsize[NSEG / 4]; /* |SF|SE|..|S0|, 2 bits for seg max size */
+ /* 00 = 1, 01 = 2, 10 = 3, 11 = 4 */
+ char segsizedesc[NSEG / 4]; /* |SF|SE|..|S0|, 2 bits for #bytes for size */
+ /* 00 = 0, 01 = 1, 10 = 2, 11 = 4 */
+ struct symstruct **symparray; /* ^array of ptrs to referenced syms */
+ struct modstruct *modnext; /* next module in order of initial reading */
+ char segsize[1]; /* up to 64 size bytes begin here */
+}; /* careful with sizeof( struct modstruct )!! */
+
+struct redlist /* list of redefined (exported) symbols */
+{
+ struct redlist *rlnext; /* next on list */
+ struct symstruct *rlsymptr; /* to symbol with same name, flags */
+ struct modstruct *rlmodptr; /* module for this redefinition */
+ offset_t rlvalue; /* value for this redefinition */
+};
+
+struct symstruct /* symbol table entry format */
+{
+ struct modstruct *modptr; /* module where symbol is defined */
+ offset_t value; /* value of symbol */
+ flags_t flags; /* see below (unsigned makes shifts logical) */
+ struct symstruct *next; /* next symbol with same hash value */
+ char name[1]; /* name is any string beginning here */
+}; /* don't use sizeof( struct symstruct )!! */
+
+#endif /* obj.h is included */
+
+/* prototypes */
+
+#ifdef __STDC__
+#define P(x) x
+#else
+#define P(x) ()
+#endif
+
+/* dump.c */
+void dumpmods P((void));
+void dumpsyms P((void));
+
+/* io.c */
+void ioinit P((char *progname));
+void closein P((void));
+void closeout P((void));
+void errtrace P((char *name, int level));
+void executable P((void));
+void flusherr P((void));
+void openin P((char *filename));
+void openout P((char *filename));
+void putstr P((char *message));
+#ifdef OBJ_H
+void put08x P((offset_t num));
+void put08lx P((offset_t num));
+#endif
+void putbstr P((unsigned width, char *str));
+void putbyte P((int ch));
+int readchar P((void));
+void readin P((char *buf, unsigned count));
+bool_pt readineofok P((char *buf, unsigned count));
+void seekin P((unsigned long offset));
+void seekout P((unsigned long offset));
+void seektrel P((unsigned long offset));
+void writechar P((int c));
+void writedrel P((char *buf, unsigned count));
+void writeout P((char *buf, unsigned count));
+void writetrel P((char *buf, unsigned count));
+void fatalerror P((char *message));
+void inputerror P((char *message));
+void input1error P((char *message));
+void outofmemory P((void));
+void prematureeof P((void));
+void redefined P((char *name, char *message, char *archentry,
+ char *deffilename, char *defarchentry));
+void reserved P((char *name));
+#ifdef OBJ_H
+void size_error P((int seg, offset_t count, offset_t size));
+#endif
+void undefined P((char *name));
+void usage P((void));
+void use_error P((char *message));
+
+/* ld.c */
+int main P((int argc, char **argv));
+
+/* readobj.c */
+void objinit P((void));
+void readsyms P((char *filename, bool_pt trace));
+#ifdef OBJ_H
+void entrysym P((struct symstruct *symptr));
+offset_t readconvsize P((unsigned countindex));
+offset_t readsize P((unsigned count));
+unsigned segsizecount P((unsigned seg, struct modstruct *modptr));
+#endif
+
+/* table.c */
+void syminit P((void));
+struct symstruct *addsym P((char *name));
+struct symstruct *findsym P((char *name));
+char *moveup P((unsigned nbytes));
+char *ourmalloc P((unsigned nbytes));
+void ourfree P((char *cptr));
+char *readstring P((void));
+void release P((char *cptr));
+char *stralloc P((char *s));
+
+/* typeconvert.c */
+u2_pt c2u2 P((char *buf));
+u4_t c4u4 P((char *buf));
+u2_pt cnu2 P((char *buf, unsigned count));
+u4_t cnu4 P((char *buf, unsigned count));
+void u2c2 P((char *buf, u2_pt offset));
+void u4c4 P((char *buf, u4_t offset));
+void u2cn P((char *buf, u2_pt offset, unsigned count));
+void u4cn P((char *buf, u4_t offset, unsigned count));
+bool_pt typeconv_init P((bool_pt big_endian, bool_pt long_big_endian));
+
+/* writebin.c */
+void writebin P((char *outfilename, bool_pt argsepid, bool_pt argbits32,
+ bool_pt argstripflag, bool_pt arguzp));
+void linksyms P((bool_pt argreloc_output));
diff --git a/ld/typeconv.c b/ld/typeconv.c
new file mode 100644
index 0000000..82dafdd
--- /dev/null
+++ b/ld/typeconv.c
@@ -0,0 +1,536 @@
+/* typeconv.c - convert between char arrays and unsigneds */
+
+/* Copyright (C) 1994 Bruce Evans */
+
+/*
+ c2u2(): 2 byte array to 2 byte unsigned
+ c4u4(): 4 byte array to 4 byte unsigned
+ cnu2(): n byte array to 2 byte unsigned
+ cnu4(): n byte array to 4 byte unsigned
+ u2c2(): 2 byte unsigned to 2 byte array
+ u2cn(): 2 byte unsigned to n byte array
+ u4c4(): 4 byte unsigned to 4 byte array
+ u4cn(): 4 byte unsigned to n byte array
+ typeconv_init: (re)initialise for given byte order.
+ Default is no swapping, but the initialisation should be done
+ anyway to provide some validity checks (returns FALSE if error).
+
+ Not provided:
+ c2u4(), c4u2(), u2c4(), u4c2().
+ Each of these is best done by truncating or extending a return value
+ or argument to the appropiate fixed-count function.
+ c4u2() has too many cases to do in-line conveniently, and the others
+ are hardly more efficient when done in-line.
+
+ 4 byte orderings for both char arrays and unsigneds are supported:
+ 0123 - little-endian
+ 3210 - big-endian
+ 2301 - little-endian with long words big-endian (pdp11)
+ 1032 - big-endian with long words little_endian (who knows?)
+
+ The unsigned's byte order is that of the machine on which these
+ routines are running.
+ It is determined at run time initialisation since the compiler/
+ preprocessor is too dumb to tell us at compile time.
+*/
+
+#include "const.h"
+#include "type.h"
+#include "globvar.h"
+
+FORWARD u2_pt c2u2_00 P((char *buf));
+FORWARD u4_pt c4u4_00 P((char *buf));
+FORWARD u2_pt c2u2_ss P((char *buf));
+FORWARD u4_pt c4u4_ss P((char *buf));
+FORWARD u4_pt c4u4_s0 P((char *buf));
+FORWARD u4_pt c4u4_0s P((char *buf));
+FORWARD void u2c2_00 P((char *buf, u2_pt offset));
+FORWARD void u4c4_00 P((char *buf, u4_t offset));
+FORWARD void u2c2_ss P((char *buf, u2_pt offset));
+FORWARD void u4c4_ss P((char *buf, u4_t offset));
+FORWARD void u4c4_s0 P((char *buf, u4_t offset));
+FORWARD void u4c4_0s P((char *buf, u4_t offset));
+
+PRIVATE u2_pt (*pc2u2) P((char *buf)) = c2u2_00;
+PRIVATE u4_pt (*pc4u4) P((char *buf)) = c4u4_00;
+PRIVATE void (*pu2c2) P((char *buf, u2_pt offset)) = u2c2_00;
+PRIVATE void (*pu4c4) P((char *buf, u4_t offset)) = u4c4_00;
+
+/* === char arrays to unsigneds === */
+
+/* no bytes swapped, longwinded to avoid alignment problems */
+
+PRIVATE u2_pt c2u2_00(buf)
+register char *buf;
+{
+ u2_t offset;
+
+ ((char *) &offset)[0] = buf[0];
+ ((char *) &offset)[1] = buf[1];
+ return offset;
+}
+
+PRIVATE u4_pt c4u4_00(buf)
+register char *buf;
+{
+ u4_t offset;
+
+ ((char *) &offset)[0] = buf[0];
+ ((char *) &offset)[1] = buf[1];
+ ((char *) &offset)[2] = buf[2];
+ ((char *) &offset)[3] = buf[3];
+ return offset;
+}
+
+/* straight swapping for little-endian to big-endian and vice versa */
+
+PRIVATE u2_pt c2u2_ss(buf)
+register char *buf;
+{
+ u2_t offset;
+
+ ((char *) &offset)[0] = buf[1];
+ ((char *) &offset)[1] = buf[0];
+ return offset;
+}
+
+PRIVATE u4_pt c4u4_ss(buf)
+register char *buf;
+{
+ u4_t offset;
+
+ ((char *) &offset)[0] = buf[3];
+ ((char *) &offset)[1] = buf[2];
+ ((char *) &offset)[2] = buf[1];
+ ((char *) &offset)[3] = buf[0];
+ return offset;
+}
+
+/* wierd swapping for different-endian u2's, same-endian u4's */
+
+PRIVATE u4_pt c4u4_s0(buf)
+register char *buf;
+{
+ u4_t offset;
+
+ ((char *) &offset)[0] = buf[1];
+ ((char *) &offset)[1] = buf[0];
+ ((char *) &offset)[2] = buf[3];
+ ((char *) &offset)[3] = buf[2];
+ return offset;
+}
+
+/* very wierd swapping for same-endian u2's, different-endian u4's */
+
+PRIVATE u4_pt c4u4_0s(buf)
+register char *buf;
+{
+ u4_t offset;
+
+ ((char *) &offset)[0] = buf[2];
+ ((char *) &offset)[1] = buf[3];
+ ((char *) &offset)[2] = buf[0];
+ ((char *) &offset)[3] = buf[1];
+ return offset;
+}
+
+/* === entry points === */
+
+PUBLIC u2_pt c2u2(buf)
+char *buf;
+{
+ return (*pc2u2) (buf);
+}
+
+PUBLIC u4_t c4u4(buf)
+char *buf;
+{
+ return (*pc4u4) (buf);
+}
+
+PUBLIC u2_pt cnu2(buf, count)
+char *buf;
+unsigned count;
+{
+ switch (count)
+ {
+ case 1:
+ return buf[0] & 0xFF;
+ case 2:
+ return (*pc2u2) (buf);
+ case 4:
+ return (u2_pt) (*pc4u4) (buf);
+ default:
+ return 0;
+ }
+}
+
+PUBLIC u4_t cnu4(buf, count)
+char *buf;
+unsigned count;
+{
+ switch (count)
+ {
+ case 1:
+ return buf[0] & 0xFF;
+ case 2:
+ return (*pc2u2) (buf);
+ case 4:
+ return (*pc4u4) (buf);
+ default:
+ return 0;
+ }
+}
+
+/* === unsigneds to char arrays === */
+
+/* no bytes swapped, longwinded to avoid alignment problems */
+
+PRIVATE void u2c2_00(buf, offset)
+register char *buf;
+u2_pt offset;
+{
+
+ buf[0] = ((char *) &offset)[0];
+ buf[1] = ((char *) &offset)[1];
+}
+
+PRIVATE void u4c4_00(buf, offset)
+register char *buf;
+u4_t offset;
+{
+ buf[0] = ((char *) &offset)[0];
+ buf[1] = ((char *) &offset)[1];
+ buf[2] = ((char *) &offset)[2];
+ buf[3] = ((char *) &offset)[3];
+}
+
+/* straight swapping for little-endian to big-endian and vice versa */
+
+PRIVATE void u2c2_ss(buf, offset)
+register char *buf;
+u2_pt offset;
+{
+ u2_t offset2;
+
+ offset2 = offset;
+ buf[0] = ((char *) &offset2)[1];
+ buf[1] = ((char *) &offset2)[0];
+}
+
+PRIVATE void u4c4_ss(buf, offset)
+register char *buf;
+u4_t offset;
+{
+ buf[0] = ((char *) &offset)[3];
+ buf[1] = ((char *) &offset)[2];
+ buf[2] = ((char *) &offset)[1];
+ buf[3] = ((char *) &offset)[0];
+}
+
+/* wierd swapping for different-endian u2's, same-endian u4's */
+
+PRIVATE void u4c4_s0(buf, offset)
+register char *buf;
+u4_t offset;
+{
+ buf[0] = ((char *) &offset)[1];
+ buf[1] = ((char *) &offset)[0];
+ buf[2] = ((char *) &offset)[3];
+ buf[3] = ((char *) &offset)[2];
+}
+
+/* very wierd swapping for same-endian u2's, different-endian u4's */
+
+PRIVATE void u4c4_0s(buf, offset)
+register char *buf;
+u4_t offset;
+{
+ buf[0] = ((char *) &offset)[2];
+ buf[1] = ((char *) &offset)[3];
+ buf[2] = ((char *) &offset)[0];
+ buf[3] = ((char *) &offset)[1];
+}
+
+/* === entry points === */
+
+PUBLIC void u2c2(buf, offset)
+register char *buf;
+u2_pt offset;
+{
+ (*pu2c2) (buf, offset);
+}
+
+PUBLIC void u4c4(buf, offset)
+register char *buf;
+u4_t offset;
+{
+ (*pu4c4) (buf, offset);
+}
+
+PUBLIC void u2cn(buf, offset, count)
+register char *buf;
+u2_pt offset;
+unsigned count;
+{
+ switch (count)
+ {
+ case 1:
+ buf[0] = (char) offset;
+ return;
+ case 2:
+ (*pu2c2) (buf, offset);
+ return;
+ case 4:
+ (*pu4c4) (buf, (u4_t) offset);
+ return;
+ }
+}
+
+PUBLIC void u4cn(buf, offset, count)
+register char *buf;
+u4_t offset;
+unsigned count;
+{
+ switch (count)
+ {
+ case 1:
+ buf[0] = (char) offset;
+ return;
+ case 2:
+ (*pu2c2) (buf, (u2_pt) (u2_t) offset);
+ return;
+ case 4:
+ (*pu4c4) (buf, offset);
+ return;
+ }
+}
+
+/* initialise type conversion, return FALSE if it cannot be handled */
+
+PUBLIC bool_pt typeconv_init(big_endian, long_big_endian)
+bool_pt big_endian;
+bool_pt long_big_endian;
+{
+ u2_pt conv2;
+ u4_pt conv4;
+ char *conv2ptr;
+ char *conv4ptr;
+
+ if (sizeof(u2_t) != 2 || sizeof(u4_t) != 4)
+ /* dumb preprocessor's don't accept sizeof in #if expressions */
+ return FALSE;
+
+ if (big_endian)
+ {
+ conv2ptr = (conv4ptr = "\1\2\3\4") + 2;
+ if (!long_big_endian)
+ conv4ptr = "\3\4\1\2";
+ }
+ else
+ {
+ conv2ptr = conv4ptr = "\4\3\2\1";
+ if (long_big_endian)
+ conv4ptr = "\2\1\4\3";
+ }
+ conv2 = c2u2_00(conv2ptr);
+ conv4 = c4u4_00(conv4ptr);
+ if (conv2 == 0x0304)
+ {
+ pc2u2 = c2u2_00;
+ pc4u4 = c4u4_00;
+ pu2c2 = u2c2_00;
+ pu4c4 = u4c4_00;
+ if (conv4 == 0x03040102L)
+ {
+ pc4u4 = c4u4_0s;
+ pu4c4 = u4c4_0s;
+ }
+ else if (conv4 != 0x01020304L)
+ return FALSE;
+ }
+ else if (conv2 == 0x0403)
+ {
+ pc2u2 = c2u2_ss;
+ pc4u4 = c4u4_ss;
+ pu2c2 = u2c2_ss;
+ pu4c4 = u4c4_ss;
+ if (conv4 == 0x02010403L)
+ {
+ pc4u4 = c4u4_s0;
+ pu4c4 = u4c4_s0;
+ }
+ else if (conv4 != 0x04030201L)
+ return FALSE;
+ }
+ else
+ return FALSE;
+ return TRUE;
+}
+
+#ifdef DEBUG_TYPECONV
+
+main()
+{
+ char *source;
+ char target[4];
+ u2_t u2;
+ u2_t u2a;
+ u4_t u4;
+ u4_t u4a;
+
+ printf("%u\n", typeconv_init(FALSE, FALSE));
+ printf("%u\n", typeconv_init(FALSE, TRUE));
+ printf("%u\n", typeconv_init(TRUE, FALSE));
+ printf("%u\n", typeconv_init(TRUE, TRUE));
+
+ typeconv_init(FALSE, FALSE);
+ source = "\4\3\2\1";
+
+ target[0] = 0;
+ target[1] = 0;
+ u2 = cnu2(source, 2);
+ u2cn(target, u2, 2);
+ if (strncmp(source, target, 2))
+ printf("oops9\n");
+
+ target[0] = 0;
+ target[1] = 0;
+ u4a = cnu4(source, 2);
+ u4cn(target, u4a, 2);
+ if (strncmp(source, target, 2))
+ printf("oops10\n");
+
+ target[0] = 0;
+ target[1] = 0;
+ target[2] = 0;
+ target[3] = 0;
+ u2a = cnu2(source, 4);
+ u2cn(target, u2a, 4);
+ if (strncmp(target, "\4\3\0\0", 4))
+ printf("oops11\n");
+
+ target[0] = 0;
+ target[1] = 0;
+ target[2] = 0;
+ target[3] = 0;
+ u4 = cnu4(source, 4);
+ u4cn(target, u4, 4);
+ if (strncmp(source, target, 4))
+ printf("oops12\n");
+
+ printf("%04x %04x %08lx %08lx\n", u2, u2a, u4, u4a);
+
+ typeconv_init(FALSE, TRUE);
+ source = "\2\1\4\3";
+
+ target[0] = 0;
+ target[1] = 0;
+ u2 = cnu2(source + 2, 2);
+ u2cn(target, u2, 2);
+ if (strncmp(source + 2, target, 2))
+ printf("oops13\n");
+
+ target[0] = 0;
+ target[1] = 0;
+ u4a = cnu4(source + 2, 2);
+ u4cn(target, u4a, 2);
+ if (strncmp(source + 2, target, 2))
+ printf("oops14\n");
+
+ target[0] = 0;
+ target[1] = 0;
+ target[2] = 0;
+ target[3] = 0;
+ u2a = cnu2(source, 4);
+ u2cn(target, u2a, 4);
+ if (strncmp(target, "\0\0\4\3", 4))
+ printf("oops15\n");
+
+ target[0] = 0;
+ target[1] = 0;
+ target[2] = 0;
+ target[3] = 0;
+ u4 = cnu4(source, 4);
+ u4cn(target, u4, 4);
+ if (strncmp(source, target, 4))
+ printf("oops16\n");
+
+ printf("%04x %04x %08lx %08lx\n", u2, u2a, u4, u4a);
+
+ typeconv_init(TRUE, FALSE);
+ source = "\3\4\1\2";
+
+ target[0] = 0;
+ target[1] = 0;
+ u2 = cnu2(source, 2);
+ u2cn(target, u2, 2);
+ if (strncmp(source, target, 2))
+ printf("oops5\n");
+
+ target[0] = 0;
+ target[1] = 0;
+ u4a = cnu4(source, 2);
+ u4cn(target, u4a, 2);
+ if (strncmp(source, target, 2))
+ printf("oops6\n");
+
+ target[0] = 0;
+ target[1] = 0;
+ target[2] = 0;
+ target[3] = 0;
+ u2a = cnu2(source, 4);
+ u2cn(target, u2a, 4);
+ if (strncmp(target, "\3\4\0\0", 4))
+ printf("oops7\n");
+
+ target[0] = 0;
+ target[1] = 0;
+ target[2] = 0;
+ target[3] = 0;
+ u4 = cnu4(source, 4);
+ u4cn(target, u4, 4);
+ if (strncmp(source, target, 4))
+ printf("oops8\n");
+
+ printf("%04x %04x %08lx %08lx\n", u2, u2a, u4, u4a);
+
+ typeconv_init(TRUE, TRUE);
+ source = "\1\2\3\4";
+
+ target[0] = 0;
+ target[1] = 0;
+ u2 = cnu2(source + 2, 2);
+ u2cn(target, u2, 2);
+ if (strncmp(source + 2, target, 2))
+ printf("oops1\n");
+
+ target[0] = 0;
+ target[1] = 0;
+ u4a = cnu4(source + 2, 2);
+ u4cn(target, u4a, 2);
+ if (strncmp(source + 2, target, 2))
+ printf("oops2\n");
+
+ target[0] = 0;
+ target[1] = 0;
+ target[2] = 0;
+ target[3] = 0;
+ u2a = cnu2(source, 4);
+ u2cn(target, u2a, 4);
+ if (strncmp(target, "\0\0\3\4", 4))
+ printf("oops3\n");
+
+ target[0] = 0;
+ target[1] = 0;
+ target[2] = 0;
+ target[3] = 0;
+ u4 = cnu4(source, 4);
+ u4cn(target, u4, 4);
+ if (strncmp(source, target, 4))
+ printf("oops4\n");
+
+ printf("%04x %04x %08lx %08lx\n", u2, u2a, u4, u4a);
+}
+
+#endif /* DEBUG_TYPECONV */
diff --git a/ld/writebin.c b/ld/writebin.c
new file mode 100644
index 0000000..a95280c
--- /dev/null
+++ b/ld/writebin.c
@@ -0,0 +1,989 @@
+extern long text_base_address;
+#define btextoffset text_base_address
+static long bdataoffset;
+#define page_size() 4096
+
+/* writebin.c - write binary file for linker */
+
+/* Copyright (C) 1994 Bruce Evans */
+
+#ifdef A_OUT_H
+# include A_OUT_H
+#else
+# ifdef BSD_A_OUT
+# ifdef STANDARD_GNU_A_OUT
+# include <a.out.h>
+# define RELOC_INFO_SIZE 8 /* unportable bitfields - bcc doesn't pack */
+# else
+# include "bsd-a.out.h"
+# define RELOC_INFO_SIZE (sizeof (struct relocation_info))
+# endif
+# define C_EXT N_EXT
+# define C_STAT 0
+# define n_was_name n_un.n_name
+# define n_was_numaux n_other
+# define n_was_other n_numaux
+# define n_was_sclass n_type
+# define n_was_strx n_un.n_strx
+# define n_was_type n_desc
+# else /* not BSD_A_OUT */
+# include "a.out.h" /* maybe local copy of <a.out.h> for X-link */
+# define n_was_name n_name
+# define n_was_numaux n_numaux
+# define n_was_other n_other
+# define n_was_sclass n_sclass
+# define n_was_strx n_value
+# define n_was_type n_type
+# endif /* BSD_A_OUT */
+#endif
+
+#include "const.h"
+#include "obj.h"
+#include "type.h"
+#undef EXTERN
+#include "globvar.h"
+
+#ifdef STDC_HEADERS_MISSING
+void *memset P((void *s, int c, unsigned n));
+#else
+#undef NULL
+#include <string.h>
+#endif
+
+#ifdef EDOS
+# define FILEHEADERLENGTH 0
+#endif
+#ifdef MINIX
+# ifdef BSD_A_OUT
+# ifdef STANDARD_GNU_A_OUT
+# define FILEHEADERLENGTH 32
+# else
+# define FILEHEADERLENGTH 48
+# endif
+# else
+# define FILEHEADERLENGTH A_MINHDR
+ /* part of header not counted in offsets */
+# endif
+#endif
+#define DPSEG 2
+
+#define CM_MASK 0xC0
+#define MODIFY_MASK 0x3F
+#define S_MASK 0x04
+#define OF_MASK 0x03
+
+#define CM_SPECIAL 0
+#define CM_ABSOLUTE 0x40
+#define CM_OFFSET_RELOC 0x80
+#define CM_SYMBOL_RELOC 0xC0
+
+#define CM_EOT 0
+#define CM_BYTE_SIZE 1
+#define CM_WORD_SIZE 2
+#define CM_LONG_SIZE 3
+#define CM_1_SKIP 17
+#define CM_2_SKIP 18
+#define CM_4_SKIP 19
+#define CM_0_SEG 32
+
+#define ABS_TEXT_MAX 64
+
+#define offsetof(struc, mem) ((int) &((struc *) 0)->mem)
+#define memsizeof(struc, mem) sizeof(((struc *) 0)->mem)
+
+PRIVATE bool_t bits32; /* nonzero for 32-bit executable */
+PRIVATE offset_t combase[NSEG]; /* bases of common parts of segments */
+PRIVATE offset_t comsz[NSEG]; /* sizes of common parts of segments */
+PRIVATE fastin_t curseg; /* current segment, 0 to $F */
+PRIVATE offset_t edataoffset; /* end of data */
+PRIVATE offset_t endoffset; /* end of bss */
+PRIVATE offset_t etextoffset; /* end of text */
+PRIVATE offset_t etextpadoff; /* end of padded text */
+#ifdef BSD_A_OUT
+PRIVATE unsigned ndreloc; /* number of data relocations */
+#endif
+PRIVATE unsigned nsym; /* number of symbols written */
+#ifdef BSD_A_OUT
+PRIVATE unsigned ntreloc; /* number of text relocations */
+PRIVATE bool_t reloc_output; /* nonzero to leave reloc info in output */
+#endif
+PRIVATE unsigned relocsize; /* current relocation size 1, 2 or 4 */
+PRIVATE offset_t segadj[NSEG]; /* adjusts (file offset - seg offset) */
+ /* depends on zero init */
+PRIVATE offset_t segbase[NSEG]; /* bases of data parts of segments */
+PRIVATE char segboundary[9] = "__seg0DH";
+ /* name of seg boundary __seg0DL to __segfCH */
+PRIVATE offset_t segpos[NSEG]; /* segment positions for current module */
+PRIVATE offset_t segsz[NSEG]; /* sizes of data parts of segments */
+ /* depends on zero init */
+PRIVATE bool_t sepid; /* nonzero for separate I & D */
+PRIVATE bool_t stripflag; /* nonzero to strip symbols */
+PRIVATE offset_t spos; /* position in current seg */
+PRIVATE bool_t uzp; /* nonzero for unmapped zero page */
+
+#ifdef EDOS
+FORWARD unsigned binheaderlength P((char *commandname));
+FORWARD char *idconvert P((struct entrylist *elptr, char *commandname));
+#endif
+FORWARD void linkmod P((struct modstruct *modptr));
+FORWARD void linkrefs P((struct modstruct *modptr));
+FORWARD void padmod P((struct modstruct *modptr));
+FORWARD void setsym P((char *name, offset_t value));
+FORWARD void symres P((char *name));
+FORWARD void setseg P((fastin_pt newseg));
+FORWARD void skip P((unsigned countsize));
+#ifdef EDOS
+FORWARD void writeheader P((char *commandname));
+#else
+FORWARD void writeheader P((void));
+#endif
+FORWARD void writenulls P((offset_t count));
+
+/* link all symbols connected to entry symbols */
+
+PUBLIC void linksyms(argreloc_output)
+bool_pt argreloc_output;
+{
+ char needlink;
+ struct entrylist *elptr;
+ struct modstruct *modptr;
+ struct symstruct *symptr;
+
+#ifdef BSD_A_OUT
+ reloc_output = argreloc_output;
+ if (argreloc_output)
+ {
+ if (modfirst->modnext != NULL)
+ fatalerror("relocatable output only works for one input file");
+ for (modptr = modfirst; modptr != NULL; modptr = modptr->modnext)
+ modptr->loadflag = TRUE;
+ return;
+ }
+#endif
+ if ((symptr = findsym("_main")) != NULL)
+ entrysym(symptr);
+ do
+ {
+ if ((elptr = entryfirst) == NULL)
+ fatalerror("no start symbol");
+ for (modptr = modfirst; modptr != NULL; modptr = modptr->modnext)
+ modptr->loadflag = FALSE;
+ for (; elptr != NULL; elptr = elptr->elnext)
+ linkrefs(elptr->elsymptr->modptr);
+ if ((symptr = findsym("start")) != NULL)
+ linkrefs(symptr->modptr);
+ needlink = FALSE;
+ {
+ struct redlist *prlptr;
+ struct redlist *rlptr;
+
+ for (rlptr = redfirst; rlptr != NULL;
+ rlptr = (prlptr = rlptr)->rlnext)
+ if (rlptr->rlmodptr->loadflag &&
+ rlptr->rlmodptr->class > rlptr->rlsymptr->modptr->class)
+ {
+ rlptr->rlsymptr->modptr = rlptr->rlmodptr;
+ rlptr->rlsymptr->value = rlptr->rlvalue;
+ if (rlptr == redfirst)
+ redfirst = rlptr->rlnext;
+ else
+ prlptr->rlnext = rlptr->rlnext;
+ needlink = TRUE;
+ }
+ }
+ }
+ while (needlink);
+}
+
+/* write binary file */
+
+PUBLIC void writebin(outfilename, argsepid, argbits32, argstripflag, arguzp)
+char *outfilename;
+bool_pt argsepid;
+bool_pt argbits32;
+bool_pt argstripflag;
+bool_pt arguzp;
+{
+ char buf4[4];
+#ifdef EDOS
+ char *commandname;
+#endif
+ char *cptr;
+ struct nlist extsym;
+ flags_t flags;
+ struct modstruct *modptr;
+ fastin_t seg;
+ unsigned sizecount;
+ offset_t tempoffset;
+
+ sepid = argsepid;
+ bits32 = argbits32;
+ stripflag = argstripflag;
+#ifdef BSD_A_OUT
+ uzp = arguzp && !reloc_output;
+#else
+ uzp = arguzp;
+#endif
+ if (uzp)
+ {
+ if (btextoffset == 0)
+ btextoffset = page_size();
+ if (bdataoffset == 0 && sepid)
+ bdataoffset = page_size();
+ }
+#ifdef EDOS
+ commandname = stralloc(outfilename);
+ if ((cptr = strchr(commandname, ':')) != NULL)
+ commandname = cptr + 1;
+ if ((cptr = strrchr(commandname, '.')) != NULL)
+ *cptr = 0;
+#endif
+
+ /* reserve special symbols use curseg to pass parameter to symres() */
+ for (curseg = 0; curseg < NSEG; ++curseg)
+ {
+ segboundary[5] = hexdigit[curseg]; /* to __segX?H */
+ segboundary[6] = 'D';
+ symres(segboundary); /* __segXDH */
+ segboundary[7] = 'L';
+ symres(segboundary); /* __segXDL */
+ segboundary[6] = 'C';
+ symres(segboundary); /* __segXCL */
+ segboundary[7] = 'H';
+ symres(segboundary); /* __segXCH */
+ }
+#ifdef EDOS
+ curseg = 0; /* data seg, s.b. variable */
+#else
+ curseg = 3;
+#endif
+ symres("__edata");
+ symres("__end");
+ curseg = 0; /* text seg, s.b. variable */
+ symres("__etext");
+
+ /* calculate segment and common sizes (sum over loaded modules) */
+ /* use zero init of segsz[] */
+ /* also relocate symbols relative to starts of their segments */
+ for (modptr = modfirst; modptr != NULL; modptr = modptr->modnext)
+ if (modptr->loadflag)
+ {
+ register struct symstruct **symparray;
+ register struct symstruct *symptr;
+
+ for (symparray = modptr->symparray;
+ (symptr = *symparray) != NULL; ++symparray)
+ if (symptr->modptr == modptr && !(symptr->flags & A_MASK))
+ {
+ if (!(symptr->flags & (I_MASK | SA_MASK)))
+ {
+ /* relocate by offset of module in segment later */
+ /* relocate by offset of segment in memory special */
+ /* symbols get relocated improperly */
+ symptr->value += segsz[symptr->flags & SEGM_MASK];
+ }
+ else if (symptr->value == 0)
+ {
+#ifdef BSD_A_OUT
+ if (!reloc_output)
+#endif
+ undefined(symptr->name);
+ }
+ else
+ {
+#ifdef BSD_A_OUT
+#if 0
+ if (!reloc_output)
+#else
+ if (!reloc_output || !(symptr->flags & I_MASK))
+#endif
+#endif
+ {
+ tempoffset = roundup(symptr->value, 4, offset_t);
+ /* temp kludge quad alignment for 386 */
+ symptr->value = comsz[seg = symptr->flags & SEGM_MASK];
+ comsz[seg] += tempoffset;
+ }
+ if (!(symptr->flags & SA_MASK))
+ symptr->flags |= C_MASK;
+ }
+ }
+ for (seg = 0, cptr = modptr->segsize; seg < NSEG; ++seg)
+ {
+ segsz[seg] += cntooffset(cptr,
+ sizecount = segsizecount((unsigned) seg, modptr));
+#ifndef EDOS
+
+ /* adjust sizes to even to get quad boundaries */
+ /* this should be specifiable dynamically */
+ segsz[seg] = roundup(segsz[seg], 4, offset_t);
+ comsz[seg] = roundup(comsz[seg], 4, offset_t);
+#endif
+ cptr += sizecount;
+ }
+ }
+
+ /* calculate seg positions now their sizes are known */
+ /* temp use fixed order 0D 0C 1D 1C 2D 2C ... */
+ /* assume seg 0 is text and rest are data */
+#ifdef EDOS
+ if (btextoffset == 0)
+ btextoffset = binheaderlength(commandname);
+#endif
+ segpos[0] = segbase[0] = spos = btextoffset;
+ combase[0] = segbase[0] + segsz[0];
+ segadj[1] = segadj[0] = -btextoffset;
+ etextpadoff = etextoffset = combase[0] + comsz[0];
+ if (sepid)
+ {
+ etextpadoff = roundup(etextoffset, 0x10, offset_t);
+ segadj[1] += etextpadoff - bdataoffset;
+ }
+ else if (bdataoffset == 0)
+ bdataoffset = etextpadoff;
+ segpos[1] = segbase[1] = edataoffset = bdataoffset;
+ combase[1] = segbase[1] + segsz[1];
+ for (seg = 2; seg < NSEG; ++seg)
+ {
+ segpos[seg] = segbase[seg] = combase[seg - 1] + comsz[seg - 1];
+ if (seg == DPSEG)
+ {
+ /* temporarily have fixed DP seg */
+ /* adjust if nec so it only spans 1 page */
+ tempoffset = segsz[seg] + comsz[seg];
+ if (tempoffset > 0x100)
+ fatalerror("direct page segment too large");
+ if ((((segbase[seg] + tempoffset) ^ segbase[seg])
+ & ~(offset_t) 0xFF) != 0)
+ segpos[seg] = segbase[seg] = (segbase[seg] + 0xFF)
+ & ~(offset_t) 0xFF;
+ }
+ combase[seg] = segbase[seg] + segsz[seg];
+ segadj[seg] = segadj[seg - 1];
+ }
+
+ /* relocate symbols by offsets of segments in memory */
+ for (modptr = modfirst; modptr != NULL; modptr = modptr->modnext)
+ if (modptr->loadflag)
+ {
+ register struct symstruct **symparray;
+ register struct symstruct *symptr;
+
+ for (symparray = modptr->symparray;
+ (symptr = *symparray) != NULL; ++symparray)
+ if (symptr->modptr == modptr && !(symptr->flags & A_MASK))
+ {
+ if (symptr->flags & (C_MASK | SA_MASK))
+ {
+#ifdef BSD_A_OUT
+#if 0
+ if (!reloc_output)
+#else
+ if (!reloc_output || !(symptr->flags & I_MASK))
+#endif
+#endif
+ symptr->value += combase[symptr->flags & SEGM_MASK];
+ }
+ else
+#ifdef BSD_A_OUT
+ if (!reloc_output || !(symptr->flags & I_MASK))
+#endif
+ symptr->value += segbase[symptr->flags & SEGM_MASK];
+ }
+ }
+
+ /* adjust special symbols */
+ for (seg = 0; seg < NSEG; ++seg)
+ {
+ if (segsz[seg] != 0)
+ /* only count data of nonzero length */
+ edataoffset = segbase[seg] + segsz[seg];
+ segboundary[5] = hexdigit[seg]; /* to __segX?H */
+ segboundary[6] = 'D';
+ setsym(segboundary, (tempoffset = segbase[seg]) + segsz[seg]);
+ /* __segXDH */
+ segboundary[7] = 'L';
+ setsym(segboundary, tempoffset); /* __segXDL */
+ segboundary[6] = 'C';
+ setsym(segboundary, tempoffset = combase[seg]);
+ /* __segXCL */
+ segboundary[7] = 'H';
+ setsym(segboundary, tempoffset + comsz[seg]);
+ /* __segXCH */
+ }
+ setsym("__etext", etextoffset);
+ setsym("__edata", edataoffset);
+ setsym("__end", endoffset = combase[NSEG - 1] + comsz[NSEG - 1]);
+
+ openout(outfilename);
+#ifdef BSD_A_OUT
+ if (reloc_output)
+ seektrel(FILEHEADERLENGTH
+ + (unsigned long) (etextpadoff - btextoffset)
+ + (unsigned long) (edataoffset - bdataoffset));
+#endif
+#ifdef EDOS
+ writeheader(commandname);
+#else
+ writeheader();
+#endif
+ for (modptr = modfirst; modptr != NULL; modptr = modptr->modnext)
+ if (modptr->loadflag)
+ {
+ linkmod(modptr);
+ padmod(modptr);
+ }
+
+ /* dump symbol table */
+#ifdef MINIX
+ if (!stripflag)
+ {
+#ifdef BSD_A_OUT
+ unsigned stringoff;
+#endif
+
+ seekout(FILEHEADERLENGTH
+ + (unsigned long) (etextpadoff - btextoffset)
+ + (unsigned long) (edataoffset - bdataoffset)
+#ifdef BSD_A_OUT
+ + ((unsigned long) ndreloc + ntreloc) * RELOC_INFO_SIZE
+#endif
+ );
+ extsym.n_was_numaux = extsym.n_was_type = 0;
+#ifdef BSD_A_OUT
+ stringoff = 4;
+#endif
+ for (modptr = modfirst; modptr != NULL; modptr = modptr->modnext)
+ if (modptr->loadflag)
+ {
+ register struct symstruct **symparray;
+ register struct symstruct *symptr;
+
+ for (symparray = modptr->symparray;
+ (symptr = *symparray) != NULL; ++symparray)
+ if (symptr->modptr == modptr)
+ {
+#ifdef BSD_A_OUT
+ offtocn((char *) &extsym.n_was_strx,
+ (offset_t) stringoff, 4);
+#else
+ strncpy((char *) &extsym.n_was_name, symptr->name,
+ sizeof extsym.n_was_name);
+#endif
+ u4cn((char *) &extsym.n_value, (u4_t) symptr->value,
+ sizeof extsym.n_value);
+ if ((flags = symptr->flags) & A_MASK)
+ extsym.n_was_sclass = N_ABS;
+ else if (flags & (E_MASK | I_MASK))
+ extsym.n_was_sclass = C_EXT;
+ else
+ extsym.n_was_sclass = C_STAT;
+ if (!(flags & I_MASK) ||
+#ifdef BSD_A_OUT
+ !reloc_output &&
+#endif
+ flags & C_MASK)
+ switch (flags & (A_MASK | SEGM_MASK))
+ {
+ case 0:
+ extsym.n_was_sclass |= N_TEXT;
+ case A_MASK:
+ break;
+ default:
+ if (flags & (C_MASK | SA_MASK))
+ extsym.n_was_sclass |= N_BSS;
+ else
+ extsym.n_was_sclass |= N_DATA;
+ break;
+ }
+ writeout((char *) &extsym, sizeof extsym);
+ ++nsym;
+#ifdef BSD_A_OUT
+ stringoff += strlen(symptr->name) + 1;
+#endif
+ }
+ }
+#ifdef BSD_A_OUT
+ offtocn((char *) &extsym.n_was_strx, (offset_t) stringoff, 4);
+ writeout((char *) &extsym.n_was_strx, 4);
+ for (modptr = modfirst; modptr != NULL; modptr = modptr->modnext)
+ if (modptr->loadflag)
+ {
+ register struct symstruct **symparray;
+ register struct symstruct *symptr;
+
+ for (symparray = modptr->symparray;
+ (symptr = *symparray) != NULL; ++symparray)
+ if (symptr->modptr == modptr)
+ writeout(symptr->name, strlen(symptr->name) + 1);
+ }
+#endif
+ seekout((unsigned long) offsetof(struct exec, a_syms));
+ u4cn(buf4, (u4_t) nsym * sizeof extsym,
+ memsizeof(struct exec, a_syms));
+ writeout(buf4, memsizeof(struct exec, a_syms));
+#ifdef BSD_A_OUT
+ seekout((unsigned long) offsetof(struct exec, a_trsize));
+ u4cn(buf4, (u4_t) ntreloc * RELOC_INFO_SIZE,
+ memsizeof(struct exec, a_trsize));
+ writeout(buf4, memsizeof(struct exec, a_trsize));
+ seekout((unsigned long) offsetof(struct exec, a_drsize));
+ u4cn(buf4, (u4_t) ndreloc * RELOC_INFO_SIZE,
+ memsizeof(struct exec, a_drsize));
+ writeout(buf4, memsizeof(struct exec, a_drsize));
+#endif
+ }
+#endif /* MINIX */
+ closeout();
+#ifdef BSD_A_OUT
+ if (!reloc_output)
+#endif
+ executable();
+}
+
+#ifdef EDOS
+
+PRIVATE unsigned binheaderlength(commandname)
+char *commandname;
+{
+ unsigned count;
+ char *name;
+ struct entrylist *elptr;
+ struct symstruct *startptr;
+
+ count = 2 + 2 + 1; /* len len nul */
+ startptr = findsym("start");
+ for (elptr = entryfirst; elptr != NULL; elptr = elptr->elnext)
+ {
+ name = idconvert(elptr, commandname);
+ count += strlen(name) + 1 + 2 + 1; /* nul off flg */
+ ourfree(name);
+ if (startptr != NULL)
+ count += 6; /* LBSR $xxxx and LBRA $xxxx */
+ }
+ return count;
+}
+
+/* convert name of symbol (entry) list element to a Basic identifier */
+/* new name is built in storage obtained from stralloc() */
+/* the special name _main is converted to the command name first */
+/* copy upper case and numerals, convert lower case to upper, ignore rest */
+
+PRIVATE char *idconvert(elptr, commandname)
+struct entrylist *elptr;
+char *commandname;
+{
+ char *name;
+ char *newname;
+
+ if (strcmp(name = elptr->elsymptr->name, "_main") == 0)
+ name = commandname;
+ newname = stralloc(name);
+ {
+ register char *t;
+ register char *s;
+
+ t = newname;
+ s = name;
+ do
+ {
+ if (*s >= '0' && *s <= '9' || *s >= 'A' && *s <= 'Z')
+ *t++ = *s;
+ if (*s >= 'a' && *s <= 'z')
+ *t++ = *s + ('A' - 'a');
+ }
+ while (*s++);
+ *t = 0;
+ }
+ if (*newname < 'A') /* numeral or null */
+ fatalerror("bad entry name");
+ return newname;
+}
+
+#endif /* EDOS */
+
+PRIVATE void linkmod(modptr)
+struct modstruct *modptr;
+{
+ char buf[ABS_TEXT_MAX];
+ int command;
+ unsigned char modify;
+ offset_t offset;
+ int symbolnum;
+ struct symstruct **symparray;
+ struct symstruct *symptr;
+
+ setseg(0);
+ relocsize = 2;
+ symparray = modptr->symparray;
+ openin(modptr->filename); /* does nothing if already open */
+ seekin(modptr->textoffset);
+ while (TRUE)
+ {
+ if ((command = readchar()) < 0)
+ prematureeof();
+ modify = command & MODIFY_MASK;
+ switch (command & CM_MASK)
+ {
+ case CM_SPECIAL:
+ switch (modify)
+ {
+ case CM_EOT:
+ segpos[curseg] = spos;
+ return;
+ case CM_BYTE_SIZE:
+ relocsize = 1;
+ break;
+ case CM_WORD_SIZE:
+ relocsize = 2;
+ break;
+ case CM_LONG_SIZE:
+#ifdef LONG_OFFSETS
+ relocsize = 4;
+ break;
+#else
+ fatalerror("relocation by long offsets not implemented");
+#endif
+ case CM_1_SKIP:
+ skip(1);
+ break;
+ case CM_2_SKIP:
+ skip(2);
+ break;
+ case CM_4_SKIP:
+ skip(4);
+ break;
+ default:
+ if ((modify -= CM_0_SEG) >= NSEG)
+ inputerror("bad data in");
+ setseg(modify);
+ break;
+ }
+ break;
+ case CM_ABSOLUTE:
+ if (modify == 0)
+ modify = ABS_TEXT_MAX;
+ readin(buf, (unsigned) modify);
+ writeout(buf, (unsigned) modify);
+ spos += (int) modify;
+ break;
+ case CM_OFFSET_RELOC:
+ offset = readsize(relocsize);
+ if (modify & R_MASK)
+ offset -= (spos + relocsize);
+ offtocn(buf, segbase[modify & SEGM_MASK] + offset, relocsize);
+ writeout(buf, relocsize);
+#ifdef BSD_A_OUT
+ if (reloc_output)
+ {
+ u4_t bitfield;
+
+ if (curseg == 0)
+ {
+ ++ntreloc;
+ offtocn(buf, spos, 4);
+ writetrel(buf, 4);
+ }
+ else
+ {
+ ++ndreloc;
+ offtocn(buf, spos - segbase[1], 4);
+ writedrel(buf, 4);
+ }
+ if ((modify & SEGM_MASK) == 0)
+ bitfield = N_TEXT;
+ else
+ bitfield = N_DATA;
+ if (modify & R_MASK)
+ bitfield |= 1L << 24;
+ if (relocsize == 2)
+ bitfield |= 1L << 25;
+ else if (relocsize == 4)
+ bitfield |= 1L << 26;
+ u4cn(buf, bitfield, 4);
+ if (curseg == 0)
+ writetrel(buf, 4);
+ else
+ writedrel(buf, 4);
+ }
+#endif /* BSD_A_OUT */
+ spos += relocsize;
+ break;
+ case CM_SYMBOL_RELOC:
+ symptr = symparray[symbolnum = readconvsize((unsigned)
+ (modify & S_MASK ? 2 : 1))];
+ offset = readconvsize((unsigned) modify & OF_MASK);
+ if (modify & R_MASK)
+ offset -= (spos + relocsize);
+#ifdef BSD_A_OUT
+ if (!reloc_output || !(symptr->flags & I_MASK))
+#endif
+ offset += symptr->value;
+ offtocn(buf, offset, relocsize);
+ writeout(buf, relocsize);
+#ifdef BSD_A_OUT
+ if (reloc_output)
+ {
+ u4_t bitfield;
+
+ if (curseg == 0)
+ {
+ ++ntreloc;
+ offtocn(buf, spos, 4);
+ writetrel(buf, 4);
+ }
+ else
+ {
+ ++ndreloc;
+ offtocn(buf, spos - segbase[1], 4);
+ writedrel(buf, 4);
+ }
+ if (symptr->flags & I_MASK)
+ bitfield = (1L << 27) | symbolnum;
+ else if ((symptr->flags & SEGM_MASK) == 0)
+ bitfield = N_TEXT;
+ else if (symptr->flags & (C_MASK | SA_MASK))
+ bitfield = N_BSS;
+ else
+ bitfield = N_DATA;
+ if (modify & R_MASK)
+ bitfield |= 1L << 24;
+ if (relocsize == 2)
+ bitfield |= 1L << 25;
+ else if (relocsize == 4)
+ bitfield |= 1L << 26;
+ u4cn(buf, bitfield, 4);
+ if (curseg == 0)
+ writetrel(buf, 4);
+ else
+ writedrel(buf, 4);
+ }
+#endif /* BSD_A_OUT */
+ spos += relocsize;
+ }
+ }
+}
+
+PRIVATE void linkrefs(modptr)
+struct modstruct *modptr;
+{
+ register struct symstruct **symparray;
+ register struct symstruct *symptr;
+
+ modptr->loadflag = TRUE;
+ for (symparray = modptr->symparray;
+ (symptr = *symparray) != NULL; ++symparray)
+ if (symptr->modptr->loadflag == FALSE)
+ linkrefs(symptr->modptr);
+}
+
+PRIVATE void padmod(modptr)
+struct modstruct *modptr;
+{
+ offset_t count;
+ fastin_t seg;
+ offset_t size;
+ unsigned sizecount;
+ char *sizeptr;
+
+ for (seg = 0, sizeptr = modptr->segsize; seg < NSEG; ++seg)
+ {
+ size = cntooffset(sizeptr,
+ sizecount = segsizecount((unsigned) seg, modptr));
+ sizeptr += sizecount;
+ if ((count = segpos[seg] - segbase[seg]) != size)
+ size_error(seg, count, size);
+
+ /* pad to quad boundary */
+ /* not padding in-between common areas which sometimes get into file */
+ if ((size = roundup(segpos[seg], 4, offset_t) - segpos[seg]) != 0)
+ {
+ setseg(seg);
+ writenulls(size);
+ segpos[seg] = spos;
+ }
+ segbase[seg] = segpos[seg];
+ }
+}
+
+PRIVATE void setsym(name, value)
+char *name;
+offset_t value;
+{
+ struct symstruct *symptr;
+
+#ifdef BSD_A_OUT
+ if (!reloc_output)
+#endif
+ if ((symptr = findsym(name)) != NULL)
+ symptr->value = value;
+}
+
+PRIVATE void symres(name)
+register char *name;
+{
+ register struct symstruct *symptr;
+
+ if ((symptr = findsym(name)) != NULL)
+ {
+ if ((symptr->flags & SEGM_MASK) == SEGM_MASK)
+ symptr->flags &= ~SEGM_MASK | curseg;
+ if (symptr->flags != (I_MASK | curseg) || symptr->value != 0)
+ reserved(name);
+#ifdef BSD_A_OUT
+ if (!reloc_output)
+#endif
+ symptr->flags = E_MASK | curseg; /* show defined, not common */
+ }
+}
+
+/* set new segment */
+
+PRIVATE void setseg(newseg)
+fastin_pt newseg;
+{
+ if (newseg != curseg)
+ {
+ segpos[curseg] = spos;
+ spos = segpos[curseg = newseg];
+ seekout(FILEHEADERLENGTH + (unsigned long) spos
+ + (unsigned long) segadj[curseg]);
+ }
+}
+
+PRIVATE void skip(countsize)
+unsigned countsize;
+{
+ writenulls((offset_t) readsize(countsize));
+}
+
+#ifdef EDOS
+
+PRIVATE void writeheader(commandname)
+char *commandname;
+{
+ char buf[MAX_OFFSET_SIZE];
+ offset_t offset;
+ unsigned headlength;
+ char *name;
+ struct entrylist *elptr;
+ struct symstruct *startptr;
+
+ headlength = binheaderlength(commandname);
+ for (elptr = entryfirst; elptr != NULL; elptr = elptr->elnext)
+ headlength -= 6;
+ offset = headlength;
+ startptr = findsym("start");
+ offtocn(buf, edataoffset, 2);
+ writeout(buf, 2);
+ writechar(0xFF); /* dummy data length 0xFFFF takes everything */
+ writechar(0xFF);
+ for (elptr = entryfirst; elptr != NULL; elptr = elptr->elnext)
+ {
+ name = idconvert(elptr, commandname);
+ writeout(name, (unsigned) strlen(name) + 1);
+ ourfree(name);
+ offtocn(buf, startptr == NULL ? elptr->elsymptr->value : offset, 2);
+ writeout(buf, 2);
+ writechar(0x82); /* 8 = set flags from here, 2 = cmd line */
+ offset += 6; /* LBSR $xxxx and LBRA $xxxx */
+ }
+ writechar(0);
+ if (startptr != NULL)
+ {
+ offset = headlength + 3; /* over 1st LBSR */
+ for (elptr = entryfirst; elptr != NULL; elptr = elptr->elnext)
+ {
+ writechar(0x17); /* LBSR */
+ offtocn(buf, startptr->value - offset, 2);
+ writeout(buf, 2);
+ writechar(0x16); /* LBRA */
+ offtocn(buf, elptr->elsymptr->value - offset - 3, 2);
+ writeout(buf, 2);
+ offset += 6;
+ }
+ }
+}
+
+#endif /* EDOS */
+
+#ifdef MINIX
+
+PRIVATE void writeheader()
+{
+ struct exec header;
+
+ memset(&header, 0, sizeof header);
+#ifdef STANDARD_GNU_A_OUT
+#ifdef N_SET_MAGIC
+ N_SET_MAGIC(header, OMAGIC);
+#else
+ *(unsigned short *) &header.a_magic = OMAGIC; /* XXX - works for 386BSD */
+#endif
+#else
+ header.a_magic[0] = A_MAGIC0;
+ header.a_magic[1] = A_MAGIC1;
+#endif
+#ifdef BSD_A_OUT
+ if (!reloc_output)
+#endif
+ {
+#ifdef STANDARD_GNU_A_OUT
+#ifdef N_SET_FLAGS
+ N_SET_FLAGS(header, 0);
+#else
+ /* XXX - works for 386BSD */
+#endif
+#else
+ header.a_flags = sepid ? A_SEP : A_EXEC;
+ if (uzp)
+ header.a_flags |= A_UZP;
+#endif
+ }
+#ifdef BSD_A_OUT
+#ifdef STANDARD_GNU_A_OUT
+#ifdef N_SET_FLAGS
+ N_SET_MACHTYPE(header, M_386);
+#else
+ /* XXX - works for 386BSD which doesn't define its own machtype :-( */
+#endif
+#else
+ header.a_cpu = (bits32 || reloc_output) ? A_I80386 : A_I8086;
+#endif
+#else
+ header.a_cpu = bits32 ? A_I80386 : A_I8086;
+#endif
+#ifndef STANDARD_GNU_A_OUT
+ header.a_hdrlen = FILEHEADERLENGTH;
+#endif
+ offtocn((char *) &header.a_text, etextpadoff - btextoffset,
+ sizeof header.a_text);
+ offtocn((char *) &header.a_data, edataoffset - bdataoffset,
+ sizeof header.a_data);
+ offtocn((char *) &header.a_bss, endoffset - edataoffset,
+ sizeof header.a_bss);
+#ifdef BSD_A_OUT
+ if (!reloc_output)
+#endif
+ {
+ if (uzp)
+ offtocn((char *) &header.a_entry, page_size(),
+ sizeof header.a_entry);
+#ifndef STANDARD_GNU_A_OUT
+ offtocn((char *) &header.a_total, (offset_t)
+ (endoffset < 0x00010000L ? 0x00010000L : endoffset + 0x0008000L),
+ sizeof header.a_total);
+#endif
+ }
+ writeout((char *) &header, FILEHEADERLENGTH);
+}
+
+#endif /* MINIX */
+
+PRIVATE void writenulls(count)
+offset_t count;
+{
+ spos += count;
+ while (count--)
+ writechar(0);
+}