Pristine Ack-5.5
[Ack-5.5.git] / util / led / scan.c
1 /*
2  * (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
3  * See the copyright notice in the ACK home directory, in the file "Copyright".
4  */
5 #ifndef lint
6 static char rcsid[] = "$Id: scan.c,v 3.19 1994/06/24 10:35:17 ceriel Exp $";
7 #endif
8
9 #ifdef SYMDBUG
10 #include <sys/types.h>
11 #include <sys/stat.h>
12 #endif /* SYMDBUG */
13 #include <arch.h>
14 #include <out.h>
15 #include <ranlib.h>
16 #include "const.h"
17 #include "assert.h"
18 #include "memory.h"
19 #include "scan.h"
20 #include "debug.h"
21
22 #define READ    0
23
24 #define IND_EMIT(x)     (IND_CHAR(x) + (ind_t)align((x).oh_nchar))
25 #define IND_RELO(x)     (IND_EMIT(x) + (x).oh_nsect * sizeof(ind_t))
26 #ifdef SYMDBUG
27 #define IND_DBUG(x)     (IND_RELO(x) + sizeof(ind_t))
28 #endif /* SYMDBUG */
29
30 extern long     lseek();
31 extern char     *core_alloc();
32 extern bool     incore;
33 extern int      infile;
34 extern int      passnumber;
35
36 char            *archname;      /* Name of archive, if reading from archive. */
37 char            *modulname;     /* Name of object module. */
38 #ifdef SYMDBUG
39 long            objectsize;
40 #endif /* SYMDBUG */
41
42 static long     align();
43 static char     *modulbase;
44 static long     modulsize();
45 static          scan_modul();
46 static bool     all_alloc();
47 static bool     direct_alloc();
48 static bool     indirect_alloc();
49 static bool     putemitindex();
50 static bool     putreloindex();
51 #ifdef SYMDBUG
52 static bool     putdbugindex();
53 #endif /* SYMDBUG */
54 static          get_indirect();
55 static          read_modul();
56
57 /*
58  * Open the file with name `filename' (if necessary) and examine the first
59  * few bytes to see if it's a plain file or an archive.
60  * In case of a plain file, the file pointer is repositioned after the
61  * examination. Otherwise it is at the beginning of the table of contents.
62  */
63 int
64 getfile(filename)
65         char            *filename;
66 {
67         unsigned int    rd_unsigned2();
68         struct ar_hdr   archive_header;
69         unsigned short  magic_number;
70 #ifdef SYMDBUG
71         struct stat     statbuf;
72         extern int      fstat();
73 #endif /* SYMDBUG */
74
75         archname = (char *)0;
76         modulname = (char *)0;
77
78         if (passnumber == FIRST || !incore) {
79                 if ((infile = open(filename, READ)) < 0)
80                         fatal("can't read %s", filename);
81                 magic_number = rd_unsigned2(infile);
82         } else {
83                 modulbase = modulptr((ind_t)0);
84                 magic_number = *(unsigned short *)modulbase;
85         }
86
87         switch (magic_number) {
88         case O_MAGIC:
89 #ifdef SYMDBUG
90                 if (passnumber == FIRST || !incore) {
91                         if (fstat(infile, &statbuf) < 0)
92                                 fatal("cannot stat %s", filename);
93                         objectsize = statbuf.st_size;
94                 }
95 #endif /* SYMDBUG */
96                 seek((long)0);
97                 modulname = filename;
98                 return PLAIN;
99         case ARMAG:
100         case AALMAG:
101                 archname = filename;
102                 if (passnumber == FIRST) {
103                         rd_arhdr(infile, &archive_header);
104                         if (strcmp(archive_header.ar_name, SYMDEF))
105                                 fatal("%s: no table of contents", filename);
106                 } else if (incore) {
107                         modulbase += sizeof(int);
108                         core_position += sizeof(int);
109                 }
110                 return ARCHIVE;
111         default:
112                 fatal("%s: wrong magic number", filename);
113         }
114         /* NOTREACHED */
115 }
116
117 /* ARGSUSED */
118 closefile(filename)
119         char    *filename;
120 {
121         if (passnumber == FIRST || !incore)
122                 close(infile);
123 }
124
125 get_archive_header(archive_header)
126         register struct ar_hdr  *archive_header;
127 {
128         if (passnumber == FIRST || !incore) {
129                 rd_arhdr(infile, archive_header);
130         } else {
131                 /* Copy structs. */
132                 *archive_header = *(struct ar_hdr *)modulbase;
133                 modulbase += int_align(sizeof(struct ar_hdr));
134                 core_position += int_align(sizeof(struct ar_hdr));
135         }
136 #ifdef SYMDBUG
137         objectsize = archive_header.ar_size;
138 #endif /* SYMDBUG */
139 }
140
141 get_modul()
142 {
143         if (passnumber == FIRST) {
144                 rd_fdopen(infile);
145                 scan_modul();
146         } else if (!incore) {
147                 rd_fdopen(infile);
148                 read_modul();
149         }
150 }
151
152 /*
153  * Read module from the current file. If it doesn't fit into core, the strategy
154  * to keep everything in core is abandoned, but we will always put the header,
155  * the section table, and the name and string table into core.
156  */
157 static
158 scan_modul()
159 {
160         bool            space;
161         struct outhead  *head;
162         struct outsect  *sect;
163
164         space = all_alloc();
165         head = (struct outhead *)modulptr(IND_HEAD);
166         if (space) {
167                 sect = (struct outsect *)modulptr(IND_SECT(*head));
168                 get_indirect(head, sect);
169         }
170         rd_name((struct outname *)modulptr(IND_NAME(*head)), head->oh_nname);
171         rd_string((char *)modulptr(IND_CHAR(*head)), head->oh_nchar);
172 #ifdef SYMDBUG
173         if (space) {
174                 get_dbug(*(ind_t *)modulptr(IND_DBUG(*head)),
175                          ojectsize - OFF_DBUG(*head)
176                 );
177         }
178 #endif /* SYMDBUG */
179 }
180
181 /*
182  * Allocate space for and read in the header and section table.
183  * First get the header. With this we can determine what to allocate
184  * for the rest of the module, and with the rest we can determine what
185  * to allocate for the section contents.
186  * If possible, allocate space for the rest of the module. Return whether
187  * this was possible.
188  */
189 static bool
190 all_alloc()
191 {
192         struct outhead  head;
193         extern ind_t    hard_alloc();
194
195         if (hard_alloc(ALLOMODL, (long)sizeof(struct outhead)) == BADOFF)
196                 fatal("no space for module header");
197         rd_ohead((struct outhead *)modulptr(IND_HEAD));
198         /*
199          * Copy the header because we need it so often.
200          */
201         head = *(struct outhead *)modulptr(IND_HEAD);
202         return direct_alloc(&head) && indirect_alloc(&head);
203 }
204
205 /*
206  * Allocate space for the rest of the direct bytes.
207  * First allocate the section table and read it in, then allocate the rest
208  * and return whether this succeeded.
209  */
210 static bool
211 direct_alloc(head)
212         struct outhead  *head;
213 {
214         ind_t           sectindex = IND_SECT(*head);
215         register struct outsect *sects;
216         unsigned short  nsect = head->oh_nsect;
217         long            size, rest;
218         extern ind_t    hard_alloc();
219         extern ind_t    alloc();
220
221 #ifdef SYMDBUG
222         rest = nsect * sizeof(ind_t) + sizeof(ind_t) + sizeof(ind_t);
223 #else /* SYMDBUG */
224         rest = nsect * sizeof(ind_t) + sizeof(ind_t);
225 #endif /* SYMDBUG */
226         /*
227          * We already allocated space for the header, we now need
228          * the section, name an string table.
229          */
230         size = modulsize(head) - sizeof(struct outhead) - rest;
231         if (hard_alloc(ALLOMODL, size) == BADOFF)
232                 fatal("no space for module");
233         rd_sect(sects = ((struct outsect *)modulptr(sectindex)), nsect);
234         while (nsect--) {
235                 if (sects->os_lign > 1) {
236                         sects->os_size += sects->os_lign - 1;
237                         sects->os_size -= sects->os_size % sects->os_lign;
238                 }
239                 sects++;
240         }
241
242         return incore && alloc(ALLOMODL, rest) != BADOFF;
243 }
244
245 /*
246  * Allocate space for the indirectly accessed pieces: the section contents and
247  * the relocation table, and put their indices in the right place.
248  */
249 static bool
250 indirect_alloc(head)
251         struct outhead  *head;
252 {
253         register int    allopiece;
254         unsigned short  nsect = head->oh_nsect;
255         unsigned short  nrelo = head->oh_nrelo;
256         ind_t           sectindex = IND_SECT(*head);
257         ind_t           emitoff = IND_EMIT(*head);
258         ind_t           relooff = IND_RELO(*head);
259 #ifdef SYMDBUG
260         ind_t           dbugoff = IND_DBUG(*head);
261         extern long     objectsize;
262         long            dbugsize = objectsize - OFF_DBUG(*head);
263 #endif /* SYMDBUG */
264
265         assert(incore);
266         for (allopiece = ALLOEMIT; allopiece < ALLOEMIT + nsect; allopiece++) {
267                 if (!putemitindex(sectindex, emitoff, allopiece))
268                         return FALSE;
269                 sectindex += sizeof(struct outsect);
270                 emitoff += sizeof(ind_t);
271         }
272 #ifdef SYMDBUG
273         return  putreloindex(relooff, (long)nrelo * sizeof(struct outrelo))
274                 &&
275                 putdbugindex(dbugoff, dbugsize);
276 #else /* SYMDBUG */
277         return putreloindex(relooff, (long)nrelo * sizeof(struct outrelo));
278 #endif /* SYMDBUG */
279 }
280
281 /*
282  * Allocate space for the contents of the section of which the table entry is
283  * at offset `sectindex'. Put the offset of the allocated piece at offset
284  * `emitoff'.
285  */
286 static bool
287 putemitindex(sectindex, emitoff, allopiece)
288         ind_t           sectindex;
289         ind_t           emitoff;
290         int             allopiece;
291 {
292         long            flen;
293         ind_t           emitindex;
294         extern ind_t    alloc();
295         static long     zeros[MAXSECT];
296         register long    zero  = zeros[allopiece - ALLOEMIT];
297
298         /*
299          * Notice that "sectindex" is not a section number!
300          * It contains the offset of the section from the beginning
301          * of the module. Thus, it cannot be used to index "zeros".
302          * AIAIAIAIA
303          */
304
305         flen = ((struct outsect *)modulptr(sectindex))->os_flen;
306         if (flen && zero) {
307                 if ((emitindex = alloc(allopiece, zero)) != BADOFF){
308                         register char *p = address(allopiece, emitindex);
309
310                         debug("Zeros %ld\n", zero, 0,0,0);
311                         while (zero--) *p++ = 0;
312                 }
313                 else     return FALSE;
314                 zero = 0;
315         }
316         zeros[allopiece - ALLOEMIT] =
317          zero + ((struct outsect *) modulptr(sectindex))->os_size - flen;
318         if ((emitindex = alloc(allopiece, flen)) != BADOFF) {
319                 *(ind_t *)modulptr(emitoff) = emitindex;
320                 return TRUE;
321         }
322         return FALSE;
323 }
324
325 /*
326  * Allocate space for a relocation table with `nrelobytes' bytes, and put the
327  * offset at `relooff'.
328  */
329 static bool
330 putreloindex(relooff, nrelobytes)
331         ind_t           relooff;
332         long            nrelobytes;
333 {
334         ind_t           reloindex;
335         extern ind_t    alloc();
336
337         if ((reloindex = alloc(ALLORELO, nrelobytes)) != BADOFF) {
338                 *(ind_t *)modulptr(relooff) = reloindex;
339                 return TRUE;
340         }
341         return FALSE;
342 }
343 #ifdef SYMDBUG
344 /*
345  * Allocate space for debugging information and put the offset at `dbugoff'.
346  */
347 static bool
348 putdbugindex(dbugoff, ndbugbytes)
349         ind_t           relooff;
350         long            ndbugbytes;
351 {
352         ind_t           dbugindex;
353         extern ind_t    alloc();
354
355         if ((dbugindex = alloc(ALLODBUG, ndbugbytes)) != BADOFF) {
356                 *(ind_t *)modulptr(dbugoff) = dbugindex;
357                 return TRUE;
358         }
359         return FALSE;
360 }
361 #endif /* SYMDBUG */
362
363 /*
364  * Compute addresses and read in. Remember that the contents of the sections
365  * and also the relocation table are accessed indirectly.
366  */
367 static
368 get_indirect(head, sect)
369         struct outhead  *head;          /* not register! Won't compile on
370                                            SCO Xenix 386 if it is!
371                                         */
372         register struct outsect *sect;
373 {
374         register ind_t          *emitindex;
375         register int            nsect;
376         register int            piece;
377         ind_t                   *reloindex;
378
379         emitindex = (ind_t *)modulptr(IND_EMIT(*head));
380         piece = ALLOEMIT;
381         for (nsect = 0; nsect < head->oh_nsect; nsect++) {
382                 rd_outsect(nsect);
383                 rd_emit(address(piece, *emitindex), sect->os_flen);
384                 piece++; emitindex++; sect++;
385         }
386         reloindex = (ind_t *)modulptr(IND_RELO(*head));
387         rd_relo((struct outrelo *)address(ALLORELO, *reloindex),
388                 head->oh_nrelo
389         );
390 }
391
392 /*
393  * Set the file pointer at `pos'.
394  */
395 seek(pos)
396         long            pos;
397 {
398         if (passnumber == FIRST || !incore)
399                 lseek(infile, pos, 0);
400 }
401
402 /*
403  * A file pointer is advanced automatically when reading, a char pointer
404  * is not. That's why we do it here. If we don't keep everything in core,
405  * we give the space allocated for a module back.
406  */
407 skip_modul(head)
408         struct outhead  *head;
409 {
410         register ind_t  skip = modulsize(head);
411
412         if (incore) {
413                 core_position += int_align(skip);
414                 if (passnumber == SECOND)
415                         modulbase += int_align(skip);
416         } else {
417                 dealloc(ALLOMODL);
418                 core_position = (ind_t)0;
419         }
420 }
421
422 /*
423  * Read in what we need in pass 2, because we couldn't keep it in core.
424  */
425 static
426 read_modul()
427 {
428         struct outhead  *head;
429         register struct outsect *sects;
430         struct outname  *names;
431         char            *chars;
432         ind_t           sectindex, nameindex, charindex;
433         unsigned short  nsect, nname;
434         long            size;
435         long            nchar;
436         extern ind_t    hard_alloc();
437
438         assert(passnumber == SECOND);
439         assert(!incore);
440         if (hard_alloc(ALLOMODL, (long)sizeof(struct outhead)) == BADOFF)
441                 fatal("no space for module header");
442         head = (struct outhead *)modulptr(IND_HEAD);
443         rd_ohead(head);
444         nsect = head->oh_nsect; sectindex = IND_SECT(*head);
445         nname = head->oh_nname; nameindex = IND_NAME(*head);
446         nchar = head->oh_nchar; charindex = IND_CHAR(*head);
447 #ifdef SYMDBUG
448         size = modulsize(head) - (nsect * sizeof(ind_t) + 2 * sizeof(ind_t));
449 #else /* SYMDBUG */
450         size = modulsize(head) - (nsect * sizeof(ind_t) + sizeof(ind_t));
451 #endif /* SYMDBUG */
452         if (hard_alloc(ALLOMODL, size) == BADOFF)
453                 fatal("no space for module");
454
455         sects = (struct outsect *)modulptr(sectindex);
456         names = (struct outname *)modulptr(nameindex);
457         chars = modulptr(charindex);
458
459         rd_sect(sects, nsect);
460         while (nsect--) {
461                 if (sects->os_lign > 1) {
462                         sects->os_size += sects->os_lign - 1;
463                         sects->os_size -= sects->os_size % sects->os_lign;
464                 }
465                 sects++;
466         }
467         rd_name(names, nname);
468         rd_string(chars, nchar);
469 }
470
471 /*
472  * Align `size' to a multiple of the size of a double.
473  * This is assumed to be a power of 2.
474  */
475 static long
476 align(size)
477         register long   size;
478 {
479         return (size + (sizeof(double) - 1)) & ~(int)(sizeof(double) - 1);
480 }
481
482 /*
483  * Compute how many DIRECT bytes must be allocated for a module of which the
484  * header is pointed to by `head':
485  *      0. the header,
486  *      1. the section table,
487  *      2. the name table,
488  *      3. the string table,
489  *      4. for each section the offset of its contents,
490  *      5. the offset of the relocation table.
491 #ifdef SYMDBUG
492  *      6. the offset of the debugging information.
493 #endif
494  */
495 static long
496 modulsize(head)
497         register struct outhead *head;
498 {
499         return  sizeof(struct outhead) +                        /* 0 */
500                 head->oh_nsect * sizeof(struct outsect) +       /* 1 */
501                 head->oh_nname * sizeof(struct outname) +       /* 2 */
502                 align(head->oh_nchar) +                         /* 3 */
503                 head->oh_nsect * sizeof(ind_t) +                /* 4 */
504 #ifdef SYMDBUG
505                 sizeof(ind_t) +                                 /* 5 */
506                 sizeof(ind_t);                                  /* 6 */
507 #else /* SYMDBUG */
508                 sizeof(ind_t);                                  /* 5 */
509 #endif /* SYMDBUG */
510 }
511
512 /* ------------------------------------------------------------------------- */
513
514 /*
515  * Walk through the relocation table of the current module. We must either walk
516  * through core or through file. Startrelo() should be called first.
517  */
518
519 static struct outrelo   *walkrelo;
520 static unsigned short cnt_relos;
521 static unsigned short relind;
522 #define _RELSIZ 64
523
524 startrelo(head)
525         register struct outhead *head;
526 {
527         ind_t           reloindex;
528
529         if (incore) {
530                 reloindex = *(ind_t *)(modulbase + IND_RELO(*head));
531                 walkrelo = (struct outrelo *)address(ALLORELO, reloindex);
532         }
533         else {
534                 relind = _RELSIZ;
535                 rd_rew_relos(head);
536                 cnt_relos = head->oh_nrelo;
537         }
538 }
539
540 struct outrelo *
541 nextrelo()
542 {
543         static struct outrelo   relobuf[_RELSIZ];
544
545         if (incore)
546                 return walkrelo++;
547
548         if (relind == _RELSIZ) {
549                 unsigned int i = cnt_relos >= _RELSIZ ? _RELSIZ : cnt_relos;
550
551                 cnt_relos -= i;
552                 rd_relo(relobuf, i);
553                 relind = 0;
554         }
555         return &relobuf[relind++];
556 }
557
558 /* ------------------------------------------------------------------------- */
559
560 /*
561  * Get the section contents in core of which the describing struct has index
562  * `sectindex'. `Head' points to the header of the module.
563  */
564 char *
565 getemit(head, sects, sectindex)
566         struct outhead  *head;
567         struct outsect  *sects;
568         int             sectindex;
569 {
570         char            *ret;
571         ind_t           off;
572         extern char     *core_alloc();
573
574         if (!incore) {
575                 ret = core_alloc(ALLOMODL, sects[sectindex].os_flen);
576                 if (ret == (char *)0)
577                         return 0;
578                 rd_outsect(sectindex);
579                 rd_emit(ret, sects[sectindex].os_flen);
580                 return ret;
581         }
582         /*
583          * We have an offset in the contents of the final output
584          * "file" where normally the contents would be.
585          */
586         off = *((ind_t *)(modulbase + IND_EMIT(*head)) + sectindex);
587         return address(ALLOEMIT + sectindex, off);
588 }
589
590 char *
591 getblk(totalsz, pblksz, sectindex)
592         long    totalsz;
593         long    *pblksz;
594         int     sectindex;
595 {
596         char    *ret;
597         long    sz = (1L << 30);
598
599         assert(!incore);
600
601         while (sz >= totalsz) sz >>= 1;
602         while (sz) {
603                 ret = core_alloc(ALLOMODL, sz);
604                 if (ret != (char *) 0) {
605                         rd_outsect(sectindex);
606                         *pblksz = sz;
607                         return ret;
608                 }
609                 sz >>= 1;
610         }
611         fatal("no space for section contents");
612         return (char *) 0;
613 }
614
615 endemit(emit)
616         char    *emit;
617 {
618         core_free(ALLOMODL, emit);
619 }