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@
30 #include <sys/types.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"
49 static void make_oldtarget_hashtable(
52 static void check_newtarget(
55 static void open_target(
58 struct nlist
**symbols
,
61 unsigned long *strsize
,
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
,
71 struct nlist
**text_symbols
,
74 static void make_global_symbols(
75 struct nlist
*symbols
,
79 long *nglobal_symbols
);
81 static long get_target_addr(
93 static int cmp_bsearch(
97 static struct ext
*lookup(
100 /* Structure of the members of the hash table for the old target */
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
];
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
;
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){
152 spec_filename
= argv
[++i
];
154 else if(strcmp(argv
[i
], "-arch") == 0){
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
]);
170 if(old_target
== NULL
)
171 old_target
= argv
[i
];
172 else if(new_target
== NULL
)
173 new_target
= argv
[i
];
179 if(old_target
== NULL
|| new_target
== NULL
)
182 if(spec_filename
!= NULL
){
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
);
193 return(EXIT_FAILURE
);
196 return(EXIT_SUCCESS
);
201 * Print the usage line and exit indicating failure.
207 fprintf(stderr
, "Usage: %s [-s spec_file] [-arch arch_type] "
208 "<old target> <new target>\n", progname
);
213 * Build the hash table of the external symbols of old target shared library.
217 make_oldtarget_hashtable(
220 struct nlist
*symbols
, *text_symbols
, *np
;
221 unsigned long nsyms
, strsize
, textaddr
, textsize
, i
,
222 target_addr
, hash_key
, text_nsect
, data_nsect
;
224 char *text
, *strings
;
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
,
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
);
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
,
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
)
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
);
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
)
285 * For each branch table slot find the name of the symbol in that slot.
287 for(i
= 0; i
< EXT_HASH_SIZE
; 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
;
309 for(i
= 0; i
< EXT_HASH_SIZE
; 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
);
325 * Check the new target shared library against the old target shared library
326 * hash table of symbols.
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
;
339 long hash_key
, ntext_symbols
, nglobal_symbols
;
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
,
351 if(new_target_ofile
.mh
->cputype
!= old_target_ofile
.mh
->cputype
)
352 fatal("cputypes and cpusubtypes of the two shared libraries are "
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
)
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)
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
391 while(np
!= text_symbols
&&
392 np
[0].n_value
== np
[-1].n_value
)
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);
398 for(j
= 0; j
< nbranch_list
; j
++){
399 if(branch_list
[j
]->max_slotnum
== slot_number
){
405 while(np
[0].n_value
== np
[1].n_value
){
406 if(strcmp(bp
->name
, np
->n_un
.n_name
) == 0)
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
418 hash_key
= hash_string(np
->n_un
.n_name
) %
420 bp
= branch_hash
[hash_key
];
422 if(strcmp(bp
->name
, np
->n_un
.n_name
) == 0){
423 if(bp
->old_name
!= NULL
){
424 if(strcmp(extp
->branch_target
,
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
);
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");
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
)
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
) %
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)
468 if(obp
!= (struct oddball
*)0 && obp
->private == 1)
471 extp
= lookup(global_symbols
[i
].n_un
.n_name
);
472 if(extp
== (struct ext
*)0){
473 if(first_new_data
== -1)
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
,
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
) %
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)
502 if(obp
!= (struct oddball
*)0 &&
503 obp
->nobranch
== 1 && obp
->private == 0){
504 extp
= lookup(global_symbols
[i
].n_un
.n_name
);
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.
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
;
543 const struct arch_flag
*family_arch_flag
;
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
)
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
)
570 arch_flag
.cputype
= ofile
->fat_archs
[0].cputype
;
571 arch_flag
.cpusubtype
= ofile
->fat_archs
[0].cpusubtype
;
574 if(ofile_first_arch(ofile
) == FALSE
)
578 if(arch_flag
.cputype
== ofile
->arch_flag
.cputype
&&
579 (arch_flag
.cpusubtype
== ofile
->arch_flag
.cpusubtype
||
582 }while(ofile_next_arch(ofile
) == TRUE
);
586 if(arch_flag
.cputype
!= ofile
->arch_flag
.cputype
||
587 (arch_flag
.cpusubtype
!= ofile
->arch_flag
.cpusubtype
&&
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 "
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
&&
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 "
636 /* Get the load comand for the symbol table and text segment */
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
++){
644 if(stp
!= (struct symtab_command
*)0)
645 fatal("More than one symtab_command in: %s", target
);
647 stp
= (struct symtab_command
*)lcp
;
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
);
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)
664 if(strcmp(s
->segname
, SEG_DATA
) == 0 &&
665 strcmp(s
->sectname
, SECT_DATA
) == 0)
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
);
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
);
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
)
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
,
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.
712 make_sorted_text_symbols(
713 struct nlist
*symbols
,
715 struct nlist
**text_symbols
,
721 for(i
= 0; i
< nsyms
; i
++){
722 if((symbols
[i
].n_type
== (N_SECT
| N_EXT
) &&
723 symbols
[i
].n_sect
== 1))
727 /* Build a table of the external text symbols sorted by their address */
728 *text_symbols
= allocate(*ntext_symbols
* sizeof(struct nlist
));
730 for(i
= 0; i
< nsyms
; i
++){
731 if((symbols
[i
].n_type
& N_EXT
) != N_EXT
)
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.
747 struct nlist
*symbols
,
749 struct nlist
**global_symbols
,
750 long *nglobal_symbols
)
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
));
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
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
,
791 if(arch_flag
.cputype
== CPU_TYPE_MC680x0
){
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)
806 fatal("Branch instruction not found at branch table "
807 "symbol: %s in: %s", name
, target
);
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);
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);
851 disp
= (inst
& 0x03ffffff) << 2;
852 target_addr
= value
+ disp
;
854 else if(arch_flag
.cputype
== CPU_TYPE_I386
){
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)
868 fatal("Branch instruction not found at branch table "
869 "symbol: %s in: %s", name
, target
);
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:
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,
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
;
923 fatal("internal error: get_target_addr() called with arch_flag."
924 "cputype set to unknown value");
931 * Function for qsort for comparing symbols.
939 return(sym1
->n_value
- sym2
->n_value
);
943 * Function for bsearch for finding a symbol.
951 return(*value
- sym
->n_value
);
955 * Lookup a name in the external hash table.
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)
972 return((struct ext
*)0);
977 * a dummy routine called by the fatal() like routines