2 * Copyright (c) 1999 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
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
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@
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
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"
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 */
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(
115 char *directory_name
,
116 enum libgcc libgcc_state
);
117 static char *new_object(
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() */
128 #define STATE_BRANCH 1
129 #define STATE_OBJECT 2
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
145 long state
, i
, hash_key
;
146 char line
[BUFSIZ
], *p
;
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
);
157 while(fgets(line
, BUFSIZ
, spec_stream
) != NULL
){
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
);
168 state
= newstate(p
, state
);
186 case STATE_UNDEFINED
:
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
);
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
);
211 if(minor_version
== 0){
212 error("shared library minor version not specified in: %s (use "
213 "#minor_version <decimal number>)", spec_filename
);
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
,
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
,
228 if(nbranch_list
== 0){
229 error("no #branch table entries specified in: %s ", spec_filename
);
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 ",
242 if(nobject_list
== 0){
243 error("no #objects entries specified in: %s ", spec_filename
);
246 for(i
= 0; i
< OBJECT_HASH_SIZE
; i
++){
248 while(op
!= (struct object
*)0){
250 error("object: %s has #init specfication in: %s but not "
251 "listed in #objects specification section", op
->name
,
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){
268 error("nobranch_text symbol: %s has a branch slot "
269 "(%ld) in: %s", bp
->name
, bp
->max_slotnum
,
273 else if(obp
->private){
274 error("private_extern symbol: %s has a branch slot "
275 "(%ld) in: %s", bp
->name
, bp
->max_slotnum
,
279 else if(obp
->undefined
){
280 error("undefined symbol: %s has a branch slot "
281 "(%ld) in: %s", bp
->name
, bp
->max_slotnum
,
293 printf("Data structures built from the specification file: %s\n",
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
,
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
;
309 printf("\t\tpinit = %s sinit = %s\n", ip
->pinit
, ip
->sinit
);
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
,
317 branch_list
[i
]->name
,
318 branch_list
[i
]->old_name
,
319 branch_list
[i
]->max_slotnum
,
320 branch_list
[i
]->next
);
323 while(ap
!= (struct alias
*)0){
324 printf("\talias list: %s %s\n", ap
->alias_name
, ap
->real_name
);
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 */
337 * If there were any errors in the spec file exit (no files have been
338 * created so no cleanup is needed). Else return.
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.
355 char *directive
, *minor_version_string
, *segment_name
, *address_string
, *q
,
356 *object_name
, *base_name
, *file_name
, *directory_name
;
358 unsigned long address
;
359 enum libgcc libgcc_state
;
361 /* step over the '#' */
363 /* if end of line just return */
366 /* skip any leading white space */
369 /* if end of line or comment return */
370 if(*p
== '\0' || *p
== '#')
372 /* now step over the directive */
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.
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.
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
;
419 if(object_hash
== (struct object
**)0){
420 object_hash
= allocate(OBJECT_HASH_SIZE
*
421 sizeof(struct object
*));
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
,
437 fatal("no file name specified for #filelist directive in: "
438 "%s on line %ld", spec_filename
, line_num
);
441 libgcc_state
= NOT_LIBGCC
;
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;
451 libgcc_state
= NEW_LIBGCC
;
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;
459 libgcc_state
= OLD_LIBGCC
;
462 fatal("junk after #filelist directive in: %s on line %ld",
463 spec_filename
, line_num
);
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.
484 fatal("no object file name specified for #init directive in: "
485 "%s on line %ld", spec_filename
, line_num
);
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
*));
495 OBJECT_HASH_SIZE
* sizeof(struct object
*));
498 base_name
= rindex(object_name
, '/');
499 if(base_name
== (char *)0)
500 base_name
= object_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
);
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
;
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
;
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
537 if(target_name
!= (char *)0)
538 fatal("#target directive appears more that once in: %s on "
539 "line %ld", spec_filename
, line_num
);
541 fatal("no file name specified for #target directive in: %s on "
542 "line %ld", spec_filename
, line_num
);
546 fatal("junk after #target directive in: %s on line %ld",
547 spec_filename
, line_num
);
548 p
= rindex(target_name
, '/');
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
);
560 target_name
= savestr(target_name
);
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.
571 fatal("no segment name and address specified for #address "
572 "directive in: %s on line %ld", spec_filename
, line_num
);
576 fatal("missing address for #address directive in: %s on line "
577 "%ld", spec_filename
, line_num
);
581 fatal("junk after #address directive in: %s on line %ld",
582 spec_filename
, line_num
);
583 address
= strtoul(address_string
, &q
, 16);
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
);
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
);
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
);
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
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
);
622 fatal("missing value for #minor_version directive in: %s on "
623 "line %ld", spec_filename
, line_num
);
624 minor_version_string
= p
;
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
);
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
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
;
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.
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
;
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.
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
;
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.
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
;
709 return(STATE_UNDEFINED
);
712 fatal("unknown directive: #%s in: %s on line: %ld", directive
,
713 spec_filename
, line_num
);
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
730 char *branch_name
, *old_name
, *q
;
731 long min_slotnum
, max_slotnum
, hash_key
, i
;
736 /* if end of line just return */
739 /* skip any leading white space */
742 /* if end of line or comment return */
743 if(*p
== '\0' || *p
== '#')
745 /* now step over the branch symbol name */
749 fatal("missing branch table possition number in: %s on line %ld",
750 spec_filename
, line_num
);
751 min_slotnum
= strtol(p
, &q
, 10);
753 fatal("bad branch table possition number in: %s on line %ld",
754 spec_filename
, line_num
);
756 fatal("branch table possition number in: %s on line %ld must be "
757 "greater than zero", spec_filename
, line_num
);
761 if(*p
!= '\0' && *p
!= '#' && *p
!= '-' && *p
!= 'o')
762 fatal("bad branch table specification in: %s on line %ld",
763 spec_filename
, line_num
);
765 p
++; /* skip the '-' */
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);
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
);
781 if(*q
!= '\0' && *q
!= '#')
782 fatal("junk after #branch specification in: %s on line %ld",
783 spec_filename
, line_num
);
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;
792 if(*p
== '\0' || *p
== '#')
793 fatal("missing symbol name after \"old_name\" for #branch "
794 "specification in: %s on line %ld", spec_filename
,
796 /* now step over the old symbol name */
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
;
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
;
821 if(bp
== (struct branch
*)0){
822 bp
= allocate(sizeof(struct branch
));
823 bp
->name
= savestr(branch_name
);
825 bp
->old_name
= savestr(old_name
);
826 if(strcmp(bp
->name
, EMPTY_SLOT_NAME
) == 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
);
852 if(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
873 /* if end of line just return */
876 /* skip any leading white space */
879 /* if end of line or comment return */
880 if(*p
== '\0' || *p
== '#')
882 /* now step over the object name */
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 */
897 char *directory_name
,
898 enum libgcc libgcc_state
)
900 FILE *filelist_stream
;
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
);
914 while(fgets(line
, BUFSIZ
, filelist_stream
) != NULL
){
916 if(strlen(line
) == BUFSIZ
- 1 && line
[BUFSIZ
- 1] != '\n')
917 fatal("line %ld in: %s too long (maximum %d)", n
, file_name
,
919 p
= strchr(line
, '\n');
921 if(directory_name
!= NULL
)
922 object_name
= makestr(directory_name
, line
, NULL
);
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.
941 enum libgcc libgcc_state
)
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
;
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.
973 fatal("object file name: %s appears more than once in: %s "
974 "on line %ld", object_name
, spec_filename
, line_num
);
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
);
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
;
995 op
->libgcc_state
= libgcc_state
;
996 op
->next
= object_hash
[hash_key
];
997 object_hash
[hash_key
] = op
;
1003 object_list
[nobject_list
++] = op
;
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
1019 char *pinit
, *sinit
;
1022 /* if end of line just return */
1025 /* skip any leading white space */
1028 /* if end of line or comment return */
1029 if(*p
== '\0' || *p
== '#')
1031 /* now step over the pointer symbol name */
1035 fatal("missing symbol name for #init specification in: %s on line "
1036 "%ld", spec_filename
, line_num
);
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.
1060 char *alias_name
, *real_name
;
1063 /* if end of line just return */
1066 /* skip any leading white space */
1069 /* if end of line or comment return */
1070 if(*p
== '\0' || *p
== '#')
1072 /* now step over the pointer symbol name */
1076 fatal("missing symbol name for #alias specification in: %s on line "
1077 "%ld", spec_filename
, line_num
);
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
);
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.
1116 struct oddball
*obp
;
1118 /* if end of line just return */
1121 /* skip any leading white space */
1124 /* if end of line or comment return */
1125 if(*p
== '\0' || *p
== '#')
1127 /* now step over the symbol name */
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)
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
;
1155 case STATE_NOBRANCH
:
1158 case STATE_UNDEFINED
:
1163 /* now step over the symbol name and see if there is another */
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.
1182 /* advance past the current word */
1183 while(!isspace(*p
) && *p
!= '\0')
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.
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.