ld09: first cut
authorAlan Cox <alan@linux.intel.com>
Mon, 8 Jun 2015 21:22:55 +0000 (22:22 +0100)
committerAlan Cox <alan@linux.intel.com>
Mon, 8 Jun 2015 21:22:55 +0000 (22:22 +0100)
Needs the output side replacing with a simple binary writer for FUZIX
format headers.

This one actually should fit nicely on a Dragon32 !

31 files changed:
Applications/ld09/Makefile [new file with mode: 0644]
Applications/ld09/align.h [new file with mode: 0644]
Applications/ld09/ar.h [new file with mode: 0644]
Applications/ld09/bindef.h [new file with mode: 0644]
Applications/ld09/byteord.h [new file with mode: 0644]
Applications/ld09/catimage.c [new file with mode: 0644]
Applications/ld09/config.h [new file with mode: 0644]
Applications/ld09/const.h [new file with mode: 0644]
Applications/ld09/dumps.c [new file with mode: 0644]
Applications/ld09/globvar.h [new file with mode: 0644]
Applications/ld09/io.c [new file with mode: 0644]
Applications/ld09/ld.c [new file with mode: 0644]
Applications/ld09/ld86r.c [new file with mode: 0644]
Applications/ld09/linksyms.c [new file with mode: 0644]
Applications/ld09/mkar.c [new file with mode: 0644]
Applications/ld09/obj.h [new file with mode: 0644]
Applications/ld09/objchop.c [new file with mode: 0644]
Applications/ld09/objdump86.c [new file with mode: 0644]
Applications/ld09/readobj.c [new file with mode: 0644]
Applications/ld09/rel_aout.h [new file with mode: 0644]
Applications/ld09/syshead.h [new file with mode: 0644]
Applications/ld09/table.c [new file with mode: 0644]
Applications/ld09/type.h [new file with mode: 0644]
Applications/ld09/typeconv.c [new file with mode: 0644]
Applications/ld09/v7_aout.h [new file with mode: 0644]
Applications/ld09/version.h [new file with mode: 0644]
Applications/ld09/writebin.c [new file with mode: 0644]
Applications/ld09/writeemu.c [new file with mode: 0644]
Applications/ld09/writex86.c [new file with mode: 0644]
Applications/ld09/x86_aout.h [new file with mode: 0644]
Applications/ld09/x86_cpm86.h [new file with mode: 0644]

