ranlib: fix it
[odcctools-svp.git] / mkshlib / parse_spec.c
bloba2cc8fc17c8e5b2a70cec3a5cf6c67c4d322bd00
1 /*
2 * Copyright (c) 1999 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
11 * file.
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
21 * @APPLE_LICENSE_HEADER_END@
23 #undef SPEC_DEBUG
25 * This file contains the routines to parse a shared library specification
26 * file and builds up the data structures to represent it. See parse_spec.h
28 #include <stdlib.h>
29 #include <stdio.h>
30 #include <ctype.h>
31 #include <strings.h>
32 #include <libc.h>
33 #include <mach/mach.h>
34 #include <mach-o/loader.h>
35 #include <mach-o/reloc.h>
36 #include "stuff/errors.h"
37 #include "stuff/allocate.h"
38 #include "stuff/hash_string.h"
39 #include "stuff/bool.h"
40 #include "stuff/bytesex.h"
42 #include "libgcc.h"
43 #include "mkshlib.h"
45 #define BRANCH_LIST_SIZE 1301 /* initial branch list table size */
46 #define OBJECT_HASH_SIZE 251 /* object table hash size (fixed, prime number) */
47 #define OBJECT_LIST_SIZE 256 /* initial object list table size */
48 #define ODDBALL_LIST_SIZE 256 /* initial oddball symbol list table size */
51 * These globals are set after parse_spec() returns with the values read from
52 * the library shared library specification file.
54 char *target_name = (char *)0; /* shared library target name */
55 unsigned long minor_version = 0;/* shared library minor version number */
56 unsigned long image_version = 0;/* shared library image version number */
57 unsigned long text_addr = BAD_ADDRESS; /* shared library __TEXT segment addr */
58 unsigned long data_addr = BAD_ADDRESS; /* shared library __DATA segment addr */
61 * Hash table for branch slots, filled in here used in creating the host library
62 * in changing symbol values to their branch table entries.
64 struct branch *branch_hash[BRANCH_HASH_SIZE];
66 struct branch **branch_list; /* linear list of branch slots */
67 static long branch_list_size; /* size of branch_list */
68 long nbranch_list; /* number of branches in branch_list */
71 * Hash table for oddball symbols, filled in here and used in creating
72 * the host library by not including priviate symbols. And is used in creating
73 * the target library in not complaining about external symbols that don't
74 * have branch table entries.
76 struct oddball *oddball_hash[ODDBALL_HASH_SIZE];
78 static struct oddball **oddball_list; /* linear list of oddball symbols */
79 static long oddball_list_size; /* size of oddball_list */
80 static long noddball_list; /* number of oddballs in oddball_list */
82 /* hash table for objects, fixed size */
83 static struct object **object_hash;
85 struct object **object_list; /* list of objects in order to be loaded*/
86 static unsigned long object_list_size;/* size of object_list */
87 unsigned long nobject_list; /* number of objects in object_list */
89 /* The list of alias structures */
90 struct alias *aliases;
92 /* the current line number for error messages */
93 static long line_num;
96 * spec_error is incremented for each error encountered and if non-zero at the
97 * end of parse_spec() a non-zero exit is performed.
99 static long spec_error;
101 /* the current object for the last #init directive seen */
102 static struct object *init_object;
104 /* The maximum number slot seen in the spec file, for error reporting only */
105 static int max_slotnum_seen = 0;
108 * functions used only for parsing the spec file.
110 static long newstate(char *p, long oldstate);
111 static void branch(char *p);
112 static void object(char *p);
113 static void filelist(
114 char *file_name,
115 char *directory_name,
116 enum libgcc libgcc_state);
117 static char *new_object(
118 char *object_name,
119 enum bool filelist,
120 enum libgcc libgcc_state);
121 static void init(char *p);
122 static void alias(char *p);
123 static void oddball(char *p, long state);
124 static char *next(char *p);
126 /* parsing states returned by newstate() */
127 #define STATE_NONE 0
128 #define STATE_BRANCH 1
129 #define STATE_OBJECT 2
130 #define STATE_INIT 3
131 #define STATE_ALIAS 4
132 #define STATE_PRIVATE 5
133 #define STATE_NOBRANCH 6
134 #define STATE_UNDEFINED 7
137 * parse_spec() parses the shared library specification file, spec_filename, and
138 * build data structures from it to drive the process to build the shared
139 * library files.
141 void
142 parse_spec(void)
144 FILE *spec_stream;
145 long state, i, hash_key;
146 char line[BUFSIZ], *p;
147 struct object *op;
148 struct oddball *obp;
149 struct branch *bp;
151 /* open the specification file to read it */
152 if((spec_stream = fopen(spec_filename, "r")) == NULL)
153 system_fatal("can't open: %s", spec_filename);
155 line_num = 0;
156 state = STATE_NONE;
157 while(fgets(line, BUFSIZ, spec_stream) != NULL){
158 line_num++;
159 if(strlen(line) == BUFSIZ - 1 && line[BUFSIZ - 1] != '\n')
160 fatal("line %ld in: %s too long (maximum %d)", line_num,
161 spec_filename, BUFSIZ);
162 p = line;
163 while(isspace(*p))
164 p++;
165 if(*p == '\0')
166 continue;
167 if(*p == '#'){
168 state = newstate(p, state);
170 else{
171 switch(state){
172 case STATE_BRANCH:
173 branch(p);
174 break;
175 case STATE_OBJECT:
176 object(p);
177 break;
178 case STATE_INIT:
179 init(p);
180 break;
181 case STATE_ALIAS:
182 alias(p);
183 break;
184 case STATE_PRIVATE:
185 case STATE_NOBRANCH:
186 case STATE_UNDEFINED:
187 oddball(p, state);
188 break;
189 default:
190 fatal("unrecognized specification in: %s on line %ld",
191 spec_filename, line_num);
196 * Make sure the NULL returned from fgets() was the end of file not an
197 * error. If it is report it and quit otherwise close the file.
199 if(ferror(spec_stream))
200 system_fatal("read error on: %s", spec_filename);
201 fclose(spec_stream);
204 * Now check that everything was specified correctly in spec file.
206 if(target_name == (char *)0){
207 error("shared library target name not specified in: %s (use "
208 "#target <name>)", spec_filename);
209 spec_error++;
211 if(minor_version == 0){
212 error("shared library minor version not specified in: %s (use "
213 "#minor_version <decimal number>)", spec_filename);
214 spec_error++;
216 if(text_addr == BAD_ADDRESS){
217 error("shared library %s segment address not specified in: %s "
218 "(use #address %s <hex address>)", SEG_TEXT, spec_filename,
219 SEG_TEXT);
220 spec_error++;
222 if(data_addr == BAD_ADDRESS){
223 error("shared library %s segment address not specified in: %s "
224 "(use #address %s <hex address>)", SEG_DATA, spec_filename,
225 SEG_DATA);
226 spec_error++;
228 if(nbranch_list == 0){
229 error("no #branch table entries specified in: %s ", spec_filename);
230 spec_error++;
233 * Check the branch table for slots that weren't specified.
235 for(i = 0; i <= max_slotnum_seen; i++){
236 if(branch_list[i] == (struct branch *)0){
237 error("branch table entry %ld not specified in: %s ",
238 i, spec_filename);
239 spec_error++;
242 if(nobject_list == 0){
243 error("no #objects entries specified in: %s ", spec_filename);
244 spec_error++;
246 for(i = 0; i < OBJECT_HASH_SIZE; i++){
247 op = object_hash[i];
248 while(op != (struct object *)0){
249 if(op->init_only){
250 error("object: %s has #init specfication in: %s but not "
251 "listed in #objects specification section", op->name,
252 spec_filename);
253 spec_error++;
255 op = op->next;
258 free(object_hash);
260 for(i = 0; i < ODDBALL_HASH_SIZE; i++){
261 obp = oddball_hash[i];
262 while(obp != (struct oddball *)0){
263 hash_key = hash_string(obp->name) % BRANCH_HASH_SIZE;
264 bp = branch_hash[hash_key];
265 while(bp != (struct branch *)0){
266 if(strcmp(bp->name, obp->name) == 0){
267 if(obp->nobranch){
268 error("nobranch_text symbol: %s has a branch slot "
269 "(%ld) in: %s", bp->name, bp->max_slotnum,
270 spec_filename);
271 spec_error++;
273 else if(obp->private){
274 error("private_extern symbol: %s has a branch slot "
275 "(%ld) in: %s", bp->name, bp->max_slotnum,
276 spec_filename);
277 spec_error++;
279 else if(obp->undefined){
280 error("undefined symbol: %s has a branch slot "
281 "(%ld) in: %s", bp->name, bp->max_slotnum,
282 spec_filename);
283 spec_error++;
286 bp = bp->next;
288 obp = obp->next;
292 #ifdef SPEC_DEBUG
293 printf("Data structures built from the specification file: %s\n",
294 spec_filename);
295 printf("\ttarget_name = %s\n", target_name);
296 printf("\tminor_version = %d\n", minor_version);
297 printf("\ttext_addr = 0x%x\n", text_addr);
298 printf("\tdata_addr = 0x%x\n", data_addr);
299 for(i = 0; i < nobject_list; i++){
300 printf("\tobject_list[%d] = 0x%x { %s, %s, 0x%x, %d, 0x%x }\n", i,
301 object_list[i],
302 object_list[i]->name,
303 object_list[i]->base_name,
304 object_list[i]->inits,
305 object_list[i]->init_only,
306 object_list[i]->next);
307 ip = object_list[i]->inits;
308 while(ip){
309 printf("\t\tpinit = %s sinit = %s\n", ip->pinit, ip->sinit);
310 ip = ip->next;
313 for(i = 0; i < branch_list_size; i++){
314 if(branch_list[i] != (struct branch *)0)
315 printf("\tbranch_list[%d] = 0x%x { %s, %s, %d, 0x%x }\n", i,
316 branch_list[i],
317 branch_list[i]->name,
318 branch_list[i]->old_name,
319 branch_list[i]->max_slotnum,
320 branch_list[i]->next);
322 ap = aliases;
323 while(ap != (struct alias *)0){
324 printf("\talias list: %s %s\n", ap->alias_name, ap->real_name);
325 ap = ap->next;
327 for(i = 0; i < noddball_list; i++){
328 printf("\toddball_list[%d] = 0x%x { %s, private = %d nobranch = %d "
329 "undefined = %d }\n", i, oddball_list[i],
330 oddball_list[i]->name, oddball_list[i]->private,
331 oddball_list[i]->nobranch, oddball_list[i]->undefined);
333 #endif /* SPEC_DEBUG */
334 free(oddball_list);
337 * If there were any errors in the spec file exit (no files have been
338 * created so no cleanup is needed). Else return.
340 if(spec_error)
341 exit(1);
345 * Newstate returns the new state for the directive passed to it and sets up to
346 * handle it. The pointer, p, is assumed to point at a '#' and the name of a
347 * directive is to follow it.
349 static
350 long
351 newstate(
352 char *p,
353 long oldstate)
355 char *directive, *minor_version_string, *segment_name, *address_string, *q,
356 *object_name, *base_name, *file_name, *directory_name;
357 long hash_key;
358 unsigned long address;
359 enum libgcc libgcc_state;
361 /* step over the '#' */
362 p++;
363 /* if end of line just return */
364 if(*p == '\0')
365 return(oldstate);
366 /* skip any leading white space */
367 while(isspace(*p))
368 p++;
369 /* if end of line or comment return */
370 if(*p == '\0' || *p == '#')
371 return(oldstate);
372 /* now step over the directive */
373 directive = p;
374 p = next(p);
377 * Find out what directive this is and set up to operate in that state.
379 if(strcmp(directive, "branch") == 0){
381 * A #branch directive is simply a #branch on it's own line.
382 * This puts us into branch state where the following lines
383 * are entries in the branch table. See branch() for their
384 * format. When this is found the data structures to hold
385 * the branch table information is created.
387 if(*p != '\0')
388 fatal("junk after #branch directive in: %s on line %ld",
389 spec_filename, line_num);
390 if(branch_list != (struct branch **)0)
391 fatal("#branch directive appears more that once in: %s on "
392 "line %ld", spec_filename, line_num);
393 branch_list = allocate(BRANCH_LIST_SIZE *
394 sizeof(struct branch *));
395 bzero(branch_list, BRANCH_LIST_SIZE * sizeof(struct branch *));
396 branch_list_size = BRANCH_LIST_SIZE;
397 return(STATE_BRANCH);
399 } else if(strcmp(directive, "objects") == 0){
401 * A #objects directive is simply a #objects on it's own line.
402 * This puts us into object state where the following lines
403 * are the objects that are to make up the shared library.
404 * See object() for their format. When this is found the
405 * data structures to hold the object information is created.
406 * Since #init's reference objects and needs the object hash
407 * table it may have already been created by a previous #init.
409 if(*p != '\0')
410 fatal("junk after #objects directive in: %s on line %ld",
411 spec_filename, line_num);
412 if(object_list != (struct object **)0)
413 fatal("#objects directive appears more that once in: %s on "
414 "line %ld", spec_filename, line_num);
415 object_list = allocate(OBJECT_LIST_SIZE *
416 sizeof(struct object *));
417 object_list_size = OBJECT_LIST_SIZE;
418 nobject_list = 0;
419 if(object_hash == (struct object **)0){
420 object_hash = allocate(OBJECT_HASH_SIZE *
421 sizeof(struct object *));
422 bzero(object_hash,
423 OBJECT_HASH_SIZE * sizeof(struct object *));
425 return(STATE_OBJECT);
427 } else if(strcmp(directive, "filelist") == 0){
429 * A #filelist directive is an #filelist followed by a file name
430 * and an optional directory name.
432 if(oldstate != STATE_OBJECT)
433 fatal("#filelist directive in: %s on line %ld seen when a "
434 "#object directive is not in effect", spec_filename,
435 line_num);
436 if(*p == '\0')
437 fatal("no file name specified for #filelist directive in: "
438 "%s on line %ld", spec_filename, line_num);
439 file_name = p;
440 p = next(p);
441 libgcc_state = NOT_LIBGCC;
442 if(*p != '\0'){
443 directory_name = p;
444 p = next(p);
445 if(*p == 'n'){
446 if(strncmp(p, "new_libgcc", sizeof("new_libgcc")-1) != 0)
447 fatal("junk after #filelist directive in: %s on line "
448 "%ld", spec_filename, line_num);
449 p += sizeof("new_libgcc") - 1;
450 p = next(p);
451 libgcc_state = NEW_LIBGCC;
453 else if(*p == 'o'){
454 if(strncmp(p, "old_libgcc", sizeof("old_libgcc")-1) != 0)
455 fatal("junk after #filelist directive in: %s on line "
456 "%ld", spec_filename, line_num);
457 p += sizeof("old_libgcc") - 1;
458 p = next(p);
459 libgcc_state = OLD_LIBGCC;
461 if(*p != '\0')
462 fatal("junk after #filelist directive in: %s on line %ld",
463 spec_filename, line_num);
465 else{
466 directory_name = NULL;
468 filelist(file_name, directory_name, libgcc_state);
469 return(STATE_OBJECT);
471 } else if(strcmp(directive, "init") == 0){
473 * An #init directive is an #init followed by an object file name
474 * on the same line. This puts us into init state where the
475 * following lines are pairs of symbols for initialization.
476 * See init() for their format. When this is found the
477 * data structures to hold the init information is created.
478 * and a pointer to the object structure, init_object,
479 * is set to chain the following init pairs off of. If no
480 * object structure exist or the the object hash table
481 * doesn't exist it is created.
483 if(*p == '\0')
484 fatal("no object file name specified for #init directive in: "
485 "%s on line %ld", spec_filename, line_num);
486 object_name = p;
487 p = next(p);
488 if(*p != '\0')
489 fatal("junk after #init directive in: %s on line %ld",
490 spec_filename, line_num);
491 if(object_hash == (struct object **)0){
492 object_hash = allocate(OBJECT_HASH_SIZE *
493 sizeof(struct object *));
494 bzero(object_hash,
495 OBJECT_HASH_SIZE * sizeof(struct object *));
498 base_name = rindex(object_name, '/');
499 if(base_name == (char *)0)
500 base_name = object_name;
501 else
502 base_name++;
503 hash_key = hash_string(base_name) % OBJECT_HASH_SIZE;
504 init_object = object_hash[hash_key];
505 while(init_object != (struct object *)0){
506 if(strcmp(init_object->base_name, base_name) == 0){
507 if(strcmp(init_object->name, object_name) != 0){
508 fatal("object files: %s and %s in: %s must have unique "
509 "base file names (%s)", init_object->name,
510 object_name, spec_filename, base_name);
512 break;
514 init_object = init_object->next;
516 if(init_object == (struct object *)0){
517 init_object = allocate(sizeof(struct object));
518 init_object->name = savestr(object_name);
519 init_object->base_name = rindex(init_object->name, '/');
520 if(init_object->base_name == (char *)0)
521 init_object->base_name = init_object->name;
522 else
523 init_object->base_name++;
524 init_object->inits = (struct init *)0;
525 init_object->init_only = 1;
526 init_object->next = object_hash[hash_key];
527 object_hash[hash_key] = init_object;
529 return(STATE_INIT);
531 } else if(strcmp(directive, "target") == 0){
533 * A #target directive is an #target followed by a name on the
534 * same line. This is the target name the shared library is known
535 * as at runtime.
537 if(target_name != (char *)0)
538 fatal("#target directive appears more that once in: %s on "
539 "line %ld", spec_filename, line_num);
540 if(*p == '\0')
541 fatal("no file name specified for #target directive in: %s on "
542 "line %ld", spec_filename, line_num);
543 target_name = p;
544 p = next(p);
545 if(*p != '\0')
546 fatal("junk after #target directive in: %s on line %ld",
547 spec_filename, line_num);
548 p = rindex(target_name, '/');
549 if(p != (char *)0)
550 p++;
551 else
552 p = target_name;
553 while(*p != '\0'){
554 if(!isalnum(*p) && *p != '_' && *p != '.' && *p != '-')
555 fatal("base name of target: %s in: %s on line %ld must have"
556 " only alphanumeric, '_', '-', or '.' characters in "
557 "it", target_name, spec_filename, line_num);
558 p++;
560 target_name = savestr(target_name);
561 return(STATE_NONE);
563 } else if(strcmp(directive, "address") == 0){
565 * An #address directive is an #address followed by a segment name
566 * and a hexidecimal value all on the same line. The segment name
567 * currently can be either __TEXT or __DATA. The address values
568 * must be on page boundaries.
570 if(*p == '\0')
571 fatal("no segment name and address specified for #address "
572 "directive in: %s on line %ld", spec_filename, line_num);
573 segment_name = p;
574 p = next(p);
575 if(*p == '\0')
576 fatal("missing address for #address directive in: %s on line "
577 "%ld", spec_filename, line_num);
578 address_string = p;
579 p = next(p);
580 if(*p != '\0')
581 fatal("junk after #address directive in: %s on line %ld",
582 spec_filename, line_num);
583 address = strtoul(address_string, &q, 16);
584 if(*q != '\0')
585 fatal("bad #address value: %s in: %s on line %ld",
586 address_string, spec_filename, line_num);
587 if(address % getpagesize() != 0)
588 fatal("#address value: 0x%x in: %s on line %ld must be a "
589 "multiple of the system pagesize (0x%x)",
590 (unsigned int)address, spec_filename, line_num,
591 (unsigned int)getpagesize());
592 if(strcmp(segment_name, SEG_TEXT) == 0){
593 if(text_addr != BAD_ADDRESS && text_addr != address)
594 fatal("#address directive for: %s segment appears more "
595 "that once in: %s on line %ld", SEG_TEXT,
596 spec_filename, line_num);
597 text_addr = address;
598 } else if(strcmp(segment_name, SEG_DATA) == 0){
599 if(data_addr != BAD_ADDRESS && data_addr != address)
600 fatal("#address directive for: %s segment appears more "
601 "that once in: %s on line %ld", SEG_DATA,
602 spec_filename, line_num);
603 data_addr = address;
604 } else {
605 fatal("segment name: %s for #address directive in: %s on "
606 "line %ld must be either %s or %s", segment_name,
607 spec_filename, line_num, SEG_TEXT, SEG_DATA);
609 return(STATE_NONE);
611 } else if(strcmp(directive, "minor_version") == 0){
613 * A #minor_version directive is an #minor_version followed by a
614 * decimal number on the same line. The version number must be
615 * greater than zero.
617 if(minor_version != 0)
618 fatal("minor_version specified more than once (in the file: %s "
619 "on the line %ld and on the command line or previouly in "
620 "the specification file)", spec_filename, line_num);
621 if(*p == '\0')
622 fatal("missing value for #minor_version directive in: %s on "
623 "line %ld", spec_filename, line_num);
624 minor_version_string = p;
625 p = next(p);
626 if(*p != '\0')
627 fatal("junk after #minor_version directive in: %s on line %ld",
628 spec_filename, line_num);
629 minor_version = atol(minor_version_string);
630 if(minor_version <= 0)
631 fatal("#minor_version value: %ld in: %s on line %ld must be "
632 "greater than 0", minor_version, spec_filename, line_num);
633 return(STATE_NONE);
635 } else if(strcmp(directive, "alias") == 0){
637 * A #alias directive is simply a #alias on it's own line.
638 * This puts us into alias state where the following lines
639 * lines are pairs of symbols for aliasing. See alias() for
640 * their format.
642 if(*p != '\0')
643 fatal("junk after #alias directive in: %s on line %ld",
644 spec_filename, line_num);
645 if(oddball_list == (struct oddball **)0){
646 oddball_list = allocate(ODDBALL_LIST_SIZE *
647 sizeof(struct oddball *));
648 oddball_list_size = OBJECT_LIST_SIZE;
649 noddball_list = 0;
651 return(STATE_ALIAS);
653 } else if(strcmp(directive, "private_externs") == 0){
655 * A #private_externs directive is simply a #private_externs on
656 * it's own line. This puts us into private state where the
657 * following lines are the names of the private externs symbols
658 * that are not to appear in the host shared library.
659 * See oddball() for their format. When this is found the
660 * data structures to hold the oddball symbols are created.
662 if(*p != '\0')
663 fatal("junk after #private_externs directive in: %s on line "
664 "%ld", spec_filename, line_num);
665 if(oddball_list == (struct oddball **)0){
666 oddball_list = allocate(ODDBALL_LIST_SIZE *
667 sizeof(struct oddball *));
668 oddball_list_size = OBJECT_LIST_SIZE;
669 noddball_list = 0;
671 return(STATE_PRIVATE);
673 } else if(strcmp(directive, "nobranch_text") == 0){
675 * A #nobranch_text directive is simply a #nobranch_text on it's
676 * own line. This puts us into nobranch state where the following
677 * lines are the names of the extern text symbols that will not
678 * have branch table entries (for now const data is in this class).
679 * See oddball() for their format. When this is found the
680 * data structures to hold the oddball symbols are created.
682 if(*p != '\0')
683 fatal("junk after #nobranch_text directive in: %s on line "
684 "%ld", spec_filename, line_num);
685 if(oddball_list == (struct oddball **)0){
686 oddball_list = allocate(ODDBALL_LIST_SIZE *
687 sizeof(struct oddball *));
688 oddball_list_size = OBJECT_LIST_SIZE;
689 noddball_list = 0;
691 return(STATE_NOBRANCH);
692 } else if(strcmp(directive, "undefined") == 0){
694 * A #undefined directive is simply a #undefined on it's
695 * own line. This puts us into undefined state where the following
696 * lines are the names of the extern text symbols that will be
697 * undefined. See oddball() for their format. When this is found
698 * the data structures to hold the oddball symbols are created.
700 if(*p != '\0')
701 fatal("junk after #undefined directive in: %s on line "
702 "%ld", spec_filename, line_num);
703 if(oddball_list == (struct oddball **)0){
704 oddball_list = allocate(ODDBALL_LIST_SIZE *
705 sizeof(struct oddball *));
706 oddball_list_size = OBJECT_LIST_SIZE;
707 noddball_list = 0;
709 return(STATE_UNDEFINED);
712 fatal("unknown directive: #%s in: %s on line: %ld", directive,
713 spec_filename, line_num);
714 return(STATE_NONE);
718 * branch is called after a #branch directive has been seen and we are in branch
719 * state. The name of a symbol for the branch table and it possition as a
720 * decimal number (or range of possitions) separated by white space appears on
721 * its own line. For each of them a branch structure is created and added
722 * to the branch_list in each possition it appears. Also it is entered in the
723 * branch hash table.
725 static
726 void
727 branch(
728 char *p)
730 char *branch_name, *old_name, *q;
731 long min_slotnum, max_slotnum, hash_key, i;
732 struct branch *bp;
734 old_name = NULL;
736 /* if end of line just return */
737 if(*p == '\0')
738 return;
739 /* skip any leading white space */
740 while(isspace(*p))
741 p++;
742 /* if end of line or comment return */
743 if(*p == '\0' || *p == '#')
744 return;
745 /* now step over the branch symbol name */
746 branch_name = p;
747 p = next(p);
748 if(*p == '\0')
749 fatal("missing branch table possition number in: %s on line %ld",
750 spec_filename, line_num);
751 min_slotnum = strtol(p, &q, 10);
752 if(q == p)
753 fatal("bad branch table possition number in: %s on line %ld",
754 spec_filename, line_num);
755 if(min_slotnum < 0)
756 fatal("branch table possition number in: %s on line %ld must be "
757 "greater than zero", spec_filename, line_num);
758 p = q;
759 while(isspace(*p))
760 p++;
761 if(*p != '\0' && *p != '#' && *p != '-' && *p != 'o')
762 fatal("bad branch table specification in: %s on line %ld",
763 spec_filename, line_num);
764 if(*p == '-'){
765 p++; /* skip the '-' */
766 while(isspace(*p))
767 p++;
768 if(*p == '\0')
769 fatal("missing upper branch table possition range in: %s on "
770 "line %ld", spec_filename, line_num);
771 max_slotnum = strtol(p, &q, 10);
772 if(q == p)
773 fatal("bad upper branch table possition range in: %s on line "
774 "%ld", spec_filename, line_num);
775 if(max_slotnum < min_slotnum)
776 fatal("bad upper branch table possition range (%ld) in: %s on "
777 "line %ld must be greater than lower (%ld)", max_slotnum,
778 spec_filename, line_num, min_slotnum);
779 while(isspace(*q))
780 q++;
781 if(*q != '\0' && *q != '#')
782 fatal("junk after #branch specification in: %s on line %ld",
783 spec_filename, line_num);
785 else if(*p == 'o'){
786 if(strncmp(p, "old_name", sizeof("old_name")-1) != 0)
787 fatal("junk after #branch specification in: %s on line %ld",
788 spec_filename, line_num);
789 p += sizeof("old_name") - 1;
790 while(isspace(*p))
791 p++;
792 if(*p == '\0' || *p == '#')
793 fatal("missing symbol name after \"old_name\" for #branch "
794 "specification in: %s on line %ld", spec_filename,
795 line_num);
796 /* now step over the old symbol name */
797 old_name = p;
798 p = next(p);
799 if(*p != '\0' && *p != '#')
800 fatal("junk after #branch specification in: %s on line %ld",
801 spec_filename, line_num);
802 max_slotnum = min_slotnum;
804 else{
805 max_slotnum = min_slotnum;
808 * put this branch name in the hash table if not in there already.
810 hash_key = hash_string(branch_name) % BRANCH_HASH_SIZE;
811 bp = branch_hash[hash_key];
812 while(bp != (struct branch *)0){
813 if(strcmp(bp->name, branch_name) == 0){
814 /* adjust the slot used for the value of this symbol */
815 if(bp->max_slotnum < max_slotnum)
816 bp->max_slotnum = max_slotnum;
817 break;
819 bp = bp->next;
821 if(bp == (struct branch *)0){
822 bp = allocate(sizeof(struct branch));
823 bp->name = savestr(branch_name);
824 if(old_name != NULL)
825 bp->old_name = savestr(old_name);
826 if(strcmp(bp->name, EMPTY_SLOT_NAME) == 0)
827 bp->empty_slot = 1;
828 else
829 bp->empty_slot = 0;
830 bp->max_slotnum = max_slotnum;
831 bp->next = branch_hash[hash_key];
832 branch_hash[hash_key] = bp;
835 * put this branch spec in the branch list in all of it's slots.
837 if(max_slotnum >= branch_list_size){
838 branch_list = reallocate(branch_list, max_slotnum * 2 *
839 sizeof(struct branch *));
840 bzero(branch_list + branch_list_size,
841 branch_list_size * sizeof(struct branch *));
842 branch_list_size = max_slotnum * 2;
844 for(i = min_slotnum; i <= max_slotnum; i++){
845 if(branch_list[i] != (struct branch *)0 &&
846 branch_list[i] != bp){
847 error("#branch position %ld multiply specified in: %s on line "
848 "%ld", i, spec_filename, line_num);
849 spec_error++;
851 else{
852 if(branch_list[i] != bp)
853 nbranch_list++;
854 branch_list[i] = bp;
857 if(max_slotnum > max_slotnum_seen)
858 max_slotnum_seen = max_slotnum;
862 * object is called after a #objects directive has been seen and we are in
863 * object state. The names of object files then appear separated by white
864 * space.
866 static
867 void
868 object(
869 char *p)
871 char *object_name;
873 /* if end of line just return */
874 if(*p == '\0')
875 return;
876 /* skip any leading white space */
877 while(isspace(*p))
878 p++;
879 /* if end of line or comment return */
880 if(*p == '\0' || *p == '#')
881 return;
882 /* now step over the object name */
883 object_name = p;
884 p = next(p);
885 while(*object_name != '\0'){
886 p = new_object(object_name, FALSE, NOT_LIBGCC);
887 /* now step over the object name and see if there is another */
888 object_name = p;
889 p = next(p);
893 static
894 void
895 filelist(
896 char *file_name,
897 char *directory_name,
898 enum libgcc libgcc_state)
900 FILE *filelist_stream;
901 long n;
902 char line[BUFSIZ], *p, *object_name;
904 if(directory_name != NULL){
905 if(directory_name[strlen(directory_name) - 1] != '/')
906 directory_name = makestr(directory_name, "/", NULL);
908 /* open the filelist file to read it */
909 if((filelist_stream = fopen(file_name, "r")) == NULL)
910 system_fatal("can't open: %s from #filelist directive in: %s on "
911 "line %ld", file_name, spec_filename, line_num);
913 n = 0;
914 while(fgets(line, BUFSIZ, filelist_stream) != NULL){
915 n++;
916 if(strlen(line) == BUFSIZ - 1 && line[BUFSIZ - 1] != '\n')
917 fatal("line %ld in: %s too long (maximum %d)", n, file_name,
918 BUFSIZ);
919 p = strchr(line, '\n');
920 *p = '\0';
921 if(directory_name != NULL)
922 object_name = makestr(directory_name, line, NULL);
923 else
924 object_name = line;
925 new_object(object_name, TRUE, libgcc_state);
927 fclose(filelist_stream);
931 * new_object() is passed an object_name and an object structure is found
932 * (as previouly entered in the hash table) or created and added to the
933 * object_list. Also it is entered in hash table if it was not found there.
934 * If this is a duplicate name and filelist is TRUE it is ignored.
936 static
937 char *
938 new_object(
939 char *object_name,
940 enum bool filelist,
941 enum libgcc libgcc_state)
943 char *p, *base_name;
944 long hash_key;
945 struct object *op;
947 if(nobject_list + 1 > object_list_size){
948 object_list = reallocate(object_list, object_list_size * 2 *
949 sizeof(struct object *));
950 object_list_size *= 2;
952 base_name = rindex(object_name, '/');
953 if(base_name == (char *)0)
954 base_name = object_name;
955 else
956 base_name++;
957 hash_key = hash_string(base_name) % OBJECT_HASH_SIZE;
958 op = object_hash[hash_key];
959 while(op != (struct object *)0){
960 if(strcmp(op->base_name, base_name) == 0){
961 if(strcmp(op->name, object_name) != 0){
962 fatal("object files: %s and %s must have unique base "
963 "file names (%s)", op->name, object_name, base_name);
966 * If this duplicate object name comes from a filelist then
967 * ignore it and use the previous one.
969 if(filelist == TRUE)
970 return(NULL);
971 if(op->init_only)
972 break;
973 fatal("object file name: %s appears more than once in: %s "
974 "on line %ld", object_name, spec_filename, line_num);
976 op = op->next;
978 p = base_name;
979 while(*p != '\0'){
980 if(!isalnum(*p) && *p != '_' && *p != '.' && *p != '-')
981 fatal("base name of object: %s in: %s on line %ld must have"
982 " only alphanumeric, '_', '-', or '.' characters in "
983 "it", object_name, spec_filename, line_num);
984 p++;
986 if(op == (struct object *)0){
987 op = allocate(sizeof(struct object));
988 bzero(op, sizeof(struct object));
989 op->name = savestr(object_name);
990 op->base_name = rindex(op->name, '/');
991 if(op->base_name == (char *)0)
992 op->base_name = op->name;
993 else
994 op->base_name++;
995 op->libgcc_state = libgcc_state;
996 op->next = object_hash[hash_key];
997 object_hash[hash_key] = op;
999 else{
1000 op->init_only = 0;
1003 object_list[nobject_list++] = op;
1004 return(p);
1008 * init is called after a #init directive has been seen and we are in init
1009 * state. The pairs of symbol names then appear separated by white space each
1010 * on their own line. A init structure is created for it and then it is
1011 * put on the chain of such structures in the object pointed to by
1012 * init_object.
1014 static
1015 void
1016 init(
1017 char *p)
1019 char *pinit, *sinit;
1020 struct init *ip;
1022 /* if end of line just return */
1023 if(*p == '\0')
1024 return;
1025 /* skip any leading white space */
1026 while(isspace(*p))
1027 p++;
1028 /* if end of line or comment return */
1029 if(*p == '\0' || *p == '#')
1030 return;
1031 /* now step over the pointer symbol name */
1032 pinit = p;
1033 p = next(p);
1034 if(*p == '\0')
1035 fatal("missing symbol name for #init specification in: %s on line "
1036 "%ld", spec_filename, line_num);
1037 sinit = p;
1038 p = next(p);
1039 if(*p != '\0')
1040 fatal("junk after #init specification in: %s on line %ld",
1041 spec_filename, line_num);
1042 ip = allocate(sizeof(struct init));
1043 ip->pinit = savestr(pinit);
1044 ip->sinit = savestr(sinit);
1045 ip->next = init_object->inits;
1046 init_object->inits = ip;
1050 * alias is called after a #alias directive has been seen and we are in alias
1051 * state. The pairs of symbol names then appear separated by white space each
1052 * on their own line. An alias structure is created for it and then it is
1053 * put on the chain of such structures.
1055 static
1056 void
1057 alias(
1058 char *p)
1060 char *alias_name, *real_name;
1061 struct alias *ap;
1063 /* if end of line just return */
1064 if(*p == '\0')
1065 return;
1066 /* skip any leading white space */
1067 while(isspace(*p))
1068 p++;
1069 /* if end of line or comment return */
1070 if(*p == '\0' || *p == '#')
1071 return;
1072 /* now step over the pointer symbol name */
1073 alias_name = p;
1074 p = next(p);
1075 if(*p == '\0')
1076 fatal("missing symbol name for #alias specification in: %s on line "
1077 "%ld", spec_filename, line_num);
1078 real_name = p;
1079 p = next(p);
1080 if(*p != '\0')
1081 fatal("junk after #alias specification in: %s on line %ld",
1082 spec_filename, line_num);
1083 ap = allocate(sizeof(struct alias));
1084 ap->alias_name = savestr(alias_name);
1085 ap->real_name = savestr(real_name);
1086 ap->next = aliases;
1087 aliases = ap;
1090 * The old alias feature of the link editor has been replace with the
1091 * indirect feature. So to get the same behavior of having the alias
1092 * symbol not appear in the output file the alias name is made a private
1093 * extern. Note this does not change the state we are in.
1095 oddball(alias_name, STATE_PRIVATE);
1099 * oddball is called after a #private_externs directive has been seen and we
1100 * are in private state, after a #nobranch_text directive has been seen and we
1101 * are in nobranch state, or after a #undefined directive has been seen and we
1102 * are in undefined state. The names of external symbols then appear separated
1103 * by white space. For each of them an oddball structure is found (as previouly
1104 * entered in the hash table) or created and added to the oddball_list. Also
1105 * it is entered in hash table if it was not found there. Then the oddball
1106 * structure is marked with the state we are in.
1108 static
1109 void
1110 oddball(
1111 char *p,
1112 long state)
1114 char *name;
1115 long hash_key;
1116 struct oddball *obp;
1118 /* if end of line just return */
1119 if(*p == '\0')
1120 return;
1121 /* skip any leading white space */
1122 while(isspace(*p))
1123 p++;
1124 /* if end of line or comment return */
1125 if(*p == '\0' || *p == '#')
1126 return;
1127 /* now step over the symbol name */
1128 name = p;
1129 p = next(p);
1130 while(*name != '\0'){
1131 if(noddball_list + 1 > oddball_list_size){
1132 oddball_list = reallocate(oddball_list, oddball_list_size * 2 *
1133 sizeof(struct oddball *));
1134 oddball_list_size *= 2;
1136 hash_key = hash_string(name) % ODDBALL_HASH_SIZE;
1137 obp = oddball_hash[hash_key];
1138 while(obp != (struct oddball *)0){
1139 if(strcmp(obp->name, name) == 0)
1140 break;
1141 obp = obp->next;
1143 if(obp == (struct oddball *)0){
1144 obp = allocate(sizeof(struct oddball));
1145 bzero(obp, sizeof(struct oddball));
1146 obp->name = savestr(name);
1147 obp->next = oddball_hash[hash_key];
1148 oddball_hash[hash_key] = obp;
1149 oddball_list[noddball_list++] = obp;
1151 switch(state){
1152 case STATE_PRIVATE:
1153 obp->private = 1;
1154 break;
1155 case STATE_NOBRANCH:
1156 obp->nobranch = 1;
1157 break;
1158 case STATE_UNDEFINED:
1159 obp->undefined = 1;
1160 break;
1163 /* now step over the symbol name and see if there is another */
1164 name = p;
1165 p = next(p);
1170 * next() is passed a pointer to string. It is assumed to point to a word
1171 * (a non isspace character). It advances over the word and places a null
1172 * after it. Then it advances to the next word and returns a pointer to
1173 * it. If there are no more words or the rest of the line is a comment
1174 * (starts with a #) then the returned pointer points at '\0'. This routine
1175 * assumes the line ends with a '\0' like fgets() reads.
1177 static
1178 char *
1179 next(
1180 char *p)
1182 /* advance past the current word */
1183 while(!isspace(*p) && *p != '\0')
1184 p++;
1186 * put a null at the end of the current word and advance p if not at end
1187 * of line so to point to the next thing.
1189 if(*p != '\0'){
1190 *p = '\0';
1191 p++;
1192 while(isspace(*p))
1193 p++;
1195 * If the next thing is a # then treat the rest of the line as a
1196 * comment and nothing else is left on the line.
1198 if(*p == '#')
1199 *p = '\0';
1201 return(p);