1 /* io.c - input/output and error modules for linker */
2 
3 /* Copyright (C) 1994 Bruce Evans */
4 
5 #include "syshead.h"
6 #include "const.h"
7 #include "type.h"
8 #include "globvar.h"
9 #include "version.h"
10 
11 #define DRELBUFSIZE	3072
12 #define ERR		(-1)
13 #define ERRBUFSIZE	1024
14 #define INBUFSIZE	1024
15 #define OUTBUFSIZE	2048
16 #define TRELBUFSIZE	1024
17 
18 #ifdef REL_OUTPUT
19 PRIVATE char *drelbuf;		/* extra output buffer for data relocations */
20 PRIVATE char *drelbufptr;	/* data relocation output buffer ptr */
21 PRIVATE char *drelbuftop;	/* data relocation output buffer top */
22 #endif
23 PRIVATE char *errbuf;		/* error buffer (actually uses STDOUT) */
24 PRIVATE char *errbufptr;	/* error buffer ptr */
25 PRIVATE char *errbuftop;	/* error buffer top */
26 PRIVATE int  errfil = STDOUT_FILENO;
27 PRIVATE char *inbuf;		/* input buffer */
28 PRIVATE char *inbufend;		/* input buffer top */
29 PRIVATE char *inbufptr;		/* end of input in input buffer */
30 PRIVATE int infd;		/* input file descriptor */
31 PRIVATE char *inputname;	/* name of current input file */
32 PRIVATE char *outbuf;		/* output buffer */
33 PRIVATE char *outbufptr;	/* output buffer ptr */
34 PRIVATE char *outbuftop;	/* output buffer top */
35 PRIVATE int outfd;		/* output file descriptor */
36 PRIVATE mode_t outputperms;	/* permissions of output file */
37 PRIVATE char *outputname;	/* name of output file */
38 PRIVATE char *refname;		/* name of program for error reference */
39 #ifdef REL_OUTPUT
40 PRIVATE char *trelbuf;		/* extra output buffer for text relocations */
41 PRIVATE char *trelbufptr;	/* text relocation output buffer ptr */
42 PRIVATE char *trelbuftop;	/* text relocation output buffer top */
43 PRIVATE int trelfd;		/* text relocation output file descriptor */
44 #endif
45 PRIVATE unsigned warncount;	/* count of warnings */
46 
47 #ifdef MSDOS
48 #define off_t	long		/* NOT a typedef */
49 #endif
50 
51 FORWARD void errexit P((char *message));
52 FORWARD void flushout P((void));
53 #ifdef REL_OUTPUT
54 FORWARD void flushtrel P((void));
55 #endif
56 FORWARD void outhexdigs P((bin_off_t num));
57 FORWARD void outputerror P((char *message));
58 FORWARD void put04x P((unsigned num));
59 FORWARD void putstrn P((char *message));
60 FORWARD void refer P((void));
61 FORWARD void stderr_out P((void));
62 
ioinit(progname)63 PUBLIC void ioinit(progname)
64 char *progname;
65 {
66     infd = ERR;
67     if (*progname)
68 	refname = progname;	/* name must be static (is argv[0]) */
69     else
70 	refname = "link";
71     for(progname=refname; *progname; progname++)
72        if(*progname=='/')
73           refname=progname+1;
74 
75 #ifdef REL_OUTPUT
76     drelbuf = malloc(DRELBUFSIZE);
77     drelbuftop = drelbuf + DRELBUFSIZE;
78 #endif
79     errbuf = malloc(ERRBUFSIZE);
80     errbufptr = errbuf;
81     errbuftop = errbuf + ERRBUFSIZE;
82     inbuf = malloc(INBUFSIZE);
83     outbuf = malloc(OUTBUFSIZE);/* outbuf invalid if this fails but then */
84 				/* will not be used - tableinit() aborts */
85     outbuftop = outbuf + OUTBUFSIZE;
86 #ifdef REL_OUTPUT
87     trelbuf = malloc(TRELBUFSIZE);
88     trelbuftop = trelbuf + TRELBUFSIZE;
89 #endif
90 }
91 
closein()92 PUBLIC void closein()
93 {
94     if (infd != ERR && close(infd) < 0)
95 	inputerror("cannot close");
96     infd = ERR;
97 }
98 
closeout()99 PUBLIC void closeout()
100 {
101 #ifdef REL_OUTPUT
102     unsigned nbytes;
103 #endif
104 
105     flushout();
106 #ifdef REL_OUTPUT
107     flushtrel();
108     nbytes = drelbufptr - drelbuf;
109     if (write(trelfd, drelbuf, nbytes) != nbytes)
110 	outputerror("cannot write");
111 #endif
112     if (close(outfd) == ERR)
113 	outputerror("cannot close");
114 #ifdef REL_OUTPUT
115     if (close(trelfd) == ERR)
116 	outputerror("cannot close");
117 #endif
118 }
119 
errtrace(name,level)120 PUBLIC void errtrace(name, level)
121 char *name;
122 int level;
123 {
124     while (level-- > 0)
125 	putbyte(' ');
126     putstrn(name);
127 }
128 
executable()129 PUBLIC void executable()
130 {
131     if (errcount)
132         unlink(outputname);
133 #ifndef MSDOS
134     else
135 	chmod(outputname, outputperms);
136 #endif
137 }
138 
flusherr()139 PUBLIC void flusherr()
140 {
141     if( errbufptr != errbuf )
142        write(errfil, errbuf, (unsigned) (errbufptr - errbuf));
143     errbufptr = errbuf;
144 }
145 
stderr_out()146 PRIVATE void stderr_out()
147 {
148    if( errfil != STDERR_FILENO )
149    {
150       flusherr();
151       errfil = STDERR_FILENO;
152    }
153 }
154 
flushout()155 PRIVATE void flushout()
156 {
157     unsigned nbytes;
158 
159     nbytes = outbufptr - outbuf;
160     if (write(outfd, outbuf, nbytes) != nbytes)
161 	outputerror("cannot write");
162     outbufptr = outbuf;
163 }
164 
165 #ifdef REL_OUTPUT
flushtrel()166 PRIVATE void flushtrel()
167 {
168     unsigned nbytes;
169 
170     nbytes = trelbufptr - trelbuf;
171     if (write(trelfd, trelbuf, nbytes) != nbytes)
172 	outputerror("cannot write");
173     trelbufptr = trelbuf;
174 }
175 #endif
176 
openin(filename)177 PUBLIC void openin(filename)
178 char *filename;
179 {
180 #if 0 /* XXX - this probably won't work with constructed lib names? */
181     if (infd == ERR || strcmp(inputname, filename) != 0)
182 #endif
183     {
184 	closein();
185 	inputname = filename;	/* this relies on filename being static */
186 #ifdef O_BINARY
187 	if ((infd = open(filename, O_BINARY|O_RDONLY)) < 0)
188 #else
189 	if ((infd = open(filename, O_RDONLY)) < 0)
190 #endif
191 	    inputerror("cannot open");
192 	inbufptr = inbufend = inbuf;
193     }
194 }
195 
openout(filename)196 PUBLIC void openout(filename)
197 char *filename;
198 {
199     mode_t oldmask;
200 
201     outputname = filename;
202 #ifdef O_BINARY
203     if ((outfd = open(filename, O_BINARY|O_WRONLY|O_CREAT|O_TRUNC, CREAT_PERMS)) == ERR)
204 #else
205     if ((outfd = creat(filename, CREAT_PERMS)) == ERR)
206 #endif
207 	outputerror("cannot open");
208 
209 #ifndef MSDOS
210     /* Can't do this on MSDOS; it upsets share.exe */
211     oldmask = umask(0); umask(oldmask);
212     outputperms = ((CREAT_PERMS | EXEC_PERMS) & ~oldmask);
213     chmod(filename, outputperms & ~EXEC_PERMS);
214 #endif
215 
216 #ifdef REL_OUTPUT
217     drelbufptr = drelbuf;
218 #endif
219     outbufptr = outbuf;
220 #ifdef REL_OUTPUT
221 #ifdef O_BINARY
222     if ((trelfd = open(filename, O_BINARY|O_WRONLY, CREAT_PERMS)) == ERR)
223 #else
224     if ((trelfd = open(filename, O_WRONLY, CREAT_PERMS)) == ERR)
225 #endif
226 	outputerror("cannot reopen");
227     trelbufptr = trelbuf;
228 #endif
229 }
230 
outhexdigs(num)231 PRIVATE void outhexdigs(num)
232 register bin_off_t num;
233 {
234     if (num >= 0x10)
235     {
236 	outhexdigs(num / 0x10);
237 	num %= 0x10;
238     }
239     putbyte(hexdigit[num]);
240 }
241 
put04x(num)242 PRIVATE void put04x(num)
243 register unsigned num;
244 {
245     putbyte(hexdigit[num / 0x1000]);
246     putbyte(hexdigit[(num / 0x100) & 0x0F]);
247     putbyte(hexdigit[(num / 0x10) & 0x0F]);
248     putbyte(hexdigit[num & 0x0F]);
249 }
250 
251 #ifdef LONG_OFFSETS
252 
put08lx(num)253 PUBLIC void put08lx(num)
254 register bin_off_t num;
255 {
256     put04x(num / 0x10000);
257     put04x(num % 0x10000);
258 }
259 
260 #else /* not LONG_OFFSETS */
261 
put08x(num)262 PUBLIC void put08x(num)
263 register bin_off_t num;
264 {
265     putstr("0000");
266     put04x(num);
267 }
268 
269 #endif /* not LONG_OFFSETS */
270 
putbstr(width,str)271 PUBLIC void putbstr(width, str)
272 unsigned width;
273 char *str;
274 {
275     unsigned length;
276 
277     for (length = strlen(str); length < width; ++length)
278 	putbyte(' ');
279     putstr(str);
280 }
281 
putbyte(ch)282 PUBLIC void putbyte(ch)
283 int ch;
284 {
285     register char *ebuf;
286 
287     ebuf = errbufptr;
288     if (ebuf >= errbuftop)
289     {
290 	flusherr();
291 	ebuf = errbufptr;
292     }
293     *ebuf++ = ch;
294     errbufptr = ebuf;
295 }
296 
putstr(message)297 PUBLIC void putstr(message)
298 char *message;
299 {
300     while (*message != 0)
301 	putbyte(*message++);
302 }
303 
putstrn(message)304 PRIVATE void putstrn(message)
305 char *message;
306 {
307     putstr(message);
308     putbyte('\n');
309     flusherr(); errfil = STDOUT_FILENO;
310 }
311 
readchar()312 PUBLIC int readchar()
313 {
314     int ch;
315 
316     register char *ibuf;
317     int nread;
318 
319     ibuf = inbufptr;
320     if (ibuf >= inbufend)
321     {
322 	ibuf = inbufptr = inbuf;
323 	nread = read(infd, ibuf, INBUFSIZE);
324 	if (nread <= 0)
325 	{
326 	    inbufend = ibuf;
327 	    return ERR;
328 	}
329 	inbufend = ibuf + nread;
330     }
331     ch = (unsigned char) *ibuf++;
332     inbufptr = ibuf;
333     return ch;
334 }
335 
readin(buf,count)336 PUBLIC void readin(buf, count)
337 char *buf;
338 unsigned count;
339 {
340     int ch;
341 
342     while (count--)
343     {
344 	if ((ch = readchar()) < 0)
345 	    prematureeof();
346 	*buf++ = ch;
347     }
348 }
349 
readineofok(buf,count)350 PUBLIC bool_pt readineofok(buf, count)
351 char *buf;
352 unsigned count;
353 {
354     int ch;
355 
356     while (count--)
357     {
358 	if ((ch = readchar()) < 0)
359 	    return TRUE;
360 	*buf++ = ch;
361     }
362     return FALSE;
363 }
364 
seekin(offset)365 PUBLIC void seekin(offset)
366 unsigned long offset;
367 {
368     inbufptr = inbufend = inbuf;
369     if (lseek(infd, (off_t) offset, SEEK_SET) != offset)
370 	prematureeof();
371 }
372 
seekout(offset)373 PUBLIC void seekout(offset)
374 unsigned long offset;
375 {
376     flushout();
377     if (lseek(outfd, (off_t) offset, SEEK_SET) != offset)
378 	outputerror("cannot seek in");
379 }
380 
381 #ifdef REL_OUTPUT
seektrel(offset)382 PUBLIC void seektrel(offset)
383 unsigned long offset;
384 {
385     flushtrel();
386     if (lseek(trelfd, (off_t) offset, SEEK_SET) != offset)
387 	outputerror("cannot seek in");
388 }
389 #endif
390 
writechar(ch)391 PUBLIC void writechar(ch)
392 int ch;
393 {
394     register char *obuf;
395 
396     obuf = outbufptr;
397     if (obuf >= outbuftop)
398     {
399 	flushout();
400 	obuf = outbufptr;
401     }
402     *obuf++ = ch;
403     outbufptr = obuf;
404 }
405 
406 #ifdef REL_OUTPUT
writedrel(buf,count)407 PUBLIC void writedrel(buf, count)
408 register char *buf;
409 unsigned count;
410 {
411     register char *rbuf;
412 
413     rbuf = drelbufptr;
414     while (count--)
415     {
416 	if (rbuf >= drelbuftop)
417 	    inputerror("data relocation buffer full while processing");
418 	*rbuf++ = *buf++;
419     }
420     drelbufptr = rbuf;
421 }
422 #endif
423 
writeout(buf,count)424 PUBLIC void writeout(buf, count)
425 register char *buf;
426 unsigned count;
427 {
428     register char *obuf;
429 
430     obuf = outbufptr;
431     while (count--)
432     {
433 	if (obuf >= outbuftop)
434 	{
435 	    outbufptr = obuf;
436 	    flushout();
437 	    obuf = outbufptr;
438 	}
439 	*obuf++ = *buf++;
440     }
441     outbufptr = obuf;
442 }
443 
444 #ifdef REL_OUTPUT
writetrel(buf,count)445 PUBLIC void writetrel(buf, count)
446 register char *buf;
447 unsigned count;
448 {
449     register char *rbuf;
450 
451     rbuf = trelbufptr;
452     while (count--)
453     {
454 	if (rbuf >= trelbuftop)
455 	{
456 	    trelbufptr = rbuf;
457 	    flushtrel();
458 	    rbuf = trelbufptr;
459 	}
460 	*rbuf++ = *buf++;
461     }
462     trelbufptr = rbuf;
463 }
464 #endif
465 
466 /* error module */
467 
errexit(message)468 PRIVATE void errexit(message)
469 char *message;
470 {
471     putstrn(message);
472     exit(2);
473 }
474 
fatalerror(message)475 PUBLIC void fatalerror(message)
476 char *message;
477 {
478     refer();
479     errexit(message);
480 }
481 
inputerror(message)482 PUBLIC void inputerror(message)
483 char *message;
484 {
485     refer();
486     putstr(message);
487     putstr(" input file ");
488     errexit(inputname);
489 }
490 
input1error(message)491 PUBLIC void input1error(message)
492 char *message;
493 {
494     refer();
495     putstr(inputname);
496     errexit(message);
497 }
498 
outputerror(message)499 PRIVATE void outputerror(message)
500 char *message;
501 {
502     refer();
503     putstr(message);
504     putstr(" output file ");
505     errexit(outputname);
506 }
507 
outofmemory()508 PUBLIC void outofmemory()
509 {
510     inputerror("out of memory while processing");
511 }
512 
prematureeof()513 PUBLIC void prematureeof()
514 {
515     inputerror("premature end of");
516 }
517 
redefined(name,message,archentry,deffilename,defarchentry)518 PUBLIC void redefined(name, message, archentry, deffilename, defarchentry)
519 char *name;
520 char *message;
521 char *archentry;
522 char *deffilename;
523 char *defarchentry;
524 {
525     ++warncount;
526     refer();
527     putstr("warning: ");
528     putstr(name);
529     putstr(" redefined");
530     putstr(message);
531     putstr(" in file ");
532     putstr(inputname);
533     if (archentry != NUL_PTR)
534     {
535 	putbyte('(');
536 	putstr(archentry);
537 	putbyte(')');
538     }
539     putstr("; using definition in ");
540     putstr(deffilename);
541     if (defarchentry != NUL_PTR)
542     {
543 	putbyte('(');
544 	putstr(defarchentry);
545 	putbyte(')');
546     }
547     putstrn("");
548 }
549 
interseg(fname,aname,name)550 PUBLIC void interseg(fname, aname, name)
551 char *fname, *aname, *name;
552 {
553     ++errcount;
554     refer();
555     putstr("error in ");
556     putstr(fname);
557     if( aname )
558     {
559        putstr("(");
560        putstr(aname);
561        putstr(")");
562     }
563     putstr(" intersegment jump to ");
564     if( name ) putstr(name);
565     else       putstr("same file");
566 
567     putstrn("");
568 }
569 
refer()570 PRIVATE void refer()
571 {
572     stderr_out();
573     putstr(refname);
574     putstr(": ");
575 }
576 
reserved(name)577 PUBLIC void reserved(name)
578 char *name;
579 {
580     ++errcount;
581     stderr_out();
582     putstr("incorrect use of reserved symbol: ");
583     putstrn(name);
584 }
585 
size_error(seg,count,size)586 PUBLIC void size_error(seg, count, size)
587 int seg;
588 bin_off_t count;
589 bin_off_t size;
590 {
591     refer();
592     putstr("seg ");
593     outhexdigs((bin_off_t) seg);
594     putstr(" has wrong size ");
595     outhexdigs(count);
596     putstr(", supposed to be ");
597     outhexdigs(size);
598     errexit("");
599 }
600 
undefined(name)601 PUBLIC void undefined(name)
602 char *name;
603 {
604     ++errcount;
605     stderr_out();
606     putstr("undefined symbol: ");
607     putstrn(name);
608 }
609 
usage()610 PUBLIC void usage()
611 {
612     stderr_out();
613     putstr("usage: ");
614     putstr(refname);
615 #ifdef REL_OUTPUT
616     errexit("\
617  [-03NMdimrstz[-]] [-llib_extension] [-o outfile] [-Ccrtfile]\n\
618        [-Llibdir] [-Olibfile] [-Ttextaddr] [-Ddataaddr] [-Hheapsize] infile...");
619 #else
620     errexit("\
621  [-03NMdimstz[-]] [-llib_extension] [-o outfile] [-Ccrtfile]\n\
622        [-Llibdir] [-Olibfile] [-Ttextaddr] [-Ddataaddr] [-Hheapsize] infile...");
623 #endif
624 }
625 
version_msg()626 PUBLIC void version_msg()
627 {
628     stderr_out();
629 #ifdef VERSION
630     putstr("ld86 version: ");
631     errexit(VERSION);
632 #else
633     errexit("ld86 version unknown");
634 #endif
635 }
636 
use_error(message)637 PUBLIC void use_error(message)
638 char *message;
639 {
640     refer();
641     putstrn(message);
642     usage();
643 }
644