summaryrefslogtreecommitdiff
path: root/ld/io.c
diff options
context:
space:
mode:
Diffstat (limited to 'ld/io.c')
-rw-r--r--ld/io.c606
1 files changed, 606 insertions, 0 deletions
diff --git a/ld/io.c b/ld/io.c
new file mode 100644
index 0000000..aef49d0
--- /dev/null
+++ b/ld/io.c
@@ -0,0 +1,606 @@
+/* io.c - input/output and error modules for linker */
+
+/* Copyright (C) 1994 Bruce Evans */
+
+#include "const.h"
+#include "obj.h" /* needed for LONG_OFFSETS and offset_t */
+#include "type.h"
+#include "globvar.h"
+
+#ifdef STDC_HEADERS_MISSING
+void exit P((int status));
+void *malloc P((unsigned size));
+#else
+#undef NULL
+#include <stdlib.h>
+#endif
+
+#ifdef POSIX_HEADERS_MISSING
+#define O_RDONLY 0
+#define O_WRONLY 1
+#define SEEK_SET 0
+#define STDOUT_FILENO 0
+#include <sys/stat.h>
+#define mode_t unsigned short
+#define off_t long
+int chmod P((const char *path, int mode));
+int close P((int fd));
+int creat P((const char *path, int mode));
+int fstat P((int fd, struct stat *statbuf));
+off_t lseek P((int fd, off_t offset, int whence));
+int open P((const char *path, int oflag, ...));
+int read P((int fd, void *buf, unsigned nbytes));
+mode_t umask P((int oldmask));
+int write P((int fd, const void *buf, unsigned nbytes));
+#else
+#undef NULL
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+#endif
+
+#define DRELBUFSIZE 3072
+#define ERR (-1)
+#define ERRBUFSIZE 1024
+#define INBUFSIZE 1024
+#define OUTBUFSIZE 2048
+#define TRELBUFSIZE 1024
+
+#ifdef BSD_A_OUT
+PRIVATE char *drelbuf; /* extra output buffer for data relocations */
+PRIVATE char *drelbufptr; /* data relocation output buffer ptr */
+PRIVATE char *drelbuftop; /* data relocation output buffer top */
+#endif
+PRIVATE char *errbuf; /* error buffer (actually uses STDOUT) */
+PRIVATE char *errbufptr; /* error buffer ptr */
+PRIVATE char *errbuftop; /* error buffer top */
+PRIVATE char *inbuf; /* input buffer */
+PRIVATE char *inbufend; /* input buffer top */
+PRIVATE char *inbufptr; /* end of input in input buffer */
+PRIVATE int infd; /* input file descriptor */
+PRIVATE char *inputname; /* name of current input file */
+PRIVATE char *outbuf; /* output buffer */
+PRIVATE char *outbufptr; /* output buffer ptr */
+PRIVATE char *outbuftop; /* output buffer top */
+PRIVATE int outfd; /* output file descriptor */
+PRIVATE mode_t outputperms; /* permissions of output file */
+PRIVATE char *outputname; /* name of output file */
+PRIVATE char *refname; /* name of program for error reference */
+#ifdef BSD_A_OUT
+PRIVATE char *trelbuf; /* extra output buffer for text relocations */
+PRIVATE char *trelbufptr; /* text relocation output buffer ptr */
+PRIVATE char *trelbuftop; /* text relocation output buffer top */
+PRIVATE int trelfd; /* text relocation output file descriptor */
+#endif
+PRIVATE unsigned warncount; /* count of warnings */
+
+FORWARD void errexit P((char *message));
+FORWARD void flushout P((void));
+#ifdef BSD_A_OUT
+FORWARD void flushtrel P((void));
+#endif
+FORWARD void outhexdigs P((offset_t num));
+FORWARD void outputerror P((char *message));
+FORWARD void put04x P((unsigned num));
+FORWARD void putstrn P((char *message));
+FORWARD void refer P((void));
+
+PUBLIC void ioinit(progname)
+char *progname;
+{
+ infd = ERR;
+ if (*progname)
+ refname = progname; /* name must be static (is argv[0]) */
+ else
+ refname = "link";
+#ifdef BSD_A_OUT
+ drelbuf = malloc(DRELBUFSIZE);
+ drelbuftop = drelbuf + DRELBUFSIZE;
+#endif
+ errbuf = malloc(ERRBUFSIZE);
+ errbufptr = errbuf;
+ errbuftop = errbuf + ERRBUFSIZE;
+ inbuf = malloc(INBUFSIZE);
+ outbuf = malloc(OUTBUFSIZE);/* outbuf invalid if this fails but then */
+ /* will not be used - tableinit() aborts */
+ outbuftop = outbuf + OUTBUFSIZE;
+#ifdef BSD_A_OUT
+ trelbuf = malloc(TRELBUFSIZE);
+ trelbuftop = trelbuf + TRELBUFSIZE;
+#endif
+}
+
+PUBLIC void closein()
+{
+ if (infd != ERR && close(infd) < 0)
+ inputerror("cannot close");
+ infd = ERR;
+}
+
+PUBLIC void closeout()
+{
+#ifdef BSD_A_OUT
+ unsigned nbytes;
+#endif
+
+ flushout();
+#ifdef BSD_A_OUT
+ flushtrel();
+ nbytes = drelbufptr - drelbuf;
+ if (write(trelfd, drelbuf, nbytes) != nbytes)
+ outputerror("cannot write");
+#endif
+ if (close(outfd) == ERR)
+ outputerror("cannot close");
+#ifdef BSD_A_OUT
+ if (close(trelfd) == ERR)
+ outputerror("cannot close");
+#endif
+}
+
+PUBLIC void errtrace(name, level)
+char *name;
+int level;
+{
+ while (level-- > 0)
+ putbyte(' ');
+ putstrn(name);
+}
+
+PUBLIC void executable()
+{
+ mode_t oldmask;
+
+ if (errcount == 0)
+ {
+ oldmask = umask(0);
+ umask(oldmask);
+ chmod(outputname, outputperms | (EXEC_PERMS & ~oldmask));
+ }
+}
+
+PUBLIC void flusherr()
+{
+ write(STDOUT_FILENO, errbuf, (unsigned) (errbufptr - errbuf));
+ errbufptr = errbuf;
+}
+
+PRIVATE void flushout()
+{
+ unsigned nbytes;
+
+ nbytes = outbufptr - outbuf;
+ if (write(outfd, outbuf, nbytes) != nbytes)
+ outputerror("cannot write");
+ outbufptr = outbuf;
+}
+
+#ifdef BSD_A_OUT
+PRIVATE void flushtrel()
+{
+ unsigned nbytes;
+
+ nbytes = trelbufptr - trelbuf;
+ if (write(trelfd, trelbuf, nbytes) != nbytes)
+ outputerror("cannot write");
+ trelbufptr = trelbuf;
+}
+#endif
+
+PUBLIC void openin(filename)
+char *filename;
+{
+#if 0 /* XXX - this probably won't work with constructed lib names? */
+ if (infd == ERR || strcmp(inputname, filename) != 0)
+#endif
+ {
+ closein();
+ inputname = filename; /* this relies on filename being static */
+ if ((infd = open(filename, O_RDONLY)) < 0)
+ inputerror("cannot open");
+ inbufptr = inbufend = inbuf;
+ }
+}
+
+PUBLIC void openout(filename)
+char *filename;
+{
+ struct stat statbuf;
+
+ outputname = filename;
+ if ((outfd = creat(filename, CREAT_PERMS)) == ERR)
+ outputerror("cannot open");
+ if (fstat(outfd, &statbuf) != 0)
+ outputerror("cannot stat");
+ outputperms = statbuf.st_mode;
+ chmod(filename, outputperms & ~EXEC_PERMS);
+#ifdef BSD_A_OUT
+ drelbufptr = drelbuf;
+#endif
+ outbufptr = outbuf;
+#ifdef BSD_A_OUT
+ if ((trelfd = open(filename, O_WRONLY)) == ERR)
+ outputerror("cannot reopen");
+ trelbufptr = trelbuf;
+#endif
+}
+
+PRIVATE void outhexdigs(num)
+register offset_t num;
+{
+ if (num >= 0x10)
+ {
+ outhexdigs(num / 0x10);
+ num %= 0x10;
+ }
+ putbyte(hexdigit[num]);
+}
+
+PRIVATE void put04x(num)
+register unsigned num;
+{
+ putbyte(hexdigit[num / 0x1000]);
+ putbyte(hexdigit[(num / 0x100) & 0x0F]);
+ putbyte(hexdigit[(num / 0x10) & 0x0F]);
+ putbyte(hexdigit[num & 0x0F]);
+}
+
+#ifdef LONG_OFFSETS
+
+PUBLIC void put08lx(num)
+register offset_t num;
+{
+ put04x(num / 0x10000);
+ put04x(num % 0x10000);
+}
+
+#else /* not LONG_OFFSETS */
+
+PUBLIC void put08x(num)
+register offset_t num;
+{
+ putstr("0000");
+ put04x(num);
+}
+
+#endif /* not LONG_OFFSETS */
+
+PUBLIC void putbstr(width, str)
+unsigned width;
+char *str;
+{
+ unsigned length;
+
+ for (length = strlen(str); length < width; ++length)
+ putbyte(' ');
+ putstr(str);
+}
+
+PUBLIC void putbyte(ch)
+int ch;
+{
+ register char *ebuf;
+
+ ebuf = errbufptr;
+ if (ebuf >= errbuftop)
+ {
+ flusherr();
+ ebuf = errbufptr;
+ }
+ *ebuf++ = ch;
+ errbufptr = ebuf;
+}
+
+PUBLIC void putstr(message)
+char *message;
+{
+ while (*message != 0)
+ putbyte(*message++);
+}
+
+PRIVATE void putstrn(message)
+char *message;
+{
+ putstr(message);
+ putbyte('\n');
+ flusherr();
+}
+
+PUBLIC int readchar()
+{
+ int ch;
+
+ register char *ibuf;
+ int nread;
+
+ ibuf = inbufptr;
+ if (ibuf >= inbufend)
+ {
+ ibuf = inbufptr = inbuf;
+ nread = read(infd, ibuf, INBUFSIZE);
+ if (nread <= 0)
+ {
+ inbufend = ibuf;
+ return ERR;
+ }
+ inbufend = ibuf + nread;
+ }
+ ch = (unsigned char) *ibuf++;
+ inbufptr = ibuf;
+ return ch;
+}
+
+PUBLIC void readin(buf, count)
+char *buf;
+unsigned count;
+{
+ int ch;
+
+ while (count--)
+ {
+ if ((ch = readchar()) < 0)
+ prematureeof();
+ *buf++ = ch;
+ }
+}
+
+PUBLIC bool_pt readineofok(buf, count)
+char *buf;
+unsigned count;
+{
+ int ch;
+
+ while (count--)
+ {
+ if ((ch = readchar()) < 0)
+ return TRUE;
+ *buf++ = ch;
+ }
+ return FALSE;
+}
+
+PUBLIC void seekin(offset)
+unsigned long offset;
+{
+ inbufptr = inbufend = inbuf;
+ if (lseek(infd, (off_t) offset, SEEK_SET) != offset)
+ prematureeof();
+}
+
+PUBLIC void seekout(offset)
+unsigned long offset;
+{
+ flushout();
+ if (lseek(outfd, (off_t) offset, SEEK_SET) != offset)
+ outputerror("cannot seek in");
+}
+
+#ifdef BSD_A_OUT
+PUBLIC void seektrel(offset)
+unsigned long offset;
+{
+ flushtrel();
+ if (lseek(trelfd, (off_t) offset, SEEK_SET) != offset)
+ outputerror("cannot seek in");
+}
+#endif
+
+PUBLIC void writechar(ch)
+int ch;
+{
+ register char *obuf;
+
+ obuf = outbufptr;
+ if (obuf >= outbuftop)
+ {
+ flushout();
+ obuf = outbufptr;
+ }
+ *obuf++ = ch;
+ outbufptr = obuf;
+}
+
+#ifdef BSD_A_OUT
+PUBLIC void writedrel(buf, count)
+register char *buf;
+unsigned count;
+{
+ register char *rbuf;
+
+ rbuf = drelbufptr;
+ while (count--)
+ {
+ if (rbuf >= drelbuftop)
+ inputerror("data relocation buffer full while processing");
+ *rbuf++ = *buf++;
+ }
+ drelbufptr = rbuf;
+}
+#endif
+
+PUBLIC void writeout(buf, count)
+register char *buf;
+unsigned count;
+{
+ register char *obuf;
+
+ obuf = outbufptr;
+ while (count--)
+ {
+ if (obuf >= outbuftop)
+ {
+ outbufptr = obuf;
+ flushout();
+ obuf = outbufptr;
+ }
+ *obuf++ = *buf++;
+ }
+ outbufptr = obuf;
+}
+
+#ifdef BSD_A_OUT
+PUBLIC void writetrel(buf, count)
+register char *buf;
+unsigned count;
+{
+ register char *rbuf;
+
+ rbuf = trelbufptr;
+ while (count--)
+ {
+ if (rbuf >= trelbuftop)
+ {
+ trelbufptr = rbuf;
+ flushtrel();
+ rbuf = trelbufptr;
+ }
+ *rbuf++ = *buf++;
+ }
+ trelbufptr = rbuf;
+}
+#endif
+
+/* error module */
+
+PRIVATE void errexit(message)
+char *message;
+{
+ putstrn(message);
+ exit(2);
+}
+
+PUBLIC void fatalerror(message)
+char *message;
+{
+ refer();
+ errexit(message);
+}
+
+PUBLIC void inputerror(message)
+char *message;
+{
+ refer();
+ putstr(message);
+ putstr(" input file ");
+ errexit(inputname);
+}
+
+PUBLIC void input1error(message)
+char *message;
+{
+ refer();
+ putstr(inputname);
+ errexit(message);
+}
+
+PRIVATE void outputerror(message)
+char *message;
+{
+ refer();
+ putstr(message);
+ putstr(" output file ");
+ errexit(outputname);
+}
+
+PUBLIC void outofmemory()
+{
+ inputerror("out of memory while processing");
+}
+
+PUBLIC void prematureeof()
+{
+ inputerror("premature end of");
+}
+
+PUBLIC void redefined(name, message, archentry, deffilename, defarchentry)
+char *name;
+char *message;
+char *archentry;
+char *deffilename;
+char *defarchentry;
+{
+ ++warncount;
+ refer();
+ putstr("warning: ");
+ putstr(name);
+ putstr(" redefined");
+ putstr(message);
+ putstr(" in file ");
+ putstr(inputname);
+ if (archentry != NULL)
+ {
+ putbyte('(');
+ putstr(archentry);
+ putbyte(')');
+ }
+ putstr("; using definition in ");
+ putstr(deffilename);
+ if (defarchentry != NULL)
+ {
+ putbyte('(');
+ putstr(defarchentry);
+ putbyte(')');
+ }
+ putbyte('\n');
+}
+
+PRIVATE void refer()
+{
+ putstr(refname);
+ putstr(": ");
+}
+
+PUBLIC void reserved(name)
+char *name;
+{
+ ++errcount;
+ putstr("incorrect use of reserved symbol: ");
+ putstrn(name);
+}
+
+PUBLIC void size_error(seg, count, size)
+char seg;
+offset_t count;
+offset_t size;
+{
+ refer();
+ putstr("seg ");
+ outhexdigs((offset_t) seg);
+ putstr(" has wrong size ");
+ outhexdigs(count);
+ putstr(", supposed to be ");
+ outhexdigs(size);
+ errexit("\n");
+}
+
+PUBLIC void undefined(name)
+char *name;
+{
+ ++errcount;
+ putstr("undefined symbol: ");
+ putstrn(name);
+}
+
+PUBLIC void usage()
+{
+ putstr("usage: ");
+ putstr(refname);
+#ifdef BSD_A_OUT
+ errexit("\
+ [-03Mimrstz[-]] [-llib_extension] [-o outfile] [-Ccrtfile]\n\
+ [-Llibdir] [-Olibfile] [-T textaddr] infile...");
+#else
+ errexit("\
+ [-03Mimstz[-]] [-llib_extension] [-o outfile] [-Ccrtfile]\n\
+ [-Llibdir] [-Olibfile] [-T textaddr] infile...");
+#endif
+}
+
+PUBLIC void use_error(message)
+char *message;
+{
+ refer();
+ putstrn(message);
+ usage();
+}