ranlib: fix it
[odcctools-svp.git] / mkshlib / cmpshlib.c
blob1be485992f21a01d824c91eee946dda5988d00f2
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 DEBUG
25 #include <stdio.h>
26 #include <stdlib.h>
27 #include <string.h>
28 #include <libc.h>
29 #include <sys/file.h>
30 #include <sys/types.h>
31 #include <sys/stat.h>
32 #include <mach/mach.h>
33 #include <mach-o/loader.h>
34 #include <mach-o/nlist.h>
35 #include <mach-o/reloc.h>
36 #include "stuff/ofile.h"
37 #include "stuff/errors.h"
38 #include "stuff/allocate.h"
39 #include "stuff/hash_string.h"
40 #include "stuff/hppa.h"
42 #include "branch.h"
43 #include "libgcc.h"
44 #include "mkshlib.h"
46 static void usage(
47 void);
49 static void make_oldtarget_hashtable(
50 char *old_target);
52 static void check_newtarget(
53 char *new_target);
55 static void open_target(
56 char *target,
57 struct ofile *ofile,
58 struct nlist **symbols,
59 unsigned long *nsyms,
60 char **strings,
61 unsigned long *strsize,
62 char **text,
63 unsigned long *textaddr,
64 unsigned long *textsize,
65 unsigned long *text_nsect,
66 unsigned long *data_nsect);
68 static void make_sorted_text_symbols(
69 struct nlist *symbols,
70 long nsyms,
71 struct nlist **text_symbols,
72 long *ntext_symbols);
74 static void make_global_symbols(
75 struct nlist *symbols,
76 long nsyms,
77 struct nlist
78 **global_symbols,
79 long *nglobal_symbols);
81 static long get_target_addr(
82 unsigned long value,
83 char *name,
84 char *text,
85 unsigned long addr,
86 unsigned long size,
87 char *target);
89 static int cmp_qsort(
90 struct nlist *sym1,
91 struct nlist *sym2);
93 static int cmp_bsearch(
94 long *value,
95 struct nlist *sym);
97 static struct ext *lookup(
98 char *name);
100 /* Structure of the members of the hash table for the old target */
101 struct ext {
102 char *name; /* symbol name */
103 long type; /* symbol type (n_type & N_TYPE) */
104 long sect; /* symbol section (n_sect) */
105 unsigned long value; /* symbol value */
106 char *branch_target; /* if non-zero the branch target symbol name */
107 struct ext *next; /* next ext on the hash chain */
109 #define EXT_HASH_SIZE 251
110 struct ext *ext_hash[EXT_HASH_SIZE];
112 __private_extern__
113 char *progname = NULL; /* name of the program for error messages (argv[0]) */
115 /* file name of the specification input file */
116 char *spec_filename = NULL;
118 char *old_target = NULL;
119 char *new_target = NULL;
122 * The architecture as specified by -arch and the cputype and cpusubtype of the
123 * shared libraries to be checked.
125 struct arch_flag arch_flag = { 0 };
128 * The ofile structures for the old an new target shared libraries to check.
130 static struct ofile old_target_ofile = { 0 };
131 static struct ofile new_target_ofile = { 0 };
133 /* the byte sex of the machine this program is running on */
134 enum byte_sex host_byte_sex = UNKNOWN_BYTE_SEX;
137 main(
138 int argc,
139 char *argv[],
140 char *envp[])
142 long i;
144 progname = argv[0];
145 host_byte_sex = get_host_byte_sex();
147 for(i = 1; i < argc; i++){
148 if(argv[i][0] == '-'){
149 if(strcmp("-s", argv[i]) == 0){
150 if(i + 1 > argc)
151 usage();
152 spec_filename = argv[++i];
154 else if(strcmp(argv[i], "-arch") == 0){
155 if(++i >= argc)
156 fatal("-arch: argument missing");
157 if(arch_flag.name != NULL)
158 fatal("-arch: multiply specified");
159 if(get_arch_from_flag(argv[i], &arch_flag) == 0){
160 error("unknown architecture specification flag: "
161 "-arch %s", argv[i]);
162 arch_usage();
163 usage();
166 else
167 usage();
169 else{
170 if(old_target == NULL)
171 old_target = argv[i];
172 else if(new_target == NULL)
173 new_target = argv[i];
174 else
175 usage();
179 if(old_target == NULL || new_target == NULL)
180 usage();
182 if(spec_filename != NULL){
183 minor_version = 1;
184 parse_spec();
186 else
187 fprintf(stderr, "%s: no -s spec_file specified (nobranch_text "
188 "symbols not checked)\n", progname);
190 make_oldtarget_hashtable(old_target);
191 check_newtarget(new_target);
192 if(errors){
193 return(EXIT_FAILURE);
195 else{
196 return(EXIT_SUCCESS);
201 * Print the usage line and exit indicating failure.
203 static
204 void
205 usage(void)
207 fprintf(stderr, "Usage: %s [-s spec_file] [-arch arch_type] "
208 "<old target> <new target>\n", progname);
209 exit(EXIT_FAILURE);
213 * Build the hash table of the external symbols of old target shared library.
215 static
216 void
217 make_oldtarget_hashtable(
218 char *old_target)
220 struct nlist *symbols, *text_symbols, *np;
221 unsigned long nsyms, strsize, textaddr, textsize, i,
222 target_addr, hash_key, text_nsect, data_nsect;
223 long ntext_symbols;
224 char *text, *strings;
225 struct ext *extp;
227 fprintf(stderr, "%s: building hash table of external symbols for old "
228 "target: %s\n", progname, old_target);
230 open_target(old_target, &old_target_ofile, &symbols, &nsyms, &strings,
231 &strsize, &text, &textaddr, &textsize, &text_nsect,
232 &data_nsect);
234 if(old_target_ofile.mh->cputype != CPU_TYPE_MC680x0 &&
235 old_target_ofile.mh->cputype != CPU_TYPE_MC88000 &&
236 old_target_ofile.mh->cputype != CPU_TYPE_POWERPC &&
237 old_target_ofile.mh->cputype != CPU_TYPE_HPPA &&
238 old_target_ofile.mh->cputype != CPU_TYPE_SPARC &&
239 old_target_ofile.mh->cputype != CPU_TYPE_I386){
240 if(arch_flag.name == NULL)
241 fatal("unknown or unsupported cputype (%d) in shared library: "
242 "%s", old_target_ofile.mh->cputype, old_target);
243 else
244 fatal("unsupported architecture for -arch %s", arch_flag.name);
246 if(arch_flag.cputype == 0){
247 arch_flag.cputype = old_target_ofile.mh->cputype;
248 arch_flag.cpusubtype = old_target_ofile.mh->cpusubtype;
250 if(arch_flag.name == NULL)
251 set_arch_flag_name(&arch_flag);
253 fprintf(stderr, "%s: checking architecture %s\n", progname,
254 arch_flag.name);
256 make_sorted_text_symbols(symbols, nsyms, &text_symbols, &ntext_symbols);
259 * Build the hash table of external symbols.
261 for(i = 0; i < nsyms; i++){
262 if((symbols[i].n_type & N_EXT) != N_EXT)
263 continue;
264 hash_key = hash_string(symbols[i].n_un.n_name) % EXT_HASH_SIZE;
265 extp = ext_hash[hash_key];
266 while(extp != (struct ext *)0){
267 if(strcmp(symbols[i].n_un.n_name, extp->name) == 0)
268 fatal("Symbol %s appears more than once in target shared "
269 "library: %s", extp->name, old_target);
270 extp = extp->next;
272 extp = allocate(sizeof(struct ext));
273 extp->name = symbols[i].n_un.n_name;
274 extp->type = symbols[i].n_type & N_TYPE;
275 extp->sect = symbols[i].n_sect;
276 extp->value = symbols[i].n_value;
277 extp->branch_target = (char *)0;
278 extp->next = ext_hash[hash_key];
279 ext_hash[hash_key] = extp;
280 if(extp->type == N_SECT && extp->sect == text_nsect)
281 ntext_symbols++;
285 * For each branch table slot find the name of the symbol in that slot.
287 for(i = 0; i < EXT_HASH_SIZE; i++){
288 extp = ext_hash[i];
289 while(extp != (struct ext *)0){
290 if((extp->type == N_SECT && extp->sect == text_nsect) &&
291 strncmp(extp->name, BRANCH_SLOT_NAME,
292 sizeof(BRANCH_SLOT_NAME) - 1) == 0){
293 target_addr = get_target_addr(extp->value, extp->name,
294 text, textaddr, textsize, old_target);
295 np = bsearch(&target_addr, text_symbols, ntext_symbols,
296 sizeof(struct nlist),
297 (int (*)(const void *, const void *)) cmp_bsearch);
298 if(np == (struct nlist *)0)
299 fatal("Can't find a text symbol for the target (0x%x) "
300 "of branch table symbol: %s in: %s",
301 (unsigned int)target_addr,extp->name, old_target);
302 extp->branch_target = np->n_un.n_name;
304 extp = extp->next;
308 #ifdef DEBUG
309 for(i = 0; i < EXT_HASH_SIZE; i++){
310 extp = ext_hash[i];
311 while(extp != (struct ext *)0){
312 printf("name = %s value = 0x%x type = 0x%x sect = %d ",
313 extp->name, extp->value, extp->type, extp->sect);
314 if(extp->branch_target != (char *)0)
315 printf("branch_target = %s\n", extp->branch_target);
316 else
317 printf("\n");
318 extp = extp->next;
321 #endif /* DEBUG */
325 * Check the new target shared library against the old target shared library
326 * hash table of symbols.
328 static
329 void
330 check_newtarget(
331 char *new_target)
333 struct nlist *symbols, *text_symbols, *global_symbols, *np;
334 unsigned long nsyms, strsize, textaddr, textsize, i, j, target_addr,
335 first_new_data, printed_first_new_data, old_name_error,
336 text_nsect, data_nsect;
337 char *strings, *text;
338 struct ext *extp;
339 long hash_key, ntext_symbols, nglobal_symbols;
340 struct oddball *obp;
341 struct branch *bp;
342 long slot_number;
344 fprintf(stderr, "%s: checking external symbols of new target: "
345 "%s\n", progname, new_target);
347 open_target(new_target, &new_target_ofile, &symbols, &nsyms, &strings,
348 &strsize, &text, &textaddr, &textsize, &text_nsect,
349 &data_nsect);
351 if(new_target_ofile.mh->cputype != old_target_ofile.mh->cputype)
352 fatal("cputypes and cpusubtypes of the two shared libraries are "
353 "not the same");
355 make_sorted_text_symbols(symbols, nsyms, &text_symbols, &ntext_symbols);
357 make_global_symbols(symbols, nsyms, &global_symbols, &nglobal_symbols);
359 /* sort the global symbols by value so they get checked in order */
360 qsort(global_symbols, nglobal_symbols, sizeof(struct nlist),
361 (int (*)(const void *, const void *))cmp_qsort);
363 /* Check jump table targets */
364 fprintf(stderr, "Checking the jump table targets\n");
365 for(i = 0; i < nglobal_symbols; i++){
366 if((global_symbols[i].n_type & N_EXT) != N_EXT)
367 continue;
368 if((global_symbols[i].n_type & N_TYPE) == N_SECT &&
369 global_symbols[i].n_sect == text_nsect){
370 if(strncmp(global_symbols[i].n_un.n_name, BRANCH_SLOT_NAME,
371 sizeof(BRANCH_SLOT_NAME) - 1) == 0){
372 extp = lookup(global_symbols[i].n_un.n_name);
373 if(extp == (struct ext *)0)
374 continue;
375 target_addr = get_target_addr(extp->value, extp->name,
376 text, textaddr, textsize, new_target);
377 np = bsearch(&target_addr, text_symbols, ntext_symbols,
378 sizeof(struct nlist),
379 (int (*)(const void *, const void *))cmp_bsearch);
380 if(np == (struct nlist *)0)
381 fatal("Can't find a text symbol for the target (0x%x) "
382 "of branch table symbol: %s in: %s",
383 (unsigned int)target_addr,extp->name, new_target);
385 * It is possible that more than one symbol exists with the
386 * same value as the branch table target. Since the text
387 * symbols are sorted by value find the first one with the
388 * same value. Then find the one that is the name of
389 * the branch table.
391 while(np != text_symbols &&
392 np[0].n_value == np[-1].n_value)
393 np--;
394 if(np[0].n_value == np[1].n_value){
395 slot_number = atol(global_symbols[i].n_un.n_name +
396 sizeof(BRANCH_SLOT_NAME) - 1);
397 bp = NULL;
398 for(j = 0; j < nbranch_list; j++){
399 if(branch_list[j]->max_slotnum == slot_number){
400 bp = branch_list[j];
401 break;
404 if(bp != NULL){
405 while(np[0].n_value == np[1].n_value){
406 if(strcmp(bp->name, np->n_un.n_name) == 0)
407 break;
408 np++;
413 if(strcmp(extp->branch_target, np->n_un.n_name) != 0){
415 * see if this branch name has an old name to check for
417 old_name_error = 0;
418 hash_key = hash_string(np->n_un.n_name) %
419 BRANCH_HASH_SIZE;
420 bp = branch_hash[hash_key];
421 while(bp != NULL){
422 if(strcmp(bp->name, np->n_un.n_name) == 0){
423 if(bp->old_name != NULL){
424 if(strcmp(extp->branch_target,
425 bp->old_name) != 0){
426 error("Branch table symbol: %s has "
427 "different targets (%s and %s) "
428 "and does not match old_name %s",
429 extp->name, extp->branch_target,
430 np->n_un.n_name, bp->old_name);
432 old_name_error = 1;
434 break;
436 bp = bp->next;
438 if(old_name_error == 0){
439 error("Branch table symbol: %s has different "
440 "targets (%s and %s)", extp->name,
441 extp->branch_target, np->n_un.n_name);
449 /* Check global data addresses */
450 fprintf(stderr, "Checking the global data addresses\n");
451 first_new_data = -1;
452 printed_first_new_data = 0;
453 for(i = 0; i < nglobal_symbols; i++){
454 if((global_symbols[i].n_type & N_EXT) != N_EXT)
455 continue;
456 if((global_symbols[i].n_type & N_TYPE) == N_SECT &&
457 global_symbols[i].n_sect == data_nsect){
459 /* if it is a private extern don't check it */
460 hash_key = hash_string(global_symbols[i].n_un.n_name) %
461 ODDBALL_HASH_SIZE;
462 obp = oddball_hash[hash_key];
463 while(obp != (struct oddball *)0){
464 if(strcmp(obp->name, global_symbols[i].n_un.n_name) == 0)
465 break;
466 obp = obp->next;
468 if(obp != (struct oddball *)0 && obp->private == 1)
469 continue;
471 extp = lookup(global_symbols[i].n_un.n_name);
472 if(extp == (struct ext *)0){
473 if(first_new_data == -1)
474 first_new_data = i;
475 continue;
477 if(global_symbols[i].n_value != extp->value){
478 if(!printed_first_new_data && first_new_data != -1){
479 error("First new data symbol: %s at address: 0x%x "
480 "before previous old data",
481 global_symbols[first_new_data].n_un.n_name,
482 (unsigned int)
483 global_symbols[first_new_data].n_value);
484 printed_first_new_data = 1;
486 error("External data symbol: %s does NOT have the same "
487 "address (0x%x and 0x%x)", extp->name,
488 (unsigned int)extp->value,
489 (unsigned int)global_symbols[i].n_value);
492 else if((global_symbols[i].n_type & N_TYPE) == N_SECT &&
493 global_symbols[i].n_sect == 1){
494 hash_key = hash_string(global_symbols[i].n_un.n_name) %
495 ODDBALL_HASH_SIZE;
496 obp = oddball_hash[hash_key];
497 while(obp != (struct oddball *)0){
498 if(strcmp(obp->name, global_symbols[i].n_un.n_name) == 0)
499 break;
500 obp = obp->next;
502 if(obp != (struct oddball *)0 &&
503 obp->nobranch == 1 && obp->private == 0){
504 extp = lookup(global_symbols[i].n_un.n_name);
505 if(extp != NULL){
506 if(global_symbols[i].n_value != extp->value){
507 error("External nobranch_text symbol: %s does "
508 "NOT have the same address (0x%x and "
509 "0x%x)", extp->name,(unsigned int)extp->value,
510 (unsigned int)global_symbols[i].n_value);
519 * Open the target shared library and return information for the symbol and
520 * string table and the text segment.
522 static
523 void
524 open_target(
525 char *target, /* name of the target shared library to open */
526 struct ofile *ofile, /* pointer to the ofile struct to use for target */
527 struct nlist **symbols,/* pointer to the symbol table to return */
528 unsigned long *nsyms, /* pointer to the number of symbols to return */
529 char **strings, /* pointer to the string table to return */
530 unsigned long *strsize,/* pointer to the string table size to return */
531 char **text, /* pointer to the text segment to return */
532 unsigned long *textaddr,/* pointer to the text segment's address to return */
533 unsigned long *textsize,/* pointer to the text segment's size to return */
534 unsigned long *text_nsect,/* pointer to the text section number to return */
535 unsigned long *data_nsect)/* pointer to the data section number to return */
537 unsigned long i, j, nsect;
538 struct load_command *lcp;
539 struct symtab_command *stp;
540 struct segment_command *text_seg, *sgp;
541 struct section *s;
542 enum bool family;
543 const struct arch_flag *family_arch_flag;
545 family = FALSE;
546 if(arch_flag.name != NULL){
547 family_arch_flag = get_arch_family_from_cputype(arch_flag.cputype);
548 if(family_arch_flag != NULL)
549 family = family_arch_flag->cpusubtype == arch_flag.cpusubtype;
553 if(ofile_map(target, NULL, NULL, ofile, FALSE) == FALSE)
554 exit(1);
556 if(ofile->file_type == OFILE_FAT){
557 if(arch_flag.name == NULL && ofile->fat_header->nfat_arch != 1)
558 fatal("-arch must be specified with use of fat files that "
559 "contain more than one architecture");
562 * Set up the ofile struct for the architecture specified by the
563 * -arch flag or the first architecture if -arch flag is NULL and
564 * there is only one architecture.
566 if(arch_flag.name == NULL){
567 /* && ofile->fat_header->nfat_arch == 1 */
568 if(ofile_first_arch(ofile) == FALSE)
569 exit(1);
570 arch_flag.cputype = ofile->fat_archs[0].cputype;
571 arch_flag.cpusubtype = ofile->fat_archs[0].cpusubtype;
573 else{
574 if(ofile_first_arch(ofile) == FALSE)
575 if(errors)
576 exit(1);
578 if(arch_flag.cputype == ofile->arch_flag.cputype &&
579 (arch_flag.cpusubtype == ofile->arch_flag.cpusubtype ||
580 family == TRUE))
581 break;
582 }while(ofile_next_arch(ofile) == TRUE);
583 if(errors)
584 exit(1);
586 if(arch_flag.cputype != ofile->arch_flag.cputype ||
587 (arch_flag.cpusubtype != ofile->arch_flag.cpusubtype &&
588 family == FALSE))
589 fatal("architecture for -arch %s not found in fat file: %s",
590 arch_flag.name, target);
591 arch_flag.cputype = ofile->arch_flag.cputype;
592 arch_flag.cpusubtype = ofile->arch_flag.cpusubtype;
595 * Now that the the ofile struct for the selected architecture
596 * is selected check to see that it is a target shared library.
598 if(ofile->arch_type == OFILE_ARCHIVE){
599 fatal("fat file: %s for architecture %s is not a target shared "
600 "library (file is an archive)", target,
601 ofile->arch_flag.name);
603 else if(ofile->arch_type == OFILE_Mach_O){
604 if(ofile->mh->filetype != MH_FVMLIB)
605 fatal("fat file: %s for architecture %s is not a target "
606 "shared library (wrong filetype)", target,
607 ofile->arch_flag.name);
609 else{ /* ofile->arch_type == OFILE_UNKNOWN */
610 fatal("fat file: %s for architecture %s is not a target shared "
611 "library (wrong magic number)", target,
612 ofile->arch_flag.name);
615 else if(ofile->file_type == OFILE_ARCHIVE){
616 fatal("file: %s is not a target shared library (file is an "
617 "archive)", target);
619 else if(ofile->file_type == OFILE_Mach_O){
620 if(arch_flag.name != NULL){
621 if(arch_flag.cputype != ofile->mh->cputype ||
622 (arch_flag.cpusubtype != ofile->mh->cpusubtype &&
623 family == FALSE))
624 fatal("architecture for -arch %s does match architecture "
625 "of file: %s", arch_flag.name, target);
627 if(ofile->mh->filetype != MH_FVMLIB)
628 fatal("file: %s is not a target shared library (wrong "
629 "filetype)", target);
631 else{ /* ofile->file_type == OFILE_UNKNOWN */
632 fatal("file: %s is not a target shared library (wrong magic "
633 "number)", target);
636 /* Get the load comand for the symbol table and text segment */
637 nsect = 1;
638 lcp = ofile->load_commands;
639 stp = (struct symtab_command *)0;
640 text_seg = (struct segment_command *)0;
641 for(i = 0; i < ofile->mh->ncmds; i++){
642 switch(lcp->cmd){
643 case LC_SYMTAB:
644 if(stp != (struct symtab_command *)0)
645 fatal("More than one symtab_command in: %s", target);
646 else
647 stp = (struct symtab_command *)lcp;
648 break;
649 case LC_SEGMENT:
650 sgp = (struct segment_command *)lcp;
651 if(strcmp(sgp->segname, SEG_TEXT) == 0){
652 if(text_seg != (struct segment_command *)0)
653 fatal("More than one segment_command for the %s "
654 "segment in: %s", SEG_TEXT, target);
655 else
656 text_seg = (struct segment_command *)lcp;
658 s = (struct section *)((char *)sgp +
659 sizeof(struct segment_command));
660 for(j = 0 ; j < sgp->nsects ; j++){
661 if(strcmp(s->segname, SEG_TEXT) == 0 &&
662 strcmp(s->sectname, SECT_TEXT) == 0)
663 *text_nsect = nsect;
664 if(strcmp(s->segname, SEG_DATA) == 0 &&
665 strcmp(s->sectname, SECT_DATA) == 0)
666 *data_nsect = nsect;
667 nsect++;
668 s++;
670 break;
672 lcp = (struct load_command *)((char *)lcp + lcp->cmdsize);
674 /* Check to see if the symbol table load command is good */
675 if(stp == (struct symtab_command *)0)
676 fatal("No symtab_command in: %s", target);
677 if(stp->nsyms == 0)
678 fatal("No symbol table in: %s", target);
679 if(stp->strsize == 0)
680 fatal("No string table in: %s", target);
681 *symbols = (struct nlist *)(ofile->object_addr + stp->symoff);
682 *nsyms = stp->nsyms;
683 if(ofile->object_byte_sex != host_byte_sex)
684 swap_nlist(*symbols, *nsyms, host_byte_sex);
685 *strings = (char *)(ofile->object_addr + stp->stroff);
686 *strsize = stp->strsize;
688 for(i = 0; i < *nsyms; i++){
689 if(((*symbols)[i].n_type & N_EXT) != N_EXT)
690 continue;
691 if((*symbols)[i].n_un.n_strx < 0 ||
692 (uint32_t)((*symbols)[i].n_un.n_strx) > *strsize)
693 fatal("Bad string table index (%d) for symbol %ld in: %s",
694 (*symbols)[i].n_un.n_strx, i, target);
695 (*symbols)[i].n_un.n_name = *strings + (*symbols)[i].n_un.n_strx;
698 /* Check to see if the load command for the text segment is good */
699 if(text_seg == (struct segment_command *)0)
700 fatal("No segment_command in: %s for the %s segment", target,
701 SEG_TEXT);
702 *text = (char *)(ofile->object_addr + text_seg->fileoff);
703 *textaddr = text_seg->vmaddr;
704 *textsize = text_seg->filesize;
708 * Build a sorted list of external text symbols.
710 static
711 void
712 make_sorted_text_symbols(
713 struct nlist *symbols,
714 long nsyms,
715 struct nlist **text_symbols,
716 long *ntext_symbols)
718 long i, j;
720 *ntext_symbols = 0;
721 for(i = 0; i < nsyms; i++){
722 if((symbols[i].n_type == (N_SECT | N_EXT) &&
723 symbols[i].n_sect == 1))
724 (*ntext_symbols)++;
727 /* Build a table of the external text symbols sorted by their address */
728 *text_symbols = allocate(*ntext_symbols * sizeof(struct nlist));
729 j = 0;
730 for(i = 0; i < nsyms; i++){
731 if((symbols[i].n_type & N_EXT) != N_EXT)
732 continue;
733 if((symbols[i].n_type & N_TYPE) == N_SECT &&
734 symbols[i].n_sect == 1)
735 (*text_symbols)[j++] = symbols[i];
737 qsort(*text_symbols, *ntext_symbols, sizeof(struct nlist),
738 (int (*)(const void *, const void *))cmp_qsort);
742 * Build a list of external symbols.
744 static
745 void
746 make_global_symbols(
747 struct nlist *symbols,
748 long nsyms,
749 struct nlist **global_symbols,
750 long *nglobal_symbols)
752 long i, j;
754 *nglobal_symbols = 0;
755 for(i = 0; i < nsyms; i++){
756 if((symbols[i].n_type & N_EXT) == N_EXT)
757 (*nglobal_symbols)++;
760 /* Build a table of the external symbols */
761 *global_symbols = allocate(*nglobal_symbols * sizeof(struct nlist));
762 j = 0;
763 for(i = 0; i < nsyms; i++){
764 if((symbols[i].n_type & N_EXT) == N_EXT)
765 (*global_symbols)[j++] = symbols[i];
770 * Return the target address of the jmp instruction in the text for the given
771 * value.
773 static
774 long
775 get_target_addr(
776 unsigned long value,
777 char *name,
778 char *text,
779 unsigned long addr,
780 unsigned long size,
781 char *target)
783 unsigned long offset, target_addr;
785 offset = value - addr;
786 if(offset < 0 || offset > size)
787 fatal("Value (0x%x) of branch table symbol: %s not in "
788 "the %s segment of: %s", (unsigned int)value, name,
789 SEG_TEXT, target);
791 if(arch_flag.cputype == CPU_TYPE_MC680x0){
792 unsigned short jmp;
794 if(offset + sizeof(short) + sizeof(long) > size)
795 fatal("Branch instruction for branch table symbol: %s "
796 "would extend past the end of the %s segment in: "
797 " %s", name, SEG_TEXT, target);
798 memcpy(&jmp, text + offset, sizeof(unsigned short));
799 if(host_byte_sex != BIG_ENDIAN_BYTE_SEX)
800 jmp = SWAP_SHORT(jmp);
802 * look for a jump op code with a absolute long effective address
803 * (a "jmp (xxx).L" instruction)
805 if(jmp != 0x4ef9)
806 fatal("Branch instruction not found at branch table "
807 "symbol: %s in: %s", name, target);
808 memcpy(&target_addr,
809 text + offset + sizeof(unsigned short),
810 sizeof(unsigned long));
811 if(host_byte_sex != BIG_ENDIAN_BYTE_SEX)
812 target_addr = SWAP_LONG(target_addr);
814 else if(arch_flag.cputype == CPU_TYPE_POWERPC){
815 unsigned long inst, disp;
817 if(offset + sizeof(long) > size)
818 fatal("Branch instruction for branch table symbol: %s "
819 "would extend past the end of the %s segment in: "
820 " %s", name, SEG_TEXT, target);
821 memcpy(&inst, text + offset, sizeof(unsigned long));
822 if(host_byte_sex != BIG_ENDIAN_BYTE_SEX)
823 inst = SWAP_LONG(inst);
824 /* look for an uncondition branch op code (a "b" instruction) */
825 if((inst & 0xfc000003) != 0x48000000)
826 fatal("Branch instruction not found at branch table "
827 "symbol: %s in: %s", name, target);
828 if((inst & 0x02000000) != 0)
829 disp = 0xfc000000 | (inst & 0x03fffffc);
830 else
831 disp = (inst & 0x03fffffc);
832 target_addr = value + disp;
834 else if(arch_flag.cputype == CPU_TYPE_MC88000){
835 unsigned long inst, disp;
837 if(offset + sizeof(long) > size)
838 fatal("Branch instruction for branch table symbol: %s "
839 "would extend past the end of the %s segment in: "
840 " %s", name, SEG_TEXT, target);
841 memcpy(&inst, text + offset, sizeof(unsigned long));
842 if(host_byte_sex != BIG_ENDIAN_BYTE_SEX)
843 inst = SWAP_LONG(inst);
844 /* look for an uncondition branch op code (a br instruction) */
845 if((inst & 0xfc000000) != 0xc0000000)
846 fatal("Branch instruction not found at branch table "
847 "symbol: %s in: %s", name, target);
848 if((inst & 0x02000000) != 0)
849 disp = 0xf0000000 | ((inst & 0x03ffffff) << 2);
850 else
851 disp = (inst & 0x03ffffff) << 2;
852 target_addr = value + disp;
854 else if(arch_flag.cputype == CPU_TYPE_I386){
855 unsigned char jmp;
856 unsigned long disp;
858 if(offset + sizeof(char) + sizeof(long) > size)
859 fatal("Branch instruction for branch table symbol: %s "
860 "would extend past the end of the %s segment in: "
861 " %s", name, SEG_TEXT, target);
862 memcpy(&jmp, text + offset, sizeof(unsigned char));
864 * look for a jump op code with a 32 bit displacement
865 * (a JMP rel32 instruction)
867 if(jmp != 0xe9)
868 fatal("Branch instruction not found at branch table "
869 "symbol: %s in: %s", name, target);
870 memcpy(&disp,
871 text + offset + sizeof(unsigned char),
872 sizeof(unsigned long));
873 if(host_byte_sex != LITTLE_ENDIAN_BYTE_SEX)
874 disp = SWAP_LONG(disp);
875 target_addr = value + sizeof(unsigned char) +
876 sizeof(unsigned long) + disp;
878 else if(arch_flag.cputype == CPU_TYPE_HPPA){
879 unsigned long inst[2], disp;
881 if(offset + 2*sizeof(long) > size)
882 fatal("Branch instruction for branch table symbol: %s "
883 "would extend past the end of the %s segment in: "
884 " %s", name, SEG_TEXT, target);
885 memcpy(&inst, text + offset, 2*sizeof(unsigned long));
886 if(host_byte_sex != BIG_ENDIAN_BYTE_SEX) {
887 inst[0] = SWAP_LONG(inst[0]);
888 inst[1] = SWAP_LONG(inst[1]);
891 * branch slot is following 2 instruction sequence:
892 * ldil L`addr,%r1
893 * be,n R`addr(%sr4,%r1)
895 if( ((inst[0] & 0xffe00000) != 0x20200000) ||
896 ((inst[1] & 0xffe0e002) != 0xe0202002))
897 fatal("Branch instruction not found at branch table "
898 "symbol: %s in: %s", name, target);
899 disp = assemble_21(inst[0]&0x1fffff)<<11;
900 disp += sign_ext(assemble_17((inst[1]&0x1f0000)>>16,
901 (inst[1]&0x1ffc)>>2,
902 inst[1]&1),17)<<2;
903 target_addr = disp;
905 else if(arch_flag.cputype == CPU_TYPE_SPARC){
906 unsigned long inst, disp;
908 if(offset + sizeof(long) > size)
909 fatal("Branch instruction for branch table symbol: %s "
910 "would extend past the end of the %s segment in: "
911 " %s", name, SEG_TEXT, target);
912 memcpy(&inst, text + offset, sizeof(unsigned long));
913 if(host_byte_sex != BIG_ENDIAN_BYTE_SEX)
914 inst = SWAP_LONG(inst);
915 /* look for an uncondition branch op code (a ba,a instruction) */
916 if((inst & 0xffc00000) != 0x30800000)
917 fatal("Branch instruction not found at branch table "
918 "symbol: %s in: %s", name, target);
919 disp = (inst & 0x03fffff) << 2;
920 target_addr = value + disp;
922 else{
923 fatal("internal error: get_target_addr() called with arch_flag."
924 "cputype set to unknown value");
925 target_addr = 0;
927 return(target_addr);
931 * Function for qsort for comparing symbols.
933 static
935 cmp_qsort(
936 struct nlist *sym1,
937 struct nlist *sym2)
939 return(sym1->n_value - sym2->n_value);
943 * Function for bsearch for finding a symbol.
945 static
947 cmp_bsearch(
948 long *value,
949 struct nlist *sym)
951 return(*value - sym->n_value);
955 * Lookup a name in the external hash table.
957 static
958 struct ext *
959 lookup(
960 char *name)
962 long hash_key;
963 struct ext *extp;
965 hash_key = hash_string(name) % EXT_HASH_SIZE;
966 extp = ext_hash[hash_key];
967 while(extp != (struct ext *)0){
968 if(strcmp(name, extp->name) == 0)
969 return(extp);
970 extp = extp->next;
972 return((struct ext *)0);
977 * a dummy routine called by the fatal() like routines
979 void
980 cleanup(
981 int sig)
983 exit(EXIT_FAILURE);