diff --git a/Applications/ld09/Makefile b/Applications/ld09/Makefile
new file mode 100644 (file)
index 0000000..b8a34b0
--- /dev/null
@@ -0,0 +1,61 @@
+PLATFORM = 6809
+CC = m6809-unknown-gcc
+# These are wrappers for lwasm and lwar
+ASM = m6809-unknown-as
+AR = m6809-unknown-ar
+LINKER = lwlink
+CFLAGS =  -I../../Library/include -I../../Library/include/6502 -Wall -pedantic -fno-strict-aliasing
+COPT = -Os
+LINKER_OPT = --format=raw -L../../Library/libs -lc6809
+LIBGCCDIR = $(dir $(shell $(CC) -print-libgcc-file-name))
+LINKER_OPT += -L$(LIBGCCDIR) -lgcc -m ld09.map
+LINKER_OPT += --script=../util/$(TARGET).link
+ASM_OPT = -o
+CRT0 = ../../Library/libs/crt0_6809.o
+
+LIBDIR =/usr/bin
+LDFLAGS        =
+
+# Will need some of these if you want native executables on non-Linux/i386
+# -DDETECTAOUT                 # Turn on detection.
+# -DV7_A_OUT                   # a.out.h is like V7
+# -DBSD_A_OUT                  # a.out.h is like BSD
+# -DSTANDARD_GNU_A_OUT         # a.out.h is like GNU normal.
+#
+# -DREL_OUTPUT -DBUGCOMPAT     # -r Produces weird *.o files.
+#
+DEFS   =-DREL_OUTPUT
+
+# An alternative file for a non-standard a.out.h (eg i386 linux on an Alpha)
+#
+# NATIVE=-DA_OUT_INCL='"a_out_local.h"' 
+
+OBJS= dumps.o io.o ld.o readobj.o table.o typeconv.o linksyms.o mkar.o \
+      writebin.o writeemu.o
+
+all: ld09 objchop
+
+ld09: $(OBJS)
+       $(LINKER) -o $@ $(LINKER_OPT) $(CRT0) $(OBJS)
+
+objchop: objchop.o
+       $(LINKER) -o $@ $(LINKER_OPT) $(CRT0) $(OBJS)
+
+clean realclean clobber:
+       rm -f *.o ld09 ld09r objchop catimage objdump09 *~
+
+$(OBJS): align.h ar.h bindef.h byteord.h config.h const.h globvar.h obj.h \
+        syshead.h type.h x86_aout.h
+
+ar.h:
+       test -f ar.h || \
+       { rm -f ar.h ; ln -s ../libc/include/ar.h . ; } || \
+       ln ../libc/include/ar.h .
+
+writebin.o: writebin.c
+       $(CC) $(CFLAGS) $(DEFS) $(NATIVE) -c $<
+
+writerel.o: writebin.c
+
+.c.o:
+       $(CC) $(COPT) $(CFLAGS) $(DEFS) -c $< -o $@
diff --git a/Applications/ld09/align.h b/Applications/ld09/align.h
new file mode 100644 (file)
index 0000000..52b1e89
--- /dev/null
@@ -0,0 +1,23 @@
+/* align.h - memory alignment requirements for linker */
+
+/* Copyright (C) 1994 Bruce Evans */
+
+#ifndef S_ALIGNMENT
+# define align(x)
+#else
+
+#if defined(__STDC__) && defined(_POSIX_SOURCE)
+# define align(x) ((x)=(void *)        \
+                  (((ssize_t)(x) + (S_ALIGNMENT-1)) & ~(S_ALIGNMENT-1)))
+#else
+# define align(x) ((x)=(void *)        \
+                  ((char *)(x) + ((S_ALIGNMENT-(char)(x)) & (S_ALIGNMENT-1))))
+#endif
+#endif
+
+
+
+
+
+
+
diff --git a/Applications/ld09/ar.h b/Applications/ld09/ar.h
new file mode 100644 (file)
index 0000000..c608371
--- /dev/null
@@ -0,0 +1,18 @@
+#ifndef __AR_H
+#define __AR_H
+
+#define ARMAG "!<arch>\n"
+#define SARMAG 8
+#define ARFMAG "`\n"
+
+struct ar_hdr {
+       char    ar_name[16],
+               ar_date[12],
+               ar_uid[6],
+               ar_gid[6],
+               ar_mode[8],
+               ar_size[10],
+               ar_fmag[2];
+};
+
+#endif /* __AR_H */
diff --git a/Applications/ld09/bindef.h b/Applications/ld09/bindef.h
new file mode 100644 (file)
index 0000000..c359509
--- /dev/null
@@ -0,0 +1,75 @@
+
+/* Only do native on Linux/i386 by default -- it's safer. */
+#ifndef DETECTAOUT
+#if defined(__i386__) && defined(__linux__)
+#define DETECTAOUT
+#else
+# ifdef A_OUT_INCL
+# define DETECTAOUT
+# endif
+#endif
+#endif
+
+#ifdef DETECTAOUT
+/* Ok, I'm just gonna make it simple ... override this if you like. */
+#ifndef A_OUT_INCL
+#define A_OUT_INCL     <a.out.h>
+#endif
+
+#include A_OUT_INCL
+
+/* Try and guess type ... */
+#ifndef V7_A_OUT
+#ifndef BSD_A_OUT
+#ifndef STANDARD_GNU_A_OUT
+
+# ifndef C_EXT
+#  define BSD_A_OUT
+# endif
+
+/* Not sure about this one ... it works here ... */
+# if defined(BSD_A_OUT) && defined(N_MAGIC)
+#  define STANDARD_GNU_A_OUT
+# endif
+
+#endif
+#endif
+#endif
+
+/* General specs as to how it works ... */
+# ifdef BSD_A_OUT
+#  ifdef STANDARD_GNU_A_OUT
+#   define RELOC_INFO_SIZE 8   /* unportable bitfields - bcc doesn't pack */
+#  else
+#   define RELOC_INFO_SIZE (sizeof (struct relocation_info))
+#  endif
+#  ifdef N_EXT
+#   define C_EXT N_EXT
+#  endif
+#  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 */
+#  define RELOC_INFO_SIZE (sizeof (struct reloc))
+#  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 */
+
+/* And finally make sure it worked */
+#if defined(A_MINHDR) || defined(BSD_A_OUT)
+#if defined(C_EXT) && defined(C_STAT) && !defined(SCNHSZ)
+
+#define AOUT_DETECTED  1
+
+#endif
+#endif
+
+#endif /* NO_AOUT */
diff --git a/Applications/ld09/byteord.h b/Applications/ld09/byteord.h
new file mode 100644 (file)
index 0000000..c854979
--- /dev/null
@@ -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 INT_BIG_ENDIAN 0
+# define LONG_BIG_ENDIAN 0     /* except longs are back to front for Xenix */
+#endif
+
+#ifdef I80386
+# define INT_BIG_ENDIAN 0
+# define LONG_BIG_ENDIAN 0
+#endif
+
+#ifdef MC6809
+# define INT_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/Applications/ld09/catimage.c b/Applications/ld09/catimage.c
new file mode 100644 (file)
index 0000000..1f5e160
--- /dev/null
@@ -0,0 +1,243 @@
+/*
+ * This program concatenates memory images the executables specified
+ * on it's command line.
+ *
+ * The 'boot' image must have a symbol table any symbols that match
+ * the below patterns have their values patched.
+ *
+ * int __seg0_text;    - Always zero
+ * int __seg0_data;    - Segment offset of data of boot executable
+ *
+ * int __seg1_text;    - Segment offset of text of first executable
+ * int __seg1_data;    - Segment offset of data of first executable
+ * int __seg2_text;    - Segment offset of text of second executable
+ * int __seg2_data;    - Segment offset of data of second executable
+ *
+ * int __seg9_text;    - Segment offset of text of executable nine
+ * int __seg9_data;    - Segment offset of data of executable nine
+ *
+ * Any segment that's not an exact multiple of 16 bytes long is rounded up.
+ *
+ */
+
+#include <stdio.h>
+#ifdef __STDC__
+#include <unistd.h>
+#include <stdlib.h>
+#endif
+#include "x86_aout.h"
+
+#ifndef __OUT_OK
+#error "Compile error: struct exec invalid (long not 32 bit ?)"
+#endif
+
+unsigned long text_offt[10];   /* Locations to patch (0=don't) */
+unsigned long data_offt[10];
+
+char * input_file = "";
+FILE * ofd;
+FILE * ifd = 0;
+struct exec header;
+
+main(argc, argv)
+int argc;
+char ** argv;
+{
+   long image_offset, text_off;
+   int  image_id;
+
+   if( argc < 3 || argc > 11 )
+      fatal("Usage: catimage mem.bin boot.out [a1.out] ... [a9.out]");
+
+   open_obj(argv[2]);
+
+   ofd = fopen(argv[1], "w");
+   if( ofd == 0 ) fatal("Cannot open output file");
+
+   read_symtable();
+
+   image_offset = 0;
+
+   for(image_id=0; image_id < argc-2; image_id++)
+   {
+      open_obj(argv[image_id+2]);
+
+      printf("File %-14s seg=0x%04lx text=0x%04lx data=0x%04lx\n",
+              input_file, (image_offset>>4),
+             (header.a_text>>4), (header.a_total>>4));
+
+      text_off = image_offset;
+      if( header.a_flags & A_SEP )
+      {
+         copy_segment(image_offset, A_TEXTPOS(header), header.a_text);
+         image_offset += header.a_text;
+         image_offset = ((image_offset+15L)&-16L);
+   
+         copy_segment(image_offset, A_DATAPOS(header), header.a_data);
+      }
+      else
+      {
+         copy_segment(image_offset, A_TEXTPOS(header),
+                     header.a_text+header.a_data);
+      }
+
+      patch_bin(text_offt[image_id], (unsigned)(text_off>>4));
+      patch_bin(data_offt[image_id], (unsigned)(image_offset>>4));
+
+      image_offset += header.a_total;
+      image_offset = ((image_offset+15L)&-16L);
+   }
+
+   if( fseek(ofd, image_offset-1, 0) < 0 )
+      fatal("Cannot seek to end of output");
+
+   fputc('\0', ofd);
+   fclose(ofd);
+
+   printf("Output file size %ldKb\n", ((image_offset+0x3FF)>>10));
+
+   if( ifd ) fclose(ifd);
+   exit(0);
+}
+
+open_obj(fname)
+char * fname;
+{
+   input_file = fname;
+
+   if( ifd ) fclose(ifd);
+
+   ifd = fopen(fname, "r");
+   if( ifd == 0 ) fatal("Cannot open input file");
+
+   if( fread(&header, A_MINHDR, 1, ifd) != 1 )
+      fatal("Incomplete executable header");
+
+   if( BADMAG(header) )
+      fatal("Input file has bad magic number");
+}
+
+copy_segment(out_offset, in_offset, length)
+long out_offset, in_offset, length;
+{
+   char buffer[1024];
+   int ssize;
+   long bsize = length;
+
+   if( fseek(ifd, in_offset, 0) < 0 )
+      fatal("Cannot seek to start of input segment");
+
+   if( fseek(ofd, out_offset, 0) < 0 )
+      fatal("Cannot seek to start of output segment");
+
+   while(bsize>0)
+   {
+      if( bsize > sizeof(buffer) ) ssize = sizeof(buffer);
+      else ssize = bsize;
+
+      if( (ssize=fread(buffer, 1, ssize, ifd)) <= 0 )
+         fatal("Error reading segment from executable");
+      if( fwrite(buffer, 1, ssize, ofd) != ssize )
+         fatal("Error writing output file");
+      bsize -= ssize;
+   }
+}
+
+patch_bin(file_off, value)
+long file_off;
+int value;
+{
+   char wbuf[4];
+   if( file_off > 0 )
+   {
+      printf("Patch at offset 0x%05lx = %04x\n", file_off, value);
+
+      wbuf[0] = value;
+      wbuf[0] = (value>>8);
+
+      if( fseek(ofd, file_off, 0) < 0 )
+        fatal("Cannot seek to patch binary");
+
+      if( fwrite(wbuf, 1, 2, ofd) != 2 )
+        fatal("Error patching output file");
+   }
+}
+
+read_symtable()
+{
+   struct nlist item;
+   int nitems;
+   long base_off = 0;
+
+   if( header.a_syms == 0 )
+      fatal("Input file has been stripped!");
+
+   if( fseek(ifd, A_SYMPOS(header), 0) < 0 )
+      fatal("Cannot seek to start of symbols");
+
+   nitems = header.a_syms;
+
+   /* Foreach symbol */
+   while( fread(&item, sizeof(struct nlist), 1, ifd) == 1 )
+   {
+      if( nitems-- <= 0 ) break;
+
+      /* Match the name */
+      if( memcmp(item.n_name, "__seg", 5) != 0 || item.n_name[6] != '_' )
+         continue;
+
+      /* Externals only */
+      if( (item.n_sclass & N_CLASS) != C_EXT )
+         continue;
+
+      /* Data seg only */
+      if( (item.n_sclass & N_SECT) != N_DATA &&
+          (item.n_sclass & N_SECT) != N_BSS  &&
+          (item.n_sclass & N_SECT) != N_TEXT )
+        continue;
+
+      if( item.n_name[5] < '0' || item.n_name[5] > '9' )
+         continue;
+
+      if( (header.a_flags & A_SEP) && (item.n_sclass & N_SECT) != N_TEXT )
+         base_off = header.a_text;
+      else
+         base_off = 0;
+
+      switch( item.n_name[7] )
+      {
+      case 'd': data_offt[item.n_name[5]-'0'] = base_off+item.n_value; break;
+      case 't': text_offt[item.n_name[5]-'0'] = base_off+item.n_value; break;
+      }
+
+#ifdef DEBUG
+      printf("%-8.8s ", item.n_name);
+      printf("%08lx ", item.n_value);
+      switch(item.n_sclass & N_CLASS)
+      {
+      case C_NULL: printf("C_NULL "); break;
+      case C_EXT:  printf("C_EXT  "); break;
+      case C_STAT: printf("C_STAT "); break;
+      default:     printf("%-6d ", (item.n_sclass & N_CLASS)); break;
+      }
+      switch(item.n_sclass & N_SECT)
+      {
+      case N_UNDF: printf("N_UNDF "); break;
+      case N_ABS : printf("N_ABS  "); break;
+      case N_TEXT: printf("N_TEXT "); break;
+      case N_DATA: printf("N_DATA "); break;
+      case N_BSS : printf("N_BSS  "); break;
+      case N_COMM: printf("N_COMM "); break;
+      }
+      printf("\n");
+#endif
+   }
+}
+
+fatal(str)
+char * str;
+{
+   fprintf(stderr, "catimage:%s: %s\n", input_file, str);
+   exit(2);
+}
+
diff --git a/Applications/ld09/config.h b/Applications/ld09/config.h
new file mode 100644 (file)
index 0000000..dc5fed4
--- /dev/null
@@ -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/Applications/ld09/const.h b/Applications/ld09/const.h
new file mode 100644 (file)
index 0000000..04d6330
--- /dev/null
@@ -0,0 +1,14 @@
+/* const.h - constants for linker */
+
+/* Copyright (C) 1994 Bruce Evans */
+
+#define FALSE  0
+#define NUL_PTR        ((void*)0)
+#define TRUE   1
+
+#define EXTERN extern
+#define FORWARD        static
+#define PRIVATE        static
+#define PUBLIC
+
+#include "config.h"
diff --git a/Applications/ld09/dumps.c b/Applications/ld09/dumps.c
new file mode 100644 (file)
index 0000000..10879b7
--- /dev/null
@@ -0,0 +1,95 @@
+/* dumps.c - print data about symbols and modules for linker */
+
+/* Copyright (C) 1994 Bruce Evans */
+
+#include "syshead.h"
+#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;
+    char *s, *d;
+    int i;
+
+    for (modptr = modfirst; modptr != NUL_PTR; modptr = modptr->modnext)
+    {
+       for(s=d=modptr->filename; *s ; s++)
+          if( *s == '/' ) d=s+1;
+        if( memcmp(d, "libc", 4) == 0 && !modptr->loadflag ) continue;
+
+       putstr(modptr->modname);
+       i = strlen(modptr->modname);
+       while(i<16) putbyte(' '),i++;
+       putbyte( modptr->loadflag ? '+':'-' );
+       putstr(d);
+       if( modptr->archentry )
+       {
+          putbyte('(');
+          putstr(modptr->archentry);
+          putbyte(')');
+       }
+       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 != NUL_PTR; modptr = modptr->modnext)
+       if (modptr->loadflag)
+       {
+           for (symparray = modptr->symparray;
+                (symptr = *symparray) != NUL_PTR; ++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
+                   if( flags & (E_MASK|C_MASK) )
+                      putstr(flags & A_MASK ? "  A" : "  R");
+                   else
+                      putstr(flags & A_MASK ? "  a" : "  r");
+                   if (uflag)
+                       putstr(" U");
+                   if (flags & C_MASK)
+                       putstr(" C");
+                   if (flags & N_MASK)
+                       putstr(" N");
+                   putbyte('\n');
+               }
+       }
+
+    putstr("Total memory used: ");
+#ifdef LONG_OFFSETS
+    put08lx(memory_used());
+#else
+    put08x(memory_used());
+#endif
+    putbyte('\n');
+}
diff --git a/Applications/ld09/globvar.h b/Applications/ld09/globvar.h
new file mode 100644 (file)
index 0000000..5663cc0
--- /dev/null
@@ -0,0 +1,25 @@
+/* globvar.h - global variables for linker */
+
+/* Copyright (C) 1994 Bruce Evans */
+
+#ifndef EXTERN
+#define EXTERN
+#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 */
+
+/* K&R _explicitly_ says extern followed by public is OK */
+extern char hexdigit[];                        /* constant */
+extern int  headerless;                        /* Don't output header on exe */
+#ifndef VERY_SMALL_MEMORY
+extern int  v7;                                /* Generate an UNIX v7 a.out header */
+#endif
+#ifndef MSDOS
+extern int  cpm86;                     /* Generate CP/M-86 CMD header */
+#endif
+
+extern bin_off_t text_base_value;      /* Base address of text seg */
+extern bin_off_t data_base_value;      /* Base or alignment of data seg */
+extern bin_off_t heap_top_value;       /* Minimum 'total' value in x86 header */
diff --git a/Applications/ld09/io.c b/Applications/ld09/io.c
new file mode 100644 (file)
index 0000000..542ab63
--- /dev/null
@@ -0,0 +1,643 @@
+/* io.c - input/output and error modules for linker */
+
+/* Copyright (C) 1994 Bruce Evans */
+
+#include "syshead.h"
+#include "const.h"
+#include "type.h"
+#include "globvar.h"
+#include "version.h"
+
+#define DRELBUFSIZE    3072
+#define ERR            (-1)
+#define ERRBUFSIZE     1024
+#define INBUFSIZE      1024
+#define OUTBUFSIZE     2048
+#define TRELBUFSIZE    1024
+
+#ifdef REL_OUTPUT
+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 int  errfil = STDOUT_FILENO;
+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 REL_OUTPUT
+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 */
+
+#ifdef MSDOS
+#define off_t  long            /* NOT a typedef */
+#endif
+
+FORWARD void errexit P((char *message));
+FORWARD void flushout P((void));
+#ifdef REL_OUTPUT
+FORWARD void flushtrel P((void));
+#endif
+FORWARD void outhexdigs P((bin_off_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));
+FORWARD void stderr_out P((void));
+
+PUBLIC void ioinit(progname)
+char *progname;
+{
+    infd = ERR;
+    if (*progname)
+       refname = progname;     /* name must be static (is argv[0]) */
+    else
+       refname = "link";
+    for(progname=refname; *progname; progname++)
+       if(*progname=='/')
+          refname=progname+1;
+
+#ifdef REL_OUTPUT
+    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 REL_OUTPUT
+    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 REL_OUTPUT
+    unsigned nbytes;
+#endif
+
+    flushout();
+#ifdef REL_OUTPUT
+    flushtrel();
+    nbytes = drelbufptr - drelbuf;
+    if (write(trelfd, drelbuf, nbytes) != nbytes)
+       outputerror("cannot write");
+#endif
+    if (close(outfd) == ERR)
+       outputerror("cannot close");
+#ifdef REL_OUTPUT
+    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()
+{
+    if (errcount)
+        unlink(outputname);
+#ifndef MSDOS
+    else
+       chmod(outputname, outputperms);
+#endif
+}
+
+PUBLIC void flusherr()
+{
+    if( errbufptr != errbuf )
+       write(errfil, errbuf, (unsigned) (errbufptr - errbuf));
+    errbufptr = errbuf;
+}
+
+PRIVATE void stderr_out()
+{
+   if( errfil != STDERR_FILENO )
+   {
+      flusherr();
+      errfil = STDERR_FILENO;
+   }
+}
+
+PRIVATE void flushout()
+{
+    unsigned nbytes;
+
+    nbytes = outbufptr - outbuf;
+    if (write(outfd, outbuf, nbytes) != nbytes)
+       outputerror("cannot write");
+    outbufptr = outbuf;
+}
+
+#ifdef REL_OUTPUT
+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 */
+#ifdef O_BINARY
+       if ((infd = open(filename, O_BINARY|O_RDONLY)) < 0)
+#else
+       if ((infd = open(filename, O_RDONLY)) < 0)
+#endif
+           inputerror("cannot open");
+       inbufptr = inbufend = inbuf;
+    }
+}
+
+PUBLIC void openout(filename)
+char *filename;
+{
+    mode_t oldmask;
+
+    outputname = filename;
+#ifdef O_BINARY
+    if ((outfd = open(filename, O_BINARY|O_WRONLY|O_CREAT|O_TRUNC, CREAT_PERMS)) == ERR)
+#else
+    if ((outfd = creat(filename, CREAT_PERMS)) == ERR)
+#endif
+       outputerror("cannot open");
+
+#ifndef MSDOS
+    /* Can't do this on MSDOS; it upsets share.exe */
+    oldmask = umask(0); umask(oldmask);
+    outputperms = ((CREAT_PERMS | EXEC_PERMS) & ~oldmask);
+    chmod(filename, outputperms & ~EXEC_PERMS);
+#endif
+
+#ifdef REL_OUTPUT
+    drelbufptr = drelbuf;
+#endif
+    outbufptr = outbuf;
+#ifdef REL_OUTPUT
+#ifdef O_BINARY
+    if ((trelfd = open(filename, O_BINARY|O_WRONLY, CREAT_PERMS)) == ERR)
+#else
+    if ((trelfd = open(filename, O_WRONLY, CREAT_PERMS)) == ERR)
+#endif
+       outputerror("cannot reopen");
+    trelbufptr = trelbuf;
+#endif
+}
+
+PRIVATE void outhexdigs(num)
+register bin_off_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 bin_off_t num;
+{
+    put04x(num / 0x10000);
+    put04x(num % 0x10000);
+}
+
+#else /* not LONG_OFFSETS */
+
+PUBLIC void put08x(num)
+register bin_off_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(); errfil = STDOUT_FILENO;
+}
+
+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 REL_OUTPUT
+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 REL_OUTPUT
+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 REL_OUTPUT
+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 != NUL_PTR)
+    {
+       putbyte('(');
+       putstr(archentry);
+       putbyte(')');
+    }
+    putstr("; using definition in ");
+    putstr(deffilename);
+    if (defarchentry != NUL_PTR)
+    {
+       putbyte('(');
+       putstr(defarchentry);
+       putbyte(')');
+    }
+    putstrn("");
+}
+
+PUBLIC void interseg(fname, aname, name)
+char *fname, *aname, *name;
+{
+    ++errcount;
+    refer();
+    putstr("error in ");
+    putstr(fname);
+    if( aname ) 
+    {
+       putstr("(");
+       putstr(aname);
+       putstr(")");
+    }
+    putstr(" intersegment jump to ");
+    if( name ) putstr(name);
+    else       putstr("same file");
+
+    putstrn("");
+}
+
+PRIVATE void refer()
+{
+    stderr_out();
+    putstr(refname);
+    putstr(": ");
+}
+
+PUBLIC void reserved(name)
+char *name;
+{
+    ++errcount;
+    stderr_out();
+    putstr("incorrect use of reserved symbol: ");
+    putstrn(name);
+}
+
+PUBLIC void size_error(seg, count, size)
+int seg;
+bin_off_t count;
+bin_off_t size;
+{
+    refer();
+    putstr("seg ");
+    outhexdigs((bin_off_t) seg);
+    putstr(" has wrong size ");
+    outhexdigs(count);
+    putstr(", supposed to be ");
+    outhexdigs(size);
+    errexit("");
+}
+
+PUBLIC void undefined(name)
+char *name;
+{
+    ++errcount;
+    stderr_out();
+    putstr("undefined symbol: ");
+    putstrn(name);
+}
+
+PUBLIC void usage()
+{
+    stderr_out();
+    putstr("usage: ");
+    putstr(refname);
+#ifdef REL_OUTPUT
+    errexit("\
+ [-03NMdimrstz[-]] [-llib_extension] [-o outfile] [-Ccrtfile]\n\
+       [-Llibdir] [-Olibfile] [-Ttextaddr] [-Ddataaddr] [-Hheapsize] infile...");
+#else
+    errexit("\
+ [-03NMdimstz[-]] [-llib_extension] [-o outfile] [-Ccrtfile]\n\
+       [-Llibdir] [-Olibfile] [-Ttextaddr] [-Ddataaddr] [-Hheapsize] infile...");
+#endif
+}
+
+PUBLIC void version_msg()
+{
+    stderr_out();
+#ifdef VERSION
+    putstr("ld86 version: ");
+    errexit(VERSION);
+#else
+    errexit("ld86 version unknown");
+#endif
+}
+
+PUBLIC void use_error(message)
+char *message;
+{
+    refer();
+    putstrn(message);
+    usage();
+}
diff --git a/Applications/ld09/ld.c b/Applications/ld09/ld.c
new file mode 100644 (file)
index 0000000..3a47268
--- /dev/null
@@ -0,0 +1,280 @@
+/* ld.c - linker for Introl format (6809 C) object files 6809/8086/80386 */
+
+/* Copyright (C) 1994 Bruce Evans */
+
+#include "syshead.h"
+#include "const.h"
+#include "byteord.h"
+#include "type.h"
+#include "globvar.h"
+
+#define MAX_LIBS       (NR_STDLIBS + 5)
+#ifdef MC6809
+#define NR_STDLIBS     1
+#else
+#define NR_STDLIBS     0
+#endif
+
+PUBLIC bin_off_t text_base_value = 0;  /* XXX */
+PUBLIC bin_off_t data_base_value = 0;  /* XXX */
+PUBLIC bin_off_t heap_top_value  = 0;  /* XXX */
+PUBLIC int headerless = 0;
+#ifndef VERY_SMALL_MEMORY
+PUBLIC int v7 = 0;
+#endif
+#ifndef MSDOS
+PUBLIC int cpm86 = 0;
+#endif
+PUBLIC char hexdigit[] = "0123456789abcdef";
+
+PRIVATE bool_t flag[128];
+PRIVATE char *libs[MAX_LIBS] = {
+#ifdef MC6809
+    "/usr/local/lib/m09/",
+#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, *s;
+    int i;
+
+    for (i = lastlib - 1; i >= 0; --i)
+    {
+       path = ourmalloc(strlen(libs[i]) + strlen(fn) + 2);
+       strcpy(path, libs[i]);
+       s = path + strlen(path);
+       if (s!=path && s[-1] != '/') strcat(path, "/");
+       strcat(path, fn);
+       if (access(path, R_OK) == 0)
+           return path;
+       ourfree(path);
+    }
+    return NUL_PTR;
+}
+
+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;
+    int icount=0;
+
+    ioinit(argv[0]);
+    objinit();
+    syminit();
+    typeconv_init(INT_BIG_ENDIAN, LONG_BIG_ENDIAN);
+#ifndef MC6809
+    flag['3'] = sizeof(char *) >= 4;
+#endif
+    outfilename = NUL_PTR;
+    for (argn = 1; argn < argc; ++argn)
+    {
+       arg = argv[argn];
+       if (*arg != '-')
+       {
+           readsyms(arg, flag['t']);
+           icount++;
+       }
+       else
+           switch (arg[1])
+           {
+           case 'v':
+              version_msg();
+           case 'r':           /* relocatable output */
+           case 't':           /* trace modules linked */
+              if (icount > 0) usage();
+#ifdef REL_OUTPUT
+           case 'B':           /* Broken -r for dosemu. */
+#endif
+           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 */
+           case 's':           /* strip symbols */
+           case 'z':           /* unmapped zero page */
+           case 'N':           /* Native format a.out */
+           case 'd':           /* Make a headerless outfile */
+#ifndef MSDOS
+           case 'c':           /* Write header in CP/M-86 format */
+#endif
+           case 'y':           /* Use a newer symbol table */
+#ifndef VERY_SMALL_MEMORY
+           case '7':           /* Produce a UNIX v7 a.out header */
+#endif
+               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)) == NUL_PTR)
+                   infilename = tfn;
+                   /*fatalerror(tfn);  * XXX - need to describe failure */
+               readsyms(infilename, flag['t']);
+               icount++;
+               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)) == NUL_PTR)
+                   infilename = arg+2;
+                   /* fatalerror(arg); * XXX */
+               readsyms(infilename, flag['t']);
+               break;
+           case 'T':           /* text base address */
+               if (arg[2] == 0 && ++argn >= argc)
+                   usage();
+               errno = 0;    
+               if (arg[2] == 0 )
+                  text_base_value = strtoul(argv[argn], (char **)0, 16);
+               else
+                  text_base_value = strtoul(arg+2, (char **)0, 16);
+               if (errno != 0)
+                   use_error("invalid text address");
+               break;
+           case 'D':           /* data base address */
+               if (arg[2] == 0 && ++argn >= argc)
+                   usage();
+               errno = 0;    
+               if (arg[2] == 0 )
+                  data_base_value = strtoul(argv[argn], (char **)0, 16);
+               else
+                  data_base_value = strtoul(arg+2, (char **)0, 16);
+               if (errno != 0)
+                   use_error("invalid data address");
+               break;
+           case 'H':           /* heap top address */
+               if (arg[2] == 0 && ++argn >= argc)
+                   usage();
+               errno = 0;    
+               if (arg[2] == 0 )
+                  heap_top_value = strtoul(argv[argn], (char **)0, 16);
+               else
+                  heap_top_value = strtoul(arg+2, (char **)0, 16);
+               if (errno != 0)
+                   use_error("invalid heap top");
+               break;
+           case 'l':           /* library name */
+               tfn = buildname(libprefix, arg + 2, libsuffix);
+               if ((infilename = expandlib(tfn)) == NUL_PTR)
+                   infilename = tfn;
+                   /* fatalerror(tfn); * XXX */
+               readsyms(infilename, flag['t']);
+               icount+=2;
+               break;
+           case 'o':           /* output file name */
+               if (arg[2] != 0 || ++argn >= argc || outfilename != NUL_PTR)
+                   usage();
+               outfilename = argv[argn];
+               break;
+           default:
+               usage();
+           }
+    }
+    if(icount==0) usage();
+
+#ifdef BUGCOMPAT
+    if( icount==1 && ( flag['r'] && !flag['N'] ) ) {
+       flag['r'] = 0;
+       flag['B'] = 1;
+    }
+#endif
+
+#ifdef REL_OUTPUT
+#ifndef MSDOS
+    if( flag['r'] && !flag['N'] )
+    {
+       /* Do a relocatable link -- actually fake it with 'ar.c' */
+       ld86r(argc, argv);
+    }
+#endif
+#endif
+
+#ifdef MSDOS
+    /* MSDOS Native is special, we make a COM file */
+    if( flag['N'] )
+    {
+       flag['N'] = 0;
+       flag['d'] = 1;
+       text_base_value = 0x100;
+    }
+#endif
+
+    /* Headerless executables can't use symbols. */
+    headerless = flag['d'];
+    if( headerless ) flag['s'] = 1;
+
+#ifndef VERY_SMALL_MEMORY
+    /* UNIX seventh edition executables */
+    v7 = flag['7'];
+#endif
+
+#ifndef MSDOS
+    /* CP/M-86 executables can't use symbols. */
+    cpm86 = flag['c'];
+    if ( cpm86 ) flag['s'] = 1;
+#endif
+
+    linksyms(flag['r'] | flag['B']);
+    if (outfilename == NUL_PTR)
+       outfilename = "a.out";
+#ifndef MSDOS
+    if( flag['N'] )
+       writebin(outfilename, flag['i'], flag['3'], flag['s'],
+            flag['z'] & flag['3']);
+    else
+#endif
+    if( flag['B'] )
+       write_dosemu(outfilename, flag['i'], flag['3'], flag['s'],
+         flag['z'] & flag['3']);
+#if 0  /* FIXME */
+    else
+       write_elks(outfilename, flag['i'], flag['3'], flag['s'],
+            flag['z'], flag['y']);
+#endif      
+    if (flag['m'])
+       dumpmods();
+    if (flag['M'])
+       dumpsyms();
+    flusherr();
+    return errcount ? 1 : 0;
+}
diff --git a/Applications/ld09/ld86r.c b/Applications/ld09/ld86r.c
new file mode 100644 (file)
index 0000000..dfc876d
--- /dev/null
@@ -0,0 +1,86 @@
+#include <stdio.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#ifdef __STDC__
+#include <stdlib.h>
+#include <unistd.h>
+#else
+#include <malloc.h>
+#endif
+
+#define ARMAG "!<arch>\n"
+#define SARMAG 8
+#define ARFMAG "`\n"
+
+struct ar_hdr {
+       char    ar_name[16],
+               ar_date[12],
+               ar_uid[6],
+               ar_gid[6],
+               ar_mode[8],
+               ar_size[10],
+               ar_fmag[2];
+} arbuf;
+
+void
+fatal(char * str) { fprintf(stderr, "%s\n", str); exit(2); }
+
+void
+main(int argc, char ** argv)
+{
+char buf[128];
+   FILE * fd, * ifd;
+   struct stat st;
+   int ar, libarg=0, need_o = 0, got_o = 0;
+
+   for(ar=1; ar<argc; ar++) if( argv[ar][0] == '-' )
+   {
+      if( argv[ar][1] == 'r' ) need_o = 1;
+      if( argv[ar][1] == 'o' ) { got_o++; libarg = 0; }
+   }
+   else
+   {
+      if( libarg == 0 ) libarg = ar;
+   }
+
+   if( libarg == 0 || got_o > 1 || need_o > got_o )
+      fatal("Err, what's the output gonna be called?");
+
+   if( (fd =fopen(argv[libarg], "wb")) == 0 ) fatal("Cannot open archive");
+   if( fwrite(ARMAG, 1, SARMAG, fd) != SARMAG)  fatal("Cannot write magic");
+
+   for(ar=1; ar<argc; ar++) if( ar != libarg && argv[ar][0] != '-' )
+   {
+      char * ptr;
+      if( stat(argv[ar], &st) < 0 ) fatal("Cannot stat object");
+      if((ptr=strchr(argv[ar], '/'))) ptr++; else ptr=argv[ar];
+      memset(&arbuf, ' ', sizeof(arbuf));
+      strcpy(buf, ptr); strcat(buf, "/                 ");
+      strncpy(arbuf.ar_name, buf, sizeof(arbuf.ar_name));
+      
+      sprintf(arbuf.ar_date, "%-12ld", (long)st.st_mtime);
+      sprintf(arbuf.ar_uid, "%-6d",    (int)(st.st_uid%1000000L));
+      sprintf(arbuf.ar_gid, "%-6d",    (int)(st.st_gid%1000000L));
+      sprintf(arbuf.ar_mode, "%-8lo",  (long)st.st_mode);
+      sprintf(arbuf.ar_size, "%-10ld", (long)st.st_size);
+      memcpy(arbuf.ar_fmag, ARFMAG, sizeof(arbuf.ar_fmag));
+
+      if( fwrite(&arbuf, 1, sizeof(arbuf), fd) != sizeof(arbuf) )
+         fatal("Cannot write header");
+
+      ptr = malloc(st.st_size+2);
+      if( ptr == 0 ) fatal("Out of memory");
+      ptr[st.st_size] = ' ';
+      if( (ifd = fopen(argv[ar], "rb")) == 0 ) fatal("Cannot open input");
+      if( fread(ptr, 1, st.st_size, ifd) != st.st_size )
+         fatal("Cannot read input file");
+      fclose(ifd);
+
+      if( st.st_size&1 ) st.st_size++;
+      if( fwrite(ptr, 1, st.st_size, fd) != st.st_size )
+         fatal("Cannot write output file");
+   }
+   fclose(fd);
+   exit(0);
+}
diff --git a/Applications/ld09/linksyms.c b/Applications/ld09/linksyms.c
new file mode 100644 (file)
index 0000000..9c1a61f
--- /dev/null
@@ -0,0 +1,85 @@
+
+/* linksyms.c - write binary file for linker */
+
+/* Copyright (C) 1994 Bruce Evans */
+
+#include "syshead.h"
+#include "const.h"
+#include "obj.h"
+#include "type.h"
+#undef EXTERN
+#include "globvar.h"
+
+FORWARD void linkrefs P((struct modstruct *modptr));
+PUBLIC bool_t reloc_output = 0;
+
+/* 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 REL_OUTPUT
+    reloc_output = argreloc_output;
+    if (argreloc_output)
+    {
+       if (modfirst->modnext != NUL_PTR)
+           fatalerror("relocatable output only works for one input file");
+       for (modptr = modfirst; modptr != NUL_PTR; modptr = modptr->modnext)
+           modptr->loadflag = TRUE;
+       return;
+    }
+#endif
+    if ((symptr = findsym("_start")) != NUL_PTR ||
+        (symptr = findsym("_main")) != NUL_PTR)
+       entrysym(symptr);
+    do
+    {
+       if ((elptr = entryfirst) == NUL_PTR)
+           fatalerror("no start symbol");
+       for (modptr = modfirst; modptr != NUL_PTR; modptr = modptr->modnext)
+           modptr->loadflag = FALSE;
+       for (; elptr != NUL_PTR; elptr = elptr->elnext)
+           linkrefs(elptr->elsymptr->modptr);
+       if ((symptr = findsym("start")) != NUL_PTR)
+           linkrefs(symptr->modptr);
+       needlink = FALSE;
+       {
+           struct redlist *prlptr = 0;
+           struct redlist *rlptr;
+
+           for (rlptr = redfirst; rlptr != NUL_PTR;
+                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);
+}
+
+PRIVATE void linkrefs(modptr)
+struct modstruct *modptr;
+{
+    register struct symstruct **symparray;
+    register struct symstruct *symptr;
+
+    modptr->loadflag = TRUE;
+    for (symparray = modptr->symparray;
+        (symptr = *symparray) != NUL_PTR; ++symparray)
+       if (symptr->modptr->loadflag == FALSE)
+           linkrefs(symptr->modptr);
+}
+
diff --git a/Applications/ld09/mkar.c b/Applications/ld09/mkar.c
new file mode 100644 (file)
index 0000000..b271a59
--- /dev/null
@@ -0,0 +1,80 @@
+
+#include <stdio.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#ifdef __STDC__
+#include <stdlib.h>
+#include <unistd.h>
+#else
+#include <malloc.h>
+#endif
+
+#include "type.h"
+#include "ar.h"
+
+static struct ar_hdr arbuf;
+
+#ifdef __STDC__
+void
+ld86r(int argc, char ** argv)
+#else
+ld86r(argc, argv)
+   int argc; char ** argv;
+#endif
+{
+char buf[128];
+   FILE * fd, * ifd;
+   struct stat st;
+   int ar, libarg=0, need_o = 0, got_o = 0;
+
+   for(ar=1; ar<argc; ar++) if( argv[ar][0] == '-' )
+   {
+      if( argv[ar][1] == 'r' ) need_o = 1;
+      if( argv[ar][1] == 'o' ) { got_o++; libarg = 0; }
+   }
+   else
+   {
+      if( libarg == 0 ) libarg = ar;
+   }
+
+   if( libarg == 0 || got_o > 1 || need_o > got_o )
+      fatalerror("-o option required for -r");
+
+   if( (fd =fopen(argv[libarg], "wb")) == 0 ) fatalerror("Cannot open archive");
+   if( fwrite(ARMAG, 1, SARMAG, fd) != SARMAG)  fatalerror("Cannot write magic");
+
+   for(ar=1; ar<argc; ar++) if( ar != libarg && argv[ar][0] != '-' )
+   {
+      char * ptr;
+      if( stat(argv[ar], &st) < 0 ) fatalerror("Cannot stat object");
+      if((ptr=strchr(argv[ar], '/'))) ptr++; else ptr=argv[ar];
+      memset(&arbuf, ' ', sizeof(arbuf));
+      strcpy(buf, ptr); strcat(buf, "/                 ");
+      strncpy(arbuf.ar_name, buf, sizeof(arbuf.ar_name));
+     
+      snprintf(arbuf.ar_date, 12, "%-12ld", (long)st.st_mtime);
+      snprintf(arbuf.ar_uid, 6, "%-6d", (int)(st.st_uid%1000000L));
+      snprintf(arbuf.ar_gid, 6, "%-6d", (int)(st.st_gid%1000000L));
+      snprintf(arbuf.ar_mode, 8, "%-8lo", (long)st.st_mode);
+      snprintf(arbuf.ar_size, 10, "%-10ld", (long)st.st_size);
+      memcpy(arbuf.ar_fmag, ARFMAG, sizeof(arbuf.ar_fmag));
+
+      if( fwrite(&arbuf, 1, sizeof(arbuf), fd) != sizeof(arbuf) )
+         fatalerror("Cannot write header");
+
+      ptr = malloc(st.st_size+2);
+      if( ptr == 0 ) fatalerror("Out of memory");
+      ptr[st.st_size] = ' ';
+      if( (ifd = fopen(argv[ar], "rb")) == 0 ) fatalerror("Cannot open input");
+      if( fread(ptr, 1, st.st_size, ifd) != st.st_size )
+         fatalerror("Cannot read input file");
+      fclose(ifd);
+
+      if( st.st_size&1 ) st.st_size++;
+      if( fwrite(ptr, 1, st.st_size, fd) != st.st_size )
+         fatalerror("Cannot write output file");
+   }
+   fclose(fd);
+   exit(0);
+}
diff --git a/Applications/ld09/obj.h b/Applications/ld09/obj.h
new file mode 100644 (file)
index 0000000..ddfa7a1
--- /dev/null
@@ -0,0 +1,50 @@
+/* obj.h - constants for Introl object modules */
+
+/* Copyright (C) 1994 Bruce Evans */
+
+#define OBJ_H
+
+#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 ld_roundup( num, boundary, type ) (num)
+#else
+# define ld_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/Applications/ld09/objchop.c b/Applications/ld09/objchop.c
new file mode 100644 (file)
index 0000000..c7631c1
--- /dev/null
@@ -0,0 +1,91 @@
+
+#include <stdio.h>
+#ifdef __STDC__
+#include <unistd.h>
+#include <stdlib.h>
+#endif
+#include "x86_aout.h"
+
+#ifndef __OUT_OK
+
+main()
+{
+   fprintf(stderr, "Compile error: struct exec invalid\n");
+   exit(1);
+}
+
+#else
+
+FILE * ifd;
+struct exec header;
+
+main(argc, argv)
+int argc;
+char ** argv;
+{
+   FILE * ofd;
+   if( argc != 5 ) fatal("Usage: objchop a.out text.bin data.bin sizes.asm");
+
+   ifd = fopen(argv[1], "r");
+   if( ifd == 0 ) fatal("Cannot open input file");
+
+   if( fread(&header, A_MINHDR, 1, ifd) != 1 )
+      fatal("Incomplete executable header");
+
+   if( BADMAG(header) )
+      fatal("Input file has bad magic number");
+
+   if( fseek(ifd, A_TEXTPOS(header), 0) < 0 )
+      fatal("Cannot seek to start of text");
+
+   write_file(argv[2], header.a_text);
+
+   if( fseek(ifd, A_DATAPOS(header), 0) < 0 )
+      fatal("Cannot seek to start of data");
+
+   write_file(argv[3], header.a_data);
+
+   ofd = fopen(argv[4], "w");
+   if( ofd == 0 ) fatal("Cannot open output file");
+
+   fprintf(ofd, "TEXT_SIZE=%ld\nDATA_SIZE=%ld\nBSS_SIZE=%ld\nALLOC_SIZE=%ld\n",
+           header.a_text, header.a_data, header.a_bss, header.a_total);
+
+   fclose(ofd);
+
+   exit(0);
+}
+
+write_file(fname, bsize)
+char * fname;
+long bsize;
+{
+   char buffer[1024];
+   int ssize;
+   FILE * ofd;
+
+   ofd = fopen(fname, "w");
+   if( ofd == 0 ) fatal("Cannot open output file");
+
+   while(bsize>0)
+   {
+      if( bsize > sizeof(buffer) ) ssize = sizeof(buffer);
+      else ssize = bsize;
+
+      if( (ssize=fread(buffer, 1, ssize, ifd)) <= 0 )
+         fatal("Error reading segment from executable");
+      if( fwrite(buffer, 1, ssize, ofd) != ssize )
+         fatal("Error writing output file");
+      bsize -= ssize;
+   }
+   fclose(ofd);
+}
+
+fatal(str)
+char * str;
+{
+   fprintf(stderr, "objchop: %s\n", str);
+   exit(2);
+}
+
+#endif
diff --git a/Applications/ld09/objdump86.c b/Applications/ld09/objdump86.c
new file mode 100644 (file)
index 0000000..85032a1
--- /dev/null
@@ -0,0 +1,972 @@
+/*
+ * This is a combination of three tools for decoding information from
+ * Dev86/ELKS object files and executables.
+ *
+ * This executable can be given the names:
+ *
+ *  objdump86: Dumps detailed information about a binary file.
+ *  size86:    Summary sizes of the data in a binary file.
+ *  nm86:      The symbol table of the binary file.
+ *
+ * None of these programs have any options.
+ * This may be a minor problem with nm86.
+ *
+ * Copyright (c) 1999 by Greg Haerr <greg@censoft.com>
+ * Added archive file reading capabilties
+ */
+
+#include <stdio.h>
+#ifdef __STDC__
+#include <stdlib.h>
+#else
+#include <malloc.h>
+#endif
+#include <string.h>
+#include "const.h"
+#include "ar.h"
+#include "obj.h"
+
+FILE * ifd;
+char * ifname;
+
+#ifdef __STDC__
+#define _(x) x
+#else 
+#define _(x) ()
+#endif 
+
+long get_long _((void));
+long get_sized _((int sz));
+unsigned int get_word _((void));
+int get_byte _((void));
+int main _((int argc, char**argv));
+void do_file _((char * fname));
+long read_arheader _((char *archentry));
+void do_module _((char * fname, char *archive));
+int error _((char * str));
+int read_objheader _((void));
+int read_sectheader _((void));
+int read_syms _((void));
+void disp_sectheader _((void));
+int disp_syms _((void));
+void read_databytes _((void));
+void hex_output _((int ch));
+void fetch_aout_hdr _((void));
+void dump_aout _((void));
+void size_aout _((void));
+void nm_aout _((void));
+#ifndef VERY_SMALL_MEMORY
+void fetch_v7_hdr _((void));
+void dump_v7 _((void));
+void size_v7 _((void));
+#endif
+
+int  obj_ver;
+int  sections;
+long segsizes[16];
+long textoff;
+long textlen;
+long str_off;
+long str_len;
+long filepos;
+int  num_syms;
+long code_bytes;
+
+char ** symnames;
+char *  strtab;
+
+struct {
+   unsigned int nameoff, symtype;
+   long offset;
+} *symtab;
+
+int display_mode = 0;
+int multiple_files = 0;
+int byte_order = 0;
+
+int opt_o;
+
+long size_text, size_data, size_bss;
+long tot_size_text=0, tot_size_data=0, tot_size_bss=0;
+
+int
+main(argc, argv)
+int argc;
+char ** argv;
+{
+   int ar;
+   char * p;
+
+   ifd = stdin;        /* In Libc6 stdin is weird */
+
+   p = strrchr(argv[0], '/');
+   if(p) p++; else p=argv[0];
+
+   if( p[0] == 's' ) display_mode = 1;
+   if( p[0] == 'n' ) display_mode = 2;
+
+   multiple_files = 0;
+   for(ar=1; ar<argc; ar++)
+   {
+      if( argv[ar][0] == '-' ) switch(argv[ar][1])
+      {
+      case 's': display_mode = 1; break;
+      case 'n': display_mode = 2; break;
+      case 'o': opt_o++; break;
+      }
+      else
+        multiple_files++;
+   }
+
+   if( !multiple_files ) exit(1);
+
+   multiple_files = (multiple_files>1);
+
+   if( display_mode == 1 )
+      printf("text\tdata\tbss\tdec\thex\tfilename\n");
+
+   for(ar=1; ar<argc; ar++) if(argv[ar][0] != '-')
+      do_file(argv[ar]);
+
+   if( display_mode == 1 && multiple_files)
+      printf("%ld\t%ld\t%ld\t%ld\t%lx\tTotal\n",
+        tot_size_text, tot_size_data, tot_size_bss,
+        tot_size_text+ tot_size_data+ tot_size_bss,
+        tot_size_text+ tot_size_data+ tot_size_bss);
+
+   return 0;
+}
+
+void
+do_file(fname)
+char * fname;
+{
+   unsigned int magic;
+   long        filelength;
+   char        archentry[sizeof(struct ar_hdr)]; /* sizeof ar_hdr.ar_name*/
+   char        filemagic[SARMAG];
+
+   ifname = fname;
+   if( (ifd=fopen(fname, "rb")) == 0 )
+   {
+      error("Cannot open file");
+      return;
+   }
+   filepos = 0L;
+
+   /* check if file is an archive*/
+   if(fread(filemagic, sizeof(filemagic), 1, ifd) == 1
+     && strncmp(filemagic, ARMAG, sizeof filemagic) == 0)
+   {
+      filepos = SARMAG;
+      while((filelength = read_arheader(archentry)) > 0) 
+      {
+        filepos += sizeof(struct ar_hdr);
+        magic = get_word();
+        if(magic == 0x86A3)
+        {      /* OMAGIC*/
+           fseek(ifd, filepos, 0);
+           do_module(archentry, fname);
+        }
+        else if(magic == 0x3C21 )      /* "!<" */
+              filelength = SARMAG;
+        filepos += ld_roundup(filelength, 2, long);
+        fseek(ifd, filepos, 0);
+      }
+   }
+   else
+   {
+      fseek(ifd, 0L, 0);
+      do_module(fname, NULL);
+   }
+   fclose(ifd);
+}
+
+/* read archive header and return length */
+long
+read_arheader(archentry)
+char *archentry;
+{
+   char *        endptr;
+   struct ar_hdr  arheader;
+
+   if(fread((char *)&arheader, sizeof(arheader), 1, ifd) != 1)
+      return 0;
+   strncpy(archentry, arheader.ar_name, sizeof(arheader.ar_name));
+   archentry[sizeof(arheader.ar_name)] = 0;
+   endptr = archentry + sizeof(arheader.ar_name);
+   do
+   {
+      *endptr-- = 0;
+   } while(endptr > archentry && (*endptr == ' ' || *endptr == '/'));
+   return strtoul(arheader.ar_size, (char **)NULL, 0);
+}
+
+void
+do_module(fname, archive)
+char * fname;
+char * archive;
+{
+   int  modno, i;
+
+   size_text = size_data = size_bss = 0;
+   byte_order = 0;
+
+   if( !display_mode )
+   {
+      if(archive)
+        printf("ARCHIVEFILE '%s'\n", archive);
+      printf("OBJECTFILE '%s'\n", fname);
+   }
+
+   switch( read_objheader() )
+   {
+   case 0: /* as86 object file */
+
+      for(modno=1; modno<=sections; modno++)
+      {
+        if( modno != 1 && !display_mode )
+            printf("OBJECTSECTION %d\n", modno);
+        if( read_sectheader() < 0 ) break;
+
+        /* segments 0, 4-E are text, 1-3 are data*/
+        for(i=0; i<16; i++)
+        {
+           if(i < 1 || i > 4)
+                size_text += segsizes[i];
+           else size_data += segsizes[i];
+        }
+
+        if( read_syms() < 0 ) break;
+
+        strtab = malloc((unsigned int)str_len+1);
+        if( strtab == 0 ) { error("Out of memory"); break; }
+        str_off = ftell(ifd);
+        fread(strtab, 1, (unsigned int)str_len, ifd);
+
+        disp_sectheader();
+        disp_syms();
+
+         if( display_mode == 0 )
+            printf("text\tdata\tbss\tdec\thex\tfilename\n");
+         if( display_mode != 2 )
+        {
+            printf("%ld\t%ld\t%ld\t%ld\t%lx\t",
+               size_text, size_data, size_bss,
+               size_text+ size_data+ size_bss,
+               size_text+ size_data+ size_bss);
+
+           if(archive) printf("%s(%s)\n", archive, fname);
+           else        printf("%s\n", fname);
+
+           tot_size_text += size_text;
+           tot_size_data += size_data;
+           tot_size_bss  += size_bss;
+        }
+
+        if( sections == 1 && display_mode != 0 )
+           break;
+
+        read_databytes();
+      }
+      break;
+
+   case 1: /* ELKS executable */
+      fseek(ifd, 0L, 0);
+      fetch_aout_hdr();
+
+      switch(display_mode)
+      {
+      case 0: dump_aout(); break;
+      case 1: size_aout(); break;
+      case 2: nm_aout(); break;
+      }
+      break;
+#ifndef VERY_SMALL_MEMORY
+   case 2: /* V7 executable */
+      fseek(ifd, 0L, 0);
+      fetch_v7_hdr();
+
+      switch(display_mode)
+      {
+      case 0: dump_v7(); break;
+      case 1: size_v7(); break;
+      case 2: error("Symbol table not supported for v7"); exit(1); break;
+      }
+      break;
+#endif
+   }
+
+   if( strtab ) free(strtab);
+   if( symnames ) free(symnames);
+   strtab = 0;
+   symnames = 0;
+}
+
+int
+error(str)
+char * str;
+{
+   switch( display_mode )
+   {
+   case 1: fprintf(stderr, "size: %s: %s\n", ifname, str); break;
+   case 2: fprintf(stderr, "nm: %s: %s\n", ifname, str); break;
+   default:
+      printf("Error: %s\n", str);
+      break;
+   }
+   return -1;
+}
+
+int
+read_objheader()
+{
+   unsigned char buf[5];
+
+   if( fread(buf, 1, 5, ifd) != 5 )
+      return error("Cannot read object header");
+
+   if( buf[0] != 0xA3 || buf[1] != 0x86 )
+   {
+      if( buf[0] == 1 && buf[1] == 3 )
+      {
+         sections = 1;
+        return 1;
+      }
+#ifndef VERY_SMALL_MEMORY
+      if( buf[1] == 1 ) /* 04xx octal */
+      {
+         sections = 1;
+         return 2;
+      }
+#endif
+      return error("Bad magic number");
+   }
+
+   if( (unsigned char)(buf[0] + buf[1] + buf[2] + buf[3]) != buf[4] )
+      return error("Bad header checksum");
+
+   sections= buf[2]+256*buf[3];
+
+   return 0;
+}
+
+int
+read_sectheader()
+{
+   long ssenc;
+   int i;
+
+   textoff = get_long();       /* Offset of bytecode in file */
+   textlen = get_long();       /* Length of text+data (no bss) in memory */
+   str_len = get_word();       /* Length of string table in file */
+   obj_ver = get_word();       /* 0.0 */
+
+   (void)get_long();           /* Ignore fives */
+   ssenc = get_long();         /* Sixteen segment size sizes */
+
+   for(i=0; i<16; i++)
+   {
+      int ss;
+      ss = (i^3);
+      ss = ((ssenc>>(2*(15-ss)))&3);
+      segsizes[i] = get_sized(ss);
+   }
+
+   num_syms = get_word();      /* Number of symbol codes */
+
+   return 0;
+}
+
+void
+disp_sectheader()
+{
+   int i;
+   if( display_mode ) return;
+
+   printf("MODULE  '%s'\n",  strtab);
+   printf("BYTEPOS %08lx\n", textoff);
+   printf("BINLEN  %08lx\n", textlen);
+   printf("STRINGS %04lx +%04lx\n", str_off, str_len);
+   printf("VERSION %d.%d\n", obj_ver/256, obj_ver%256);
+
+   for(i=0; i<16; i++)
+      if( segsizes[i] )
+        printf("SEG%x %08lx\n", i, segsizes[i]);
+
+   printf("\n");
+   printf("SYMS %u\n", num_syms);
+}
+
+int
+read_syms()
+{
+   int i;
+
+   if( num_syms < 0 ) return error("Bad symbol table");
+
+   symnames = malloc(num_syms*sizeof(char*)+1);
+   if( symnames == 0 ) return error("Out of memory");
+
+   symtab = calloc(num_syms, sizeof(*symtab));
+   if( symtab == 0 ) return error("Out of memory");
+
+   for(i=0; i<num_syms; i++)
+   {
+      unsigned int symtype;
+
+      symtab[i].nameoff = get_word();
+      symtab[i].symtype = get_word();
+      symtype = (symtab[i].symtype & 0x3FFF);
+
+      if (symtab[i].nameoff == -1 || symtab[i].symtype == -1) {
+        printf("!!! EOF in symbol table\n");
+        break;
+      }
+      symtab[i].offset = get_sized((symtab[i].symtype>>14)&3);
+
+      if( symtype == 0x43 || symtype == 0x2003 )
+         size_bss += symtab[i].offset;
+   }
+
+   return 0;
+}
+
+int
+disp_syms()
+{
+   int i;
+
+   if(display_mode == 2 && multiple_files && !opt_o)
+     printf("\n%s:\n", ifname);
+
+   for(i=0; i<num_syms; i++)
+   {
+      long offset=0;
+      unsigned int nameoff, symtype;
+
+      nameoff = symtab[i].nameoff;
+      symtype = symtab[i].symtype;
+      offset = symtab[i].offset;
+
+      symtype &= 0x3FFF;
+      if (nameoff > str_len || nameoff < 0)
+        symnames[i] = strtab + str_len;
+      else
+        symnames[i] = strtab+nameoff;
+
+      if( !display_mode )
+      {
+         printf("SYM %-4d %08lx ", i, offset);
+
+         printf("%s", (symtype&0x2000)?"C":".");
+         printf("%s", (symtype&0x0100)?"N":".");
+         printf("%s", (symtype&0x0080)?"E":".");
+         printf("%s", (symtype&0x0040)?"I":".");
+         printf("%c", "T12D456789abcdeUAhijklmnopqrstuv"[symtype&0x1F]); 
+         if( symtype &0x1E20 )
+            printf(" %04x", symtype); 
+         printf(" %s\n", symnames[i]);
+      }
+      if( display_mode == 2 )
+      {
+        if (opt_o)
+           printf("%s: ", ifname);
+        if( symtype == 0x004f || symtype == 0x0040 )
+            printf("         ");
+        else
+            printf("%08lx ", offset);
+        switch(symtype)
+        {
+        case 0x004F: putchar('U'); break;
+        case 0x0000: putchar('t'); break;
+        case 0x0003: putchar('d'); break;
+        case 0x2003: putchar('b'); break;
+        case 0x0043: putchar('C'); break;
+        case 0x0083: putchar('D'); break;
+        case 0x0080: putchar('T'); break;
+        case 0x0040: putchar('T'); break;
+        case 0x0180: putchar('N'); break;
+        case 0x0010: putchar('a'); break;
+        case 0x0090: putchar('A'); break;
+        default:     
+                     if((symtype & ~0xF) == 0x40 )
+                         putchar('u');
+                     else if((symtype & ~0xF) == 0x80 )
+                          printf("%c", "T12D456789abcdeU"[symtype&0xF]); 
+                     else
+                         putchar('?');
+                     break;
+        }
+         printf(" %s\n", symnames[i]);
+      }
+   }
+   if( !display_mode )
+      printf("\n");
+
+   return 0;
+}
+
+void
+read_databytes()
+{
+static char * relstr[] = {"ERR", "DB", "DW", "DD"};
+   long l, cpos;
+   int ch, i;
+   int curseg = 0;
+   int relsize = 0;
+
+   cpos = ftell(ifd);
+   fseek(ifd, filepos+textoff, 0);
+
+   printf("\nBYTECODE\n");
+   for(;;)
+   {
+      if( (ch=get_byte()) == -1 ) break;
+
+      if( ch == 0 ) break;
+
+      switch( ch & 0xC0 )
+      {
+      case 0x00:  switch(ch & 0xF0)
+                  {
+                  case 0x00: /* Relocator size */
+                            printf("RELSZ %d\n", relsize= (ch&0xF));
+                            if(relsize>3) relsize=3;
+                            break;
+                  case 0x10: /* Skip bytes */
+                            printf("SKP %ld\n", get_sized(ch&0xF));
+                            break;
+                  case 0x20: /* Segment */
+                            printf("SEG %x\n", curseg= (ch&0xF));
+                            break;
+                  default:   printf("CODE %02x - unknown\n", ch);
+                             goto break_break ;
+                  }
+                 break;
+      case 0x40:  /* Raw bytes */
+                  {
+                     int abscnt = (ch&0x3F);
+                    if( abscnt == 0 ) abscnt = 64;
+                    for( i=0; i<abscnt; i++ )
+                    {
+                        if( (ch=get_byte()) == -1 ) break;
+                       hex_output(ch);
+                    }
+                    hex_output(EOF);
+            
+                    if( ch == -1 ) goto break_break;
+                  }
+                  break;
+      case 0x80:  /* Relocator - simple */
+                  l = get_sized(relsize);
+                 printf("%s SEG%x%s%s", relstr[relsize],
+                        (ch&0xF),
+                        (ch&0x20)?"-PC":"",
+                        (ch&0x10)?"+?":"");
+                 if(l)
+                    printf("+0x%04lx", l);
+                 putchar('\n');
+                  break;
+      case 0xC0:  /* Relocator - symbol relative */
+                  if( ch & 0x18 )
+                 {
+                    printf("CODE %02x - unknown\n", ch);
+                    goto break_break;
+                 }
+                  if( ch & 4 ) i = get_word();
+                  else         i = get_byte();
+                 l = get_sized(ch&3);
+
+                 printf("%s %s%s%s", relstr[relsize],
+                        symnames[i],
+                        (ch&0x20)?"-PC":"",
+                        (ch&0x18)?"+?":"");
+                 if(l)
+                    printf("+0x%04lx", l);
+                 putchar('\n');
+                  break;
+      }
+   }
+break_break:;
+   printf("\n");
+   fseek(ifd, cpos, 0);
+}
+
+long
+get_sized(sz)
+int sz;
+{
+   switch(sz)
+   {
+   case 0: return 0;
+   case 1: return get_byte();
+   case 2: return get_word();
+   case 3: return get_long();
+   }
+   return -1;
+}
+
+long
+get_long()
+{
+   long retv = 0;
+   int i;
+   for(i=0; i<32; i+=16)
+   {
+      unsigned int v = get_word();
+      if( byte_order & 2 )
+         retv += ((long)v<<(16-i));
+      else
+         retv += ((long)v<<i);
+   }
+   return retv;
+}
+
+unsigned int
+get_word()
+{
+   long retv = 0;
+   int i;
+   for(i=0; i<16; i+=8)
+   {
+      int v = getc(ifd);
+      if( v == EOF ) return -1;
+      code_bytes++;
+      if( byte_order & 1 )
+         retv += (v<<(8-i));
+      else
+         retv += (v<<i);
+   }
+   return retv;
+}
+
+int
+get_byte()
+{
+   int v = getc(ifd);
+   if (v == EOF) return -1; 
+   code_bytes++;
+   return v;
+}
+
+void
+hex_output(ch)
+int ch;
+{
+static char linebuf[80];
+static char buf[20];
+static int pos = 0;
+
+   if( ch == EOF )
+   {
+      if(pos)
+        printf(": %.66s\n", linebuf);
+      pos = 0;
+   }
+   else
+   {
+      if(!pos)
+         memset(linebuf, ' ', sizeof(linebuf));
+      sprintf(buf, "%02x", ch&0xFF);
+      memcpy(linebuf+pos*3+(pos>7), buf, 2);
+      if( ch > ' ' && ch <= '~' ) linebuf[50+pos] = ch;
+      else  linebuf[50+pos] = '.';
+      pos = ((pos+1) & 0xF);
+      if( pos == 0 )
+      {
+         printf(": %.66s\n", linebuf);
+         memset(linebuf, ' ', sizeof(linebuf));
+      }
+   }
+}
+
+/************************************************************************/
+/* ELKS a.out versions
+ */
+
+long header[12];
+int  h_len, h_flgs, h_cpu;
+
+void
+fetch_aout_hdr()
+{
+   int i;
+
+   header[0] = get_long();
+   header[1] = get_long();
+   byte_order = ((header[0]>>24) & 3);
+
+   h_len  = (header[1] & 0xFF);
+   h_flgs = ((header[0]>>16) & 0xFF);
+   h_cpu  = ((header[0]>>24) & 0xFF);
+
+   for(i=2; i<8; i++)
+   {
+      if( i*4 <= h_len )
+         header[i] = get_long();
+      else
+         header[i] = 0;
+   }
+}
+
+void
+dump_aout()
+{
+static char * cpu[] = { "unknown", "8086", "m68k", "ns16k", "i386", "sparc" };
+static char * byteord[] = { "LITTLE_ENDIAN", "(2143)","(3412)","BIG_ENDIAN" };
+   int i;
+   long l;
+
+   if( h_cpu > 0x17 ) h_cpu &= 3;
+
+   printf("HLEN %d\n", h_len);
+   printf("CPU  %s %s\n", cpu[h_cpu>>2], byteord[h_cpu&3]);
+
+   printf("FLAGS:");
+   if( h_flgs & 0x01 ) printf(" A_UZP");
+   if( h_flgs & 0x02 ) printf(" A_PAL");
+   if( h_flgs & 0x04 ) printf(" A_NSYM");
+   if( h_flgs & 0x08 ) printf(" FLG-08");
+   if( h_flgs & 0x10 ) printf(" A_EXEC");
+   if( h_flgs & 0x20 ) printf(" A_SEP");
+   if( h_flgs & 0x40 ) printf(" A_PURE");
+   if( h_flgs & 0x80 ) printf(" A_TOVLY");
+   printf("\n");
+
+   if( header[5] )
+      printf("a_entry  = 0x%08lx\n", header[5]);
+   printf("a_total  = 0x%08lx\n", header[6]);
+   if( header[7] )
+      printf("a_syms   = 0x%08lx\n", header[7]);
+
+   if( h_len >= 36 )
+      printf("a_trsize = 0x%08lx\n", header[8]);
+   if( h_len >= 40 )
+      printf("a_drsize = 0x%08lx\n", header[9]);
+   if( h_len >= 44 )
+      printf("a_tbase  = 0x%08lx\n", header[10]);
+   if( h_len >= 48 )
+      printf("a_dbase  = 0x%08lx\n", header[11]);
+   printf("\n");
+
+   size_aout();
+   printf("\n");
+
+   if( header[7] )
+   {
+      printf("SYMBOLS\n");
+      nm_aout();
+   }
+   else
+      printf("NO SYMBOLS\n");
+   printf("\n");
+
+   printf("TEXTSEG\n");
+   fseek(ifd, (long)h_len, 0);
+   for(l=0; l<header[2]; l++)
+   {
+      if( (i=getc(ifd)) == EOF ) break;
+      hex_output(i);
+   }
+   hex_output(EOF);
+
+   printf("DATASEG\n");
+   fseek(ifd, (long)h_len+header[2], 0);
+   for(l=0; l<header[3]; l++)
+   {
+      if( (i=getc(ifd)) == EOF ) break;
+      hex_output(i);
+   }
+   hex_output(EOF);
+}
+
+void
+size_aout()
+{
+   if( display_mode == 0 )
+      printf("text\tdata\tbss\tdec\thex\tfilename\n");
+
+   printf("%ld\t%ld\t%ld\t%ld\t%lx\t%s\n",
+      header[2], header[3], header[4],
+      header[2]+ header[3]+ header[4],
+      header[2]+ header[3]+ header[4],
+      ifname);
+
+   tot_size_text += header[2];
+   tot_size_data += header[3];
+   tot_size_bss  += header[4];
+}
+
+void
+nm_aout()
+{
+   char n_name[10];
+   long n_value;
+   int n_sclass, n_numaux, n_type;
+   long bytes_left;
+   int  pending_nl = 0;
+
+   fseek(ifd, h_len+header[2]+header[3]+header[8]+header[9], 0);
+
+   if( h_flgs & 4 ) 
+      { error("Executable has new format symbol table.\n"); return; }
+
+   bytes_left = header[7];
+
+   if( bytes_left == 0 )
+      printf("No symbols in '%s'\n", ifname);
+   else if(multiple_files && !opt_o)
+     printf("\n%s:\n", ifname);
+
+   while(bytes_left > 16)
+   {
+      if( fread(n_name, 1, 8, ifd) != 8 ) break;
+      n_name[8] = 0;
+      n_value  = get_long();
+      if( (n_sclass = getc(ifd)) == EOF ) break;
+      if( (n_numaux = getc(ifd)) == EOF ) break;
+      n_type = get_word();
+
+      if( pending_nl && n_sclass == 0 )
+      {
+         printf("%s", n_name);
+         continue;
+      }
+
+      if( pending_nl ) putchar('\n');
+      if (opt_o)
+         printf("%s: ", ifname);
+      if( n_sclass == 0x10 )
+         printf("         ");
+      else
+         printf("%08lx ", n_value);
+      switch(n_sclass)
+      {
+      case 0x01: printf("a "); break;      
+      case 0x12: printf("T "); break;
+      case 0x13: printf("D "); break;
+      case 0x14: printf("C "); break;
+      case 0x1a: printf("t "); break;
+      case 0x1b: printf("d "); break;
+      case 0x1c: printf("b "); break;
+      case 0x10: printf("U "); break;
+      default:   if( display_mode )
+                 {
+                   printf("? "); break;
+                 }
+
+                 printf("n_sclass=");
+                 switch(n_sclass>>3)
+                {
+                case 0: printf("C_NULL,"); break;
+                case 2: printf("C_EXT,"); break;
+                case 3: printf("C_STAT,"); break;
+                default: printf("%04o,", n_sclass&0xF8);
+                }
+                 switch(n_sclass&7)
+                {
+                case 0: printf("N_UNDF "); break;
+                case 1: printf("N_ABS "); break;
+                case 2: printf("N_TEXT "); break;
+                case 3: printf("N_DATA "); break;
+                case 4: printf("N_BSS "); break;
+                case 5: printf("N_COMM "); break;
+                default: printf("%o ", n_sclass&7); break;
+                }
+                break;
+      }
+
+      if( display_mode == 0 )
+      {
+        if( n_numaux )
+            printf("n_numaux=%02x ", n_numaux);
+        if( n_type )
+            printf("n_type=%04x ", n_type);
+      }
+
+      printf("%s", n_name);
+
+      pending_nl=1;
+   }
+
+   if( pending_nl ) putchar('\n');
+}
+
+#ifndef VERY_SMALL_MEMORY
+/************************************************************************/
+/* V7 a.out versions
+ */
+
+void
+fetch_v7_hdr()
+{
+   int i;
+
+   h_len  = 8;
+   for(i=0; i<h_len; i++)
+   {
+      header[i] = get_word();
+   }
+}
+
+void
+size_v7()
+{
+   if( display_mode == 0 )
+      printf("text\tdata\tbss\tdec\thex\tfilename\n");
+
+   printf("%ld\t%ld\t%ld\t%ld\t%lx\t%s\n",
+      header[1], header[2], header[3],
+      header[1]+ header[2]+ header[3],
+      header[1]+ header[2]+ header[3],
+      ifname);
+
+   tot_size_text += header[1];
+   tot_size_data += header[2];
+   tot_size_bss  += header[3];
+}
+
+void
+dump_v7()
+{
+   int i;
+   long l;
+
+   printf("TYPE:");
+   switch (header[0]) {
+   case 0405: printf(" overlay"); break;
+   case 0407: printf(" impure"); break;
+   case 0410: printf(" read-only text"); break;
+   case 0411: printf(" pure"); break;
+   case 0413: printf(" demand load"); break;
+   default: printf(" (unknown)"); break;
+   }
+   printf("\n");
+
+   if( header[5] )
+      printf("a_entry  = 0x%08lx\n", header[5]);
+   printf("\n");
+
+   size_aout();
+   printf("\n");
+
+   printf("TEXTSEG\n");
+   fseek(ifd, (long)h_len, 0);
+   for(l=0; l<header[1]; l++)
+   {
+      if( (i=getc(ifd)) == EOF ) break;
+      hex_output(i);
+   }
+   hex_output(EOF);
+
+   printf("DATASEG\n");
+   fseek(ifd, (long)h_len+header[1], 0);
+   for(l=0; l<header[2]; l++)
+   {
+      if( (i=getc(ifd)) == EOF ) break;
+      hex_output(i);
+   }
+   hex_output(EOF);
+}
+#endif
diff --git a/Applications/ld09/readobj.c b/Applications/ld09/readobj.c
new file mode 100644 (file)
index 0000000..6cc9a84
--- /dev/null
@@ -0,0 +1,373 @@
+/* readobj.c - read object file for linker */
+
+/* Copyright (C) 1994 Bruce Evans */
+
+#include "syshead.h"
+#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"
+
+/*
+   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, bin_off_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 = NUL_PTR;
+    entryfirst = entrylast = NUL_PTR;
+    redfirst = redlast = NUL_PTR;
+}
+
+/* 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 *) NUL_PTR);
+       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)
+       {
+           unsigned int magic;
+           if (trace)
+               errtrace(archentry, 2);
+           filepos += sizeof(struct ar_hdr);
+            magic = (unsigned) readsize(2);
+            if(magic == OMAGIC)
+           {
+               seekin(filepos);
+               for (modcount = readfileheader(); modcount-- != 0;)
+               {
+                   readmodule(stralloc(filename), archentry);
+                   modlast->textoffset += filepos;
+               }
+           }
+           else if( magic == 0x3C21 ) /* "!<" */
+              filelength = SARMAG;
+           seekin(filepos += ld_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 == ' ' || *endptr == '/'));
+    return strtoul(arheader.ar_size, (char **) NUL_PTR, 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 (checksum failed)");
+    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 */
+    {
+       bin_off_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)) != NUL_PTR)
+       {
+           /*
+              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) & (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 = NUL_PTR;
+}
+
+/* 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 != NUL_PTR; elptr = elptr->elnext)
+       if (symptr == elptr->elsymptr)
+           return;
+    elptr = (struct entrylist *) ourmalloc(sizeof(struct entrylist));
+    elptr->elnext = NUL_PTR;
+    elptr->elsymptr = symptr;
+    if (entryfirst == NUL_PTR)
+       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 = NUL_PTR;
+    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 == NUL_PTR)
+       modfirst = modptr;
+    else
+       modlast->modnext = modptr;
+    modlast = modptr;
+}
+
+PRIVATE bool_pt redsym(symptr, value)
+register struct symstruct *symptr;
+bin_off_t value;
+{
+    register struct redlist *rlptr;
+    char class;
+
+    if (symptr->modptr->class != (class = modlast->class))
+       for (rlptr = redfirst;; rlptr = rlptr->rlnext)
+       {
+           if (rlptr == NUL_PTR)
+           {
+               rlptr = (struct redlist *)
+                   ourmalloc(sizeof(struct redlist));
+               rlptr->rlnext = NUL_PTR;
+               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 == NUL_PTR)
+                   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 bin_off_t readconvsize(countindex)
+unsigned countindex;
+{
+    return readsize(convertsize[countindex]);
+}
+
+PUBLIC bin_off_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/Applications/ld09/rel_aout.h b/Applications/ld09/rel_aout.h
new file mode 100644 (file)
index 0000000..9316a72
--- /dev/null
@@ -0,0 +1,383 @@
+#ifndef _BSD_A_OUT_H
+#define _BSD_A_OUT_H
+
+struct exec {                  /* a.out header */
+  unsigned char        a_magic[2];     /* magic number */
+  unsigned char        a_flags;        /* flags, see below */
+  unsigned char        a_cpu;          /* cpu id */
+  unsigned char        a_hdrlen;       /* length of header */
+  unsigned char        a_unused;       /* reserved for future use */
+  unsigned short a_version;    /* version stamp (not used at present) */
+  long         a_text;         /* size of text segement in bytes */
+  long         a_data;         /* size of data segment in bytes */
+  long         a_bss;          /* size of bss segment in bytes */
+  long         a_entry;        /* entry point */
+  long         a_total;        /* total memory allocated */
+  long         a_syms;         /* size of symbol table */
+                               /* SHORT FORM ENDS HERE */
+
+  long         a_trsize;       /* text relocation size */
+  long         a_drsize;       /* data relocation size */
+  long         a_tbase;        /* text relocation base */
+  long         a_dbase;        /* data relocation base */
+};
+
+#define A_MAGIC0       ((unsigned char) 0x01)
+#define A_MAGIC1       ((unsigned char) 0x03)
+#define BADMAG(X)    ((X).a_magic[0] != A_MAGIC0 || (X).a_magic[1] != A_MAGIC1)
+
+/* CPU Id of TARGET machine (byte order coded in low order two bits) */
+#define A_NONE 0x00    /* unknown */
+#define A_I8086        0x04    /* intel i8086/8088 */
+#define A_M68K 0x0B    /* motorola m68000 */
+#define A_NS16K        0x0C    /* national semiconductor 16032 */
+#define A_I80386 0x10  /* intel i80386 */
+#define A_SPARC        0x17    /* Sun SPARC */
+
+#define A_BLR(cputype) ((cputype&0x01)!=0) /* TRUE if bytes left-to-right */
+#define A_WLR(cputype) ((cputype&0x02)!=0) /* TRUE if words left-to-right */
+
+/* Flags. */
+#define A_UZP  0x01    /* unmapped zero page (pages) */
+#define A_EXEC 0x10    /* executable */
+#define A_SEP  0x20    /* separate I/D */
+#define A_PURE 0x40    /* pure text */         /* not used */
+#define A_TOVLY        0x80    /* text overlay */      /* not used */
+
+/* Tell a.out.gnu.h not to define `struct exec'.  */
+#define __STRUCT_EXEC_OVERRIDE__
+
+/* Hide M_386 from enum declaration in a.out.h. */
+#define M_386 HIDE_M_386
+
+#ifndef __A_OUT_GNU_H__
+#define __A_OUT_GNU_H__
+
+#if defined(sequent) && defined(i386)
+#define a_magic a_info
+#include <a.out.h>
+#undef a_magic
+#define __STRUCT_EXEC_OVERRIDE__
+#define N_NLIST_DECLARED
+#define N_RELOCATION_INFO_DECLARED
+#endif
+
+#define __GNU_EXEC_MACROS__
+
+#ifndef __STRUCT_EXEC_OVERRIDE__
+
+struct exec
+{
+  unsigned long a_info;                /* Use macros N_MAGIC, etc for access */
+  unsigned long a_text;                /* length of text, in bytes */
+  unsigned long a_data;                /* length of data, in bytes */
+  unsigned long a_bss;         /* length of uninitialized data area for file, in bytes */
+  unsigned long a_syms;                /* length of symbol table data in file, in bytes */
+  unsigned long a_entry;       /* start address */
+  unsigned long a_trsize;      /* length of relocation info for text, in bytes */
+  unsigned long a_drsize;      /* length of relocation info for data, in bytes */
+};
+
+#endif /* __STRUCT_EXEC_OVERRIDE__ */
+
+/* these go in the N_MACHTYPE field */
+enum machine_type {
+#if defined (M_OLDSUN2)
+  M__OLDSUN2 = M_OLDSUN2,
+#else
+  M_OLDSUN2 = 0,
+#endif
+#if defined (M_68010)
+  M__68010 = M_68010,
+#else
+  M_68010 = 1,
+#endif
+#if defined (M_68020)
+  M__68020 = M_68020,
+#else
+  M_68020 = 2,
+#endif
+#if defined (M_SPARC)
+  M__SPARC = M_SPARC,
+#else
+  M_SPARC = 3,
+#endif
+  /* skip a bunch so we don't run into any of sun's numbers */
+  M_386 = 100,
+};
+
+#if !defined (N_MAGIC)
+#define N_MAGIC(exec) ((exec).a_info & 0xffff)
+#endif
+#define N_MACHTYPE(exec) ((enum machine_type)(((exec).a_info >> 16) & 0xff))
+#define N_FLAGS(exec) (((exec).a_info >> 24) & 0xff)
+#define N_SET_INFO(exec, magic, type, flags) \
+       ((exec).a_info = ((magic) & 0xffff) \
+        | (((int)(type) & 0xff) << 16) \
+        | (((flags) & 0xff) << 24))
+#define N_SET_MAGIC(exec, magic) \
+       ((exec).a_info = (((exec).a_info & 0xffff0000) | ((magic) & 0xffff)))
+
+#define N_SET_MACHTYPE(exec, machtype) \
+       ((exec).a_info = \
+        ((exec).a_info&0xff00ffff) | ((((int)(machtype))&0xff) << 16))
+
+#define N_SET_FLAGS(exec, flags) \
+       ((exec).a_info = \
+        ((exec).a_info&0x00ffffff) | (((flags) & 0xff) << 24))
+
+#ifndef OMAGIC
+/* Code indicating object file or impure executable.  */
+#define OMAGIC 0407
+/* Code indicating pure executable.  */
+#define NMAGIC 0410
+/* Code indicating demand-paged executable.  */
+#define ZMAGIC 0413
+#endif /* not OMAGIC */
+
+#if !defined (N_BADMAG)
+#define N_BADMAG(x)                                    \
+ (N_MAGIC(x) != OMAGIC && N_MAGIC(x) != NMAGIC         \
+  && N_MAGIC(x) != ZMAGIC)
+#endif
+
+#define _N_BADMAG(x)                                   \
+ (N_MAGIC(x) != OMAGIC && N_MAGIC(x) != NMAGIC         \
+  && N_MAGIC(x) != ZMAGIC)
+
+#define _N_HDROFF(x) (SEGMENT_SIZE - sizeof (struct exec))
+
+#if !defined (N_TXTOFF)
+#define N_TXTOFF(x) \
+ (N_MAGIC(x) == ZMAGIC ? _N_HDROFF((x)) + sizeof (struct exec) : sizeof (struct exec))
+#endif
+
+#if !defined (N_DATOFF)
+#define N_DATOFF(x) (N_TXTOFF(x) + (x).a_text)
+#endif
+
+#if !defined (N_TRELOFF)
+#define N_TRELOFF(x) (N_DATOFF(x) + (x).a_data)
+#endif
+
+#if !defined (N_DRELOFF)
+#define N_DRELOFF(x) (N_TRELOFF(x) + (x).a_trsize)
+#endif
+
+#if !defined (N_SYMOFF)
+#define N_SYMOFF(x) (N_DRELOFF(x) + (x).a_drsize)
+#endif
+
+#if !defined (N_STROFF)
+#define N_STROFF(x) (N_SYMOFF(x) + (x).a_syms)
+#endif
+
+/* Address of text segment in memory after it is loaded.  */
+#if !defined (N_TXTADDR)
+#define N_TXTADDR(x) 0
+#endif
+
+/* Address of data segment in memory after it is loaded.
+   Note that it is up to you to define SEGMENT_SIZE
+   on machines not listed here.  */
+#if defined(vax) || defined(hp300) || defined(pyr)
+#define SEGMENT_SIZE PAGE_SIZE
+#endif
+#ifdef hp300
+#define        PAGE_SIZE       4096
+#endif
+#ifdef sony
+#define        SEGMENT_SIZE    0x2000
+#endif /* Sony.  */
+#ifdef is68k
+#define SEGMENT_SIZE 0x20000
+#endif
+#if defined(m68k) && defined(PORTAR)
+#define PAGE_SIZE 0x400
+#define SEGMENT_SIZE PAGE_SIZE
+#endif
+
+#define _N_SEGMENT_ROUND(x) (((x) + SEGMENT_SIZE - 1) & ~(SEGMENT_SIZE - 1))
+
+#define _N_TXTENDADDR(x) (N_TXTADDR(x)+(x).a_text)
+
+#ifndef N_DATADDR
+#define N_DATADDR(x) \
+    (N_MAGIC(x)==OMAGIC? (_N_TXTENDADDR(x)) \
+     : (_N_SEGMENT_ROUND (_N_TXTENDADDR(x))))
+#endif
+
+/* Address of bss segment in memory after it is loaded.  */
+#if !defined (N_BSSADDR)
+#define N_BSSADDR(x) (N_DATADDR(x) + (x).a_data)
+#endif
+\f
+#if !defined (N_NLIST_DECLARED)
+struct nlist {
+  union {
+    char *n_name;
+    struct nlist *n_next;
+    long n_strx;
+  } n_un;
+  unsigned char n_type;
+  char n_other;
+  short n_desc;
+  unsigned long n_value;
+};
+#endif /* no N_NLIST_DECLARED.  */
+
+#if !defined (N_UNDF)
+#define N_UNDF 0
+#endif
+#if !defined (N_ABS)
+#define N_ABS 2
+#endif
+#if !defined (N_TEXT)
+#define N_TEXT 4
+#endif
+#if !defined (N_DATA)
+#define N_DATA 6
+#endif
+#if !defined (N_BSS)
+#define N_BSS 8
+#endif
+#if !defined (N_COMM)
+#define N_COMM 18
+#endif
+#if !defined (N_FN)
+#define N_FN 15
+#endif
+
+#if !defined (N_EXT)
+#define N_EXT 1
+#endif
+#if !defined (N_TYPE)
+#define N_TYPE 036
+#endif
+#if !defined (N_STAB)
+#define N_STAB 0340
+#endif
+
+/* The following type indicates the definition of a symbol as being
+   an indirect reference to another symbol.  The other symbol
+   appears as an undefined reference, immediately following this symbol.
+
+   Indirection is asymmetrical.  The other symbol's value will be used
+   to satisfy requests for the indirect symbol, but not vice versa.
+   If the other symbol does not have a definition, libraries will
+   be searched to find a definition.  */
+#define N_INDR 0xa
+
+/* The following symbols refer to set elements.
+   All the N_SET[ATDB] symbols with the same name form one set.
+   Space is allocated for the set in the text section, and each set
+   element's value is stored into one word of the space.
+   The first word of the space is the length of the set (number of elements).
+
+   The address of the set is made into an N_SETV symbol
+   whose name is the same as the name of the set.
+   This symbol acts like a N_DATA global symbol
+   in that it can satisfy undefined external references.  */
+
+/* These appear as input to LD, in a .o file.  */
+#define        N_SETA  0x14            /* Absolute set element symbol */
+#define        N_SETT  0x16            /* Text set element symbol */
+#define        N_SETD  0x18            /* Data set element symbol */
+#define        N_SETB  0x1A            /* Bss set element symbol */
+
+/* This is output from LD.  */
+#define N_SETV 0x1C            /* Pointer to set vector in data area.  */
+\f
+#if !defined (N_RELOCATION_INFO_DECLARED)
+/* This structure describes a single relocation to be performed.
+   The text-relocation section of the file is a vector of these structures,
+   all of which apply to the text section.
+   Likewise, the data-relocation section applies to the data section.  */
+
+struct relocation_info
+{
+  /* Address (within segment) to be relocated.  */
+  unsigned long r_address;
+#if 0
+  /* The meaning of r_symbolnum depends on r_extern.  */
+  unsigned int r_symbolnum:24;
+  /* Nonzero means value is a pc-relative offset
+     and it should be relocated for changes in its own address
+     as well as for changes in the symbol or section specified.  */
+  unsigned int r_pcrel:1;
+  /* Length (as exponent of 2) of the field to be relocated.
+     Thus, a value of 2 indicates 1<<2 bytes.  */
+  unsigned int r_length:2;
+  /* 1 => relocate with value of symbol.
+          r_symbolnum is the index of the symbol
+         in file's the symbol table.
+     0 => relocate with the address of a segment.
+          r_symbolnum is N_TEXT, N_DATA, N_BSS or N_ABS
+         (the N_EXT bit may be set also, but signifies nothing).  */
+  unsigned int r_extern:1;
+  /* Four bits that aren't used, but when writing an object file
+     it is desirable to clear them.  */
+  unsigned int r_pad:4;
+#else
+  unsigned long foo;
+#endif
+};
+#endif /* no N_RELOCATION_INFO_DECLARED.  */
+
+
+#endif /* __A_OUT_GNU_H__ */
+
+#undef M_386
+#define M_386 A_I80386
+
+#undef N_MAGIC
+#define N_MAGIC3(magic0, magic1, type) \
+       ((magic0) | ((magic1) << 8) | ((type) << 16))
+#define N_MAGIC(exec) \
+       N_MAGIC3((exec).a_magic[0], (exec).a_magic[1], (exec).a_flags)
+       
+#undef N_MACHTYPE
+#define N_MACHTYPE(exec) ((enum machine_type)((exec).a_cpu))
+
+#undef N_FLAGS
+#define N_FLAGS(exec) 0
+
+#undef N_SET_INFO
+#define N_SET_INFO(exec, magic, type, flags) \
+       ((exec).a_magic[0] = (magic) & 0xff, \
+        (exec).a_magic[1] = ((magic) >> 8) & 0xff, \
+        (exec).a_flags = ((magic) >> 16) & 0xff, \
+        (exec).a_cpu = (type) & 0xff)
+        
+#undef N_SET_MAGIC
+#define N_SET_MAGIC(exec, magic) \
+       ((exec).a_magic[0] = (magic) & 0xff, \
+        (exec).a_magic[1] = ((magic) >> 8) & 0xff, \
+        (exec).a_flags = ((magic) >> 16) & 0xff)
+
+#undef N_SET_MACHTYPE
+#define N_SET_MACHTYPE(exec, machtype) \
+       ((exec).a_cpu = (machtype) & 0xff, \
+        (exec).a_hdrlen = sizeof (exec))
+
+#undef N_SET_FLAGS
+#define N_SET_FLAGS(exec, flags) /* nothing */
+
+#undef OMAGIC
+#define OMAGIC N_MAGIC3(A_MAGIC0, A_MAGIC1, 0)
+
+#undef NMAGIC
+#define NMAGIC N_MAGIC3(A_MAGIC0, A_MAGIC1, A_EXEC)
+
+#undef ZMAGIC
+#define ZMAGIC N_MAGIC3(A_MAGIC0, A_MAGIC1, A_EXEC)
+
+#undef _N_HDROFF
+#define _N_HDROFF(x) 0
+
+#undef PAGE_SIZE
+#define PAGE_SIZE 16
+#define SEGMENT_SIZE PAGE_SIZE
+#define getpagesize() PAGE_SIZE
+
+#endif /* _BSD_A_OUT_H */
diff --git a/Applications/ld09/syshead.h b/Applications/ld09/syshead.h
new file mode 100644 (file)
index 0000000..f107ac3
--- /dev/null
@@ -0,0 +1,18 @@
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+
+/******************************************************************************/
+
+/* EEEEyuk!! */
+
+#ifdef __STDC__
+#define P(x)   x
+#else
+#define P(x)   ()
+#endif
+
diff --git a/Applications/ld09/table.c b/Applications/ld09/table.c
new file mode 100644 (file)
index 0000000..f960da0
--- /dev/null
@@ -0,0 +1,230 @@
+/* table.c - table-handler module for linker */
+
+/* Copyright (C) 1994 Bruce Evans */
+
+#include "syshead.h"
+#include "const.h"
+#include "align.h"
+#include "obj.h"
+#include "type.h"
+#include "globvar.h"
+
+#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 */
+
+PUBLIC  int maxused = 0;       /* Stats */
+PRIVATE int mainavail, usedtop;        /* Stats */
+
+FORWARD struct symstruct **gethashptr P((char *name));
+FORWARD void check_used P((void));
+
+/* initialise symbol table */
+
+PUBLIC void syminit()
+{
+    unsigned i;
+
+    for (i = sizeof(int) <= 2 ? 0xE000 : (unsigned) 0x38000;
+        i != 0; i -= 512)
+       if ((tableptr = malloc(i)) != NUL_PTR)
+           break;
+    if (tableptr == NUL_PTR)
+       outofmemory();
+    tableend = tableptr + i;
+    for (i = 0; i < HASHTABSIZE; i++)
+       hashtab[i] = NUL_PTR;
+
+    mainavail = tableend - tableptr;
+    usedtop = 0;
+}
+
+/* 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 = 0;
+    struct symstruct *symptr;
+
+    hashptr = gethashptr(name);
+    symptr = *hashptr;
+    while (symptr != NUL_PTR)
+    {
+       oldsymptr = symptr;
+       symptr = symptr->next;
+    }
+    align(tableptr);
+    symptr = (struct symstruct *) tableptr;
+    if ((tableptr = symptr->name + (strlen(name) + 1)) > tableend)
+       outofmemory();
+    symptr->modptr = NUL_PTR;
+    symptr->next = NUL_PTR;
+    if (name != symptr->name)
+       strcpy(symptr->name, name);     /* should't happen */
+    if (*hashptr == NUL_PTR)
+       *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 != NUL_PTR && (!(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;
+
+    usedtop   += nbytes;
+    mainavail -= nbytes;
+
+    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;
+{
+    check_used();
+    tableptr = cptr;
+    check_used();
+}
+
+/* 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)
+    {
+        /* Stats: need a checkused against 's', maybe. */
+       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;
+{
+    check_used();
+    mainavail += cptr - tableend;
+    usedtop -= cptr - tableend;
+
+    tableend = cptr;
+}
+
+PRIVATE void check_used()
+{
+   int used;
+
+   used = usedtop + mainavail - (tableend - tableptr);
+   if (used > maxused) maxused = used;
+}
+
+PUBLIC int memory_used()
+{
+   check_used();
+   return maxused;
+}
+
+/* allocate space for string */
+
+PUBLIC char *stralloc(s)
+char *s;
+{
+    return strcpy(ourmalloc((unsigned) strlen(s) + 1), s);
+}
diff --git a/Applications/ld09/type.h b/Applications/ld09/type.h
new file mode 100644 (file)
index 0000000..5301b6f
--- /dev/null
@@ -0,0 +1,176 @@
+/* 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;
+
+typedef unsigned flags_t;      /* unsigned makes shifts logical */
+
+#ifdef LONG_OFFSETS
+typedef unsigned long bin_off_t;
+#else
+typedef unsigned bin_off_t;
+#endif
+
+#ifdef OBJ_H                   /* obj.h is included */
+
+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 */
+    bin_off_t rlvalue;         /* value for this redefinition */
+};
+
+struct symstruct               /* symbol table entry format */
+{
+    struct modstruct *modptr;  /* module where symbol is defined */
+    bin_off_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 */
+
+#ifndef P
+#ifdef __STDC__
+#define P(x)   x
+#else
+#define P(x)   ()
+#endif
+#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));
+void put08x P((bin_off_t num));
+void put08lx P((bin_off_t num));
+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 interseg P((char *fname, char *aname, char *name));
+void reserved P((char *name));
+void size_error P((int seg, bin_off_t count, bin_off_t size));
+void undefined P((char *name));
+void usage P((void));
+void version_msg 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));
+unsigned segsizecount P((unsigned seg, struct modstruct *modptr));
+#endif
+bin_off_t readconvsize P((unsigned countindex));
+bin_off_t readsize P((unsigned count));
+
+/* 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));
+int memory_used P((void));
+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 write_dosemu P((char *outfilename, bool_pt argsepid, bool_pt argbits32,
+                bool_pt argstripflag, bool_pt arguzp));
+
+/* write_elks.c */
+void write_elks P((char *outfilename, bool_pt argsepid, bool_pt argbits32,
+                bool_pt argstripflag, bool_pt arguzp, bool_pt nsym));
+
+/* linksym.c */
+void linksyms P((bool_pt argreloc_output));
+
+/* mkar.c */
+void ld86r P((int argc, char ** argv));
diff --git a/Applications/ld09/typeconv.c b/Applications/ld09/typeconv.c
new file mode 100644 (file)
index 0000000..d8c0c89
--- /dev/null
@@ -0,0 +1,191 @@
+
+/*
+ * Type conversion routines, these have been rewritten for portability.
+ *
+ * The only requirement is now that the u2_t and u4_t must be big enough.
+ */
+
+#include "syshead.h"
+#include "const.h"
+#include "type.h"
+#include "globvar.h"
+
+void xxerr P((char *));
+void xxerr(x) char * x; { write(2, x, strlen(x)); }
+
+static int no_swap   = 1;
+
+static int long_off[4] = {0,1,2,3};
+static int int_off[2] = {0,1};
+
+PUBLIC bool_pt typeconv_init(big_endian, long_big_endian)
+bool_pt big_endian;
+bool_pt long_big_endian;
+{
+   int i;
+   no_swap = (!big_endian && !long_big_endian);
+
+   for(i=0; i<4; i++) long_off[i] = i;
+   for(i=0; i<2; i++) int_off[i] = i;
+
+   if( long_big_endian )
+   {
+      i = long_off[0]; long_off[0] = long_off[2]; long_off[2] = i;
+      i = long_off[1]; long_off[1] = long_off[3]; long_off[3] = i;
+   }
+   if( big_endian )
+   {
+      i = long_off[2]; long_off[2] = long_off[3]; long_off[3] = i;
+      i = long_off[0]; long_off[0] = long_off[1]; long_off[1] = i;
+
+      i = int_off[0]; int_off[0] = int_off[1]; int_off[1] = i;
+   }
+   return 1;
+}
+
+PUBLIC void u2c2(buf, offset)
+char *buf;
+u2_pt offset;
+{
+#ifdef __AS386_16__
+   if( no_swap )
+   {
+      *((unsigned short*)buf) = offset;        /* UNALIGNED ACCESS! */
+      return;
+   }
+#endif
+   buf[int_off[0]] = offset;
+   buf[int_off[1]] = (offset>>8);
+}
+
+PUBLIC void u4c4(buf, offset)
+char *buf;
+u4_t offset;
+{
+   int i;
+#ifdef __AS386_16__
+   if( no_swap )
+   {
+      *((unsigned long*)buf) = offset; /* UNALIGNED ACCESS! */
+      return;
+   }
+#endif
+   for(i=0; i<4; i++)
+   {
+      buf[long_off[i]] = offset;
+      offset >>= 8;
+   }
+}
+
+PUBLIC void u4cn(buf, offset, count)
+char *buf;
+u4_t offset;
+unsigned count;
+{
+    switch(count)
+    {
+    case 1:
+       buf[0] = (char) offset;
+       return;
+    case 2:
+       u2c2(buf, (u2_pt) offset);
+       return;
+    case 4:
+       u4c4(buf, (u4_t) offset);
+       return;
+    default:
+        xxerr("WARNING: typeconv.c(u4cn) illegal count\n");
+       return;
+    }
+}
+
+PUBLIC void u2cn(buf, offset, count)
+char *buf;
+u2_pt offset;
+unsigned count;
+{
+    switch(count)
+    {
+    case 1:
+       buf[0] = (char) offset;
+       return;
+    case 2:
+       u2c2(buf, (u2_pt) offset);
+       return;
+    case 4:
+       u4c4(buf, (u4_t) offset);
+       return;
+    default:
+        xxerr("WARNING: typeconv.c(u2cn) illegal count\n");
+       return;
+    }
+}
+
+PUBLIC u2_pt c2u2(buf)
+char *buf;
+{
+    u2_pt res;
+#ifdef __AS386_16__
+   if( no_swap ) return *((u2_pt *)buf);       /* UNALIGNED ACCESS! */
+#endif
+
+    res  =   ((unsigned char *)buf) [int_off[0]]
+         + ((((unsigned char *)buf) [int_off[1]]) << 8);
+    return res;
+}
+
+PUBLIC u4_t c4u4(buf)
+char *buf;
+{
+    u4_t res;
+    int i;
+#ifdef __AS386_16__
+   if( no_swap ) return *((u4_t *)buf);                /* UNALIGNED ACCESS! */
+#endif
+    res = 0;
+    for(i=3; i>=0; i--)
+    {
+        res = (res<<8) + ((unsigned char *)buf) [long_off[i]];
+    }
+    return res;
+}
+
+PUBLIC u4_t cnu4(buf, count)
+char *buf;
+unsigned count;
+{
+    switch (count)
+    {
+    case 0:
+       return 0;
+    case 1:
+       return buf[0] & 0xFF;
+    case 2:
+       return c2u2(buf);
+    case 4:
+       return c4u4(buf);
+    default:
+        xxerr("WARNING: typeconv.c(cnu4) illegal count\n");
+       return 0;
+    }
+}
+
+PUBLIC u2_pt cnu2(buf, count)
+char *buf;
+unsigned count;
+{
+    switch (count)
+    {
+    case 0:
+       return 0;
+    case 1:
+       return buf[0] & 0xFF;
+    case 2:
+       return c2u2(buf);
+    case 4:
+       return (u2_pt) c4u4(buf);
+    default:
+        xxerr("WARNING: typeconv.c(cnu2) illegal count\n");
+       return 0;
+    }
+}
diff --git a/Applications/ld09/v7_aout.h b/Applications/ld09/v7_aout.h
new file mode 100644 (file)
index 0000000..020079b
--- /dev/null
@@ -0,0 +1,26 @@
+/* Header format of 16-bit
+ * Seventh edition UNIX executables */
+
+#ifndef _V7_A_OUT_H
+#define _V7_A_OUT_H
+
+#define V7_MAGIC4 0405 /* v7 overlay */
+#define V7_OMAGIC 0407 /* I&D in one segment (impure) */
+#define V7_NMAGIC 0410 /* read-only text */
+#define V7_MAGIC3 0411 /* v7 separate I&D (pure) */
+#define V7_ZMAGIC 0413 /* v8 demand load */
+
+#define V7_HEADERLEN 16
+
+struct  v7_exec {
+    short magic;
+    unsigned short textsize;
+    unsigned short datasize;
+    unsigned short bsssize;
+    unsigned short symtabsize;
+    unsigned short entry;
+    unsigned short pad;
+    unsigned short noreloc;
+};
+
+#endif /* _V7_A_OUT_H */
diff --git a/Applications/ld09/version.h b/Applications/ld09/version.h
new file mode 100644 (file)
index 0000000..0af81ac
--- /dev/null
@@ -0,0 +1 @@
+#define VERSION "0.16.21"
diff --git a/Applications/ld09/writebin.c b/Applications/ld09/writebin.c
new file mode 100644 (file)
index 0000000..8535068
--- /dev/null
@@ -0,0 +1,1065 @@
+
+/* writebin.c - write binary file for linker */
+
+/* Copyright (C) 1994 Bruce Evans */
+
+#include "syshead.h"
+#include "bindef.h"
+#include "const.h"
+#include "obj.h"
+#include "type.h"
+#include "globvar.h"
+
+#ifdef AOUT_DETECTED
+#define btextoffset (text_base_value)
+#define bdataoffset (data_base_value)
+#define page_size() 4096
+
+#ifdef __ELF__
+#ifndef ELF_SYMS
+#define ELF_SYMS 1
+#endif
+#endif
+
+#ifdef EDOS
+# define FILEHEADERLENGTH 0
+#endif
+#ifdef MINIX
+# ifdef BSD_A_OUT
+#  ifdef STANDARD_GNU_A_OUT
+#   define HEADERLEN (sizeof(struct exec))
+#  else
+#   define HEADERLEN (48)
+#  endif
+# else
+#  ifdef REL_OUTPUT
+#   define HEADERLEN (reloc_output?sizeof(struct exec):A_MINHDR)
+                               /* part of header not counted in offsets */
+#  else
+#   define HEADERLEN (A_MINHDR)
+#  endif
+# endif
+# ifndef FILEHEADERLENGTH
+#  define FILEHEADERLENGTH (headerless?0:HEADERLEN)
+# 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 bin_off_t combase[NSEG];/* bases of common parts of segments */
+PRIVATE bin_off_t comsz[NSEG]; /* sizes of common parts of segments */
+PRIVATE fastin_t curseg;       /* current segment, 0 to $F */
+PRIVATE bin_off_t edataoffset; /* end of data */
+PRIVATE bin_off_t endoffset;   /* end of bss */
+PRIVATE bin_off_t etextoffset; /* end of text */
+PRIVATE bin_off_t etextpadoff; /* end of padded text */
+#ifdef REL_OUTPUT
+PRIVATE unsigned ndreloc;      /* number of data relocations */
+#endif
+PRIVATE unsigned nsym;         /* number of symbols written */
+#ifdef REL_OUTPUT
+PRIVATE unsigned ntreloc;      /* number of text relocations */
+extern bool_t reloc_output;    /* nonzero to leave reloc info in output */
+#endif
+PRIVATE unsigned relocsize;    /* current relocation size 1, 2 or 4 */
+PRIVATE bin_off_t segadj[NSEG];        /* adjusts (file offset - seg offset) */
+                               /* depends on zero init */
+PRIVATE bin_off_t segbase[NSEG];/* bases of data parts of segments */
+PRIVATE char segboundary[9] = "__seg0DH";
+                               /* name of seg boundary __seg0DL to __segfCH */
+PRIVATE bin_off_t segpos[NSEG];        /* segment positions for current module */
+PRIVATE bin_off_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 bin_off_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 padmod P((struct modstruct *modptr));
+FORWARD void setsym P((char *name, bin_off_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((bin_off_t count));
+
+/* write binary file */
+#ifndef FUNCNAME 
+#define FUNCNAME writebin
+#endif
+
+PUBLIC void FUNCNAME(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;
+    bin_off_t tempoffset;
+
+    sepid = argsepid;
+    bits32 = argbits32;
+    stripflag = argstripflag;
+#ifdef REL_OUTPUT
+    uzp = arguzp && !reloc_output;
+#else
+    uzp = arguzp;
+#endif
+    if (uzp)
+    {
+       if (btextoffset == 0)
+#ifdef QMAGIC
+           btextoffset = page_size()+HEADERLEN;
+#else
+           btextoffset = page_size();
+#endif
+       if (bdataoffset == 0 && sepid)
+           bdataoffset = page_size();
+    }
+#ifdef EDOS
+    commandname = stralloc(outfilename);
+    if ((cptr = strchr(commandname, ':')) != NUL_PTR)
+       commandname = cptr + 1;
+    if ((cptr = strrchr(commandname, '.')) != NUL_PTR)
+       *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 */
+#ifndef DATASEGS
+        if( curseg > 3 )
+       {
+          segboundary[6] = 'S';
+          segboundary[7] = 'O';
+          symres(segboundary); /* __segXSO */
+        }
+#endif
+    }
+#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");
+    symres("__segoff");
+
+    /* 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 != NUL_PTR; modptr = modptr->modnext)
+       if (modptr->loadflag)
+       {
+           register struct symstruct **symparray;
+           register struct symstruct *symptr;
+
+           for (symparray = modptr->symparray;
+                (symptr = *symparray) != NUL_PTR; ++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 REL_OUTPUT
+                       if (!reloc_output)
+#endif
+                           undefined(symptr->name);
+                   }
+                   else
+                   {
+#ifdef REL_OUTPUT
+#if 0
+                       if (!reloc_output)
+#else  
+                       if (!reloc_output || !(symptr->flags & I_MASK))
+#endif                 
+#endif
+                       {
+                           tempoffset = ld_roundup(symptr->value, 4, bin_off_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] = ld_roundup(segsz[seg], 4, bin_off_t);
+               comsz[seg] = ld_roundup(comsz[seg], 4, bin_off_t);
+#endif
+               cptr += sizecount;
+           }
+       }
+
+    /* calculate seg positions now their sizes are known */
+    /* temp use fixed order 0D 0C 1D 1C 2D 2C ... */
+    /*
+#ifdef DATASEGS
+     * Assume seg 0 is text and rest are data
+#else
+     * Assume seg 1..3 are data, Seg 0 is real text, seg 4+ are far text
+#endif
+     */
+#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 = ld_roundup(etextoffset, 0x10, bin_off_t);
+       segadj[1] += etextpadoff - bdataoffset;
+    }
+#ifdef QMAGIC
+    else if (uzp && bdataoffset == 0)
+    {
+       bdataoffset = ld_roundup(etextoffset, page_size(), bin_off_t);
+       etextpadoff = ld_roundup(etextoffset, page_size(), bin_off_t);
+       segadj[1] += etextpadoff - bdataoffset;
+    }
+#endif
+    else if (bdataoffset == 0)
+       bdataoffset = etextpadoff;
+    segpos[1] = segbase[1] = edataoffset = bdataoffset;
+    combase[1] = segbase[1] + segsz[1];
+#ifndef DATASEGS
+    for (seg = 4; seg < NSEG; ++seg)
+    {
+       segpos[seg] = segbase[seg] = 0;
+       combase[seg] = segbase[seg] + segsz[seg];
+       segadj[seg] = etextpadoff;
+
+       etextpadoff += ld_roundup(segsz[seg] + comsz[seg], 0x10, bin_off_t);
+       segadj[1]   += ld_roundup(segsz[seg] + comsz[seg], 0x10, bin_off_t);
+    }
+    for (seg = 2; seg < 4; ++seg)
+#else
+    for (seg = 2; seg < NSEG; ++seg)
+#endif
+    {
+       segpos[seg] = segbase[seg] = combase[seg - 1] + comsz[seg - 1];
+#ifdef MC6809
+       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])
+                & ~(bin_off_t) 0xFF) != 0)
+               segpos[seg] = segbase[seg] = (segbase[seg] + 0xFF)
+                                            & ~(bin_off_t) 0xFF;
+       }
+#endif
+
+#ifdef QMAGIC
+       if(seg==3 && uzp && !stripflag) /* XXX Stripped last seek needed */
+       {
+          bin_off_t val;
+          val = ld_roundup(segbase[seg]+segsz[seg], page_size(), bin_off_t);
+          segsz[seg] = val - segbase[seg];
+       }
+#endif 
+       combase[seg] = segbase[seg] + segsz[seg];
+       segadj[seg] = segadj[seg - 1];
+    }
+
+    /* relocate symbols by offsets of segments in memory */
+    for (modptr = modfirst; modptr != NUL_PTR; modptr = modptr->modnext)
+       if (modptr->loadflag)
+       {
+           register struct symstruct **symparray;
+           register struct symstruct *symptr;
+
+           for (symparray = modptr->symparray;
+                (symptr = *symparray) != NUL_PTR; ++symparray)
+               if (symptr->modptr == modptr && !(symptr->flags & A_MASK))
+               {
+                   if (symptr->flags & (C_MASK | SA_MASK))
+                   {
+#ifdef REL_OUTPUT
+#if 0
+                       if (!reloc_output)
+#else  
+                       if (!reloc_output || !(symptr->flags & I_MASK))
+#endif                 
+#endif
+                           symptr->value += combase[symptr->flags & SEGM_MASK];
+                   }
+                   else
+#ifdef REL_OUTPUT
+                   if (!reloc_output || !(symptr->flags & I_MASK))
+#endif
+                       symptr->value += segbase[symptr->flags & SEGM_MASK];
+               }
+       }
+
+    /* adjust special symbols */
+    for (seg = 0; seg < NSEG; ++seg)
+    {
+#ifdef DATASEGS
+       if (segsz[seg] != 0)
+           /* only count data of nonzero length */
+#else
+       if (segsz[seg] != 0 && seg < 4)
+#endif
+           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 */
+#ifndef DATASEGS
+        if( seg > 3 )
+       {
+          segboundary[6] = 'S';
+          segboundary[7] = 'O';
+          setsym(segboundary, (bin_off_t)(segadj[seg]-segadj[0])/0x10);
+          /* __segXSO */
+        }
+#endif
+    }
+    setsym("__etext", etextoffset);
+    setsym("__edata", edataoffset);
+#ifdef DATASEGS
+    setsym("__end", endoffset = combase[NSEG - 1] + comsz[NSEG - 1]);
+#else
+    setsym("__end", endoffset = combase[3] + comsz[3]);
+#endif
+    setsym("__segoff", (bin_off_t)(segadj[1]-segadj[0])/0x10);
+    if( !bits32 )
+    {
+        if( etextoffset > 65536L )
+            fatalerror("text segment too large for 16bit");
+        if( endoffset > 65536L )
+            fatalerror("data segment too large for 16bit");
+    }
+
+    openout(outfilename);
+#ifdef REL_OUTPUT
+    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 != NUL_PTR; 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 REL_OUTPUT
+               + ((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 != NUL_PTR; modptr = modptr->modnext)
+           if (modptr->loadflag)
+           {
+               register struct symstruct **symparray;
+               register struct symstruct *symptr;
+
+               for (symparray = modptr->symparray;
+                    (symptr = *symparray) != NUL_PTR; ++symparray)
+                   if (symptr->modptr == modptr)
+                   {
+#ifdef BSD_A_OUT
+                       offtocn((char *) &extsym.n_was_strx,
+                               (bin_off_t) stringoff, 4);
+#else
+#if ELF_SYMS
+                       if( symptr->name[0] == '_' && symptr->name[1] )
+                          strncpy((char *) extsym.n_was_name, symptr->name+1,
+                                  sizeof extsym.n_was_name);
+                       else
+                       {
+                          memcpy((char *) extsym.n_was_name, "__", 2);
+                          strncpy((char *) extsym.n_was_name+2, symptr->name,
+                                  sizeof(extsym.n_was_name)-2);
+                       }
+#else
+                       strncpy((char *) extsym.n_was_name, symptr->name,
+                               sizeof extsym.n_was_name);
+#endif
+#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 REL_OUTPUT
+                            !reloc_output &&
+#endif
+                            (flags & C_MASK)))
+                           switch (flags & (A_MASK | SEGM_MASK))
+                           {
+#ifdef DATASEGS
+                           case 0:
+#else
+                           default:
+#endif
+                               extsym.n_was_sclass |= N_TEXT;
+                           case A_MASK:
+                               break;
+#ifdef DATASEGS
+                           default:
+#else
+                           case 1: case 2: case 3:
+                           case A_MASK|1: case A_MASK|2: case A_MASK|3:
+#endif
+                               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
+#if ELF_SYMS
+                       stringoff += strlen(symptr->name);
+                       if( symptr->name[0] != '_' || symptr->name[1] == '\0' )
+                          stringoff += 3;
+#else
+                       stringoff += strlen(symptr->name) + 1;
+#endif
+#endif
+                   }
+           }
+#ifdef BSD_A_OUT
+       offtocn((char *) &extsym.n_was_strx, (bin_off_t) stringoff, 4);
+       writeout((char *) &extsym.n_was_strx, 4);
+       for (modptr = modfirst; modptr != NUL_PTR; modptr = modptr->modnext)
+           if (modptr->loadflag)
+           {
+               register struct symstruct **symparray;
+               register struct symstruct *symptr;
+
+               for (symparray = modptr->symparray;
+                    (symptr = *symparray) != NUL_PTR; ++symparray)
+                   if (symptr->modptr == modptr)
+#if ELF_SYMS
+                    {
+                      if( symptr->name[0] == '_' && symptr->name[1] )
+                         writeout(symptr->name + 1, strlen(symptr->name));
+                      else
+                      {
+                         writeout("__", 2);
+                         writeout(symptr->name, strlen(symptr->name) + 1);
+                      }
+                   }
+#else
+                       writeout(symptr->name, strlen(symptr->name) + 1);
+#endif
+           }
+#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 REL_OUTPUT
+       if( FILEHEADERLENGTH >= offsetof(struct exec, a_trsize)+8)
+       {
+               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 REL_OUTPUT
+    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 != NUL_PTR; elptr = elptr->elnext)
+    {
+       name = idconvert(elptr, commandname);
+       count += strlen(name) + 1 + 2 + 1;      /* nul off flg */
+       ourfree(name);
+       if (startptr != NUL_PTR)
+           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;
+    bin_off_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)
+           {
+#ifndef DATASEGS
+                int m = (modify & SEGM_MASK);
+               if( curseg != m && m != SEGM_MASK )
+                  interseg(modptr->filename, modptr->archentry, (char*)0);
+#endif
+               offset -= (spos + relocsize);
+            }
+           offtocn(buf, segbase[modify & SEGM_MASK] + offset, relocsize);
+           writeout(buf, relocsize);
+#ifdef REL_OUTPUT
+           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 /* REL_OUTPUT */
+           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)
+           {
+#ifndef DATASEGS
+                int m = (symptr->flags & SEGM_MASK);
+               if( curseg != m && m != SEGM_MASK )
+                  interseg(modptr->filename, modptr->archentry, symptr->name);
+#endif
+               offset -= (spos + relocsize);
+           }
+#ifdef REL_OUTPUT
+           if (!reloc_output || !(symptr->flags & I_MASK))
+#endif
+               offset += symptr->value;            
+           offtocn(buf, offset, relocsize);
+           writeout(buf, relocsize);
+#ifdef REL_OUTPUT
+           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 /* REL_OUTPUT */
+           spos += relocsize;
+       }
+    }
+}
+
+PRIVATE void padmod(modptr)
+struct modstruct *modptr;
+{
+    bin_off_t count;
+    fastin_t seg;
+    bin_off_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 = ld_roundup(segpos[seg], 4, bin_off_t) - segpos[seg]) != 0)
+       {
+           setseg(seg);
+           writenulls(size);
+           segpos[seg] = spos;
+       }
+       segbase[seg] = segpos[seg];
+    }
+}
+
+PRIVATE void setsym(name, value)
+char *name;
+bin_off_t value;
+{
+    struct symstruct *symptr;
+
+#ifdef REL_OUTPUT
+    if (!reloc_output)
+#endif
+       if ((symptr = findsym(name)) != NUL_PTR)
+           symptr->value = value;
+}
+
+PRIVATE void symres(name)
+register char *name;
+{
+    register struct symstruct *symptr;
+
+    if ((symptr = findsym(name)) != NUL_PTR)
+    {
+       if ((symptr->flags & SEGM_MASK) == SEGM_MASK)
+           symptr->flags &= ~SEGM_MASK | curseg;
+       if (symptr->flags != (I_MASK | curseg) || symptr->value != 0)
+           reserved(name);
+#ifdef REL_OUTPUT
+       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((bin_off_t) readsize(countsize));
+}
+
+#ifdef EDOS
+
+PRIVATE void writeheader(commandname)
+char *commandname;
+{
+    char buf[MAX_OFFSET_SIZE];
+    bin_off_t offset;
+    unsigned headlength;
+    char *name;
+    struct entrylist *elptr;
+    struct symstruct *startptr;
+
+    headlength = binheaderlength(commandname);
+    for (elptr = entryfirst; elptr != NUL_PTR; 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 != NUL_PTR; elptr = elptr->elnext)
+    {
+       name = idconvert(elptr, commandname);
+       writeout(name, (unsigned) strlen(name) + 1);
+       ourfree(name);
+       offtocn(buf, startptr == NUL_PTR ? 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 != NUL_PTR)
+    {
+       offset = headlength + 3;        /* over 1st LBSR */
+       for (elptr = entryfirst; elptr != NUL_PTR; 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
+#ifdef QMAGIC
+    if(uzp)
+       N_SET_MAGIC(header, QMAGIC);
+    else
+#endif
+    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 REL_OUTPUT
+    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
+#ifdef QMAGIC
+    if (uzp)
+       offtocn((char *) &header.a_text, etextpadoff - btextoffset+HEADERLEN,
+              sizeof header.a_text);
+    else
+#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 REL_OUTPUT
+    if (!reloc_output)
+#endif
+    {
+       offtocn((char *) &header.a_entry, btextoffset,
+                   sizeof header.a_entry);
+#ifndef STANDARD_GNU_A_OUT
+       offtocn((char *) &header.a_total, (bin_off_t)
+           (endoffset < 0x00010000L ? 0x00010000L : endoffset + 0x0008000L),
+               sizeof header.a_total);
+#endif
+    }
+    if( FILEHEADERLENGTH )
+       writeout((char *) &header, FILEHEADERLENGTH);
+}
+
+#endif /* MINIX */
+
+PRIVATE void writenulls(count)
+bin_off_t count;
+{
+    long lcount = count;
+    if( lcount < 0 )
+       fatalerror("org command requires reverse seek");
+    spos += count;
+    while (count-- > 0)
+       writechar(0);
+}
+#else
+
+#ifndef FUNCNAME
+#define FUNCNAME writebin
+#endif
+
+PUBLIC void FUNCNAME(outfilename, argsepid, argbits32, argstripflag, arguzp)
+char *outfilename;
+bool_pt argsepid;
+bool_pt argbits32;
+bool_pt argstripflag;
+bool_pt arguzp;
+{
+    char * s  = "WARNING: Native a.out generation not included, sorry\n";
+    write(2, s, strlen(s));
+/*    write_elks(outfilename, argsepid, argbits32, argstripflag, arguzp, 0); */
+}
+#endif
diff --git a/Applications/ld09/writeemu.c b/Applications/ld09/writeemu.c
new file mode 100644 (file)
index 0000000..b0438fc
--- /dev/null
@@ -0,0 +1,20 @@
+/*
+ * This uses a special version of writebin for bug compatibility with
+ * the old bin86 package.
+ *
+ * This _should_ be replaced by a function that writes out a as86 object
+ * but then it would completely **** up dosemu compiles.
+ *
+ * NOTE: A some time I intend to replace this with a routine that generates
+ *       an as86 object file.
+ */
+
+#undef  A_OUT_INCL
+#define A_OUT_INCL             "rel_aout.h"
+#define BSD_A_OUT              1
+#define FILEHEADERLENGTH       32
+#define ELF_SYMS               0
+
+#define FUNCNAME               write_dosemu
+
+#include "writebin.c"
diff --git a/Applications/ld09/writex86.c b/Applications/ld09/writex86.c
new file mode 100644 (file)
index 0000000..feb7b55
--- /dev/null
@@ -0,0 +1,743 @@
+/* writex86.c - write binary file for linker */
+
+/* Copyright (C) 1994 Bruce Evans */
+
+#include "syshead.h"
+#include "x86_aout.h"
+#ifndef VERY_SMALL_MEMORY
+#include "v7_aout.h"
+#endif
+#ifndef MSDOS
+#include "x86_cpm86.h"
+#endif
+#include "const.h"
+#include "obj.h"
+#include "type.h"
+#include "globvar.h"
+
+#define btextoffset (text_base_value)
+#define bdataoffset (data_base_value)
+#define page_size() ((bin_off_t)4096)
+
+#ifndef ELF_SYMS
+#define ELF_SYMS 0
+#endif
+
+#ifdef MSDOS
+#  define FILEHEADERLENGTH (headerless?0:A_MINHDR)
+#else
+# ifdef VERY_SMALL_MEMORY
+#  define FILEHEADERLENGTH (headerless?0:(cpm86?CPM86_HEADERLEN:A_MINHDR))
+# else
+#  define FILEHEADERLENGTH (headerless?0:(cpm86?CPM86_HEADERLEN:(v7?V7_HEADERLEN:A_MINHDR)))
+# endif
+#endif
+                               /* part of header not counted in offsets */
+#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 bin_off_t combase[NSEG];/* bases of common parts of segments */
+PRIVATE bin_off_t comsz[NSEG]; /* sizes of common parts of segments */
+PRIVATE fastin_t curseg;       /* current segment, 0 to $F */
+PRIVATE bin_off_t edataoffset; /* end of data */
+PRIVATE bin_off_t endoffset;   /* end of bss */
+PRIVATE bin_off_t etextoffset; /* end of text */
+PRIVATE bin_off_t etextpadoff; /* end of padded text */
+PRIVATE unsigned nsym;         /* number of symbols written */
+PRIVATE unsigned relocsize;    /* current relocation size 1, 2 or 4 */
+PRIVATE bin_off_t segadj[NSEG];        /* adjusts (file offset - seg offset) */
+                               /* depends on zero init */
+PRIVATE bin_off_t segbase[NSEG];/* bases of data parts of segments */
+PRIVATE char segboundary[9] = "__seg0DH";
+                               /* name of seg boundary __seg0DL to __segfCH */
+PRIVATE bin_off_t segpos[NSEG];        /* segment positions for current module */
+PRIVATE bin_off_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 bin_off_t spos;                /* position in current seg */
+PRIVATE bool_t uzp;            /* nonzero for unmapped zero page */
+PRIVATE bool_t xsym;           /* extended symbol table */
+
+FORWARD void linkmod P((struct modstruct *modptr));
+FORWARD void padmod P((struct modstruct *modptr));
+FORWARD void setsym P((char *name, bin_off_t value));
+FORWARD void symres P((char *name));
+FORWARD void setseg P((fastin_pt newseg));
+FORWARD void skip P((unsigned countsize));
+FORWARD void writeheader P((void));
+#ifndef VERY_SMALL_MEMORY
+FORWARD void v7header P((void));
+#endif
+#ifndef MSDOS
+FORWARD void cpm86header P((void));
+#endif
+FORWARD void writenulls P((bin_off_t count));
+
+EXTERN bool_t reloc_output;
+
+/* write binary file */
+
+PUBLIC void write_elks(outfilename, argsepid, argbits32, argstripflag, arguzp, argxsym)
+char *outfilename;
+bool_pt argsepid;
+bool_pt argbits32;
+bool_pt argstripflag;
+bool_pt arguzp;
+bool_pt argxsym;
+{
+    char buf4[4];
+    char *cptr;
+    struct nlist extsym;
+    flags_t flags;
+    struct modstruct *modptr;
+    fastin_t seg;
+    unsigned sizecount;
+    bin_off_t tempoffset;
+
+    if( reloc_output )
+#ifndef MSDOS
+       fatalerror("Output binformat not configured relocatable, use -N");
+#else
+       fatalerror("Cannot use -r under MSDOS, sorry");
+#endif
+
+    sepid = argsepid;
+    bits32 = argbits32;
+    stripflag = argstripflag;
+    uzp = arguzp;
+    xsym = argxsym;
+    if (uzp)
+    {
+       if (btextoffset == 0)
+           btextoffset = page_size();
+       if (bdataoffset == 0 && sepid)
+           bdataoffset = page_size();
+    }
+
+    /* 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 */
+#ifndef DATASEGS
+        if( curseg > 3 )
+       {
+          segboundary[6] = 'S';
+          segboundary[7] = 'O';
+          symres(segboundary); /* __segXSO */
+        }
+#endif
+    }
+    curseg = 3;
+    symres("__edata");
+    symres("__end");
+    symres("__heap_top");
+    curseg = 0;                        /* text seg, s.b. variable */
+    symres("__etext");
+    symres("__segoff");
+
+    /* 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 != NUL_PTR; modptr = modptr->modnext)
+       if (modptr->loadflag)
+       {
+           register struct symstruct **symparray;
+           register struct symstruct *symptr;
+
+           for (symparray = modptr->symparray;
+                (symptr = *symparray) != NUL_PTR; ++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)
+                   {
+                           undefined(symptr->name);
+                   }
+                   else
+                   {
+                       tempoffset = ld_roundup(symptr->value, 4, bin_off_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));
+
+               /* adjust sizes to even to get quad boundaries */
+               /* this should be specifiable dynamically */
+               segsz[seg] = ld_roundup(segsz[seg], 4, bin_off_t);
+               comsz[seg] = ld_roundup(comsz[seg], 4, bin_off_t);
+               cptr += sizecount;
+           }
+       }
+
+    /* calculate seg positions now their sizes are known */
+    /*
+#ifdef DATASEGS
+     * Assume seg 0 is text and rest are data
+#else
+     * Assume seg 1..3 are data, Seg 0 is real text, seg 4+ are far text
+#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 = ld_roundup(etextoffset, 0x10, bin_off_t);
+       segadj[1] += etextpadoff - bdataoffset;
+    }
+    else if (bdataoffset == 0)
+       bdataoffset = etextpadoff;
+    segpos[1] = segbase[1] = edataoffset = bdataoffset;
+    combase[1] = segbase[1] + segsz[1];
+#ifndef DATASEGS
+    for (seg = 4; seg < NSEG; ++seg)
+    {
+       segpos[seg] = segbase[seg] = 0;
+       combase[seg] = segbase[seg] + segsz[seg];
+       segadj[seg] = etextpadoff;
+
+       etextpadoff += ld_roundup(segsz[seg] + comsz[seg], 0x10, bin_off_t);
+       segadj[1]   += ld_roundup(segsz[seg] + comsz[seg], 0x10, bin_off_t);
+    }
+    for (seg = 2; seg < 4; ++seg)
+#else
+    for (seg = 2; seg < NSEG; ++seg)
+#endif
+    {
+       segpos[seg] = segbase[seg] = combase[seg - 1] + comsz[seg - 1];
+#ifdef MC6809
+       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])
+                & ~(bin_off_t) 0xFF) != 0)
+               segpos[seg] = segbase[seg] = (segbase[seg] + 0xFF)
+                                            & ~(bin_off_t) 0xFF;
+       }
+#endif
+       combase[seg] = segbase[seg] + segsz[seg];
+       segadj[seg] = segadj[seg - 1];
+    }
+
+    /* relocate symbols by offsets of segments in memory */
+    for (modptr = modfirst; modptr != NUL_PTR; modptr = modptr->modnext)
+       if (modptr->loadflag)
+       {
+           register struct symstruct **symparray;
+           register struct symstruct *symptr;
+
+           for (symparray = modptr->symparray;
+                (symptr = *symparray) != NUL_PTR; ++symparray)
+               if (symptr->modptr == modptr && !(symptr->flags & A_MASK))
+               {
+                   if (symptr->flags & (C_MASK | SA_MASK))
+                       symptr->value += combase[symptr->flags & SEGM_MASK];
+                   else
+                       symptr->value += segbase[symptr->flags & SEGM_MASK];
+               }
+       }
+
+    /* adjust special symbols */
+    for (seg = 0; seg < NSEG; ++seg)
+    {
+#ifdef DATASEGS
+       if (segsz[seg] != 0)
+           /* only count data of nonzero length */
+#else
+       if (segsz[seg] != 0 && seg < 4)
+#endif
+           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 */
+#ifndef DATASEGS
+        if( seg > 3 )
+       {
+          segboundary[6] = 'S';
+          segboundary[7] = 'O';
+          setsym(segboundary, (bin_off_t)(segadj[seg]-segadj[0])/0x10);
+          /* __segXSO */
+        }
+#endif
+    }
+    setsym("__etext", etextoffset);
+    setsym("__edata", edataoffset);
+#ifdef DATASEGS
+    setsym("__end", endoffset = combase[NSEG - 1] + comsz[NSEG - 1]);
+#else
+    setsym("__end", endoffset = combase[3] + comsz[3]);
+#endif
+    setsym("__segoff", (bin_off_t)(segadj[1]-segadj[0])/0x10);
+    if( !bits32 )
+    {
+        if( etextoffset > 65536L )
+            fatalerror("text segment too large for 16bit");
+        if( endoffset > 65536L )
+            fatalerror("data segment too large for 16bit");
+    }
+
+    if( heap_top_value < 0x100 || endoffset > heap_top_value-0x100)
+       heap_top_value = endoffset + 0x8000;
+    if( heap_top_value > 0x10000 && !bits32 ) heap_top_value = 0x10000;
+    setsym("__heap_top", (bin_off_t)heap_top_value);
+
+    openout(outfilename);
+#ifndef MSDOS
+    if (cpm86) cpm86header();
+    else
+#endif
+#ifndef VERY_SMALL_MEMORY
+    if (v7)
+       v7header();
+    else
+#endif
+       writeheader();
+    for (modptr = modfirst; modptr != NUL_PTR; modptr = modptr->modnext)
+       if (modptr->loadflag)
+       {
+           linkmod(modptr);
+           padmod(modptr);
+       }
+
+    /* dump symbol table */
+    if (!stripflag)
+    {
+       seekout(FILEHEADERLENGTH
+               + (unsigned long) (etextpadoff - btextoffset)
+               + (unsigned long) (edataoffset - bdataoffset)
+               );
+       extsym.n_numaux = extsym.n_type = 0;
+       for (modptr = modfirst; modptr != NUL_PTR; modptr = modptr->modnext)
+           if (modptr->loadflag)
+           {
+               register struct symstruct **symparray;
+               register struct symstruct *symptr;
+
+               for (symparray = modptr->symparray;
+                    (symptr = *symparray) != NUL_PTR; ++symparray)
+                   if (symptr->modptr == modptr)
+                   {
+#if ELF_SYMS
+                       if (symptr->name[0] == '_' && symptr->name[1] )
+                         strncpy((char *) extsym.n_name, symptr->name+1,
+                               sizeof extsym.n_name);
+                       else
+                       {
+                         memcpy((char *) extsym.n_name, "$", 1);
+                         strncpy((char *) extsym.n_name+1, symptr->name,
+                               sizeof(extsym.n_name)-1);
+                       }
+#else
+                       strncpy((char *) extsym.n_name, symptr->name,
+                               sizeof extsym.n_name);
+#endif
+                       u4cn((char *) &extsym.n_value, (u4_t) symptr->value,
+                            sizeof extsym.n_value);
+                       if ((flags = symptr->flags) & A_MASK)
+                           extsym.n_sclass = N_ABS;
+                       else if (flags & (E_MASK | I_MASK))
+                           extsym.n_sclass = C_EXT;
+                       else
+                           extsym.n_sclass = C_STAT;
+                       if (!(flags & I_MASK) ||
+                            flags & C_MASK)
+                           switch (flags & (A_MASK | SEGM_MASK))
+                           {
+#ifdef DATASEGS
+                           case 0:
+#else
+                           default:
+#endif
+                               extsym.n_sclass |= N_TEXT;
+                           case A_MASK:
+                               break;
+#ifdef DATASEGS
+                           default:
+#else
+                           case 1: case 2: case 3:
+                           case A_MASK|1: case A_MASK|2: case A_MASK|3:
+#endif
+                               if (flags & (C_MASK | SA_MASK))
+                                   extsym.n_sclass |= N_BSS;
+                               else
+                                   extsym.n_sclass |= N_DATA;
+                               break;
+                           }
+                       writeout((char *) &extsym, sizeof extsym);
+                       ++nsym;
+#if !ELF_SYMS
+                       if( xsym )
+                       {
+                          int i;
+                          extsym.n_sclass = 0;
+                          memset((void*)&extsym.n_value,0,
+                                  sizeof(extsym.n_value));
+
+                          for(i=sizeof extsym.n_name; i<strlen(symptr->name);
+                              i+=sizeof extsym.n_name)
+                          {
+                             strncpy((char *) extsym.n_name, symptr->name+i,
+                               sizeof extsym.n_name);
+                             writeout((char *) &extsym, sizeof extsym);
+                             ++nsym;
+                          }
+                       }
+#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));
+    }
+    closeout();
+    executable();
+}
+
+PRIVATE void linkmod(modptr)
+struct modstruct *modptr;
+{
+    char buf[ABS_TEXT_MAX];
+    int command;
+    unsigned char modify;
+    bin_off_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)
+           {
+#ifndef DATASEGS
+                int m = (modify & SEGM_MASK);
+               if( curseg != m && m != SEGM_MASK )
+                  interseg(modptr->filename, modptr->archentry, (char*)0);
+#endif
+               offset -= (spos + relocsize);
+            }
+           offtocn(buf, segbase[modify & SEGM_MASK] + offset, relocsize);
+           writeout(buf, relocsize);
+           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)
+           {
+#ifndef DATASEGS
+                int m = (symptr->flags & SEGM_MASK);
+               if( curseg != m && m != SEGM_MASK )
+                  interseg(modptr->filename, modptr->archentry, symptr->name);
+#endif
+               offset -= (spos + relocsize);
+           }
+           offset += symptr->value;        
+           offtocn(buf, offset, relocsize);
+           writeout(buf, relocsize);
+           spos += relocsize;
+       }
+    }
+}
+
+PRIVATE void padmod(modptr)
+struct modstruct *modptr;
+{
+    bin_off_t count;
+    fastin_t seg;
+    bin_off_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 = ld_roundup(segpos[seg], 4, bin_off_t) - segpos[seg]) != 0)
+       {
+           setseg(seg);
+           writenulls(size);
+           segpos[seg] = spos;
+       }
+       segbase[seg] = segpos[seg];
+    }
+}
+
+PRIVATE void setsym(name, value)
+char *name;
+bin_off_t value;
+{
+    struct symstruct *symptr;
+
+    if ((symptr = findsym(name)) != NUL_PTR)
+       symptr->value = value;
+}
+
+PRIVATE void symres(name)
+register char *name;
+{
+    register struct symstruct *symptr;
+
+    if ((symptr = findsym(name)) != NUL_PTR)
+    {
+       if ((symptr->flags & SEGM_MASK) == SEGM_MASK)
+           symptr->flags &= ~SEGM_MASK | curseg;
+       if (symptr->flags != (I_MASK | curseg) || symptr->value != 0)
+           reserved(name);
+       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((bin_off_t) readsize(countsize));
+}
+
+#ifndef MSDOS
+PRIVATE void cpm86header()
+{
+    struct cpm86_exec header;
+    memset(&header, 0, sizeof header);
+
+    if (sepid)
+    {
+      header.ce_group[0].cg_type = CG_CODE;
+      u2c2(header.ce_group[0].cg_len, (15 + etextpadoff) / 16);
+      u2c2(header.ce_group[0].cg_min, (15 + etextpadoff) / 16);
+      header.ce_group[1].cg_type = CG_DATA;
+      u2c2(header.ce_group[1].cg_len, (15 + edataoffset) / 16);
+      u2c2(header.ce_group[1].cg_min, (15 + endoffset  ) / 16);
+      u2c2(header.ce_group[1].cg_max, 0x1000);
+    }
+    else
+    {
+      header.ce_group[0].cg_type = CG_CODE;
+      u2c2(header.ce_group[0].cg_len, (15 + edataoffset) / 16);
+      u2c2(header.ce_group[0].cg_min, (15 + endoffset  ) / 16);
+    }
+    if( FILEHEADERLENGTH )
+       writeout((char *) &header, FILEHEADERLENGTH);
+}
+#endif
+
+PRIVATE void writeheader()
+{
+    struct exec header;
+
+    memset(&header, 0, sizeof header);
+    header.a_magic[0] = A_MAGIC0;
+    header.a_magic[1] = A_MAGIC1;
+    header.a_flags = sepid ? A_SEP : A_EXEC;
+    if (uzp)
+       header.a_flags |= A_UZP;
+    header.a_cpu = bits32 ? A_I80386 : A_I8086;
+    header.a_hdrlen = FILEHEADERLENGTH;
+    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);
+    if (uzp)
+       offtocn((char *) &header.a_entry, page_size(),
+               sizeof header.a_entry);
+
+    offtocn((char *) &header.a_total, (bin_off_t) heap_top_value,
+           sizeof header.a_total);
+    if( FILEHEADERLENGTH )
+       writeout((char *) &header, FILEHEADERLENGTH);
+}
+
+#ifndef VERY_SMALL_MEMORY
+PRIVATE void v7header()
+{
+    struct v7_exec header;
+
+    if( sizeof header != FILEHEADERLENGTH )
+       fatalerror("Executable miscompiled, computed wrong header size");
+
+    memset(&header, 0, sizeof header);
+
+    if( bits32 )
+       fatalerror("V7 a.out format is for 16-bit only");
+
+    offtocn((char *) &header.magic, sepid ? V7_MAGIC3 : V7_OMAGIC,
+            sizeof header.magic);
+
+    offtocn((char *) &header.textsize, etextpadoff - btextoffset,
+            sizeof header.textsize);
+    offtocn((char *) &header.datasize, edataoffset - bdataoffset,
+            sizeof header.datasize);
+    offtocn((char *) &header.bsssize, endoffset - edataoffset,
+            sizeof header.bsssize);
+
+    if( !stripflag )
+       fatalerror("Symbol table not implemented for V7 yet");
+
+    if( uzp )
+       fatalerror("No QMAGIC for V7");
+
+    offtocn((char *) &header.entry, entryfirst->elsymptr->value,
+            sizeof header.entry);
+
+    if( FILEHEADERLENGTH )
+       writeout((char *) &header, FILEHEADERLENGTH);
+}
+#endif
+
+PRIVATE void writenulls(count)
+bin_off_t count;
+{
+    long lcount = count;
+    spos += count;
+#if 0
+    /* This will only work if we record the highest spos found an seek there
+     * at the end of the generation
+     */
+
+    seekout(FILEHEADERLENGTH + (unsigned long) spos
+        + (unsigned long) segadj[curseg]);
+    return;
+
+#endif
+    if( lcount < 0 )
+       fatalerror("org command requires reverse seek");
+    while (count-- > 0)
+       writechar(0);
+}
diff --git a/Applications/ld09/x86_aout.h b/Applications/ld09/x86_aout.h
new file mode 100644 (file)
index 0000000..542a70d
--- /dev/null
@@ -0,0 +1,132 @@
+/* Copyright (C) 1990-1996 
+ * This file is part of the ld86 command for Linux-86 
+ * It is distributed under the GNU Library General Public License.
+ *
+ * - This may actually be BSD or Minix code, can someone clarify please. -RDB
+ */
+
+#ifndef __AOUT_H
+#define __AOUT_H
+
+/* If the host isn't an x86 all bets are off, use chars. */
+#if defined(i386) || defined(__BCC__) || defined(MSDOS)
+typedef long Long;
+#define __OUT_OK 1
+#else
+/* Beware: this will probably allow some BE hosts to generate broken files. */
+#ifdef INT32_MAX
+#include <stdint.h>
+typedef int32_t Long;
+#define __OUT_OK 1
+#else
+typedef char Long[4];
+#endif
+#endif
+
+struct exec {                  /* a.out header */
+  unsigned char        a_magic[2];     /* magic number */
+  unsigned char        a_flags;        /* flags, see below */
+  unsigned char        a_cpu;          /* cpu id */
+  unsigned char        a_hdrlen;       /* length of header */
+  unsigned char        a_unused;       /* reserved for future use */
+  unsigned char a_version[2];  /* version stamp (not used at present) */
+  Long         a_text;         /* size of text segement in bytes */
+  Long         a_data;         /* size of data segment in bytes */
+  Long         a_bss;          /* size of bss segment in bytes */
+  Long         a_entry;        /* entry point */
+  Long         a_total;        /* total memory allocated */
+  Long         a_syms;         /* size of symbol table */
+
+  /* SHORT FORM ENDS HERE */
+  Long         a_trsize;       /* text relocation size */
+  Long         a_drsize;       /* data relocation size */
+  Long         a_tbase;        /* text relocation base */
+  Long         a_dbase;        /* data relocation base */
+};
+
+#define A_MAGIC0      (unsigned char) 0x01
+#define A_MAGIC1      (unsigned char) 0x03
+#define BADMAG(X)     ((X).a_magic[0] != A_MAGIC0 ||(X).a_magic[1] != A_MAGIC1)
+
+/* CPU Id of TARGET machine (byte order coded in low order two bits) */
+#define A_NONE  0x00   /* unknown */
+#define A_I8086         0x04   /* intel i8086/8088 */
+#define A_M68K  0x0B   /* motorola m68000 */
+#define A_NS16K         0x0C   /* national semiconductor 16032 */
+#define A_I80386 0x10  /* intel i80386 */
+#define A_SPARC         0x17   /* Sun SPARC */
+
+#define A_BLR(cputype) ((cputype&0x01)!=0) /* TRUE if bytes left-to-right */
+#define A_WLR(cputype) ((cputype&0x02)!=0) /* TRUE if words left-to-right */
+
+/* Flags. */
+#define A_UZP  0x01    /* unmapped zero page (pages) */
+#define A_PAL  0x02    /* page aligned executable */
+#define A_NSYM 0x04    /* new style symbol table */
+#define A_EXEC 0x10    /* executable */
+#define A_SEP  0x20    /* separate I/D */
+#define A_PURE 0x40    /* pure text */
+#define A_TOVLY        0x80    /* text overlay */
+
+/* Offsets of various things. */
+#define A_MINHDR       32
+#define        A_TEXTPOS(X)    ((long)(X).a_hdrlen)
+#define        A_HASRELS(X)    ((X).a_hdrlen > (unsigned char) A_MINHDR)
+#define A_HASEXT(X)    ((X).a_hdrlen > (unsigned char) (A_MINHDR +  8))
+#define A_HASLNS(X)    ((X).a_hdrlen > (unsigned char) (A_MINHDR + 16))
+#define A_HASTOFF(X)   ((X).a_hdrlen > (unsigned char) (A_MINHDR + 24))
+#ifdef __OUT_OK
+#define A_DATAPOS(X)   (A_TEXTPOS(X) + (X).a_text)
+#define A_TRELPOS(X)   (A_DATAPOS(X) + (X).a_data)
+#define A_DRELPOS(X)   (A_TRELPOS(X) + (X).a_trsize)
+#define A_SYMPOS(X)    (A_TRELPOS(X) + (A_HASRELS(X) ? \
+                       ((X).a_trsize + (X).a_drsize) : 0))
+#endif
+
+struct reloc {
+  long r_vaddr;                        /* virtual address of reference */
+  unsigned short r_symndx;     /* internal segnum or extern symbol num */
+  unsigned short r_type;       /* relocation type */
+};
+
+/* r_tyep values: */
+#define R_ABBS         0
+#define R_RELLBYTE     2
+#define R_PCRBYTE      3
+#define R_RELWORD      4
+#define R_PCRWORD      5
+#define R_RELLONG      6
+#define R_PCRLONG      7
+#define R_REL3BYTE     8
+#define R_KBRANCHE     9
+
+/* r_symndx for internal segments */
+#define S_ABS          ((unsigned short)-1)
+#define S_TEXT         ((unsigned short)-2)
+#define S_DATA         ((unsigned short)-3)
+#define S_BSS          ((unsigned short)-4)
+
+struct nlist {                 /* symbol table entry */
+  char n_name[8];              /* symbol name */
+  Long n_value;                        /* value */
+  unsigned char        n_sclass;       /* storage class */
+  unsigned char        n_numaux;       /* number of auxiliary entries (not used) */
+  unsigned short n_type;       /* language base and derived type (not used) */
+};
+
+/* Low bits of storage class (section). */
+#define        N_SECT            07    /* section mask */
+#define N_UNDF           00    /* undefined */
+#define N_ABS            01    /* absolute */
+#define N_TEXT           02    /* text */
+#define N_DATA           03    /* data */
+#define        N_BSS             04    /* bss */
+#define N_COMM           05    /* (common) */
+
+/* High bits of storage class. */
+#define N_CLASS                0370    /* storage class mask */
+#define C_NULL         0
+#define C_EXT          0020    /* external symbol */
+#define C_STAT         0030    /* static */
+
+#endif /* _AOUT_H */
diff --git a/Applications/ld09/x86_cpm86.h b/Applications/ld09/x86_cpm86.h
new file mode 100644 (file)
index 0000000..0a858f5
--- /dev/null
@@ -0,0 +1,44 @@
+/* Copyright (C) 2002
+ * This file is part of the ld86 command for Linux-86 
+ * It is distributed under the GNU Library General Public License.
+ *
+ * CP/M-86 CMD file header
+ */
+
+#ifndef __CPM86_H
+#define __CPM86_H
+
+typedef char Short16[2];
+
+struct  cpm86_group {
+       unsigned char cg_type;  /* 1=Code 2=Data */
+       Short16       cg_len;   /* Group length, paragraphs */
+       Short16       cg_base;  /* Group address, normally 0 for relocatable */
+       Short16       cg_min;   /* Minimum size, normally = group length */
+       Short16       cg_max;   /* Maximum size, normally 0x1000 (64k) */
+};
+
+
+struct cpm86_exec {                    /* CP/M-86 header */
+       struct cpm86_group ce_group[8];
+       unsigned char ce_spare[51];
+       Short16       ce_rsxs;          /* Record with RSX list */
+       Short16       ce_fixups;        /* Record with fixups */
+       unsigned char ce_flags;         /* Concurrent CP/M flags */
+};
+
+/* Group types */
+#define CG_EMPTY 0
+#define CG_CODE  1
+#define CG_DATA  2
+#define CG_EXTRA 3
+#define CG_STACK 4
+#define CG_AUX1  5
+#define CG_AUX2  6
+#define CG_AUX3  7
+#define CG_AUX4  8
+#define CG_PURE  9     /* Code that is known to be pure */
+
+#define CPM86_HEADERLEN 0x80
+
+#endif /* _CPM86_H */