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