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