Integrate cctools-667.4.0 changes
[striptease.git] / strip.c
blob4072bdeac7a84a031557653f7065b6b9297341dc
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@
24 * The strip(1) and nmedit(l) program. This understands only Mach-O format
25 * files (with the restriction the symbol table is at the end of the file) and
26 * fat files with Mach-O files in them.
28 #include <stdio.h>
29 #include <stdlib.h>
30 #include <string.h>
31 #include <limits.h>
32 #include <ctype.h>
33 #include <libc.h>
34 #include <sys/types.h>
35 #include <sys/stat.h>
36 #include <mach-o/loader.h>
37 #include <mach-o/reloc.h>
38 #include <mach-o/nlist.h>
39 #include <mach-o/stab.h>
40 #include "stuff/breakout.h"
41 #include "stuff/allocate.h"
42 #include "stuff/errors.h"
43 #include "stuff/round.h"
44 #include "stuff/reloc.h"
45 #include "stuff/reloc.h"
46 #include "stuff/symbol_list.h"
47 #include "stuff/unix_standard_mode.h"
49 /* These are set from the command line arguments */
50 __private_extern__
51 char *progname = NULL; /* name of the program for error messages (argv[0]) */
52 static char *output_file;/* name of the output file */
53 static char *sfile; /* filename of global symbol names to keep */
54 static char *Rfile; /* filename of global symbol names to remove */
55 static long Aflag; /* save only absolute symbols with non-zero value and
56 .objc_class_name_* symbols */
57 static long iflag; /* -i ignore symbols in -s file not in object */
58 #ifdef NMEDIT
59 static long pflag; /* make all defined global symbols private extern */
60 #else /* !defined(NMEDIT) */
61 static char *dfile; /* filename of filenames of debugger symbols to keep */
62 static long uflag; /* save undefined symbols */
63 static long rflag; /* save symbols referenced dynamically */
64 static long nflag; /* save N_SECT global symbols */
65 static long Sflag; /* -S strip only debugger symbols N_STAB */
66 static long xflag; /* -x strip non-globals */
67 static long Xflag; /* -X strip local symbols with 'L' names */
68 static long cflag; /* -c strip section contents from dynamic libraries
69 files to create stub libraries */
70 static long no_uuid; /* -no_uuid strip LC_UUID load commands */
71 static long strip_all = 1;
73 * This is set on an object by object basis if the strip_all flag is still set
74 * and the object is an executable that is for use with the dynamic linker.
75 * This has the same effect as -r and -u.
77 static enum bool default_dyld_executable = FALSE;
78 #endif /* NMEDIT */
81 * Data structures to perform selective stripping of symbol table entries.
82 * save_symbols is the names of the symbols from the -s <file> argument.
83 * remove_symbols is the names of the symbols from the -R <file> argument.
85 static struct symbol_list *save_symbols = NULL;
86 static unsigned long nsave_symbols = 0;
87 static struct symbol_list *remove_symbols = NULL;
88 static unsigned long nremove_symbols = 0;
91 * saves points to an array of longs that is allocated. This array is a map of
92 * old symbol indexes to new symbol indexes. The new symbol indexes are
93 * plus 1 and zero value means that old symbol is not in the new symbol table.
94 * ref_saves is used in the same way but for the reference table.
95 * nmedits is an array and indexed by the symbol index the value indicates if
96 * the symbol was edited and turned into a non-global.
98 static long *saves = NULL;
99 #ifndef NMEDIT
100 static long *ref_saves = NULL;
101 #else
102 static enum bool *nmedits = NULL;
103 #endif
106 * These hold the new symbol and string table created by strip_symtab()
107 * and the new counts of local, defined external and undefined symbols.
109 static struct nlist *new_symbols = NULL;
110 static struct nlist_64 *new_symbols64 = NULL;
111 static unsigned long new_nsyms = 0;
112 static char *new_strings = NULL;
113 static unsigned long new_strsize = 0;
114 static unsigned long new_nlocalsym = 0;
115 static unsigned long new_nextdefsym = 0;
116 static unsigned long new_nundefsym = 0;
119 * These hold the new table of contents, reference table and module table for
120 * dylibs.
122 static struct dylib_table_of_contents *new_tocs = NULL;
123 static unsigned long new_ntoc = 0;
124 static struct dylib_reference *new_refs = NULL;
125 static unsigned long new_nextrefsyms = 0;
126 #ifdef NMEDIT
127 static struct dylib_module *new_mods = NULL;
128 static struct dylib_module_64 *new_mods64 = NULL;
129 static unsigned long new_nmodtab = 0;
130 #endif
132 #ifndef NMEDIT
134 * The list of file names to save debugging symbols from.
136 static char **debug_filenames = NULL;
137 static long ndebug_filenames = 0;
138 struct undef_map {
139 unsigned long index;
140 struct nlist symbol;
142 struct undef_map64 {
143 unsigned long index;
144 struct nlist_64 symbol64;
146 static char *qsort_strings = NULL;
147 #endif /* !defined(NMEDIT) */
150 /* Internal routines */
151 static void usage(
152 void);
154 static void strip_file(
155 char *input_file,
156 struct arch_flag *arch_flags,
157 unsigned long narch_flags,
158 enum bool all_archs);
160 static void strip_arch(
161 struct arch *archs,
162 unsigned long narchs,
163 struct arch_flag *arch_flags,
164 unsigned long narch_flags,
165 enum bool all_archs);
167 static void strip_object(
168 struct arch *arch,
169 struct member *member,
170 struct object *object);
172 static void check_object_relocs(
173 struct arch *arch,
174 struct member *member,
175 struct object *object,
176 char *segname,
177 char *sectname,
178 unsigned long long sectsize,
179 char *contents,
180 struct relocation_info *relocs,
181 uint32_t nreloc,
182 struct nlist *symbols,
183 struct nlist_64 *symbols64,
184 unsigned long nsyms,
185 char *strings,
186 long *missing_reloc_symbols,
187 enum byte_sex host_byte_sex);
189 static void check_indirect_symtab(
190 struct arch *arch,
191 struct member *member,
192 struct object *object,
193 unsigned long nitems,
194 unsigned long reserved1,
195 unsigned long section_type,
196 char *contents,
197 struct nlist *symbols,
198 struct nlist_64 *symbols64,
199 unsigned long nsyms,
200 char *strings,
201 long *missing_reloc_symbols,
202 enum byte_sex host_byte_sex);
204 #ifndef NMEDIT
205 static enum bool strip_symtab(
206 struct arch *arch,
207 struct member *member,
208 struct object *object,
209 struct nlist *symbols,
210 struct nlist_64 *symbols64,
211 unsigned long nsyms,
212 char *strings,
213 unsigned long strsize,
214 struct dylib_table_of_contents *tocs,
215 unsigned long ntoc,
216 struct dylib_module *mods,
217 struct dylib_module_64 *mods64,
218 unsigned long nmodtab,
219 struct dylib_reference *refs,
220 unsigned long nextrefsyms,
221 uint32_t *indirectsyms,
222 unsigned long nindirectsyms);
224 static void strip_LC_UUID_commands(
225 struct arch *arch,
226 struct member *member,
227 struct object *object);
229 #ifndef NMEDIT
230 static void strip_LC_CODE_SIGNATURE_commands(
231 struct arch *arch,
232 struct member *member,
233 struct object *object);
234 #endif /* !(NMEDIT) */
236 static enum bool private_extern_reference_by_module(
237 unsigned long symbol_index,
238 struct dylib_reference *refs,
239 unsigned long nextrefsyms);
241 static enum bool symbol_pointer_used(
242 unsigned long symbol_index,
243 uint32_t *indirectsyms,
244 unsigned long nindirectsyms);
246 static int cmp_qsort_undef_map(
247 const struct undef_map *sym1,
248 const struct undef_map *sym2);
250 static int cmp_qsort_undef_map_64(
251 const struct undef_map64 *sym1,
252 const struct undef_map64 *sym2);
253 #endif /* !defined(NMEDIT) */
255 #ifdef NMEDIT
256 static enum bool edit_symtab(
257 struct arch *arch,
258 struct member *member,
259 struct object *object,
260 struct nlist *symbols,
261 struct nlist_64 *symbols64,
262 unsigned long nsyms,
263 char *strings,
264 unsigned long strsize,
265 struct dylib_table_of_contents *tocs,
266 unsigned long ntoc,
267 struct dylib_module *mods,
268 struct dylib_module_64 *mods64,
269 unsigned long nmodtab,
270 struct dylib_reference *refs,
271 unsigned long nextrefsyms);
272 #endif /* NMEDIT */
274 #ifndef NMEDIT
275 static void setup_debug_filenames(
276 char *dfile);
278 static int cmp_qsort_filename(
279 const char **name1,
280 const char **name2);
282 static int cmp_bsearch_filename(
283 const char *name1,
284 const char **name2);
285 #endif /* NMEDIT */
287 #ifdef NMEDIT
289 * This variable and routines are used for nmedit(1) only.
291 static char *global_strings = NULL;
293 static int cmp_qsort_global(
294 const struct nlist **sym1,
295 const struct nlist **sym2);
297 static int cmp_qsort_global_64(
298 const struct nlist_64 **sym1,
299 const struct nlist_64 **sym2);
301 static int cmp_bsearch_global_stab(
302 const char *name,
303 const struct nlist **sym);
305 static int cmp_bsearch_global_stab_64(
306 const char *name,
307 const struct nlist_64 **sym);
309 static int cmp_bsearch_global(
310 const char *name,
311 const struct nlist **sym);
313 static int cmp_bsearch_global_64(
314 const char *name,
315 const struct nlist_64 **sym);
316 #endif /* NMEDIT */
319 main(
320 int argc,
321 char *argv[],
322 char *envp[])
324 int i;
325 unsigned long j, args_left, files_specified;
326 struct arch_flag *arch_flags;
327 unsigned long narch_flags;
328 enum bool all_archs;
329 struct symbol_list *sp;
331 progname = argv[0];
333 arch_flags = NULL;
334 narch_flags = 0;
335 all_archs = FALSE;
337 files_specified = 0;
338 args_left = 1;
339 for (i = 1; i < argc; i++){
340 if(argv[i][0] == '-'){
341 if(argv[i][1] == '\0'){
342 args_left = 0;
343 break;
345 if(strcmp(argv[i], "-o") == 0){
346 if(i + 1 >= argc)
347 fatal("-o requires an argument");
348 if(output_file != NULL)
349 fatal("only one -o option allowed");
350 output_file = argv[i + 1];
351 i++;
353 else if(strcmp(argv[i], "-s") == 0){
354 if(i + 1 >= argc)
355 fatal("-s requires an argument");
356 if(sfile != NULL)
357 fatal("only one -s option allowed");
358 sfile = argv[i + 1];
359 i++;
361 else if(strcmp(argv[i], "-R") == 0){
362 if(i + 1 >= argc)
363 fatal("-R requires an argument");
364 if(Rfile != NULL)
365 fatal("only one -R option allowed");
366 Rfile = argv[i + 1];
367 i++;
369 #ifndef NMEDIT
370 else if(strcmp(argv[i], "-d") == 0){
371 if(i + 1 >= argc)
372 fatal("-d requires an argument");
373 if(dfile != NULL)
374 fatal("only one -d option allowed");
375 dfile = argv[i + 1];
376 i++;
378 else if(strcmp(argv[i], "-no_uuid") == 0){
379 no_uuid = 1;
381 #endif /* !defined(NMEDIT) */
382 else if(strcmp(argv[i], "-arch") == 0){
383 if(i + 1 == argc){
384 error("missing argument(s) to %s option", argv[i]);
385 usage();
387 if(strcmp("all", argv[i+1]) == 0){
388 all_archs = TRUE;
390 else{
391 arch_flags = reallocate(arch_flags,
392 (narch_flags + 1) * sizeof(struct arch_flag));
393 if(get_arch_from_flag(argv[i+1],
394 arch_flags + narch_flags) == 0){
395 error("unknown architecture specification flag: "
396 "%s %s", argv[i], argv[i+1]);
397 arch_usage();
398 usage();
400 for(j = 0; j < narch_flags; j++){
401 if(arch_flags[j].cputype ==
402 arch_flags[narch_flags].cputype &&
403 (arch_flags[j].cpusubtype & ~CPU_SUBTYPE_MASK) ==
404 (arch_flags[narch_flags].cpusubtype &
405 ~CPU_SUBTYPE_MASK) &&
406 strcmp(arch_flags[j].name,
407 arch_flags[narch_flags].name) == 0)
408 break;
410 if(j == narch_flags)
411 narch_flags++;
413 i++;
415 else{
416 for(j = 1; argv[i][j] != '\0'; j++){
417 switch(argv[i][j]){
418 #ifdef NMEDIT
419 case 'p':
420 pflag = 1;
421 break;
422 #else /* !defined(NMEDIT) */
423 case 'S':
424 Sflag = 1;
425 strip_all = 0;
426 break;
427 case 'X':
428 Xflag = 1;
429 strip_all = 0;
430 break;
431 case 'x':
432 xflag = 1;
433 strip_all = 0;
434 break;
435 case 'i':
436 iflag = 1;
437 break;
438 case 'u':
439 uflag = 1;
440 strip_all = 0;
441 break;
442 case 'r':
443 rflag = 1;
444 strip_all = 0;
445 break;
446 case 'n':
447 nflag = 1;
448 strip_all = 0;
449 break;
450 #endif /* !defined(NMEDIT) */
451 case 'A':
452 Aflag = 1;
453 #ifndef NMEDIT
454 strip_all = 0;
455 #endif /* !defined(NMEDIT) */
456 break;
457 #ifndef NMEDIT
458 case 'c':
459 cflag = 1;
460 strip_all = 0;
461 break;
462 #endif /* NMEDIT */
463 default:
464 error("unrecognized option: %s", argv[i]);
465 usage();
470 else
471 files_specified++;
473 if(args_left == 0)
474 files_specified += argc - (i + 1);
476 if(files_specified > 1 && output_file != NULL){
477 error("-o <filename> can only be used when one file is specified");
478 usage();
481 if(sfile){
482 setup_symbol_list(sfile, &save_symbols, &nsave_symbols);
484 #ifdef NMEDIT
485 else{
486 if(Rfile == NULL && pflag == 0){
487 error("-s <filename>, -R <filename> or -p argument required");
488 usage();
491 #endif /* NMEDIT */
493 if(Rfile){
494 setup_symbol_list(Rfile, &remove_symbols, &nremove_symbols);
495 if(sfile){
496 for(j = 0; j < nremove_symbols ; j++){
497 sp = bsearch(remove_symbols[j].name,
498 save_symbols, nsave_symbols,
499 sizeof(struct symbol_list),
500 (int (*)(const void *, const void *))
501 symbol_list_bsearch);
502 if(sp != NULL){
503 error("symbol name: %s is listed in both -s %s and -R "
504 "%s files (can't be both saved and removed)",
505 remove_symbols[j].name, sfile, Rfile);
508 if(errors)
509 exit(EXIT_FAILURE);
513 /* the default when no -arch flags is present is to strip all archs */
514 if(narch_flags == 0)
515 all_archs = TRUE;
517 #ifndef NMEDIT
518 if(dfile){
519 setup_debug_filenames(dfile);
521 #endif /* !defined(NMEDIT) */
523 files_specified = 0;
524 args_left = 1;
525 for (i = 1; i < argc; i++) {
526 if(args_left && argv[i][0] == '-'){
527 if(argv[i][1] == '\0')
528 args_left = 0;
529 else if(strcmp(argv[i], "-o") == 0 ||
530 strcmp(argv[i], "-s") == 0 ||
531 strcmp(argv[i], "-R") == 0 ||
532 #ifndef NMEDIT
533 strcmp(argv[i], "-d") == 0 ||
534 #endif /* !defined(NMEDIT) */
535 strcmp(argv[i], "-arch") == 0)
536 i++;
538 else{
539 char resolved_path[PATH_MAX + 1];
541 if(realpath(argv[i], resolved_path) == NULL)
542 strip_file(argv[i], arch_flags, narch_flags, all_archs);
543 else
544 strip_file(resolved_path, arch_flags,narch_flags,all_archs);
545 files_specified++;
548 if(files_specified == 0)
549 fatal("no files specified");
551 if(errors)
552 return(EXIT_FAILURE);
553 else
554 return(EXIT_SUCCESS);
557 static
558 void
559 usage(
560 void)
562 #ifndef NMEDIT
563 fprintf(stderr, "Usage: %s [-AnuSXx] [-] [-d filename] [-s filename] "
564 "[-R filename] [-o output] file [...] \n", progname);
565 #else /* defined(NMEDIT) */
566 fprintf(stderr, "Usage: %s -s filename [-R filename] [-p] [-A] [-] "
567 "[-o output] file [...] \n",
568 progname);
569 #endif /* NMEDIT */
570 exit(EXIT_FAILURE);
573 static
574 void
575 strip_file(
576 char *input_file,
577 struct arch_flag *arch_flags,
578 unsigned long narch_flags,
579 enum bool all_archs)
581 struct arch *archs;
582 unsigned long narchs;
583 struct stat stat_buf;
584 unsigned long previous_errors;
585 enum bool unix_standard_mode;
586 int cwd_fd;
587 char *rename_file;
588 #ifndef NMEDIT
589 char *p;
590 #endif
592 archs = NULL;
593 narchs = 0;
594 previous_errors = errors;
595 errors = 0;
597 /* breakout the file for processing */
598 breakout(input_file, &archs, &narchs, FALSE);
599 if(errors)
600 return;
602 /* checkout the file for symbol table replacement processing */
603 checkout(archs, narchs);
605 /* process the symbols in the input file */
606 strip_arch(archs, narchs, arch_flags, narch_flags, all_archs);
607 if(errors)
608 return;
610 /* create the output file */
611 if(stat(input_file, &stat_buf) == -1)
612 system_error("can't stat input file: %s", input_file);
613 if(output_file != NULL){
614 writeout(archs, narchs, output_file, stat_buf.st_mode & 0777,
615 TRUE, FALSE, FALSE, NULL);
617 else{
618 unix_standard_mode = get_unix_standard_mode();
619 rename_file = NULL;
620 cwd_fd = -1;
621 #ifdef NMEDIT
622 output_file = makestr(input_file, ".nmedit", NULL);
623 #else /* !defined(NMEDIT) */
625 * In UNIX standard conformance mode we are not allowed to replace
626 * a file that is not writeable.
628 if(unix_standard_mode == TRUE &&
629 access(input_file, W_OK) == -1){
630 system_error("file: %s is not writable", input_file);
631 goto strip_file_return;
633 output_file = makestr(input_file, ".strip", NULL);
636 * The UNIX standard conformance test suite expects files of
637 * MAXPATHLEN to work.
639 if(strlen(output_file) >= MAXPATHLEN){
641 * If there is a directory path in the name try to change
642 * the current working directory to that path.
644 if((p = rindex(output_file, '/')) != NULL){
645 if((cwd_fd = open(".", O_RDONLY, 0)) == -1){
646 system_error("can't open current working directory");
647 goto strip_file_return;
649 *p = '\0';
650 if(chdir(output_file) == -1){
651 system_error("can't change current working directory "
652 "to: %s", output_file);
653 goto strip_file_return;
655 p = rindex(input_file, '/');
656 rename_file = makestr(p + 1, NULL);
659 * Create what might be a short enough name.
661 free(output_file);
662 output_file = makestr("strip.XXXXXX", NULL);
663 output_file = mktemp(output_file);
665 #endif /* NMEDIT */
666 writeout(archs, narchs, output_file, stat_buf.st_mode & 0777,
667 TRUE, FALSE, FALSE, NULL);
668 if(rename_file != NULL){
669 if(rename(output_file, rename_file) == -1)
670 system_error("can't move temporary file: %s to file: %s",
671 output_file, rename_file);
672 free(rename_file);
674 else{
675 if(rename(output_file, input_file) == -1)
676 system_error("can't move temporary file: %s to input "
677 "file: %s", output_file, input_file);
679 free(output_file);
680 output_file = NULL;
683 * If we changed the current working directory change back to
684 * the previous working directory.
686 if(cwd_fd != -1){
687 if(fchdir(cwd_fd) == -1)
688 system_error("can't change back to previous working "
689 "directory");
690 if(close(cwd_fd) == -1)
691 system_error("can't close previous working directory");
695 #ifndef NMEDIT
696 strip_file_return:
697 #endif /* !defined(NMEDIT) */
698 /* clean-up data structures */
699 free_archs(archs, narchs);
701 errors += previous_errors;
704 static
705 void
706 strip_arch(
707 struct arch *archs,
708 unsigned long narchs,
709 struct arch_flag *arch_flags,
710 unsigned long narch_flags,
711 enum bool all_archs)
713 unsigned long i, j, k, offset, size, missing_syms;
714 cpu_type_t cputype;
715 cpu_subtype_t cpusubtype;
716 struct arch_flag host_arch_flag;
717 enum bool arch_process, any_processing, *arch_flag_processed, family;
718 const struct arch_flag *family_arch_flag;
721 * Using the specified arch_flags process specified objects for those
722 * architecures.
724 any_processing = FALSE;
725 arch_flag_processed = NULL;
726 if(narch_flags != 0)
727 arch_flag_processed = allocate(narch_flags * sizeof(enum bool));
728 memset(arch_flag_processed, '\0', narch_flags * sizeof(enum bool));
729 for(i = 0; i < narchs; i++){
731 * Determine the architecture (cputype and cpusubtype) of arch[i]
733 cputype = 0;
734 cpusubtype = 0;
735 if(archs[i].type == OFILE_ARCHIVE){
736 for(j = 0; j < archs[i].nmembers; j++){
737 if(archs[i].members[j].type == OFILE_Mach_O){
738 cputype = archs[i].members[j].object->mh_cputype;
739 cpusubtype = archs[i].members[j].object->mh_cpusubtype;
740 break;
744 else if(archs[i].type == OFILE_Mach_O){
745 cputype = archs[i].object->mh_cputype;
746 cpusubtype = archs[i].object->mh_cpusubtype;
748 else if(archs[i].fat_arch != NULL){
749 cputype = archs[i].fat_arch->cputype;
750 cpusubtype = archs[i].fat_arch->cpusubtype;
752 arch_process = FALSE;
753 if(all_archs == TRUE){
754 arch_process = TRUE;
756 else if(narch_flags != 0){
757 family = FALSE;
758 if(narch_flags == 1){
759 family_arch_flag =
760 get_arch_family_from_cputype(arch_flags[0].cputype);
761 if(family_arch_flag != NULL)
762 family = (enum bool)
763 ((family_arch_flag->cpusubtype & ~CPU_SUBTYPE_MASK) ==
764 (arch_flags[0].cpusubtype & ~CPU_SUBTYPE_MASK));
766 for(j = 0; j < narch_flags; j++){
767 if(arch_flags[j].cputype == cputype &&
768 ((arch_flags[j].cpusubtype & ~CPU_SUBTYPE_MASK) ==
769 (cpusubtype & ~CPU_SUBTYPE_MASK) ||
770 family == TRUE)){
771 arch_process = TRUE;
772 arch_flag_processed[j] = TRUE;
773 break;
777 else{
778 (void)get_arch_from_host(&host_arch_flag, NULL);
779 if(host_arch_flag.cputype == cputype &&
780 (host_arch_flag.cpusubtype & ~CPU_SUBTYPE_MASK) ==
781 (cpusubtype & ~CPU_SUBTYPE_MASK))
782 arch_process = TRUE;
784 if(narchs != 1 && arch_process == FALSE)
785 continue;
786 any_processing = TRUE;
789 * Now this arch[i] has been selected to be processed so process it
790 * according to its type.
792 if(archs[i].type == OFILE_ARCHIVE){
793 for(j = 0; j < archs[i].nmembers; j++){
794 if(archs[i].members[j].type == OFILE_Mach_O){
795 strip_object(archs + i, archs[i].members + j,
796 archs[i].members[j].object);
799 missing_syms = 0;
800 if(iflag == 0){
801 for(k = 0; k < nsave_symbols; k++){
802 if(save_symbols[k].seen == FALSE){
803 if(missing_syms == 0){
804 error_arch(archs + i, NULL, "symbols names "
805 "listed in: %s not in: ", sfile);
806 missing_syms = 1;
808 fprintf(stderr, "%s\n", save_symbols[k].name);
812 for(k = 0; k < nsave_symbols; k++){
813 save_symbols[k].seen = FALSE;
815 missing_syms = 0;
816 if(iflag == 0){
817 for(k = 0; k < nremove_symbols; k++){
818 if(remove_symbols[k].seen == FALSE){
819 if(missing_syms == 0){
820 error_arch(archs + i, NULL, "symbols names "
821 "listed in: %s not defined in: ",
822 Rfile);
823 missing_syms = 1;
825 fprintf(stderr, "%s\n", remove_symbols[k].name);
829 for(k = 0; k < nremove_symbols; k++){
830 remove_symbols[k].seen = FALSE;
833 * Reset the library offsets and size.
835 offset = 0;
836 for(j = 0; j < archs[i].nmembers; j++){
837 archs[i].members[j].offset = offset;
838 size = 0;
839 if(archs[i].members[j].member_long_name == TRUE){
840 size = round(archs[i].members[j].member_name_size, 8) +
841 (round(sizeof(struct ar_hdr), 8) -
842 sizeof(struct ar_hdr));
843 archs[i].toc_long_name = TRUE;
845 if(archs[i].members[j].object != NULL){
846 size +=
847 round(archs[i].members[j].object->object_size -
848 archs[i].members[j].object->input_sym_info_size +
849 archs[i].members[j].object->output_sym_info_size,
851 sprintf(archs[i].members[j].ar_hdr->ar_size, "%-*ld",
852 (int)sizeof(archs[i].members[j].ar_hdr->ar_size),
853 (long)(size));
855 * This has to be done by hand because sprintf puts a
856 * null at the end of the buffer.
858 memcpy(archs[i].members[j].ar_hdr->ar_fmag, ARFMAG,
859 (int)sizeof(archs[i].members[j].ar_hdr->ar_fmag));
861 else{
862 size += archs[i].members[j].unknown_size;
864 offset += sizeof(struct ar_hdr) + size;
866 archs[i].library_size = offset;
868 else if(archs[i].type == OFILE_Mach_O){
869 strip_object(archs + i, NULL, archs[i].object);
871 else {
872 warning_arch(archs + i, NULL, "can't process non-object and "
873 "non-archive file: ");
874 return;
877 if(all_archs == FALSE && narch_flags != 0){
878 for(i = 0; i < narch_flags; i++){
879 if(arch_flag_processed[i] == FALSE)
880 error("file: %s does not contain architecture: %s",
881 archs[0].file_name, arch_flags[i].name);
883 free(arch_flag_processed);
885 if(any_processing == FALSE)
886 fatal("no processing done on input file: %s (specify a -arch flag)",
887 archs[0].file_name);
890 static
891 void
892 strip_object(
893 struct arch *arch,
894 struct member *member,
895 struct object *object)
897 enum byte_sex host_byte_sex;
898 struct nlist *symbols;
899 struct nlist_64 *symbols64;
900 unsigned long nsyms;
901 char *strings;
902 unsigned long strsize;
903 unsigned long offset;
904 struct dylib_table_of_contents *tocs;
905 unsigned long ntoc;
906 struct dylib_module *mods;
907 struct dylib_module_64 *mods64;
908 unsigned long nmodtab;
909 struct dylib_reference *refs;
910 unsigned long nextrefsyms;
911 uint32_t *indirectsyms;
912 unsigned long nindirectsyms;
913 unsigned long i, j;
914 struct load_command *lc;
915 struct segment_command *sg;
916 struct segment_command_64 *sg64;
917 struct section *s;
918 struct section_64 *s64;
919 struct relocation_info *relocs;
920 struct scattered_relocation_info *sreloc;
921 long missing_reloc_symbols;
922 unsigned long stride, section_type, nitems;
923 char *contents;
924 #ifndef NMEDIT
925 uint32_t flags;
926 unsigned long k;
927 #endif
928 uint32_t ncmds;
930 host_byte_sex = get_host_byte_sex();
932 /* Don't do anything to stub dylibs which have no load commands. */
933 if(object->mh_filetype == MH_DYLIB_STUB){
934 if((object->mh != NULL && object->mh->ncmds == 0) ||
935 (object->mh64 != NULL && object->mh64->ncmds == 0)){
936 return;
939 if(object->st == NULL || object->st->nsyms == 0){
940 warning_arch(arch, member, "input object file stripped: ");
941 return;
944 nsyms = object->st->nsyms;
945 if(object->mh != NULL){
946 symbols = (struct nlist *)
947 (object->object_addr + object->st->symoff);
948 if(object->object_byte_sex != host_byte_sex)
949 swap_nlist(symbols, nsyms, host_byte_sex);
950 symbols64 = NULL;
952 else{
953 symbols = NULL;
954 symbols64 = (struct nlist_64 *)
955 (object->object_addr + object->st->symoff);
956 if(object->object_byte_sex != host_byte_sex)
957 swap_nlist_64(symbols64, nsyms, host_byte_sex);
959 strings = object->object_addr + object->st->stroff;
960 strsize = object->st->strsize;
962 #ifndef NMEDIT
963 if(object->mh != NULL)
964 flags = object->mh->flags;
965 else
966 flags = object->mh64->flags;
967 if(object->mh_filetype == MH_DYLIB &&
968 (flags & MH_PREBOUND) != MH_PREBOUND){
969 arch->dont_update_LC_ID_DYLIB_timestamp = TRUE;
971 if(object->mh_filetype != MH_DYLIB && cflag)
972 fatal_arch(arch, member, "-c can't be used on non-dynamic "
973 "library: ");
974 #endif /* !(NMEDIT) */
975 if(object->mh_filetype == MH_DYLIB_STUB)
976 fatal_arch(arch, member, "dynamic stub library can't be changed "
977 "once created: ");
979 if(object->mh_filetype == MH_DYLIB){
980 tocs = (struct dylib_table_of_contents *)
981 (object->object_addr + object->dyst->tocoff);
982 ntoc = object->dyst->ntoc;
983 nmodtab = object->dyst->nmodtab;
984 if(object->mh != NULL){
985 mods = (struct dylib_module *)
986 (object->object_addr + object->dyst->modtaboff);
987 if(object->object_byte_sex != host_byte_sex)
988 swap_dylib_module(mods, nmodtab, host_byte_sex);
989 mods64 = NULL;
991 else{
992 mods = NULL;
993 mods64 = (struct dylib_module_64 *)
994 (object->object_addr + object->dyst->modtaboff);
995 if(object->object_byte_sex != host_byte_sex)
996 swap_dylib_module_64(mods64, nmodtab, host_byte_sex);
998 refs = (struct dylib_reference *)
999 (object->object_addr + object->dyst->extrefsymoff);
1000 nextrefsyms = object->dyst->nextrefsyms;
1001 if(object->object_byte_sex != host_byte_sex){
1002 swap_dylib_table_of_contents(tocs, ntoc, host_byte_sex);
1003 swap_dylib_reference(refs, nextrefsyms, host_byte_sex);
1005 #ifndef NMEDIT
1007 * In the -c flag is specified then strip the section contents of
1008 * this dynamic library and change it into a stub library. When
1009 * creating a stub library the timestamp is not changed.
1011 if(cflag){
1012 arch->dont_update_LC_ID_DYLIB_timestamp = TRUE;
1014 lc = object->load_commands;
1015 if(object->mh != NULL){
1016 ncmds = object->mh->ncmds;
1017 object->mh_filetype = MH_DYLIB_STUB;
1018 object->mh->filetype = MH_DYLIB_STUB;
1020 else{
1021 ncmds = object->mh64->ncmds;
1022 object->mh_filetype = MH_DYLIB_STUB;
1023 object->mh64->filetype = MH_DYLIB_STUB;
1025 for(i = 0; i < ncmds; i++){
1026 if(lc->cmd == LC_SEGMENT){
1027 sg = (struct segment_command *)lc;
1028 if(strcmp(sg->segname, SEG_LINKEDIT) != 0){
1030 * Zero out the section offset, reloff, and size
1031 * fields as the section contents are being removed.
1033 s = (struct section *)
1034 ((char *)sg + sizeof(struct segment_command));
1035 for(j = 0; j < sg->nsects; j++){
1037 * For section types with indirect tables we
1038 * do not zero out the section size in a stub
1039 * library. As the section size is needed to
1040 * know now many indirect table entries the
1041 * section has. This is a bit odd but programs
1042 * dealing with MH_DYLIB_STUB filetypes special
1043 * case this.
1045 section_type = s[j].flags & SECTION_TYPE;
1046 if(section_type != S_SYMBOL_STUBS &&
1047 section_type != S_LAZY_SYMBOL_POINTERS &&
1048 section_type != S_NON_LAZY_SYMBOL_POINTERS){
1049 s[j].size = 0;
1051 s[j].addr = 0;
1052 s[j].offset = 0;
1053 s[j].reloff = 0;
1055 /* zero out file offset and size in the segment */
1056 sg->fileoff = 0;
1057 sg->filesize = 0;
1060 else if(lc->cmd == LC_SEGMENT_64){
1061 sg64 = (struct segment_command_64 *)lc;
1062 if(strcmp(sg64->segname, SEG_LINKEDIT) != 0){
1064 * Zero out the section offset, reloff, and size
1065 * fields as the section contents are being removed.
1067 s64 = (struct section_64 *)
1068 ((char *)sg64 +
1069 sizeof(struct segment_command_64));
1070 for(j = 0; j < sg64->nsects; j++){
1072 * For section types with indirect tables we
1073 * do not zero out the section size in a stub
1074 * library. As the section size is needed to
1075 * know now many indirect table entries the
1076 * section has. This is a bit odd but programs
1077 * dealing with MH_DYLIB_STUB filetypes special
1078 * case this.
1080 section_type = s64[j].flags & SECTION_TYPE;
1081 if(section_type != S_SYMBOL_STUBS &&
1082 section_type != S_LAZY_SYMBOL_POINTERS &&
1083 section_type != S_NON_LAZY_SYMBOL_POINTERS){
1084 s64[j].size = 0;
1086 s64[j].addr = 0;
1087 s64[j].offset = 0;
1088 s64[j].reloff = 0;
1090 /* zero out file offset and size in the segment */
1091 sg64->fileoff = 0;
1092 sg64->filesize = 0;
1095 lc = (struct load_command *)((char *)lc + lc->cmdsize);
1098 * To get the right amount of the file copied out by writeout()
1099 * for the case when we are stripping out the section contents
1100 * we reduce the object size by the size of the section contents
1101 * including the padding after the load commands. Then this
1102 * size minus the size of the input symbolic information is
1103 * copied out.
1105 if(object->mh != NULL){
1106 object->object_size -= (object->seg_linkedit->fileoff -
1107 (sizeof(struct mach_header) +
1108 object->mh->sizeofcmds));
1110 * Set the file offset to the link edit information to be
1111 * right after the load commands.
1113 object->seg_linkedit->fileoff =
1114 sizeof(struct mach_header) +
1115 object->mh->sizeofcmds;
1117 else{
1118 object->object_size -= (object->seg_linkedit64->fileoff -
1119 (sizeof(struct mach_header_64) +
1120 object->mh64->sizeofcmds));
1122 * Set the file offset to the link edit information to be
1123 * right after the load commands.
1125 object->seg_linkedit64->fileoff =
1126 sizeof(struct mach_header_64) +
1127 object->mh64->sizeofcmds;
1130 #endif /* !(NMEDIT) */
1132 else{
1133 tocs = NULL;
1134 ntoc = 0;
1135 mods = NULL;
1136 mods64 = NULL;
1137 nmodtab = 0;
1138 refs = NULL;
1139 nextrefsyms = 0;
1143 * coalesced symbols can be stripped only if they are not used via an
1144 * symbol pointer. So to know that strip_symtab() needs to be passed
1145 * the indirect symbol table.
1147 if(object->dyst != NULL && object->dyst->nindirectsyms != 0){
1148 nindirectsyms = object->dyst->nindirectsyms;
1149 indirectsyms = (uint32_t *)
1150 (object->object_addr + object->dyst->indirectsymoff);
1151 if(object->object_byte_sex != host_byte_sex)
1152 swap_indirect_symbols(indirectsyms, nindirectsyms,
1153 host_byte_sex);
1155 else{
1156 indirectsyms = NULL;
1157 nindirectsyms = 0;
1160 if(object->mh != NULL)
1161 object->input_sym_info_size =
1162 nsyms * sizeof(struct nlist) +
1163 strsize;
1164 else
1165 object->input_sym_info_size =
1166 nsyms * sizeof(struct nlist_64) +
1167 strsize;
1168 #ifndef NMEDIT
1169 if(object->mh != NULL)
1170 flags = object->mh->flags;
1171 else
1172 flags = object->mh64->flags;
1173 if(strip_all &&
1174 (flags & MH_DYLDLINK) == MH_DYLDLINK &&
1175 object->mh_filetype == MH_EXECUTE)
1176 default_dyld_executable = TRUE;
1177 else
1178 default_dyld_executable = FALSE;
1179 #endif /* !defined(NMEDIT) */
1181 #ifndef NMEDIT
1182 if(sfile != NULL || Rfile != NULL || dfile != NULL || Aflag || uflag ||
1183 Sflag || xflag || Xflag || nflag || rflag ||
1184 default_dyld_executable || object->mh_filetype == MH_DYLIB ||
1185 object->mh_filetype == MH_DYLINKER)
1186 #endif /* !defined(NMEDIT) */
1188 #ifdef NMEDIT
1189 if(edit_symtab(arch, member, object, symbols, symbols64, nsyms,
1190 strings, strsize, tocs, ntoc, mods, mods64, nmodtab, refs,
1191 nextrefsyms) == FALSE)
1192 return;
1193 #else /* !defined(NMEDIT) */
1194 if(strip_symtab(arch, member, object, symbols, symbols64, nsyms,
1195 strings, strsize, tocs, ntoc, mods, mods64, nmodtab, refs,
1196 nextrefsyms, indirectsyms, nindirectsyms) == FALSE)
1197 return;
1198 if(no_uuid == TRUE)
1199 strip_LC_UUID_commands(arch, member, object);
1200 #endif /* !defined(NMEDIT) */
1201 if(object->mh != NULL)
1202 object->output_sym_info_size =
1203 new_nsyms * sizeof(struct nlist) +
1204 new_strsize;
1205 else
1206 object->output_sym_info_size =
1207 new_nsyms * sizeof(struct nlist_64) +
1208 new_strsize;
1210 object->st->nsyms = new_nsyms;
1211 object->st->strsize = new_strsize;
1213 if(object->mh != NULL)
1214 object->output_symbols = new_symbols;
1215 else
1216 object->output_symbols64 = new_symbols64;
1217 object->output_nsymbols = new_nsyms;
1218 object->output_strings = new_strings;
1219 object->output_strings_size = new_strsize;
1221 if(object->split_info_cmd != NULL){
1222 object->output_split_info_data = object->object_addr +
1223 object->split_info_cmd->dataoff;
1224 object->output_split_info_data_size =
1225 object->split_info_cmd->datasize;
1227 if(object->code_sig_cmd != NULL){
1228 #ifndef NMEDIT
1229 if(!cflag)
1230 #endif /* !(NMEDIT) */
1232 object->output_code_sig_data = object->object_addr +
1233 object->code_sig_cmd->dataoff;
1234 object->output_code_sig_data_size =
1235 object->code_sig_cmd->datasize;
1239 if(object->dyst != NULL){
1240 object->dyst->ilocalsym = 0;
1241 object->dyst->nlocalsym = new_nlocalsym;
1242 object->dyst->iextdefsym = new_nlocalsym;
1243 object->dyst->nextdefsym = new_nextdefsym;
1244 object->dyst->iundefsym = new_nlocalsym + new_nextdefsym;
1245 object->dyst->nundefsym = new_nundefsym;
1246 if(object->dyst->nindirectsyms != 0){
1247 object->output_indirect_symtab = indirectsyms;
1248 if(object->object_byte_sex != host_byte_sex)
1249 swap_indirect_symbols(indirectsyms, nindirectsyms,
1250 object->object_byte_sex);
1254 * If the -c option is specified the object's filetype will
1255 * have been changed from MH_DYLIB to MH_DYLIB_STUB above.
1257 if(object->mh_filetype == MH_DYLIB ||
1258 object->mh_filetype == MH_DYLIB_STUB){
1259 object->output_tocs = new_tocs;
1260 object->output_ntoc = new_ntoc;
1261 #ifdef NMEDIT
1262 if(object->mh != NULL)
1263 object->output_mods = new_mods;
1264 else
1265 object->output_mods64 = new_mods64;
1266 object->output_nmodtab = new_nmodtab;
1267 #else
1268 object->output_mods = mods;
1269 object->output_nmodtab = nmodtab;
1270 #endif
1271 object->output_refs = new_refs;
1272 object->output_nextrefsyms = new_nextrefsyms;
1273 if(object->object_byte_sex != host_byte_sex){
1274 swap_dylib_table_of_contents(new_tocs, new_ntoc,
1275 object->object_byte_sex);
1276 #ifdef NMEDIT
1277 if(object->mh != NULL)
1278 swap_dylib_module(new_mods, new_nmodtab,
1279 object->object_byte_sex);
1280 else
1281 swap_dylib_module_64(new_mods64, new_nmodtab,
1282 object->object_byte_sex);
1283 #else
1284 if(object->mh != NULL)
1285 swap_dylib_module(mods, nmodtab,
1286 object->object_byte_sex);
1287 else
1288 swap_dylib_module_64(mods64, nmodtab,
1289 object->object_byte_sex);
1290 #endif
1291 swap_dylib_reference(new_refs, new_nextrefsyms,
1292 object->object_byte_sex);
1295 object->input_sym_info_size +=
1296 object->dyst->nlocrel * sizeof(struct relocation_info) +
1297 object->dyst->nextrel * sizeof(struct relocation_info) +
1298 object->dyst->ntoc * sizeof(struct dylib_table_of_contents)+
1299 object->dyst->nextrefsyms * sizeof(struct dylib_reference);
1300 if(object->mh != NULL){
1301 object->input_sym_info_size +=
1302 object->dyst->nmodtab * sizeof(struct dylib_module) +
1303 object->dyst->nindirectsyms * sizeof(uint32_t);
1305 else{
1306 object->input_sym_info_size +=
1307 object->dyst->nmodtab * sizeof(struct dylib_module_64) +
1308 object->dyst->nindirectsyms * sizeof(uint32_t) +
1309 object->input_indirectsym_pad;
1311 #ifndef NMEDIT
1313 * When stripping out the section contents to create a
1314 * dynamic library stub the relocation info also gets
1315 * stripped.
1317 if(!cflag)
1318 #endif /* !(NMEDIT) */
1320 object->output_sym_info_size +=
1321 object->dyst->nlocrel * sizeof(struct relocation_info) +
1322 object->dyst->nextrel * sizeof(struct relocation_info);
1324 object->output_sym_info_size +=
1325 new_ntoc * sizeof(struct dylib_table_of_contents)+
1326 new_nextrefsyms * sizeof(struct dylib_reference) +
1327 object->dyst->nindirectsyms * sizeof(uint32_t) +
1328 object->input_indirectsym_pad;
1329 if(object->mh != NULL){
1330 object->output_sym_info_size +=
1331 object->dyst->nmodtab * sizeof(struct dylib_module);
1333 else{
1334 object->output_sym_info_size +=
1335 object->dyst->nmodtab * sizeof(struct dylib_module_64);
1337 if(object->hints_cmd != NULL){
1338 object->input_sym_info_size +=
1339 object->hints_cmd->nhints *
1340 sizeof(struct twolevel_hint);
1341 object->output_sym_info_size +=
1342 object->hints_cmd->nhints *
1343 sizeof(struct twolevel_hint);
1345 if(object->split_info_cmd != NULL){
1346 object->input_sym_info_size +=
1347 object->split_info_cmd->datasize;
1348 object->output_sym_info_size +=
1349 object->split_info_cmd->datasize;
1351 if(object->code_sig_cmd != NULL){
1352 object->input_sym_info_size =
1353 round(object->input_sym_info_size, 16);
1354 object->input_sym_info_size +=
1355 object->code_sig_cmd->datasize;
1356 #ifndef NMEDIT
1357 if(cflag){
1358 strip_LC_CODE_SIGNATURE_commands(arch, member, object);
1360 else
1361 #endif /* !(NMEDIT) */
1363 object->output_sym_info_size =
1364 round(object->output_sym_info_size, 16);
1365 object->output_sym_info_size +=
1366 object->code_sig_cmd->datasize;
1370 object->dyst->ntoc = new_ntoc;
1371 object->dyst->nextrefsyms = new_nextrefsyms;
1373 if(object->seg_linkedit != NULL ||
1374 object->seg_linkedit64 != NULL){
1375 if(object->mh != NULL)
1376 offset = object->seg_linkedit->fileoff;
1377 else
1378 offset = object->seg_linkedit64->fileoff;
1380 else{
1381 offset = ULONG_MAX;
1382 if(object->dyst->nlocrel != 0 &&
1383 object->dyst->locreloff < offset)
1384 offset = object->dyst->locreloff;
1385 if(object->st->nsyms != 0 &&
1386 object->st->symoff < offset)
1387 offset = object->st->symoff;
1388 if(object->dyst->nextrel != 0 &&
1389 object->dyst->extreloff < offset)
1390 offset = object->dyst->extreloff;
1391 if(object->dyst->nindirectsyms != 0 &&
1392 object->dyst->indirectsymoff < offset)
1393 offset = object->dyst->indirectsymoff;
1394 if(object->dyst->ntoc != 0 &&
1395 object->dyst->tocoff < offset)
1396 offset = object->dyst->tocoff;
1397 if(object->dyst->nmodtab != 0 &&
1398 object->dyst->modtaboff < offset)
1399 offset = object->dyst->modtaboff;
1400 if(object->dyst->nextrefsyms != 0 &&
1401 object->dyst->extrefsymoff < offset)
1402 offset = object->dyst->extrefsymoff;
1403 if(object->st->strsize != 0 &&
1404 object->st->stroff < offset)
1405 offset = object->st->stroff;
1408 if(object->dyst->nlocrel != 0){
1409 object->output_loc_relocs = (struct relocation_info *)
1410 (object->object_addr + object->dyst->locreloff);
1411 #ifndef NMEDIT
1413 * When stripping out the section contents to create a
1414 * dynamic library stub the relocation info also gets
1415 * stripped.
1417 if(cflag){
1418 object->dyst->nlocrel = 0;
1419 object->dyst->locreloff = 0;
1421 else
1422 #endif /* defined(NMEDIT) */
1424 object->dyst->locreloff = offset;
1425 offset += object->dyst->nlocrel *
1426 sizeof(struct relocation_info);
1429 else
1430 object->dyst->locreloff = 0;
1432 if(object->split_info_cmd != NULL){
1433 object->split_info_cmd->dataoff = offset;
1434 offset += object->split_info_cmd->datasize;
1437 if(object->st->nsyms != 0){
1438 object->st->symoff = offset;
1439 if(object->mh != NULL)
1440 offset += object->st->nsyms * sizeof(struct nlist);
1441 else
1442 offset += object->st->nsyms * sizeof(struct nlist_64);
1444 else
1445 object->st->symoff = 0;
1447 if(object->hints_cmd != NULL){
1448 if(object->hints_cmd->nhints != 0){
1449 object->output_hints = (struct twolevel_hint *)
1450 (object->object_addr + object->hints_cmd->offset);
1451 object->hints_cmd->offset = offset;
1452 offset += object->hints_cmd->nhints *
1453 sizeof(struct twolevel_hint);
1455 else
1456 object->hints_cmd->offset = 0;
1459 if(object->dyst->nextrel != 0){
1460 object->output_ext_relocs = (struct relocation_info *)
1461 (object->object_addr + object->dyst->extreloff);
1462 #ifndef NMEDIT
1464 * When stripping out the section contents to create a
1465 * dynamic library stub the relocation info also gets
1466 * stripped.
1468 if(cflag){
1469 object->dyst->nextrel = 0;
1470 object->dyst->extreloff = 0;
1472 else
1473 #endif /* defined(NMEDIT) */
1475 object->dyst->extreloff = offset;
1476 offset += object->dyst->nextrel *
1477 sizeof(struct relocation_info);
1480 else
1481 object->dyst->extreloff = 0;
1483 if(object->dyst->nindirectsyms != 0){
1484 object->dyst->indirectsymoff = offset;
1485 offset += object->dyst->nindirectsyms * sizeof(uint32_t) +
1486 object->input_indirectsym_pad;
1488 else
1489 object->dyst->indirectsymoff = 0;;
1491 if(object->dyst->ntoc != 0){
1492 object->dyst->tocoff = offset;
1493 offset += object->dyst->ntoc *
1494 sizeof(struct dylib_table_of_contents);
1496 else
1497 object->dyst->tocoff = 0;
1499 if(object->dyst->nmodtab != 0){
1500 #ifndef NMEDIT
1502 * When stripping out the section contents to create a
1503 * dynamic library stub zero out the fields in the module
1504 * table for the sections and relocation information and
1505 * clear Objective-C address and size from modules.
1507 if(cflag){
1508 if(object->mh != NULL){
1509 for(k = 0; k < object->dyst->nmodtab; k++){
1510 mods[k].iinit_iterm = 0;
1511 mods[k].ninit_nterm = 0;
1512 mods[k].iextrel = 0;
1513 mods[k].nextrel = 0;
1514 mods[k].objc_module_info_addr = 0;
1515 mods[k].objc_module_info_size = 0;
1518 else{
1519 for(k = 0; k < object->dyst->nmodtab; k++){
1520 mods64[k].iinit_iterm = 0;
1521 mods64[k].ninit_nterm = 0;
1522 mods64[k].iextrel = 0;
1523 mods64[k].nextrel = 0;
1524 mods64[k].objc_module_info_addr = 0;
1525 mods64[k].objc_module_info_size = 0;
1529 #endif /* !(NMEDIT) */
1530 object->dyst->modtaboff = offset;
1531 if(object->mh != NULL)
1532 offset += object->dyst->nmodtab *
1533 sizeof(struct dylib_module);
1534 else
1535 offset += object->dyst->nmodtab *
1536 sizeof(struct dylib_module_64);
1538 else
1539 object->dyst->modtaboff = 0;
1541 if(object->dyst->nextrefsyms != 0){
1542 object->dyst->extrefsymoff = offset;
1543 offset += object->dyst->nextrefsyms *
1544 sizeof(struct dylib_reference);
1546 else
1547 object->dyst->extrefsymoff = 0;
1549 if(object->st->strsize != 0){
1550 object->st->stroff = offset;
1551 offset += object->st->strsize;
1553 else
1554 object->st->stroff = 0;
1556 if(object->code_sig_cmd != NULL){
1557 offset = round(offset, 16);
1558 object->code_sig_cmd->dataoff = offset;
1559 offset += object->code_sig_cmd->datasize;
1562 else{
1563 if(new_strsize != 0){
1564 if(object->mh != NULL)
1565 object->st->stroff = object->st->symoff +
1566 new_nsyms * sizeof(struct nlist);
1567 else
1568 object->st->stroff = object->st->symoff +
1569 new_nsyms * sizeof(struct nlist_64);
1571 else
1572 object->st->stroff = 0;
1573 if(new_nsyms == 0)
1574 object->st->symoff = 0;
1577 #ifndef NMEDIT
1578 else{
1579 if(saves != NULL)
1580 free(saves);
1581 saves = (long *)allocate(object->st->nsyms * sizeof(long));
1582 bzero(saves, object->st->nsyms * sizeof(long));
1584 object->output_sym_info_size = 0;
1585 object->st->symoff = 0;
1586 object->st->nsyms = 0;
1587 object->st->stroff = 0;
1588 object->st->strsize = 0;
1589 if(object->dyst != NULL){
1590 object->dyst->ilocalsym = 0;
1591 object->dyst->nlocalsym = 0;
1592 object->dyst->iextdefsym = 0;
1593 object->dyst->nextdefsym = 0;
1594 object->dyst->iundefsym = 0;
1595 object->dyst->nundefsym = 0;
1598 * We set these so that checking can be done below to report the
1599 * symbols that can't be stripped because of relocation entries
1600 * or indirect symbol table entries. If these table are non-zero
1601 * number of entries it will be an error as we are trying to
1602 * strip everything.
1604 if(object->dyst != NULL){
1605 if(object->dyst->nextrel != 0){
1606 object->output_ext_relocs = (struct relocation_info *)
1607 (object->object_addr + object->dyst->extreloff);
1609 if(object->dyst->nindirectsyms != 0){
1610 object->output_indirect_symtab = (uint32_t *)
1611 (object->object_addr +
1612 object->dyst->indirectsymoff);
1613 if(object->object_byte_sex != host_byte_sex)
1614 swap_indirect_symbols(
1615 object->output_indirect_symtab,
1616 object->dyst->nindirectsyms,
1617 object->object_byte_sex);
1620 * Since this file has a dynamic symbol table and if this file
1621 * has local relocation entries on input make sure they are
1622 * there on output. This is a rare case that it will not have
1623 * external relocs or indirect symbols but can happen as is the
1624 * case with the dynamic linker itself.
1626 if(object->dyst->nlocrel != 0){
1627 object->output_loc_relocs = (struct relocation_info *)
1628 (object->object_addr + object->dyst->locreloff);
1629 object->output_sym_info_size +=
1630 object->dyst->nlocrel * sizeof(struct relocation_info);
1634 #endif /* !defined(NMEDIT) */
1637 * Always clear the prebind checksum if any when creating a new file.
1639 if(object->cs != NULL)
1640 object->cs->cksum = 0;
1642 if(object->seg_linkedit != NULL){
1643 object->seg_linkedit->filesize += object->output_sym_info_size -
1644 object->input_sym_info_size;
1645 object->seg_linkedit->vmsize = object->seg_linkedit->filesize;
1647 else if(object->seg_linkedit64 != NULL){
1648 /* Do this in two steps to avoid 32/64-bit casting problems. */
1649 object->seg_linkedit64->filesize -= object->input_sym_info_size;
1650 object->seg_linkedit64->filesize += object->output_sym_info_size;
1651 object->seg_linkedit64->vmsize = object->seg_linkedit64->filesize;
1655 * Check and update the external relocation entries to make sure
1656 * referenced symbols are not stripped and refer to the new symbol
1657 * table indexes.
1659 * The external relocation entries can be located in one of two places,
1660 * first off of the sections or second off of the dynamic symtab.
1662 missing_reloc_symbols = 0;
1663 lc = object->load_commands;
1664 if(object->mh != NULL)
1665 ncmds = object->mh->ncmds;
1666 else
1667 ncmds = object->mh64->ncmds;
1668 for(i = 0; i < ncmds; i++){
1669 if(lc->cmd == LC_SEGMENT &&
1670 object->seg_linkedit != (struct segment_command *)lc){
1671 sg = (struct segment_command *)lc;
1672 s = (struct section *)((char *)sg +
1673 sizeof(struct segment_command));
1674 for(j = 0; j < sg->nsects; j++){
1675 if(s->nreloc != 0){
1676 if(s->reloff + s->nreloc *
1677 sizeof(struct relocation_info) >
1678 object->object_size){
1679 fatal_arch(arch, member, "truncated or malformed "
1680 "object (relocation entries for section (%.16s,"
1681 "%.16s) extends past the end of the file)",
1682 s->segname, s->sectname);
1684 relocs = (struct relocation_info *)
1685 (object->object_addr + s->reloff);
1686 if(object->object_byte_sex != host_byte_sex)
1687 swap_relocation_info(relocs, s->nreloc,
1688 host_byte_sex);
1689 if(s->offset + s->size > object->object_size){
1690 fatal_arch(arch, member, "truncated or malformed "
1691 "object (contents of section (%.16s,"
1692 "%.16s) extends past the end of the file)",
1693 s->segname, s->sectname);
1695 contents = object->object_addr + s->offset;
1696 check_object_relocs(arch, member, object, s->segname,
1697 s->sectname, s->size, contents, relocs, s->nreloc,
1698 symbols, symbols64, nsyms, strings,
1699 &missing_reloc_symbols, host_byte_sex);
1700 if(object->object_byte_sex != host_byte_sex)
1701 swap_relocation_info(relocs, s->nreloc,
1702 object->object_byte_sex);
1704 s++;
1707 else if(lc->cmd == LC_SEGMENT_64 &&
1708 object->seg_linkedit64 != (struct segment_command_64 *)lc){
1709 sg64 = (struct segment_command_64 *)lc;
1710 s64 = (struct section_64 *)((char *)sg64 +
1711 sizeof(struct segment_command_64));
1712 for(j = 0; j < sg64->nsects; j++){
1713 if(s64->nreloc != 0){
1714 if(s64->reloff + s64->nreloc *
1715 sizeof(struct relocation_info) >
1716 object->object_size){
1717 fatal_arch(arch, member, "truncated or malformed "
1718 "object (relocation entries for section (%.16s,"
1719 "%.16s) extends past the end of the file)",
1720 s64->segname, s64->sectname);
1722 relocs = (struct relocation_info *)
1723 (object->object_addr + s64->reloff);
1724 if(object->object_byte_sex != host_byte_sex)
1725 swap_relocation_info(relocs, s64->nreloc,
1726 host_byte_sex);
1727 if(s64->offset + s64->size > object->object_size){
1728 fatal_arch(arch, member, "truncated or malformed "
1729 "object (contents of section (%.16s,"
1730 "%.16s) extends past the end of the file)",
1731 s64->segname, s64->sectname);
1733 contents = object->object_addr + s64->offset;
1734 check_object_relocs(arch, member, object, s64->segname,
1735 s64->sectname, s64->size, contents, relocs,
1736 s64->nreloc, symbols, symbols64, nsyms, strings,
1737 &missing_reloc_symbols, host_byte_sex);
1738 if(object->object_byte_sex != host_byte_sex)
1739 swap_relocation_info(relocs, s64->nreloc,
1740 object->object_byte_sex);
1742 s64++;
1745 lc = (struct load_command *)((char *)lc + lc->cmdsize);
1747 if(object->dyst != NULL && object->dyst->nextrel != 0){
1748 relocs = object->output_ext_relocs;
1749 if(object->object_byte_sex != host_byte_sex)
1750 swap_relocation_info(relocs, object->dyst->nextrel,
1751 host_byte_sex);
1753 for(i = 0; i < object->dyst->nextrel; i++){
1754 if((relocs[i].r_address & R_SCATTERED) == 0 &&
1755 relocs[i].r_extern == 1){
1756 if(relocs[i].r_symbolnum > nsyms){
1757 fatal_arch(arch, member, "bad r_symbolnum for external "
1758 "relocation entry %ld in: ", i);
1760 if(saves[relocs[i].r_symbolnum] == 0){
1761 if(missing_reloc_symbols == 0){
1762 error_arch(arch, member, "symbols referenced by "
1763 "relocation entries that can't be stripped in: ");
1764 missing_reloc_symbols = 1;
1766 if(object->mh != NULL){
1767 fprintf(stderr, "%s\n", strings + symbols
1768 [relocs[i].r_symbolnum].n_un.n_strx);
1770 else {
1771 fprintf(stderr, "%s\n", strings + symbols64
1772 [relocs[i].r_symbolnum].n_un.n_strx);
1774 saves[relocs[i].r_symbolnum] = -1;
1776 if(saves[relocs[i].r_symbolnum] != -1){
1777 relocs[i].r_symbolnum =
1778 saves[relocs[i].r_symbolnum] - 1;
1781 else{
1782 fatal_arch(arch, member, "bad external relocation entry "
1783 "%ld (not external) in: ", i);
1785 if((relocs[i].r_address & R_SCATTERED) == 0){
1786 if(reloc_has_pair(object->mh_cputype, relocs[i].r_type))
1787 i++;
1789 else{
1790 sreloc = (struct scattered_relocation_info *)relocs + i;
1791 if(reloc_has_pair(object->mh_cputype, sreloc->r_type))
1792 i++;
1795 if(object->object_byte_sex != host_byte_sex)
1796 swap_relocation_info(relocs, object->dyst->nextrel,
1797 object->object_byte_sex);
1801 * Check and update the indirect symbol table entries to make sure
1802 * referenced symbols are not stripped and refer to the new symbol
1803 * table indexes.
1805 if(object->dyst != NULL && object->dyst->nindirectsyms != 0){
1806 if(object->object_byte_sex != host_byte_sex)
1807 swap_indirect_symbols(object->output_indirect_symtab,
1808 object->dyst->nindirectsyms, host_byte_sex);
1810 lc = object->load_commands;
1811 if(object->mh != NULL)
1812 ncmds = object->mh->ncmds;
1813 else
1814 ncmds = object->mh64->ncmds;
1815 for(i = 0; i < ncmds; i++){
1816 if(lc->cmd == LC_SEGMENT &&
1817 object->seg_linkedit != (struct segment_command *)lc){
1818 sg = (struct segment_command *)lc;
1819 s = (struct section *)((char *)sg +
1820 sizeof(struct segment_command));
1821 for(j = 0; j < sg->nsects; j++){
1822 section_type = s->flags & SECTION_TYPE;
1823 if(section_type == S_LAZY_SYMBOL_POINTERS ||
1824 section_type == S_NON_LAZY_SYMBOL_POINTERS)
1825 stride = 4;
1826 else if(section_type == S_SYMBOL_STUBS)
1827 stride = s->reserved2;
1828 else{
1829 s++;
1830 continue;
1832 nitems = s->size / stride;
1833 contents = object->object_addr + s->offset;
1834 check_indirect_symtab(arch, member, object, nitems,
1835 s->reserved1, section_type, contents, symbols,
1836 symbols64, nsyms, strings, &missing_reloc_symbols,
1837 host_byte_sex);
1838 s++;
1841 else if(lc->cmd == LC_SEGMENT_64 &&
1842 object->seg_linkedit64 != (struct segment_command_64 *)lc){
1843 sg64 = (struct segment_command_64 *)lc;
1844 s64 = (struct section_64 *)((char *)sg64 +
1845 sizeof(struct segment_command_64));
1846 for(j = 0; j < sg64->nsects; j++){
1847 section_type = s64->flags & SECTION_TYPE;
1848 if(section_type == S_LAZY_SYMBOL_POINTERS ||
1849 section_type == S_NON_LAZY_SYMBOL_POINTERS)
1850 stride = 8;
1851 else if(section_type == S_SYMBOL_STUBS)
1852 stride = s64->reserved2;
1853 else{
1854 s64++;
1855 continue;
1857 nitems = s64->size / stride;
1858 contents = object->object_addr + s64->offset;
1859 check_indirect_symtab(arch, member, object, nitems,
1860 s64->reserved1, section_type, contents, symbols,
1861 symbols64, nsyms, strings, &missing_reloc_symbols,
1862 host_byte_sex);
1863 s64++;
1866 lc = (struct load_command *)((char *)lc + lc->cmdsize);
1869 if(object->object_byte_sex != host_byte_sex)
1870 swap_indirect_symbols(object->output_indirect_symtab,
1871 object->dyst->nindirectsyms, object->object_byte_sex);
1875 * Issue a warning if object file has a code signature that the
1876 * operation will invalidate it.
1878 if(object->code_sig_cmd != NULL)
1879 warning_arch(arch, member, "changes being made to the file will "
1880 "invalidate the code signature in: ");
1884 * check_object_relocs() is used to check and update the external relocation
1885 * entries from a section in an object file, to make sure referenced symbols
1886 * are not stripped and are changed to refer to the new symbol table indexes.
1888 static
1889 void
1890 check_object_relocs(
1891 struct arch *arch,
1892 struct member *member,
1893 struct object *object,
1894 char *segname,
1895 char *sectname,
1896 unsigned long long sectsize,
1897 char *contents,
1898 struct relocation_info *relocs,
1899 uint32_t nreloc,
1900 struct nlist *symbols,
1901 struct nlist_64 *symbols64,
1902 unsigned long nsyms,
1903 char *strings,
1904 long *missing_reloc_symbols,
1905 enum byte_sex host_byte_sex)
1907 unsigned long k, n_strx;
1908 uint64_t n_value;
1909 #ifdef NMEDIT
1910 unsigned long value, n_ext;
1911 uint64_t value64;
1912 #endif
1913 struct scattered_relocation_info *sreloc;
1915 for(k = 0; k < nreloc; k++){
1916 if((relocs[k].r_address & R_SCATTERED) == 0 &&
1917 relocs[k].r_extern == 1){
1918 if(relocs[k].r_symbolnum > nsyms){
1919 fatal_arch(arch, member, "bad r_symbolnum for relocation "
1920 "entry %ld in section (%.16s,%.16s) in: ", k, segname,
1921 sectname);
1923 if(object->mh != NULL){
1924 n_strx = symbols[relocs[k].r_symbolnum].n_un.n_strx;
1925 n_value = symbols[relocs[k].r_symbolnum].n_value;
1927 else{
1928 n_strx = symbols64[relocs[k].r_symbolnum].n_un.n_strx;
1929 n_value = symbols64[relocs[k].r_symbolnum].n_value;
1931 #ifndef NMEDIT
1932 if(saves[relocs[k].r_symbolnum] == 0){
1933 if(*missing_reloc_symbols == 0){
1934 error_arch(arch, member, "symbols referenced by "
1935 "relocation entries that can't be stripped in: ");
1936 *missing_reloc_symbols = 1;
1938 fprintf(stderr, "%s\n", strings + n_strx);
1939 saves[relocs[k].r_symbolnum] = -1;
1941 #else /* defined(NMEDIT) */
1943 * We are letting nmedit change global coalesed symbols into
1944 * statics in MH_OBJECT file types only. Relocation entries to
1945 * global coalesced symbols are external relocs.
1947 if(object->mh != NULL)
1948 n_ext = new_symbols[saves[relocs[k].r_symbolnum] - 1].
1949 n_type & N_EXT;
1950 else
1951 n_ext = new_symbols64[saves[relocs[k].r_symbolnum] - 1].
1952 n_type & N_EXT;
1953 if(n_ext != N_EXT &&
1954 object->mh_cputype != CPU_TYPE_X86_64){
1956 * We need to do the relocation for this external relocation
1957 * entry so the item to be relocated is correct for a local
1958 * relocation entry. We don't need to do this for x86-64.
1960 if(relocs[k].r_address + sizeof(long) > sectsize){
1961 fatal_arch(arch, member, "truncated or malformed "
1962 "object (r_address of relocation entry %lu of "
1963 "section (%.16s,%.16s) extends past the end "
1964 "of the section)", k, segname, sectname);
1966 if(object->mh != NULL){
1967 value = *(unsigned long *)
1968 (contents + relocs[k].r_address);
1969 if(object->object_byte_sex != host_byte_sex)
1970 value = SWAP_LONG(value);
1972 * We handle a very limited form here. Only VANILLA
1973 * (r_type == 0) long (r_length==2) absolute or pcrel
1974 * that won't need a scattered relocation entry.
1976 if(relocs[k].r_type != 0 ||
1977 relocs[k].r_length != 2){
1978 fatal_arch(arch, member, "don't have "
1979 "code to convert external relocation "
1980 "entry %ld in section (%.16s,%.16s) "
1981 "for global coalesced symbol: %s "
1982 "in: ", k, segname, sectname,
1983 strings + n_strx);
1985 value += n_value;
1986 if(object->object_byte_sex != host_byte_sex)
1987 value = SWAP_LONG(value);
1988 *(unsigned long *)(contents + relocs[k].r_address) =
1989 value;
1991 else{
1992 value64 = *(uint64_t *)(contents + relocs[k].r_address);
1993 if(object->object_byte_sex != host_byte_sex)
1994 value64 = SWAP_LONG_LONG(value64);
1996 * We handle a very limited form here. Only VANILLA
1997 * (r_type == 0) quad (r_length==3) absolute or pcrel
1998 * that won't need a scattered relocation entry.
2000 if(relocs[k].r_type != 0 ||
2001 relocs[k].r_length != 3){
2002 fatal_arch(arch, member, "don't have "
2003 "code to convert external relocation "
2004 "entry %ld in section (%.16s,%.16s) "
2005 "for global coalesced symbol: %s "
2006 "in: ", k, segname, sectname,
2007 strings + n_strx);
2009 value64 += n_value;
2010 if(object->object_byte_sex != host_byte_sex)
2011 value64 = SWAP_LONG_LONG(value);
2012 *(uint64_t *)(contents + relocs[k].r_address) = value64;
2015 * Turn the extern reloc into a local.
2017 if(object->mh != NULL)
2018 relocs[k].r_symbolnum =
2019 new_symbols[saves[relocs[k].r_symbolnum] - 1].n_sect;
2020 else
2021 relocs[k].r_symbolnum =
2022 new_symbols64[saves[relocs[k].r_symbolnum] - 1].n_sect;
2023 relocs[k].r_extern = 0;
2025 #endif /* NMEDIT */
2026 if(relocs[k].r_extern == 1 &&
2027 saves[relocs[k].r_symbolnum] != -1){
2028 relocs[k].r_symbolnum = saves[relocs[k].r_symbolnum] - 1;
2031 if((relocs[k].r_address & R_SCATTERED) == 0){
2032 if(reloc_has_pair(object->mh_cputype, relocs[k].r_type) == TRUE)
2033 k++;
2035 else{
2036 sreloc = (struct scattered_relocation_info *)relocs + k;
2037 if(reloc_has_pair(object->mh_cputype, sreloc->r_type) == TRUE)
2038 k++;
2044 * check_indirect_symtab() checks and updates the indirect symbol table entries
2045 * to make sure referenced symbols are not stripped and refer to the new symbol
2046 * table indexes.
2048 static
2049 void
2050 check_indirect_symtab(
2051 struct arch *arch,
2052 struct member *member,
2053 struct object *object,
2054 unsigned long nitems,
2055 unsigned long reserved1,
2056 unsigned long section_type,
2057 char *contents,
2058 struct nlist *symbols,
2059 struct nlist_64 *symbols64,
2060 unsigned long nsyms,
2061 char *strings,
2062 long *missing_reloc_symbols,
2063 enum byte_sex host_byte_sex)
2065 unsigned long k, index;
2066 uint8_t n_type;
2067 uint32_t n_strx, value;
2068 uint64_t value64;
2069 enum bool made_local;
2071 for(k = 0; k < nitems; k++){
2072 made_local = FALSE;
2073 index = object->output_indirect_symtab[reserved1 + k];
2074 if(index == INDIRECT_SYMBOL_LOCAL ||
2075 index == INDIRECT_SYMBOL_ABS ||
2076 index == (INDIRECT_SYMBOL_LOCAL | INDIRECT_SYMBOL_ABS))
2077 continue;
2078 if(index > nsyms)
2079 fatal_arch(arch, member,"indirect symbol table entry %ld (past " "the end of the symbol table) in: ", reserved1 + k);
2080 #ifdef NMEDIT
2081 if(pflag == 0 && nmedits[index] == TRUE && saves[index] != -1)
2082 #else
2083 if(saves[index] == 0)
2084 #endif
2087 * Indirect symbol table entries for defined symbols in a
2088 * non-lazy pointer section that are not saved are changed to
2089 * INDIRECT_SYMBOL_LOCAL which their values just have to be
2090 * slid if the are not absolute symbols.
2092 if(object->mh != NULL){
2093 n_type = symbols[index].n_type;
2094 n_strx = symbols[index].n_un.n_strx;
2096 else{
2097 n_type = symbols64[index].n_type;
2098 n_strx = symbols64[index].n_un.n_strx;
2100 if((n_type && N_TYPE) != N_UNDF &&
2101 (n_type && N_TYPE) != N_PBUD &&
2102 section_type == S_NON_LAZY_SYMBOL_POINTERS){
2103 object->output_indirect_symtab[reserved1 + k] =
2104 INDIRECT_SYMBOL_LOCAL;
2105 if((n_type & N_TYPE) == N_ABS)
2106 object->output_indirect_symtab[reserved1 + k] |=
2107 INDIRECT_SYMBOL_ABS;
2108 made_local = TRUE;
2110 * When creating a stub shared library the section contents
2111 * are not updated since they will be stripped.
2113 if(object->mh_filetype != MH_DYLIB_STUB){
2114 if(object->mh != NULL){
2115 value = symbols[index].n_value;
2116 if (symbols[index].n_desc & N_ARM_THUMB_DEF)
2117 value |= 1;
2118 if(object->object_byte_sex != host_byte_sex)
2119 value = SWAP_LONG(value);
2120 *(uint32_t *)(contents + k * 4) = value;
2122 else{
2123 value64 = symbols64[index].n_value;
2124 if(object->object_byte_sex != host_byte_sex)
2125 value64 = SWAP_LONG_LONG(value64);
2126 *(uint64_t *)(contents + k * 8) = value64;
2130 #ifdef NMEDIT
2131 else {
2132 object->output_indirect_symtab[reserved1 + k] =
2133 saves[index] - 1;
2135 #else /* !defined(NMEDIT) */
2136 else{
2137 if(*missing_reloc_symbols == 0){
2138 error_arch(arch, member, "symbols referenced by "
2139 "indirect symbol table entries that can't be "
2140 "stripped in: ");
2141 *missing_reloc_symbols = 1;
2143 fprintf(stderr, "%s\n", strings + n_strx);
2144 saves[index] = -1;
2146 #endif /* !defined(NMEDIT) */
2148 #ifdef NMEDIT
2149 else
2150 #else /* !defined(NMEDIT) */
2151 if(made_local == FALSE && saves[index] != -1)
2152 #endif /* !defined(NMEDIT) */
2154 object->output_indirect_symtab[reserved1+k] = saves[index] - 1;
2159 #ifndef NMEDIT
2161 * This is called if there is a -d option specified. It reads the file with
2162 * the strings in it and places them in the array debug_filenames and sorts
2163 * them by name. The file that contains the file names must have names one
2164 * per line with no white space (except the newlines).
2166 static
2167 void
2168 setup_debug_filenames(
2169 char *dfile)
2171 int fd, i, strings_size;
2172 struct stat stat_buf;
2173 char *strings, *p;
2175 if((fd = open(dfile, O_RDONLY)) < 0){
2176 system_error("can't open: %s", dfile);
2177 return;
2179 if(fstat(fd, &stat_buf) == -1){
2180 system_error("can't stat: %s", dfile);
2181 close(fd);
2182 return;
2184 strings_size = stat_buf.st_size;
2185 strings = (char *)allocate(strings_size + 1);
2186 strings[strings_size] = '\0';
2187 if(read(fd, strings, strings_size) != strings_size){
2188 system_error("can't read: %s", dfile);
2189 close(fd);
2190 return;
2192 p = strings;
2193 for(i = 0; i < strings_size; i++){
2194 if(*p == '\n'){
2195 *p = '\0';
2196 ndebug_filenames++;
2198 p++;
2200 debug_filenames = (char **)allocate(ndebug_filenames * sizeof(char *));
2201 p = strings;
2202 for(i = 0; i < ndebug_filenames; i++){
2203 debug_filenames[i] = p;
2204 p += strlen(p) + 1;
2206 qsort(debug_filenames, ndebug_filenames, sizeof(char *),
2207 (int (*)(const void *, const void *))cmp_qsort_filename);
2209 #ifdef DEBUG
2210 printf("Debug filenames:\n");
2211 for(i = 0; i < ndebug_filenames; i++){
2212 printf("filename = %s\n", debug_filenames[i]);
2214 #endif /* DEBUG */
2218 * Strip the symbol table to the level specified by the command line arguments.
2219 * The new symbol table is built and new_symbols is left pointing to it. The
2220 * number of new symbols is left in new_nsyms, the new string table is built
2221 * and new_stings is left pointing to it and new_strsize is left containing it.
2222 * This routine returns zero if successfull and non-zero otherwise.
2224 static
2225 enum bool
2226 strip_symtab(
2227 struct arch *arch,
2228 struct member *member,
2229 struct object *object,
2230 struct nlist *symbols,
2231 struct nlist_64 *symbols64,
2232 unsigned long nsyms,
2233 char *strings,
2234 unsigned long strsize,
2235 struct dylib_table_of_contents *tocs,
2236 unsigned long ntoc,
2237 struct dylib_module *mods,
2238 struct dylib_module_64 *mods64,
2239 unsigned long nmodtab,
2240 struct dylib_reference *refs,
2241 unsigned long nextrefsyms,
2242 uint32_t *indirectsyms,
2243 unsigned long nindirectsyms)
2245 unsigned long i, j, k, n, inew_syms, save_debug, missing_syms;
2246 unsigned long missing_symbols;
2247 char *p, *q, **pp, *basename;
2248 struct symbol_list *sp;
2249 unsigned long new_ext_strsize, len, *changes, inew_undefsyms;
2250 unsigned char nsects;
2251 struct load_command *lc;
2252 struct segment_command *sg;
2253 struct segment_command_64 *sg64;
2254 struct section *s, **sections;
2255 struct section_64 *s64, **sections64;
2256 uint32_t ncmds, mh_flags, s_flags, n_strx;
2257 struct nlist *sym;
2258 struct undef_map *undef_map;
2259 struct undef_map64 *undef_map64;
2260 uint8_t n_type, n_sect;
2261 uint16_t n_desc;
2262 uint64_t n_value;
2263 uint32_t module_name, iextdefsym, nextdefsym, ilocalsym, nlocalsym;
2264 uint32_t irefsym, nrefsym;
2266 save_debug = 0;
2267 if(saves != NULL)
2268 free(saves);
2269 saves = (long *)allocate(nsyms * sizeof(long));
2270 bzero(saves, nsyms * sizeof(long));
2271 changes = NULL;
2272 for(i = 0; i < nsave_symbols; i++)
2273 save_symbols[i].sym = NULL;
2274 for(i = 0; i < nremove_symbols; i++)
2275 remove_symbols[i].sym = NULL;
2276 if(member == NULL){
2277 for(i = 0; i < nsave_symbols; i++)
2278 save_symbols[i].seen = FALSE;
2279 for(i = 0; i < nremove_symbols; i++)
2280 remove_symbols[i].seen = FALSE;
2283 new_nsyms = 0;
2284 new_strsize = sizeof(long);
2285 new_nlocalsym = 0;
2286 new_nextdefsym = 0;
2287 new_nundefsym = 0;
2288 new_ext_strsize = 0;
2291 * Gather an array of section struct pointers so we can later determine
2292 * if we run into a global symbol in a coalesced section and not strip
2293 * those symbols.
2294 * statics.
2296 nsects = 0;
2297 lc = object->load_commands;
2298 if(object->mh != NULL)
2299 ncmds = object->mh->ncmds;
2300 else
2301 ncmds = object->mh64->ncmds;
2302 for(i = 0; i < ncmds; i++){
2303 if(lc->cmd == LC_SEGMENT){
2304 sg = (struct segment_command *)lc;
2305 nsects += sg->nsects;
2307 else if(lc->cmd == LC_SEGMENT_64){
2308 sg64 = (struct segment_command_64 *)lc;
2309 nsects += sg64->nsects;
2311 lc = (struct load_command *)((char *)lc + lc->cmdsize);
2313 if(object->mh != NULL){
2314 sections = allocate(nsects * sizeof(struct section *));
2315 sections64 = NULL;
2317 else{
2318 sections = NULL;
2319 sections64 = allocate(nsects * sizeof(struct section_64 *));
2321 nsects = 0;
2322 lc = object->load_commands;
2323 for(i = 0; i < ncmds; i++){
2324 if(lc->cmd == LC_SEGMENT){
2325 sg = (struct segment_command *)lc;
2326 s = (struct section *)((char *)sg +
2327 sizeof(struct segment_command));
2328 for(j = 0; j < sg->nsects; j++)
2329 sections[nsects++] = s++;
2331 else if(lc->cmd == LC_SEGMENT_64){
2332 sg64 = (struct segment_command_64 *)lc;
2333 s64 = (struct section_64 *)((char *)sg64 +
2334 sizeof(struct segment_command_64));
2335 for(j = 0; j < sg64->nsects; j++)
2336 sections64[nsects++] = s64++;
2338 lc = (struct load_command *)((char *)lc + lc->cmdsize);
2341 for(i = 0; i < nsyms; i++){
2342 s_flags = 0;
2343 if(object->mh != NULL){
2344 mh_flags = object->mh->flags;
2345 n_strx = symbols[i].n_un.n_strx;
2346 n_type = symbols[i].n_type;
2347 n_sect = symbols[i].n_sect;
2348 if((n_type & N_TYPE) == N_SECT){
2349 if(n_sect == 0 || n_sect > nsects){
2350 error_arch(arch, member, "bad n_sect for symbol "
2351 "table entry %ld in: ", i);
2352 return(FALSE);
2354 s_flags = sections[n_sect - 1]->flags;
2356 n_desc = symbols[i].n_desc;
2357 n_value = symbols[i].n_value;
2359 else{
2360 mh_flags = object->mh64->flags;
2361 n_strx = symbols64[i].n_un.n_strx;
2362 n_type = symbols64[i].n_type;
2363 n_sect = symbols64[i].n_sect;
2364 if((n_type & N_TYPE) == N_SECT){
2365 if(n_sect == 0 || n_sect > nsects){
2366 error_arch(arch, member, "bad n_sect for symbol "
2367 "table entry %ld in: ", i);
2368 return(FALSE);
2370 s_flags = sections64[n_sect - 1]->flags;
2372 n_desc = symbols64[i].n_desc;
2373 n_value = symbols64[i].n_value;
2375 if(n_strx != 0){
2376 if(n_strx > strsize){
2377 error_arch(arch, member, "bad string index for symbol "
2378 "table entry %ld in: ", i);
2379 return(FALSE);
2382 if((n_type & N_TYPE) == N_INDR){
2383 if(n_value != 0){
2384 if(n_value > strsize){
2385 error_arch(arch, member, "bad string index for "
2386 "indirect symbol table entry %ld in: ", i);
2387 return(FALSE);
2391 if((n_type & N_EXT) == 0){ /* local symbol */
2393 * strip -x or -X on an x86_64 .o file should do nothing.
2395 if(object->mh == NULL &&
2396 object->mh64->cputype == CPU_TYPE_X86_64 &&
2397 object->mh64->filetype == MH_OBJECT &&
2398 (xflag == 1 || Xflag == 1)){
2399 if(n_strx != 0)
2400 new_strsize += strlen(strings + n_strx) + 1;
2401 new_nlocalsym++;
2402 new_nsyms++;
2403 saves[i] = new_nsyms;
2406 * The cases a local symbol might be saved is with -X -S or
2407 * with -d filename.
2409 else if((!strip_all && (Xflag || Sflag)) || dfile){
2410 if(n_type & N_STAB){ /* debug symbol */
2411 if(dfile && n_type == N_SO){
2412 if(n_strx != 0){
2413 basename = strrchr(strings + n_strx, '/');
2414 if(basename != NULL)
2415 basename++;
2416 else
2417 basename = strings + n_strx;
2418 pp = bsearch(basename, debug_filenames,
2419 ndebug_filenames, sizeof(char *),
2420 (int (*)(const void *, const void *)
2421 )cmp_bsearch_filename);
2423 * Save the bracketing N_SO. For each N_SO that
2424 * has a filename there is an N_SO that has a
2425 * name of "" which ends the stabs for that file
2427 if(*basename != '\0'){
2428 if(pp != NULL)
2429 save_debug = 1;
2430 else
2431 save_debug = 0;
2433 else{
2435 * This is a bracketing SO so if we are
2436 * currently saving debug symbols save this
2437 * last one and turn off saving debug syms.
2439 if(save_debug){
2440 if(n_strx != 0)
2441 new_strsize += strlen(strings +
2442 n_strx) + 1;
2443 new_nlocalsym++;
2444 new_nsyms++;
2445 saves[i] = new_nsyms;
2447 save_debug = 0;
2450 else{
2451 save_debug = 0;
2454 if(saves[i] == 0 && (!Sflag || save_debug)){
2455 if(n_strx != 0)
2456 new_strsize += strlen(strings + n_strx) + 1;
2457 new_nlocalsym++;
2458 new_nsyms++;
2459 saves[i] = new_nsyms;
2462 else{ /* non-debug local symbol */
2463 if(xflag == 0 && (Sflag || Xflag)){
2464 if(Xflag == 0 ||
2465 (n_strx != 0 &&
2466 strings[n_strx] != 'L')){
2468 * If this file is a for the dynamic linker and
2469 * this symbol is in a section marked so that
2470 * static symbols are stripped then don't
2471 * keep this symbol.
2473 if((mh_flags & MH_DYLDLINK) != MH_DYLDLINK ||
2474 (n_type & N_TYPE) != N_SECT ||
2475 (s_flags & S_ATTR_STRIP_STATIC_SYMS) !=
2476 S_ATTR_STRIP_STATIC_SYMS){
2477 new_strsize += strlen(strings + n_strx) + 1;
2478 new_nlocalsym++;
2479 new_nsyms++;
2480 saves[i] = new_nsyms;
2485 * Treat a local symbol that was a private extern as if
2486 * were global if it is referenced by a module and save
2487 * it.
2489 if((n_type & N_PEXT) == N_PEXT){
2490 if(saves[i] == 0 &&
2491 private_extern_reference_by_module(
2492 i, refs ,nextrefsyms) == TRUE){
2493 if(n_strx != 0)
2494 new_strsize += strlen(strings + n_strx) + 1;
2495 new_nlocalsym++;
2496 new_nsyms++;
2497 saves[i] = new_nsyms;
2500 * We need to save symbols that were private externs
2501 * that are used with indirect symbols.
2503 if(saves[i] == 0 &&
2504 symbol_pointer_used(i, indirectsyms,
2505 nindirectsyms) == TRUE){
2506 if(n_strx != 0){
2507 len = strlen(strings + n_strx) + 1;
2508 new_strsize += len;
2510 new_nlocalsym++;
2511 new_nsyms++;
2512 saves[i] = new_nsyms;
2518 * Treat a local symbol that was a private extern as if were
2519 * global if it is not referenced by a module.
2521 else if((n_type & N_PEXT) == N_PEXT){
2522 if(saves[i] == 0 && sfile){
2523 sp = bsearch(strings + n_strx,
2524 save_symbols, nsave_symbols,
2525 sizeof(struct symbol_list),
2526 (int (*)(const void *, const void *))
2527 symbol_list_bsearch);
2528 if(sp != NULL){
2529 if(sp->sym == NULL){
2530 if(object->mh != NULL)
2531 sp->sym = &(symbols[i]);
2532 else
2533 sp->sym = &(symbols64[i]);
2534 sp->seen = TRUE;
2536 if(n_strx != 0)
2537 new_strsize += strlen(strings + n_strx) + 1;
2538 new_nlocalsym++;
2539 new_nsyms++;
2540 saves[i] = new_nsyms;
2543 if(saves[i] == 0 &&
2544 private_extern_reference_by_module(
2545 i, refs ,nextrefsyms) == TRUE){
2546 if(n_strx != 0)
2547 new_strsize += strlen(strings + n_strx) + 1;
2548 new_nlocalsym++;
2549 new_nsyms++;
2550 saves[i] = new_nsyms;
2553 * We need to save symbols that were private externs that
2554 * are used with indirect symbols.
2556 if(saves[i] == 0 &&
2557 symbol_pointer_used(i, indirectsyms, nindirectsyms) ==
2558 TRUE){
2559 if(n_strx != 0){
2560 len = strlen(strings + n_strx) + 1;
2561 new_strsize += len;
2563 new_nlocalsym++;
2564 new_nsyms++;
2565 saves[i] = new_nsyms;
2569 else{ /* global symbol */
2571 * strip -R on an x86_64 .o file should do nothing.
2573 if(Rfile &&
2574 (object->mh != NULL ||
2575 object->mh64->cputype != CPU_TYPE_X86_64 ||
2576 object->mh64->filetype != MH_OBJECT)){
2577 sp = bsearch(strings + n_strx,
2578 remove_symbols, nremove_symbols,
2579 sizeof(struct symbol_list),
2580 (int (*)(const void *, const void *))
2581 symbol_list_bsearch);
2582 if(sp != NULL){
2583 if((n_type & N_TYPE) == N_UNDF ||
2584 (n_type & N_TYPE) == N_PBUD){
2585 error_arch(arch, member, "symbol: %s undefined"
2586 " and can't be stripped from: ",
2587 sp->name);
2589 else if(sp->sym != NULL){
2590 sym = (struct nlist *)sp->sym;
2591 if((sym->n_type & N_PEXT) != N_PEXT)
2592 error_arch(arch, member, "more than one symbol "
2593 "for: %s found in: ", sp->name);
2595 else{
2596 if(object->mh != NULL)
2597 sp->sym = &(symbols[i]);
2598 else
2599 sp->sym = &(symbols64[i]);
2600 sp->seen = TRUE;
2602 if(n_desc & REFERENCED_DYNAMICALLY){
2603 error_arch(arch, member, "symbol: %s is dynamically"
2604 " referenced and can't be stripped "
2605 "from: ", sp->name);
2607 if((n_type & N_TYPE) == N_SECT &&
2608 (s_flags & SECTION_TYPE) == S_COALESCED){
2609 error_arch(arch, member, "symbol: %s is a global "
2610 "coalesced symbol and can't be "
2611 "stripped from: ", sp->name);
2613 /* don't save this symbol */
2614 continue;
2617 if(Aflag && (n_type & N_TYPE) == N_ABS &&
2618 (n_value != 0 ||
2619 (n_strx != 0 &&
2620 strncmp(strings + n_strx,
2621 ".objc_class_name_",
2622 sizeof(".objc_class_name_") - 1) == 0))){
2623 len = strlen(strings + n_strx) + 1;
2624 new_strsize += len;
2625 new_ext_strsize += len;
2626 new_nextdefsym++;
2627 new_nsyms++;
2628 saves[i] = new_nsyms;
2630 if(saves[i] == 0 && (uflag || default_dyld_executable) &&
2631 ((((n_type & N_TYPE) == N_UNDF) &&
2632 n_value == 0) ||
2633 (n_type & N_TYPE) == N_PBUD)){
2634 if(n_strx != 0){
2635 len = strlen(strings + n_strx) + 1;
2636 new_strsize += len;
2637 new_ext_strsize += len;
2639 new_nundefsym++;
2640 new_nsyms++;
2641 saves[i] = new_nsyms;
2643 if(saves[i] == 0 && nflag &&
2644 (n_type & N_TYPE) == N_SECT){
2645 if(n_strx != 0){
2646 len = strlen(strings + n_strx) + 1;
2647 new_strsize += len;
2648 new_ext_strsize += len;
2650 new_nextdefsym++;
2651 new_nsyms++;
2652 saves[i] = new_nsyms;
2654 if(saves[i] == 0 && sfile){
2655 sp = bsearch(strings + n_strx,
2656 save_symbols, nsave_symbols,
2657 sizeof(struct symbol_list),
2658 (int (*)(const void *, const void *))
2659 symbol_list_bsearch);
2660 if(sp != NULL){
2661 if(sp->sym != NULL){
2662 sym = (struct nlist *)sp->sym;
2663 if((sym->n_type & N_PEXT) != N_PEXT)
2664 error_arch(arch, member, "more than one symbol "
2665 "for: %s found in: ", sp->name);
2667 else{
2668 if(object->mh != NULL)
2669 sp->sym = &(symbols[i]);
2670 else
2671 sp->sym = &(symbols64[i]);
2672 sp->seen = TRUE;
2673 len = strlen(strings + n_strx) + 1;
2674 new_strsize += len;
2675 new_ext_strsize += len;
2676 if((n_type & N_TYPE) == N_UNDF ||
2677 (n_type & N_TYPE) == N_PBUD)
2678 new_nundefsym++;
2679 else
2680 new_nextdefsym++;
2681 new_nsyms++;
2682 saves[i] = new_nsyms;
2687 * We only need to save coalesced symbols that are used as
2688 * indirect symbols in 32-bit applications.
2690 * In 64-bit applications, we only need to save coalesced
2691 * symbols that are used as weak definitions.
2693 if(object->mh != NULL &&
2694 saves[i] == 0 &&
2695 (n_type & N_TYPE) == N_SECT &&
2696 (s_flags & SECTION_TYPE) == S_COALESCED &&
2697 symbol_pointer_used(i, indirectsyms, nindirectsyms) == TRUE){
2698 if(n_strx != 0){
2699 len = strlen(strings + n_strx) + 1;
2700 new_strsize += len;
2701 new_ext_strsize += len;
2703 new_nextdefsym++;
2704 new_nsyms++;
2705 saves[i] = new_nsyms;
2707 if(saves[i] == 0 &&
2708 (n_type & N_TYPE) == N_SECT &&
2709 (n_desc & N_WEAK_DEF) != 0){
2710 if(n_strx != 0){
2711 len = strlen(strings + n_strx) + 1;
2712 new_strsize += len;
2713 new_ext_strsize += len;
2715 new_nextdefsym++;
2716 new_nsyms++;
2717 saves[i] = new_nsyms;
2719 if(saves[i] == 0 && ((Xflag || Sflag || xflag) ||
2720 ((rflag || default_dyld_executable) &&
2721 n_desc & REFERENCED_DYNAMICALLY))){
2722 len = strlen(strings + n_strx) + 1;
2723 new_strsize += len;
2724 new_ext_strsize += len;
2725 if((n_type & N_TYPE) == N_INDR){
2726 len = strlen(strings + n_value) + 1;
2727 new_strsize += len;
2728 new_ext_strsize += len;
2730 if((n_type & N_TYPE) == N_UNDF ||
2731 (n_type & N_TYPE) == N_PBUD)
2732 new_nundefsym++;
2733 else
2734 new_nextdefsym++;
2735 new_nsyms++;
2736 saves[i] = new_nsyms;
2741 * The module table's module names are placed with the external strings.
2742 * So size them and add this to the external string size.
2744 for(i = 0; i < nmodtab; i++){
2745 if(object->mh != NULL)
2746 module_name = mods[i].module_name;
2747 else
2748 module_name = mods64[i].module_name;
2749 if(module_name == 0 || module_name > strsize){
2750 error_arch(arch, member, "bad string index for module_name "
2751 "of module table entry %ld in: ", i);
2752 return(FALSE);
2754 len = strlen(strings + module_name) + 1;
2755 new_strsize += len;
2756 new_ext_strsize += len;
2760 * Updating the reference table may require a symbol not yet listed as
2761 * as saved to be present in the output file. If a defined external
2762 * symbol is removed and there is a undefined reference to it in the
2763 * reference table an undefined symbol needs to be created for it in
2764 * the output file. If this happens the number of new symbols and size
2765 * of the new strings are adjusted. And the array changes[] is set to
2766 * map the old symbol index to the new symbol index for the symbol that
2767 * is changed to an undefined symbol.
2769 missing_symbols = 0;
2770 if(ref_saves != NULL)
2771 free(ref_saves);
2772 ref_saves = (long *)allocate(nextrefsyms * sizeof(long));
2773 bzero(ref_saves, nextrefsyms * sizeof(long));
2774 changes = (unsigned long *)allocate(nsyms * sizeof(long));
2775 bzero(changes, nsyms * sizeof(long));
2776 new_nextrefsyms = 0;
2777 for(i = 0; i < nextrefsyms; i++){
2778 if(refs[i].isym > nsyms){
2779 error_arch(arch, member, "bad symbol table index for "
2780 "reference table entry %ld in: ", i);
2781 return(FALSE);
2783 if(saves[refs[i].isym]){
2784 new_nextrefsyms++;
2785 ref_saves[i] = new_nextrefsyms;
2787 else{
2788 if(refs[i].flags == REFERENCE_FLAG_UNDEFINED_NON_LAZY ||
2789 refs[i].flags == REFERENCE_FLAG_UNDEFINED_LAZY){
2790 if(changes[refs[i].isym] == 0){
2791 if(object->mh != NULL)
2792 n_strx = symbols[refs[i].isym].n_un.n_strx;
2793 else
2794 n_strx = symbols64[refs[i].isym].n_un.n_strx;
2795 len = strlen(strings + n_strx) + 1;
2796 new_strsize += len;
2797 new_ext_strsize += len;
2798 new_nundefsym++;
2799 new_nsyms++;
2800 changes[refs[i].isym] = new_nsyms;
2801 new_nextrefsyms++;
2802 ref_saves[i] = new_nextrefsyms;
2805 else{
2806 if(refs[i].flags ==
2807 REFERENCE_FLAG_PRIVATE_UNDEFINED_NON_LAZY ||
2808 refs[i].flags == REFERENCE_FLAG_PRIVATE_UNDEFINED_LAZY){
2809 if(missing_symbols == 0){
2810 error_arch(arch, member, "private extern symbols "
2811 "referenced by modules can't be stripped in: ");
2812 missing_symbols = 1;
2814 if(object->mh != NULL)
2815 n_strx = symbols[refs[i].isym].n_un.n_strx;
2816 else
2817 n_strx = symbols64[refs[i].isym].n_un.n_strx;
2818 fprintf(stderr, "%s\n", strings + n_strx);
2819 saves[refs[i].isym] = -1;
2824 if(missing_symbols == 1)
2825 return(FALSE);
2827 if(member == NULL){
2828 missing_syms = 0;
2829 if(iflag == 0){
2830 for(i = 0; i < nsave_symbols; i++){
2831 if(save_symbols[i].sym == NULL){
2832 if(missing_syms == 0){
2833 error_arch(arch, member, "symbols names listed "
2834 "in: %s not in: ", sfile);
2835 missing_syms = 1;
2837 fprintf(stderr, "%s\n", save_symbols[i].name);
2841 missing_syms = 0;
2843 * strip -R on an x86_64 .o file should do nothing.
2845 if(iflag == 0 &&
2846 (object->mh != NULL ||
2847 object->mh64->cputype != CPU_TYPE_X86_64 ||
2848 object->mh64->filetype != MH_OBJECT)){
2849 for(i = 0; i < nremove_symbols; i++){
2850 if(remove_symbols[i].sym == NULL){
2851 if(missing_syms == 0){
2852 error_arch(arch, member, "symbols names listed "
2853 "in: %s not in: ", Rfile);
2854 missing_syms = 1;
2856 fprintf(stderr, "%s\n", remove_symbols[i].name);
2862 if(object->mh != NULL){
2863 new_symbols = (struct nlist *)
2864 allocate(new_nsyms * sizeof(struct nlist));
2865 new_symbols64 = NULL;
2867 else{
2868 new_symbols = NULL;
2869 new_symbols64 = (struct nlist_64 *)
2870 allocate(new_nsyms * sizeof(struct nlist_64));
2872 new_strsize = round(new_strsize, sizeof(long));
2873 new_strings = (char *)allocate(new_strsize);
2874 new_strings[new_strsize - 3] = '\0';
2875 new_strings[new_strsize - 2] = '\0';
2876 new_strings[new_strsize - 1] = '\0';
2878 memset(new_strings, '\0', sizeof(long));
2879 p = new_strings + sizeof(long);
2880 q = p + new_ext_strsize;
2882 /* if all strings were stripped set the size to zero */
2883 if(new_strsize == sizeof(long))
2884 new_strsize = 0;
2887 * Now create a symbol table and string table in this order
2888 * symbol table
2889 * local symbols
2890 * external defined symbols
2891 * undefined symbols
2892 * string table
2893 * external strings
2894 * local strings
2896 inew_syms = 0;
2897 for(i = 0; i < nsyms; i++){
2898 if(saves[i]){
2899 if(object->mh != NULL){
2900 n_strx = symbols[i].n_un.n_strx;
2901 n_type = symbols[i].n_type;
2903 else{
2904 n_strx = symbols64[i].n_un.n_strx;
2905 n_type = symbols64[i].n_type;
2907 if((n_type & N_EXT) == 0){
2908 if(object->mh != NULL)
2909 new_symbols[inew_syms] = symbols[i];
2910 else
2911 new_symbols64[inew_syms] = symbols64[i];
2912 if(n_strx != 0){
2913 strcpy(q, strings + n_strx);
2914 if(object->mh != NULL)
2915 new_symbols[inew_syms].n_un.n_strx =
2916 q - new_strings;
2917 else
2918 new_symbols64[inew_syms].n_un.n_strx =
2919 q - new_strings;
2920 q += strlen(q) + 1;
2922 inew_syms++;
2923 saves[i] = inew_syms;
2927 for(i = 0; i < nsyms; i++){
2928 if(saves[i]){
2929 if(object->mh != NULL){
2930 n_strx = symbols[i].n_un.n_strx;
2931 n_type = symbols[i].n_type;
2932 n_value = symbols[i].n_value;
2934 else{
2935 n_strx = symbols64[i].n_un.n_strx;
2936 n_type = symbols64[i].n_type;
2937 n_value = symbols64[i].n_value;
2939 if((n_type & N_EXT) == N_EXT &&
2940 ((n_type & N_TYPE) != N_UNDF &&
2941 (n_type & N_TYPE) != N_PBUD)){
2942 if(object->mh != NULL)
2943 new_symbols[inew_syms] = symbols[i];
2944 else
2945 new_symbols64[inew_syms] = symbols64[i];
2946 if(n_strx != 0){
2947 strcpy(p, strings + n_strx);
2948 if(object->mh != NULL)
2949 new_symbols[inew_syms].n_un.n_strx =
2950 p - new_strings;
2951 else
2952 new_symbols64[inew_syms].n_un.n_strx =
2953 p - new_strings;
2954 p += strlen(p) + 1;
2956 if((n_type & N_TYPE) == N_INDR){
2957 if(n_value != 0){
2958 strcpy(p, strings + n_value);
2959 if(object->mh != NULL)
2960 new_symbols[inew_syms].n_value =
2961 p - new_strings;
2962 else
2963 new_symbols64[inew_syms].n_value =
2964 p - new_strings;
2965 p += strlen(p) + 1;
2968 inew_syms++;
2969 saves[i] = inew_syms;
2974 * Build the new undefined symbols into a map and sort it.
2976 inew_undefsyms = 0;
2977 if(object->mh != NULL){
2978 undef_map = (struct undef_map *)allocate(new_nundefsym *
2979 sizeof(struct undef_map));
2980 undef_map64 = NULL;
2982 else{
2983 undef_map = NULL;
2984 undef_map64 = (struct undef_map64 *)allocate(new_nundefsym *
2985 sizeof(struct undef_map64));
2987 for(i = 0; i < nsyms; i++){
2988 if(saves[i]){
2989 if(object->mh != NULL){
2990 n_strx = symbols[i].n_un.n_strx;
2991 n_type = symbols[i].n_type;
2993 else{
2994 n_strx = symbols64[i].n_un.n_strx;
2995 n_type = symbols64[i].n_type;
2997 if((n_type & N_EXT) == N_EXT &&
2998 ((n_type & N_TYPE) == N_UNDF ||
2999 (n_type & N_TYPE) == N_PBUD)){
3000 if(object->mh != NULL)
3001 undef_map[inew_undefsyms].symbol = symbols[i];
3002 else
3003 undef_map64[inew_undefsyms].symbol64 = symbols64[i];
3004 if(n_strx != 0){
3005 strcpy(p, strings + n_strx);
3006 if(object->mh != NULL)
3007 undef_map[inew_undefsyms].symbol.n_un.n_strx =
3008 p - new_strings;
3009 else
3010 undef_map64[inew_undefsyms].symbol64.n_un.n_strx =
3011 p - new_strings;
3012 p += strlen(p) + 1;
3014 if(object->mh != NULL)
3015 undef_map[inew_undefsyms].index = i;
3016 else
3017 undef_map64[inew_undefsyms].index = i;
3018 inew_undefsyms++;
3022 for(i = 0; i < nsyms; i++){
3023 if(changes[i]){
3024 if(object->mh != NULL)
3025 n_strx = symbols[i].n_un.n_strx;
3026 else
3027 n_strx = symbols64[i].n_un.n_strx;
3028 if(n_strx != 0){
3029 strcpy(p, strings + n_strx);
3030 if(object->mh != NULL)
3031 undef_map[inew_undefsyms].symbol.n_un.n_strx =
3032 p - new_strings;
3033 else
3034 undef_map64[inew_undefsyms].symbol64.n_un.n_strx =
3035 p - new_strings;
3036 p += strlen(p) + 1;
3038 if(object->mh != NULL){
3039 undef_map[inew_undefsyms].symbol.n_type = N_UNDF | N_EXT;
3040 undef_map[inew_undefsyms].symbol.n_sect = NO_SECT;
3041 undef_map[inew_undefsyms].symbol.n_desc = 0;
3042 undef_map[inew_undefsyms].symbol.n_value = 0;
3043 undef_map[inew_undefsyms].index = i;
3045 else{
3046 undef_map64[inew_undefsyms].symbol64.n_type = N_UNDF |N_EXT;
3047 undef_map64[inew_undefsyms].symbol64.n_sect = NO_SECT;
3048 undef_map64[inew_undefsyms].symbol64.n_desc = 0;
3049 undef_map64[inew_undefsyms].symbol64.n_value = 0;
3050 undef_map64[inew_undefsyms].index = i;
3052 inew_undefsyms++;
3055 /* Sort the undefined symbols by name */
3056 qsort_strings = new_strings;
3057 if(object->mh != NULL)
3058 qsort(undef_map, new_nundefsym, sizeof(struct undef_map),
3059 (int (*)(const void *, const void *))cmp_qsort_undef_map);
3060 else
3061 qsort(undef_map64, new_nundefsym, sizeof(struct undef_map64),
3062 (int (*)(const void *, const void *))cmp_qsort_undef_map_64);
3063 /* Copy the symbols now in sorted order into new_symbols */
3064 for(i = 0; i < new_nundefsym; i++){
3065 if(object->mh != NULL){
3066 new_symbols[inew_syms] = undef_map[i].symbol;
3067 inew_syms++;
3068 saves[undef_map[i].index] = inew_syms;
3070 else{
3071 new_symbols64[inew_syms] = undef_map64[i].symbol64;
3072 inew_syms++;
3073 saves[undef_map64[i].index] = inew_syms;
3078 * Fixup the module table's module name strings adding them to the
3079 * string table. Also fix the indexes into the symbol table for
3080 * external and local symbols. And fix up the indexes into the
3081 * reference table.
3083 for(i = 0; i < nmodtab; i++){
3084 if(object->mh != NULL){
3085 strcpy(p, strings + mods[i].module_name);
3086 mods[i].module_name = p - new_strings;
3087 iextdefsym = mods[i].iextdefsym;
3088 nextdefsym = mods[i].nextdefsym;
3089 ilocalsym = mods[i].ilocalsym;
3090 nlocalsym = mods[i].nlocalsym;
3091 irefsym = mods[i].irefsym;
3092 nrefsym = mods[i].nrefsym;
3094 else{
3095 strcpy(p, strings + mods64[i].module_name);
3096 mods64[i].module_name = p - new_strings;
3097 iextdefsym = mods64[i].iextdefsym;
3098 nextdefsym = mods64[i].nextdefsym;
3099 ilocalsym = mods64[i].ilocalsym;
3100 nlocalsym = mods64[i].nlocalsym;
3101 irefsym = mods64[i].irefsym;
3102 nrefsym = mods64[i].nrefsym;
3104 p += strlen(p) + 1;
3106 if(iextdefsym > nsyms){
3107 error_arch(arch, member, "bad index into externally defined "
3108 "symbols of module table entry %ld in: ", i);
3109 return(FALSE);
3111 if(iextdefsym + nextdefsym > nsyms){
3112 error_arch(arch, member, "bad number of externally defined "
3113 "symbols of module table entry %ld in: ", i);
3114 return(FALSE);
3116 for(j = iextdefsym; j < iextdefsym + nextdefsym; j++){
3117 if(saves[j] != 0 && changes[j] == 0)
3118 break;
3120 n = 0;
3121 for(k = j; k < iextdefsym + nextdefsym; k++){
3122 if(saves[k] != 0 && changes[k] == 0)
3123 n++;
3125 if(n == 0){
3126 if(object->mh != NULL){
3127 mods[i].iextdefsym = 0;
3128 mods[i].nextdefsym = 0;
3130 else{
3131 mods64[i].iextdefsym = 0;
3132 mods64[i].nextdefsym = 0;
3135 else{
3136 if(object->mh != NULL){
3137 mods[i].iextdefsym = saves[j] - 1;
3138 mods[i].nextdefsym = n;
3140 else{
3141 mods64[i].iextdefsym = saves[j] - 1;
3142 mods64[i].nextdefsym = n;
3146 if(ilocalsym > nsyms){
3147 error_arch(arch, member, "bad index into symbols for local "
3148 "symbols of module table entry %ld in: ", i);
3149 return(FALSE);
3151 if(ilocalsym + nlocalsym > nsyms){
3152 error_arch(arch, member, "bad number of local "
3153 "symbols of module table entry %ld in: ", i);
3154 return(FALSE);
3156 for(j = ilocalsym; j < ilocalsym + nlocalsym; j++){
3157 if(saves[j] != 0)
3158 break;
3160 n = 0;
3161 for(k = j; k < ilocalsym + nlocalsym; k++){
3162 if(saves[k] != 0)
3163 n++;
3165 if(n == 0){
3166 if(object->mh != NULL){
3167 mods[i].ilocalsym = 0;
3168 mods[i].nlocalsym = 0;
3170 else{
3171 mods64[i].ilocalsym = 0;
3172 mods64[i].nlocalsym = 0;
3175 else{
3176 if(object->mh != NULL){
3177 mods[i].ilocalsym = saves[j] - 1;
3178 mods[i].nlocalsym = n;
3180 else{
3181 mods64[i].ilocalsym = saves[j] - 1;
3182 mods64[i].nlocalsym = n;
3186 if(irefsym > nextrefsyms){
3187 error_arch(arch, member, "bad index into reference table "
3188 "of module table entry %ld in: ", i);
3189 return(FALSE);
3191 if(irefsym + nrefsym > nextrefsyms){
3192 error_arch(arch, member, "bad number of reference table "
3193 "entries of module table entry %ld in: ", i);
3194 return(FALSE);
3196 for(j = irefsym; j < irefsym + nrefsym; j++){
3197 if(ref_saves[j] != 0)
3198 break;
3200 n = 0;
3201 for(k = j; k < irefsym + nrefsym; k++){
3202 if(ref_saves[k] != 0)
3203 n++;
3205 if(n == 0){
3206 if(object->mh != NULL){
3207 mods[i].irefsym = 0;
3208 mods[i].nrefsym = 0;
3210 else{
3211 mods64[i].irefsym = 0;
3212 mods64[i].nrefsym = 0;
3215 else{
3216 if(object->mh != NULL){
3217 mods[i].irefsym = ref_saves[j] - 1;
3218 mods[i].nrefsym = n;
3220 else{
3221 mods64[i].irefsym = ref_saves[j] - 1;
3222 mods64[i].nrefsym = n;
3228 * Create a new reference table.
3230 new_refs = allocate(new_nextrefsyms * sizeof(struct dylib_reference));
3231 j = 0;
3232 for(i = 0; i < nextrefsyms; i++){
3233 if(ref_saves[i]){
3234 if(saves[refs[i].isym]){
3235 new_refs[j].isym = saves[refs[i].isym] - 1;
3236 new_refs[j].flags = refs[i].flags;
3238 else{
3239 if(refs[i].flags == REFERENCE_FLAG_UNDEFINED_NON_LAZY ||
3240 refs[i].flags == REFERENCE_FLAG_UNDEFINED_LAZY){
3241 new_refs[j].isym = changes[refs[i].isym] - 1;
3242 new_refs[j].flags = refs[i].flags;
3245 j++;
3250 * Create a new dylib table of contents.
3252 new_ntoc = 0;
3253 for(i = 0; i < ntoc; i++){
3254 if(tocs[i].symbol_index >= nsyms){
3255 error_arch(arch, member, "bad symbol index for table of "
3256 "contents table entry %ld in: ", i);
3257 return(FALSE);
3259 if(saves[tocs[i].symbol_index] != 0 &&
3260 changes[tocs[i].symbol_index] == 0)
3261 new_ntoc++;
3263 new_tocs = allocate(new_ntoc * sizeof(struct dylib_table_of_contents));
3264 j = 0;
3265 for(i = 0; i < ntoc; i++){
3266 if(saves[tocs[i].symbol_index] != 0 &&
3267 changes[tocs[i].symbol_index] == 0){
3268 new_tocs[j].symbol_index = saves[tocs[i].symbol_index] - 1;
3269 new_tocs[j].module_index = tocs[i].module_index;
3270 j++;
3274 if(undef_map != NULL)
3275 free(undef_map);
3276 if(undef_map64 != NULL)
3277 free(undef_map64);
3278 if(changes != NULL)
3279 free(changes);
3280 if(sections != NULL)
3281 free(sections);
3282 if(sections64 != NULL)
3283 free(sections64);
3285 if(errors == 0)
3286 return(TRUE);
3287 else
3288 return(FALSE);
3292 * strip_LC_UUID_commands() is called when -no_uuid is specified to remove any
3293 * LC_UUID load commands from the object's load commands.
3295 static
3296 void
3297 strip_LC_UUID_commands(
3298 struct arch *arch,
3299 struct member *member,
3300 struct object *object)
3302 uint32_t i, ncmds, nuuids, mh_sizeofcmds, sizeofcmds;
3303 struct load_command *lc1, *lc2, *new_load_commands;
3304 struct segment_command *sg;
3307 * See if there are any LC_UUID load commands.
3309 nuuids = 0;
3310 lc1 = arch->object->load_commands;
3311 if(arch->object->mh != NULL){
3312 ncmds = arch->object->mh->ncmds;
3313 mh_sizeofcmds = arch->object->mh->sizeofcmds;
3315 else{
3316 ncmds = arch->object->mh64->ncmds;
3317 mh_sizeofcmds = arch->object->mh64->sizeofcmds;
3319 for(i = 0; i < ncmds; i++){
3320 if(lc1->cmd == LC_UUID){
3321 nuuids++;
3323 lc1 = (struct load_command *)((char *)lc1 + lc1->cmdsize);
3325 /* if no LC_UUID load commands just return */
3326 if(nuuids == 0)
3327 return;
3330 * Allocate space for the new load commands as zero it out so any holes
3331 * will be zero bytes.
3333 new_load_commands = allocate(mh_sizeofcmds);
3334 memset(new_load_commands, '\0', mh_sizeofcmds);
3337 * Copy all the load commands except the LC_UUID load commands into the
3338 * allocated space for the new load commands.
3340 lc1 = arch->object->load_commands;
3341 lc2 = new_load_commands;
3342 sizeofcmds = 0;
3343 for(i = 0; i < ncmds; i++){
3344 if(lc1->cmd != LC_UUID){
3345 memcpy(lc2, lc1, lc1->cmdsize);
3346 sizeofcmds += lc2->cmdsize;
3347 lc2 = (struct load_command *)((char *)lc2 + lc2->cmdsize);
3349 lc1 = (struct load_command *)((char *)lc1 + lc1->cmdsize);
3353 * Finally copy the updated load commands over the existing load
3354 * commands.
3356 memcpy(arch->object->load_commands, new_load_commands, sizeofcmds);
3357 if(mh_sizeofcmds > sizeofcmds){
3358 memset((char *)arch->object->load_commands + sizeofcmds, '\0',
3359 (mh_sizeofcmds - sizeofcmds));
3361 ncmds -= nuuids;
3362 if(arch->object->mh != NULL) {
3363 arch->object->mh->sizeofcmds = sizeofcmds;
3364 arch->object->mh->ncmds = ncmds;
3365 } else {
3366 arch->object->mh64->sizeofcmds = sizeofcmds;
3367 arch->object->mh64->ncmds = ncmds;
3369 free(new_load_commands);
3371 /* reset the pointers into the load commands */
3372 lc1 = arch->object->load_commands;
3373 for(i = 0; i < ncmds; i++){
3374 switch(lc1->cmd){
3375 case LC_SYMTAB:
3376 arch->object->st = (struct symtab_command *)lc1;
3377 break;
3378 case LC_DYSYMTAB:
3379 arch->object->dyst = (struct dysymtab_command *)lc1;
3380 break;
3381 case LC_TWOLEVEL_HINTS:
3382 arch->object->hints_cmd = (struct twolevel_hints_command *)lc1;
3383 break;
3384 case LC_PREBIND_CKSUM:
3385 arch->object->cs = (struct prebind_cksum_command *)lc1;
3386 break;
3387 case LC_SEGMENT:
3388 sg = (struct segment_command *)lc1;
3389 if(strcmp(sg->segname, SEG_LINKEDIT) == 0)
3390 arch->object->seg_linkedit = sg;
3391 break;
3392 case LC_SEGMENT_SPLIT_INFO:
3393 object->split_info_cmd = (struct linkedit_data_command *)lc1;
3394 break;
3395 case LC_CODE_SIGNATURE:
3396 object->code_sig_cmd = (struct linkedit_data_command *)lc1;
3397 break;
3399 lc1 = (struct load_command *)((char *)lc1 + lc1->cmdsize);
3403 #ifndef NMEDIT
3405 * strip_LC_CODE_SIGNATURE_commands() is called when -c is specified to remove
3406 * any LC_CODE_SIGNATURE load commands from the object's load commands.
3408 static
3409 void
3410 strip_LC_CODE_SIGNATURE_commands(
3411 struct arch *arch,
3412 struct member *member,
3413 struct object *object)
3415 uint32_t i, ncmds, mh_sizeofcmds, sizeofcmds;
3416 struct load_command *lc1, *lc2, *new_load_commands;
3417 struct segment_command *sg;
3420 * See if there is an LC_CODE_SIGNATURE load command and if no command
3421 * just return.
3423 if(object->code_sig_cmd == NULL)
3424 return;
3427 * Allocate space for the new load commands and zero it out so any holes
3428 * will be zero bytes.
3430 if(arch->object->mh != NULL){
3431 ncmds = arch->object->mh->ncmds;
3432 mh_sizeofcmds = arch->object->mh->sizeofcmds;
3434 else{
3435 ncmds = arch->object->mh64->ncmds;
3436 mh_sizeofcmds = arch->object->mh64->sizeofcmds;
3438 new_load_commands = allocate(mh_sizeofcmds);
3439 memset(new_load_commands, '\0', mh_sizeofcmds);
3442 * Copy all the load commands except the LC_CODE_SIGNATURE load commands
3443 * into the allocated space for the new load commands.
3445 lc1 = arch->object->load_commands;
3446 lc2 = new_load_commands;
3447 sizeofcmds = 0;
3448 for(i = 0; i < ncmds; i++){
3449 if(lc1->cmd != LC_CODE_SIGNATURE){
3450 memcpy(lc2, lc1, lc1->cmdsize);
3451 sizeofcmds += lc2->cmdsize;
3452 lc2 = (struct load_command *)((char *)lc2 + lc2->cmdsize);
3454 lc1 = (struct load_command *)((char *)lc1 + lc1->cmdsize);
3458 * Finally copy the updated load commands over the existing load
3459 * commands.
3461 memcpy(arch->object->load_commands, new_load_commands, sizeofcmds);
3462 if(mh_sizeofcmds > sizeofcmds){
3463 memset((char *)arch->object->load_commands + sizeofcmds, '\0',
3464 (mh_sizeofcmds - sizeofcmds));
3466 ncmds -= 1;
3467 if(arch->object->mh != NULL) {
3468 arch->object->mh->sizeofcmds = sizeofcmds;
3469 arch->object->mh->ncmds = ncmds;
3470 } else {
3471 arch->object->mh64->sizeofcmds = sizeofcmds;
3472 arch->object->mh64->ncmds = ncmds;
3474 free(new_load_commands);
3476 /* reset the pointers into the load commands */
3477 object->code_sig_cmd = NULL;
3478 lc1 = arch->object->load_commands;
3479 for(i = 0; i < ncmds; i++){
3480 switch(lc1->cmd){
3481 case LC_SYMTAB:
3482 arch->object->st = (struct symtab_command *)lc1;
3483 break;
3484 case LC_DYSYMTAB:
3485 arch->object->dyst = (struct dysymtab_command *)lc1;
3486 break;
3487 case LC_TWOLEVEL_HINTS:
3488 arch->object->hints_cmd = (struct twolevel_hints_command *)lc1;
3489 break;
3490 case LC_PREBIND_CKSUM:
3491 arch->object->cs = (struct prebind_cksum_command *)lc1;
3492 break;
3493 case LC_SEGMENT:
3494 sg = (struct segment_command *)lc1;
3495 if(strcmp(sg->segname, SEG_LINKEDIT) == 0)
3496 arch->object->seg_linkedit = sg;
3497 break;
3498 case LC_SEGMENT_SPLIT_INFO:
3499 object->split_info_cmd = (struct linkedit_data_command *)lc1;
3500 break;
3502 lc1 = (struct load_command *)((char *)lc1 + lc1->cmdsize);
3506 * To get the right amount of the file copied out by writeout() for the
3507 * case when we are stripping out the section contents we already reduce
3508 * the object size by the size of the section contents including the
3509 * padding after the load commands. So here we need to further reduce
3510 * it by the load command for the LC_CODE_SIGNATURE (a struct
3511 * linkedit_data_command) we are removing.
3513 object->object_size -= sizeof(struct linkedit_data_command);
3515 * Then this size minus the size of the input symbolic information is
3516 * what is copied out from the file by writeout(). Which in this case
3517 * is just the new headers.
3521 * Finally for -c the file offset to the link edit information is to be
3522 * right after the load commands. So reset this for the updated size
3523 * of the load commands without the LC_CODE_SIGNATURE.
3525 if(object->mh != NULL)
3526 object->seg_linkedit->fileoff = sizeof(struct mach_header) +
3527 sizeofcmds;
3528 else
3529 object->seg_linkedit64->fileoff = sizeof(struct mach_header_64) +
3530 sizeofcmds;
3532 #endif /* !(NMEDIT) */
3535 * private_extern_reference_by_module() is passed a symbol_index of a private
3536 * extern symbol and the module table. If the symbol_index appears in the
3537 * module symbol table this returns TRUE else it returns FALSE.
3539 static
3540 enum bool
3541 private_extern_reference_by_module(
3542 unsigned long symbol_index,
3543 struct dylib_reference *refs,
3544 unsigned long nextrefsyms)
3546 unsigned long i;
3548 for(i = 0; i < nextrefsyms; i++){
3549 if(refs[i].isym == symbol_index){
3550 if(refs[i].flags == REFERENCE_FLAG_PRIVATE_UNDEFINED_NON_LAZY ||
3551 refs[i].flags == REFERENCE_FLAG_PRIVATE_UNDEFINED_LAZY){
3552 return(TRUE);
3556 return(FALSE);
3560 * symbol_pointer_used() is passed a symbol_index and the indirect table. If
3561 * the symbol_index appears in the indirect symbol table this returns TRUE else
3562 * it returns FALSE.
3564 static
3565 enum bool
3566 symbol_pointer_used(
3567 unsigned long symbol_index,
3568 uint32_t *indirectsyms,
3569 unsigned long nindirectsyms)
3571 unsigned long i;
3573 for(i = 0; i < nindirectsyms; i++){
3574 if(indirectsyms[i] == symbol_index)
3575 return(TRUE);
3577 return(FALSE);
3581 * Function for qsort for comparing undefined map entries.
3583 static
3585 cmp_qsort_undef_map(
3586 const struct undef_map *sym1,
3587 const struct undef_map *sym2)
3589 return(strcmp(qsort_strings + sym1->symbol.n_un.n_strx,
3590 qsort_strings + sym2->symbol.n_un.n_strx));
3593 static
3595 cmp_qsort_undef_map_64(
3596 const struct undef_map64 *sym1,
3597 const struct undef_map64 *sym2)
3599 return(strcmp(qsort_strings + sym1->symbol64.n_un.n_strx,
3600 qsort_strings + sym2->symbol64.n_un.n_strx));
3602 #endif /* !defined(NMEDIT) */
3604 #ifndef NMEDIT
3606 * Function for qsort for comparing object names.
3608 static
3610 cmp_qsort_filename(
3611 const char **name1,
3612 const char **name2)
3614 return(strcmp(*name1, *name2));
3618 * Function for bsearch for finding a object name.
3620 static
3622 cmp_bsearch_filename(
3623 const char *name1,
3624 const char **name2)
3626 return(strcmp(name1, *name2));
3628 #endif /* !defined(NMEDIT) */
3630 #ifdef NMEDIT
3631 static
3632 enum bool
3633 edit_symtab(
3634 struct arch *arch,
3635 struct member *member,
3636 struct object *object,
3637 struct nlist *symbols,
3638 struct nlist_64 *symbols64,
3639 unsigned long nsyms,
3640 char *strings,
3641 unsigned long strsize,
3642 struct dylib_table_of_contents *tocs,
3643 unsigned long ntoc,
3644 struct dylib_module *mods,
3645 struct dylib_module_64 *mods64,
3646 unsigned long nmodtab,
3647 struct dylib_reference *refs,
3648 unsigned long nextrefsyms)
3650 unsigned long i, j, k;
3651 unsigned char data_n_sect, nsects;
3652 struct load_command *lc;
3653 struct segment_command *sg;
3654 struct segment_command_64 *sg64;
3655 struct section *s, **sections;
3656 struct section_64 *s64, **sections64;
3658 unsigned long missing_syms;
3659 struct symbol_list *sp;
3660 struct nlist **global_symbol;
3661 struct nlist_64 **global_symbol64;
3662 enum bool global_symbol_found;
3663 char *global_name, save_char;
3664 enum bool dwarf_debug_map;
3665 enum byte_sex host_byte_sex;
3666 long missing_reloc_symbols;
3667 enum bool edit_symtab_return;
3669 char *p, *q;
3670 unsigned long new_ext_strsize, len, inew_syms;
3672 struct nlist **changed_globals;
3673 struct nlist_64 **changed_globals64;
3674 unsigned long nchanged_globals;
3675 uint32_t ncmds, s_flags, n_strx, module_name, ilocalsym, nlocalsym;
3676 uint32_t iextdefsym, nextdefsym;
3677 uint8_t n_type, n_sect, global_symbol_n_sect;
3678 uint64_t n_value;
3679 enum bool warned_about_global_coalesced_symbols;
3681 edit_symtab_return = TRUE;
3682 host_byte_sex = get_host_byte_sex();
3683 missing_reloc_symbols = 0;
3684 warned_about_global_coalesced_symbols = FALSE;
3686 if(nmedits != NULL)
3687 free(nmedits);
3688 nmedits = allocate(nsyms * sizeof(enum bool));
3689 for(i = 0; i < nsyms; i++)
3690 nmedits[i] = FALSE;
3693 * If nmedit is operating on a dynamic library then symbols are turned
3694 * into private externs with the extern bit off not into static symbols.
3696 if(object->mh_filetype == MH_DYLIB && pflag == TRUE){
3697 error_arch(arch, member, "can't use -p with dynamic libraries");
3698 return(FALSE);
3702 * As part of the MAJOR guess for the second pass to fix stabs for the
3703 * globals symbols that get turned into non-global symbols. We need to
3704 * change the stabs. To do this we to know if a N_GSYM is for a data
3705 * symbol or not to know to turn it into an N_STSYM or a N_FUN.
3706 * This logic as determined by compiling test cases with and without
3707 * the key word 'static' and looking at the difference between the STABS
3708 * the compiler generates and trying to match that here.
3710 * We also use this loop and the next to gather an array of section
3711 * struct pointers so we can later determine if we run into a global
3712 * symbol in a coalesced section and not turn those symbols into
3713 * statics.
3715 j = 0;
3716 nsects = 0;
3717 n_sect = 1;
3718 data_n_sect = NO_SECT;
3719 lc = object->load_commands;
3720 if(object->mh != NULL)
3721 ncmds = object->mh->ncmds;
3722 else
3723 ncmds = object->mh64->ncmds;
3724 for(i = 0; i < ncmds; i++){
3725 if(lc->cmd == LC_SEGMENT){
3726 sg = (struct segment_command *)lc;
3727 s = (struct section *)((char *)sg +
3728 sizeof(struct segment_command));
3729 nsects += sg->nsects;
3730 for(j = 0; j < sg->nsects; j++){
3731 if(strcmp(s->segname, SEG_DATA) == 0 &&
3732 strcmp(s->sectname, SECT_DATA) == 0 &&
3733 data_n_sect == NO_SECT){
3734 data_n_sect = n_sect;
3735 break;
3737 n_sect++;
3738 s++;
3741 else if(lc->cmd == LC_SEGMENT_64){
3742 sg64 = (struct segment_command_64 *)lc;
3743 s64 = (struct section_64 *)((char *)sg64 +
3744 sizeof(struct segment_command_64));
3745 nsects += sg64->nsects;
3746 for(j = 0; j < sg64->nsects; j++){
3747 if(strcmp(s64->segname, SEG_DATA) == 0 &&
3748 strcmp(s64->sectname, SECT_DATA) == 0 &&
3749 data_n_sect == NO_SECT){
3750 data_n_sect = n_sect;
3751 break;
3753 n_sect++;
3754 s64++;
3757 lc = (struct load_command *)((char *)lc + lc->cmdsize);
3759 if(object->mh != NULL){
3760 sections = allocate(nsects * sizeof(struct section *));
3761 sections64 = NULL;
3763 else{
3764 sections = NULL;
3765 sections64 = allocate(nsects * sizeof(struct section_64 *));
3767 nsects = 0;
3768 lc = object->load_commands;
3769 for(i = 0; i < ncmds; i++){
3770 if(lc->cmd == LC_SEGMENT){
3771 sg = (struct segment_command *)lc;
3772 s = (struct section *)((char *)sg +
3773 sizeof(struct segment_command));
3774 for(j = 0; j < sg->nsects; j++){
3775 sections[nsects++] = s++;
3778 else if(lc->cmd == LC_SEGMENT_64){
3779 sg64 = (struct segment_command_64 *)lc;
3780 s64 = (struct section_64 *)((char *)sg64 +
3781 sizeof(struct segment_command_64));
3782 for(j = 0; j < sg64->nsects; j++){
3783 sections64[nsects++] = s64++;
3786 lc = (struct load_command *)((char *)lc + lc->cmdsize);
3790 * Zero out the saved symbols so they can be recorded for this file.
3792 for(i = 0; i < nsave_symbols; i++)
3793 save_symbols[i].sym = NULL;
3794 for(i = 0; i < nremove_symbols; i++)
3795 remove_symbols[i].sym = NULL;
3796 if(member == NULL){
3797 for(i = 0; i < nsave_symbols; i++)
3798 save_symbols[i].seen = FALSE;
3799 for(i = 0; i < nremove_symbols; i++)
3800 remove_symbols[i].seen = FALSE;
3803 nchanged_globals = 0;
3804 if(object->mh != NULL){
3805 changed_globals = allocate(nsyms * sizeof(struct nlist *));
3806 changed_globals64 = NULL;
3807 for(i = 0; i < nsyms; i++)
3808 changed_globals[i] = NULL;
3810 else{
3811 changed_globals = NULL;
3812 changed_globals64 = allocate(nsyms * sizeof(struct nlist_64 *));
3813 for(i = 0; i < nsyms; i++)
3814 changed_globals64[i] = NULL;
3818 * These are the variables for the new symbol table and new string
3819 * table. Since this routine only turns globals into non-globals the
3820 * number of symbols does not change. But the count of local, defined
3821 * external symbols does change.
3823 new_nsyms = nsyms;
3824 new_nlocalsym = 0;
3825 new_nextdefsym = 0;
3826 new_nundefsym = 0;
3828 new_strsize = sizeof(long);
3829 new_ext_strsize = 0;
3832 * First pass: turn the globals symbols into non-global symbols.
3834 for(i = 0; i < nsyms; i++){
3835 len = 0;
3836 s_flags = 0;
3837 if(object->mh != NULL){
3838 n_strx = symbols[i].n_un.n_strx;
3839 n_type = symbols[i].n_type;
3840 n_sect = symbols[i].n_sect;
3841 if((n_type & N_TYPE) == N_SECT)
3842 s_flags = sections[n_sect - 1]->flags;
3843 n_value = symbols[i].n_value;
3845 else{
3846 n_strx = symbols64[i].n_un.n_strx;
3847 n_type = symbols64[i].n_type;
3848 n_sect = symbols64[i].n_sect;
3849 if((n_type & N_TYPE) == N_SECT)
3850 s_flags = sections64[n_sect - 1]->flags;
3851 n_value = symbols64[i].n_value;
3853 if(n_strx != 0){
3854 if(n_strx > strsize){
3855 error_arch(arch, member, "bad string index for symbol "
3856 "table entry %lu in: ", i);
3857 return(FALSE);
3859 len = strlen(strings + n_strx) + 1;
3861 if(n_type & N_EXT){
3862 if((n_type & N_TYPE) != N_UNDF &&
3863 (n_type & N_TYPE) != N_PBUD){
3864 if((n_type & N_TYPE) == N_SECT){
3865 if(n_sect > nsects){
3866 error_arch(arch, member, "bad n_sect for symbol "
3867 "table entry %lu in: ", i);
3868 return(FALSE);
3870 if(((s_flags & SECTION_TYPE) == S_COALESCED) &&
3871 pflag == FALSE &&
3872 object->mh_filetype != MH_OBJECT){
3873 /* this remains a global defined symbol */
3874 if(warned_about_global_coalesced_symbols == FALSE){
3875 warning_arch(arch, member, "can't make global "
3876 "coalesced symbols (like %s) into static "
3877 "symbols (use ld(1)'s "
3878 "-exported_symbols_list option) in a final "
3879 "linked image: ", strings + n_strx);
3880 warned_about_global_coalesced_symbols = TRUE;
3882 new_nextdefsym++;
3883 new_ext_strsize += len;
3884 new_strsize += len;
3885 sp = bsearch(strings + n_strx,
3886 remove_symbols, nremove_symbols,
3887 sizeof(struct symbol_list),
3888 (int (*)(const void *, const void *))
3889 symbol_list_bsearch);
3890 if(sp != NULL){
3891 if(sp->sym != NULL){
3892 error_arch(arch, member, "more than one "
3893 "symbol for: %s found in: ", sp->name);
3894 return(FALSE);
3896 else{
3897 if(object->mh != NULL)
3898 sp->sym = &(symbols[i]);
3899 else
3900 sp->sym = &(symbols64[i]);
3901 sp->seen = TRUE;
3902 warning_arch(arch, member, "can't make "
3903 "global coalesced symbol: %s into a "
3904 "static symbol in: ", sp->name);
3908 * In case the user has listed this coalesced
3909 * symbol in the save list look for it and mark it
3910 * as seen so we don't complain about not seeing it.
3912 sp = bsearch(strings + n_strx,
3913 save_symbols, nsave_symbols,
3914 sizeof(struct symbol_list),
3915 (int (*)(const void *, const void *))
3916 symbol_list_bsearch);
3917 if(sp != NULL){
3918 if(sp->sym != NULL){
3919 error_arch(arch, member, "more than one "
3920 "symbol for: %s found in: ", sp->name);
3921 return(FALSE);
3923 else{
3924 if(object->mh != NULL)
3925 sp->sym = &(symbols[i]);
3926 else
3927 sp->sym = &(symbols64[i]);
3928 sp->seen = TRUE;
3931 continue; /* leave this symbol unchanged */
3934 sp = bsearch(strings + n_strx,
3935 remove_symbols, nremove_symbols,
3936 sizeof(struct symbol_list),
3937 (int (*)(const void *, const void *))
3938 symbol_list_bsearch);
3939 if(sp != NULL){
3940 if(sp->sym != NULL){
3941 error_arch(arch, member, "more than one symbol "
3942 "for: %s found in: ", sp->name);
3943 return(FALSE);
3945 else{
3946 if(object->mh != NULL)
3947 sp->sym = &(symbols[i]);
3948 else
3949 sp->sym = &(symbols64[i]);
3950 sp->seen = TRUE;
3951 goto change_symbol;
3954 else{
3956 * If there is no list of saved symbols, then all
3957 * symbols will be saved unless listed in the remove
3958 * list.
3960 if(sfile == NULL){
3962 * There is no save list, so if there is also no
3963 * remove list but the -p flag is specified or it is
3964 * a dynamic library then change all symbols.
3966 if((pflag || object->mh_filetype == MH_DYLIB)
3967 && nremove_symbols == 0)
3968 goto change_symbol;
3969 /* this remains a global defined symbol */
3970 new_nextdefsym++;
3971 new_ext_strsize += len;
3972 new_strsize += len;
3973 continue; /* leave this symbol unchanged */
3976 sp = bsearch(strings + n_strx,
3977 save_symbols, nsave_symbols,
3978 sizeof(struct symbol_list),
3979 (int (*)(const void *, const void *))
3980 symbol_list_bsearch);
3981 if(sp != NULL){
3982 if(sp->sym != NULL){
3983 error_arch(arch, member, "more than one symbol "
3984 "for: %s found in: ", sp->name);
3985 return(FALSE);
3987 else{
3988 if(object->mh != NULL)
3989 sp->sym = &(symbols[i]);
3990 else
3991 sp->sym = &(symbols64[i]);
3992 sp->seen = TRUE;
3993 /* this remains a global defined symbol */
3994 new_nextdefsym++;
3995 new_ext_strsize += len;
3996 new_strsize += len;
3999 else{
4000 if(Aflag && n_type == (N_EXT | N_ABS) &&
4001 (n_value != 0 ||
4002 (n_strx != 0 &&
4003 strncmp(strings + n_strx,
4004 ".objc_class_name_",
4005 sizeof(".objc_class_name_") - 1) == 0))){
4006 /* this remains a global defined symbol */
4007 new_nextdefsym++;
4008 new_ext_strsize += len;
4009 new_strsize += len;
4011 else{
4012 change_symbol:
4013 if((n_type & N_TYPE) != N_INDR){
4014 nmedits[i] = TRUE;
4015 if(object->mh != NULL)
4016 changed_globals[nchanged_globals++] =
4017 symbols + i;
4018 else
4019 changed_globals64[nchanged_globals++] =
4020 symbols64 + i;
4021 if(pflag){
4022 /* this remains a global defined symbol */
4023 new_nextdefsym++;
4024 new_ext_strsize += len;
4025 new_strsize += len;
4027 else{
4028 /* this will become a non-global symbol */
4029 new_nlocalsym++;
4030 new_strsize += len;
4033 else{
4034 /* this remains a global defined symbol */
4035 new_nextdefsym++;
4036 new_ext_strsize += len;
4037 new_strsize += len;
4042 else{
4043 /* this is an undefined symbol */
4044 new_nundefsym++;
4045 new_ext_strsize += len;
4046 new_strsize += len;
4049 else{
4050 /* this is a local symbol */
4051 new_nlocalsym++;
4052 new_strsize += len;
4057 * The module table's module names are placed with the external
4058 * strings. So size them and add this to the external string size.
4060 for(i = 0; i < nmodtab; i++){
4061 if(object->mh != NULL)
4062 module_name = mods[i].module_name;
4063 else
4064 module_name = mods64[i].module_name;
4065 if(module_name == 0 || module_name > strsize){
4066 error_arch(arch, member, "bad string index for module_name "
4067 "of module table entry %ld in: ", i);
4068 return(FALSE);
4070 len = strlen(strings + module_name) + 1;
4071 new_strsize += len;
4072 new_ext_strsize += len;
4076 * Warn about symbols to be saved that were missing.
4078 if(member == NULL){
4079 missing_syms = 0;
4080 if(iflag == 0){
4081 for(i = 0; i < nsave_symbols; i++){
4082 if(save_symbols[i].sym == NULL){
4083 if(missing_syms == 0){
4084 error_arch(arch, member, "symbols names listed "
4085 "in: %s not in: ", sfile);
4086 missing_syms = 1;
4088 fprintf(stderr, "%s\n", save_symbols[i].name);
4091 for(i = 0; i < nremove_symbols; i++){
4092 if(remove_symbols[i].sym == NULL){
4093 if(missing_syms == 0){
4094 error_arch(arch, member, "symbols names listed "
4095 "in: %s not in: ", Rfile);
4096 missing_syms = 1;
4098 fprintf(stderr, "%s\n", remove_symbols[i].name);
4105 * Second pass: fix stabs for the globals symbols that got turned into
4106 * non-global symbols. This is a MAJOR guess. The specific changes
4107 * to do here were determined by compiling test cases with and without
4108 * the key word 'static' and looking at the difference between the STABS
4109 * the compiler generates and trying to match that here.
4111 global_strings = strings;
4112 if(object->mh != NULL)
4113 qsort(changed_globals, nchanged_globals, sizeof(struct nlist *),
4114 (int (*)(const void *, const void *))cmp_qsort_global);
4115 else
4116 qsort(changed_globals64, nchanged_globals,sizeof(struct nlist_64 *),
4117 (int (*)(const void *, const void *))cmp_qsort_global_64);
4118 dwarf_debug_map = FALSE;
4119 for(i = 0; i < nsyms; i++){
4120 uint16_t n_desc;
4121 if(object->mh != NULL){
4122 n_strx = symbols[i].n_un.n_strx;
4123 n_type = symbols[i].n_type;
4124 n_desc = symbols[i].n_desc;
4126 else{
4127 n_strx = symbols64[i].n_un.n_strx;
4128 n_type = symbols64[i].n_type;
4129 n_desc = symbols64[i].n_desc;
4131 if(n_type == N_SO)
4132 dwarf_debug_map = FALSE;
4133 else if (n_type == N_OSO)
4134 dwarf_debug_map = n_desc != 0;
4135 else if (dwarf_debug_map && n_type == N_GSYM){
4136 global_name = strings + n_strx;
4137 if(object->mh != NULL){
4138 global_symbol = bsearch(global_name, changed_globals,
4139 nchanged_globals,sizeof(struct nlist *),
4140 (int (*)(const void *, const void *))
4141 cmp_bsearch_global);
4142 if(global_symbol != NULL){
4143 symbols[i].n_type = N_STSYM;
4144 symbols[i].n_sect = (*global_symbol)->n_sect;
4145 symbols[i].n_value = (*global_symbol)->n_value;
4148 else{
4149 global_symbol64 = bsearch(global_name, changed_globals64,
4150 nchanged_globals,
4151 sizeof(struct nlist_64 *),
4152 (int (*)(const void *, const void *))
4153 cmp_bsearch_global_64);
4154 if(global_symbol64 != NULL){
4155 symbols64[i].n_type = N_STSYM;
4156 symbols64[i].n_sect = (*global_symbol64)->n_sect;
4157 symbols64[i].n_value = (*global_symbol64)->n_value;
4161 else if(! dwarf_debug_map &&
4162 (n_type == N_GSYM || n_type == N_FUN) &&
4163 (n_strx != 0 && strings[n_strx] != '\0')){
4164 global_name = strings + n_strx;
4165 if((global_name[0] == '+' || global_name[0] == '-') &&
4166 global_name[1] == '['){
4167 j = 2;
4168 while(j + n_strx < strsize && global_name[j] != ']')
4169 j++;
4170 if(j + n_strx < strsize && global_name[j] == ']')
4171 j++;
4173 else
4174 j = 0;
4175 while(j + n_strx < strsize && global_name[j] != ':')
4176 j++;
4177 if(j + n_strx >= strsize){
4178 error_arch(arch, member, "bad N_STAB symbol name for entry "
4179 "%lu (does not contain ':' separating name from type) "
4180 "in: ", i);
4181 return(FALSE);
4183 save_char = global_name[j];
4184 global_name[j] = '\0';
4186 global_symbol_found = FALSE;
4187 global_symbol_n_sect = 0;
4188 if(object->mh != NULL){
4189 global_symbol = bsearch(global_name, changed_globals,
4190 nchanged_globals,sizeof(struct nlist *),
4191 (int (*)(const void *, const void *))
4192 cmp_bsearch_global_stab);
4193 global_symbol64 = NULL;
4194 if(global_symbol != NULL){
4195 global_symbol_found = TRUE;
4196 global_symbol_n_sect = (*global_symbol)->n_sect;
4199 else{
4200 global_symbol64 = bsearch(global_name, changed_globals64,
4201 nchanged_globals,
4202 sizeof(struct nlist_64 *),
4203 (int (*)(const void *, const void *))
4204 cmp_bsearch_global_stab_64);
4205 global_symbol = NULL;
4206 if(global_symbol64 != NULL){
4207 global_symbol_found = TRUE;
4208 global_symbol_n_sect = (*global_symbol64)->n_sect;
4211 global_name[j] = save_char;
4212 if(global_symbol_found == TRUE){
4213 if(n_type == N_GSYM){
4214 if(global_symbol_n_sect == data_n_sect){
4215 if(object->mh != NULL)
4216 symbols[i].n_type = N_STSYM;
4217 else
4218 symbols64[i].n_type = N_STSYM;
4220 else{
4221 if(object->mh != NULL)
4222 symbols[i].n_type = N_FUN;
4223 else
4224 symbols64[i].n_type = N_FUN;
4226 if(object->mh != NULL){
4227 symbols[i].n_sect = (*global_symbol)->n_sect;
4228 symbols[i].n_value = (*global_symbol)->n_value;
4229 symbols[i].n_desc = (*global_symbol)->n_desc;
4231 else{
4232 symbols64[i].n_sect = (*global_symbol64)->n_sect;
4233 symbols64[i].n_value = (*global_symbol64)->n_value;
4234 symbols64[i].n_desc = (*global_symbol64)->n_desc;
4236 if(j + 1 + n_strx >= strsize ||
4237 global_name[j+1] != 'G'){
4238 error_arch(arch, member, "bad N_GSYM symbol name "
4239 "for entry %lu (does not have type 'G' after "
4240 "':' in name) in: ", i);
4241 return(FALSE);
4243 global_name[j+1] = 'S';
4245 else{ /* n_type == N_FUN */
4246 if(j + 1 + n_strx >= strsize ||
4247 global_name[j+1] == 'F'){
4248 global_name[j+1] = 'f';
4254 global_strings = NULL;
4257 * Now what needs to be done is to create the new symbol table moving
4258 * those global symbols being changed into non-globals into the areas
4259 * in the symbol table for local symbols. The symbol table and string
4260 * table must be in this order:
4262 * symbol table
4263 * local symbols
4264 * external defined symbols
4265 * undefined symbols
4266 * string table
4267 * external strings
4268 * local strings
4270 if(saves != NULL)
4271 free(saves);
4272 saves = (long *)allocate(nsyms * sizeof(long));
4273 bzero(saves, nsyms * sizeof(long));
4275 if(object->mh != NULL){
4276 new_symbols = (struct nlist *)
4277 allocate(new_nsyms * sizeof(struct nlist));
4278 new_symbols64 = NULL;
4280 else{
4281 new_symbols = NULL;
4282 new_symbols64 = (struct nlist_64 *)
4283 allocate(new_nsyms * sizeof(struct nlist_64));
4285 new_strsize = round(new_strsize, sizeof(long));
4286 new_strings = (char *)allocate(new_strsize);
4287 new_strings[new_strsize - 3] = '\0';
4288 new_strings[new_strsize - 2] = '\0';
4289 new_strings[new_strsize - 1] = '\0';
4291 memset(new_strings, '\0', sizeof(long));
4292 p = new_strings + sizeof(long);
4293 q = p + new_ext_strsize;
4296 * If this is a dynamic library the movement of the symbols has to be
4297 * done with respect to the modules. As the local symbols, and external
4298 * defined symbols are grouped together for each module. Then a new
4299 * module table needs to be created with the new indexes into the symbol
4300 * table for each module.
4302 new_nmodtab = nmodtab;
4303 new_ntoc = ntoc;
4304 new_nextrefsyms = nextrefsyms;
4305 if(object->mh_filetype == MH_DYLIB && nmodtab != 0){
4306 if(object->mh != NULL){
4307 new_mods = allocate(nmodtab * sizeof(struct dylib_module));
4308 new_mods64 = NULL;
4310 else{
4311 new_mods = NULL;
4312 new_mods64 = allocate(nmodtab * sizeof(struct dylib_module_64));
4315 inew_syms = 0;
4317 * This first loop through the module table sets the index and
4318 * counts of the local symbols for each module.
4320 for(i = 0; i < nmodtab; i++){
4322 * First put the existing local symbols into the new symbol
4323 * table.
4325 if(object->mh != NULL){
4326 new_mods[i].ilocalsym = inew_syms;
4327 new_mods[i].nlocalsym = 0;
4328 ilocalsym = mods[i].ilocalsym;
4329 nlocalsym = mods[i].nlocalsym;
4331 else{
4332 new_mods64[i].ilocalsym = inew_syms;
4333 new_mods64[i].nlocalsym = 0;
4334 ilocalsym = mods64[i].ilocalsym;
4335 nlocalsym = mods64[i].nlocalsym;
4337 for(j = ilocalsym; j < ilocalsym + nlocalsym; j++){
4338 if(object->mh != NULL){
4339 n_strx = symbols[j].n_un.n_strx;
4340 n_type = symbols[j].n_type;
4342 else{
4343 n_strx = symbols64[j].n_un.n_strx;
4344 n_type = symbols64[j].n_type;
4346 if((n_type & N_EXT) == 0){
4347 if(object->mh != NULL)
4348 new_symbols[inew_syms] = symbols[j];
4349 else
4350 new_symbols64[inew_syms] = symbols64[j];
4351 if(n_strx != 0){
4352 strcpy(q, strings + n_strx);
4353 if(object->mh != NULL)
4354 new_symbols[inew_syms].n_un.n_strx =
4355 q - new_strings;
4356 else
4357 new_symbols64[inew_syms].n_un.n_strx =
4358 q - new_strings;
4359 q += strlen(q) + 1;
4361 inew_syms++;
4362 saves[j] = inew_syms;
4363 if(object->mh != NULL)
4364 new_mods[i].nlocalsym++;
4365 else
4366 new_mods64[i].nlocalsym++;
4370 * Next put the global symbols that were changed into
4371 * non-global symbols into the new symbol table and moved their
4372 * counts to the local symbol counts.
4374 if(object->mh != NULL){
4375 iextdefsym = mods[i].iextdefsym;
4376 nextdefsym = mods[i].nextdefsym;
4378 else{
4379 iextdefsym = mods64[i].iextdefsym;
4380 nextdefsym = mods64[i].nextdefsym;
4382 for(j = iextdefsym; j < iextdefsym + nextdefsym; j++){
4383 if(object->mh != NULL){
4384 n_strx = symbols[j].n_un.n_strx;
4385 n_type = symbols[j].n_type;
4387 else{
4388 n_strx = symbols64[j].n_un.n_strx;
4389 n_type = symbols64[j].n_type;
4391 if((n_type & N_EXT) != 0){
4392 if(nmedits[j] == TRUE){
4394 * Change the new symbol to a private extern symbol
4395 * with the extern bit off.
4397 if(object->mh != NULL){
4398 new_symbols[inew_syms] = symbols[j];
4399 new_symbols[inew_syms].n_type |= N_PEXT;
4400 new_symbols[inew_syms].n_type &= ~N_EXT;
4402 else{
4403 new_symbols64[inew_syms] = symbols64[j];
4404 new_symbols64[inew_syms].n_type |= N_PEXT;
4405 new_symbols64[inew_syms].n_type &= ~N_EXT;
4407 if(n_strx != 0){
4408 strcpy(q, strings + n_strx);
4409 if(object->mh != NULL)
4410 new_symbols[inew_syms].n_un.n_strx =
4411 q - new_strings;
4412 else
4413 new_symbols64[inew_syms].n_un.n_strx =
4414 q - new_strings;
4415 q += strlen(q) + 1;
4417 inew_syms++;
4418 saves[j] = inew_syms;
4419 if(object->mh != NULL)
4420 new_mods[i].nlocalsym++;
4421 else
4422 new_mods64[i].nlocalsym++;
4428 * Next put the unchanged defined global symbols into the new
4429 * symbol table.
4431 for(i = 0; i < nmodtab; i++){
4432 if(object->mh != NULL){
4433 new_mods[i].iextdefsym = inew_syms;
4434 new_mods[i].nextdefsym = 0;
4435 iextdefsym = mods[i].iextdefsym;
4436 nextdefsym = mods[i].nextdefsym;
4438 else{
4439 new_mods64[i].iextdefsym = inew_syms;
4440 new_mods64[i].nextdefsym = 0;
4441 iextdefsym = mods64[i].iextdefsym;
4442 nextdefsym = mods64[i].nextdefsym;
4444 for(j = iextdefsym; j < iextdefsym + nextdefsym; j++){
4445 if(object->mh != NULL){
4446 n_strx = symbols[j].n_un.n_strx;
4447 n_type = symbols[j].n_type;
4449 else{
4450 n_strx = symbols64[j].n_un.n_strx;
4451 n_type = symbols64[j].n_type;
4453 if((n_type & N_EXT) != 0){
4454 if(nmedits[j] == FALSE){
4455 if(object->mh != NULL)
4456 new_symbols[inew_syms] = symbols[j];
4457 else
4458 new_symbols64[inew_syms] = symbols64[j];
4459 if(n_strx != 0){
4460 strcpy(p, strings + n_strx);
4461 if(object->mh != NULL)
4462 new_symbols[inew_syms].n_un.n_strx =
4463 p - new_strings;
4464 else
4465 new_symbols64[inew_syms].n_un.n_strx =
4466 p - new_strings;
4467 p += strlen(p) + 1;
4469 inew_syms++;
4470 saves[j] = inew_syms;
4471 if(object->mh != NULL)
4472 new_mods[i].nextdefsym++;
4473 else
4474 new_mods64[i].nextdefsym++;
4480 * Last put the undefined symbols into the new symbol table.
4482 for(i = 0; i < nsyms; i++){
4483 if(object->mh != NULL){
4484 n_strx = symbols[i].n_un.n_strx;
4485 n_type = symbols[i].n_type;
4487 else{
4488 n_strx = symbols64[i].n_un.n_strx;
4489 n_type = symbols64[i].n_type;
4491 if((n_type & N_EXT) != 0 &&
4492 ((n_type & N_TYPE) == N_UNDF ||
4493 (n_type & N_TYPE) == N_PBUD)){
4494 if(object->mh != NULL)
4495 new_symbols[inew_syms] = symbols[i];
4496 else
4497 new_symbols64[inew_syms] = symbols64[i];
4498 if(n_strx != 0){
4499 strcpy(p, strings + n_strx);
4500 if(object->mh != NULL)
4501 new_symbols[inew_syms].n_un.n_strx =
4502 p - new_strings;
4503 else
4504 new_symbols64[inew_syms].n_un.n_strx =
4505 p - new_strings;
4506 p += strlen(p) + 1;
4508 inew_syms++;
4509 saves[i] = inew_syms;
4514 * Place the module table's module names with the external strings
4515 * and set the names in the new module table. And then copy the
4516 * other unchanged fields.
4518 for(i = 0; i < nmodtab; i++){
4519 if(object->mh != NULL){
4520 strcpy(p, strings + mods[i].module_name);
4521 new_mods[i].module_name = p - new_strings;
4522 p += strlen(p) + 1;
4524 new_mods[i].irefsym = mods[i].irefsym;
4525 new_mods[i].nrefsym = mods[i].nrefsym;
4526 new_mods[i].iextrel = mods[i].iextrel;
4527 new_mods[i].nextrel = mods[i].nextrel;
4528 new_mods[i].iinit_iterm = mods[i].iinit_iterm;
4529 new_mods[i].ninit_nterm = mods[i].ninit_nterm;
4530 new_mods[i].objc_module_info_addr =
4531 mods[i].objc_module_info_addr;
4532 new_mods[i].objc_module_info_size =
4533 mods[i].objc_module_info_size;
4535 else{
4536 strcpy(p, strings + mods64[i].module_name);
4537 new_mods64[i].module_name = p - new_strings;
4538 p += strlen(p) + 1;
4540 new_mods64[i].irefsym = mods64[i].irefsym;
4541 new_mods64[i].nrefsym = mods64[i].nrefsym;
4542 new_mods64[i].iextrel = mods64[i].iextrel;
4543 new_mods64[i].nextrel = mods64[i].nextrel;
4544 new_mods64[i].iinit_iterm = mods64[i].iinit_iterm;
4545 new_mods64[i].ninit_nterm = mods64[i].ninit_nterm;
4546 new_mods64[i].objc_module_info_addr =
4547 mods64[i].objc_module_info_addr;
4548 new_mods64[i].objc_module_info_size =
4549 mods64[i].objc_module_info_size;
4554 * Update the reference table with the new symbol indexes for all
4555 * entries and change type of reference (the flags field) for those
4556 * symbols that got changed from globals to non-globals.
4558 new_nextrefsyms = nextrefsyms;
4559 new_refs = allocate(new_nextrefsyms *
4560 sizeof(struct dylib_reference));
4561 j = 0;
4562 for(i = 0; i < nextrefsyms; i++){
4563 if(nmedits[refs[i].isym] == TRUE){
4564 if(refs[i].flags == REFERENCE_FLAG_DEFINED)
4565 new_refs[i].flags =
4566 REFERENCE_FLAG_PRIVATE_DEFINED;
4567 else if(refs[i].flags == REFERENCE_FLAG_UNDEFINED_NON_LAZY)
4568 new_refs[i].flags =
4569 REFERENCE_FLAG_PRIVATE_UNDEFINED_NON_LAZY;
4570 else if(refs[i].flags == REFERENCE_FLAG_UNDEFINED_LAZY)
4571 new_refs[i].flags =
4572 REFERENCE_FLAG_PRIVATE_UNDEFINED_LAZY;
4573 else
4574 new_refs[i].flags = refs[i].flags;
4576 else{
4577 new_refs[i].flags = refs[i].flags;
4579 new_refs[i].isym = saves[refs[i].isym] - 1;
4583 * Create a new dylib table of contents without the global symbols
4584 * that got turned into non-globals.
4586 new_ntoc = ntoc - nchanged_globals;
4587 new_tocs = allocate(new_ntoc *
4588 sizeof(struct dylib_table_of_contents));
4589 k = 0;
4590 for(i = 0; i < ntoc; i++){
4591 if(tocs[i].symbol_index >= nsyms){
4592 error_arch(arch, member, "bad symbol index for table of "
4593 "contents table entry %ld in: ", i);
4594 return(FALSE);
4596 if(nmedits[tocs[i].symbol_index] == FALSE){
4597 new_tocs[k].symbol_index = saves[tocs[i].symbol_index] - 1;
4598 new_tocs[k].module_index = tocs[i].module_index;
4599 k++;
4604 * If is not a dynamic library so all global symbols changed into
4605 * statics can be moved to the end of the local symbols. If the pflag
4606 * is set then the changed symbols remain global and just get the
4607 * private extern bit set.
4609 else{
4611 * First put the existing local symbols into the new symbol table.
4613 inew_syms = 0;
4614 for(i = 0; i < nsyms; i++){
4615 if(object->mh != NULL){
4616 n_strx = symbols[i].n_un.n_strx;
4617 n_type = symbols[i].n_type;
4619 else{
4620 n_strx = symbols64[i].n_un.n_strx;
4621 n_type = symbols64[i].n_type;
4623 if((n_type & N_EXT) == 0){
4624 if(object->mh != NULL)
4625 new_symbols[inew_syms] = symbols[i];
4626 else
4627 new_symbols64[inew_syms] = symbols64[i];
4628 if(n_strx != 0){
4629 strcpy(q, strings + n_strx);
4630 if(object->mh != NULL)
4631 new_symbols[inew_syms].n_un.n_strx =
4632 q - new_strings;
4633 else
4634 new_symbols64[inew_syms].n_un.n_strx =
4635 q - new_strings;
4636 q += strlen(q) + 1;
4638 inew_syms++;
4639 saves[i] = inew_syms;
4643 * Next put the global symbols that were changed into statics
4644 * symbols into the new symbol table.
4646 if(pflag == FALSE){
4647 for(i = 0; i < nsyms; i++){
4648 if(object->mh != NULL){
4649 n_strx = symbols[i].n_un.n_strx;
4650 n_type = symbols[i].n_type;
4652 else{
4653 n_strx = symbols64[i].n_un.n_strx;
4654 n_type = symbols64[i].n_type;
4656 if((n_type & N_EXT) != 0){
4657 if(nmedits[i] == TRUE){
4659 * Change the new symbol to not be an extern symbol
4660 * by turning off the extern bit.
4662 if(object->mh != NULL){
4663 new_symbols[inew_syms] = symbols[i];
4664 new_symbols[inew_syms].n_type &= ~N_EXT;
4665 new_symbols[inew_syms].n_desc &= ~N_WEAK_DEF;
4667 else{
4668 new_symbols64[inew_syms] = symbols64[i];
4669 new_symbols64[inew_syms].n_type &= ~N_EXT;
4670 new_symbols64[inew_syms].n_desc &= ~N_WEAK_DEF;
4672 if(n_strx != 0){
4673 strcpy(q, strings + n_strx);
4674 if(object->mh != NULL)
4675 new_symbols[inew_syms].n_un.n_strx =
4676 q - new_strings;
4677 else
4678 new_symbols64[inew_syms].n_un.n_strx =
4679 q - new_strings;
4680 q += strlen(q) + 1;
4682 inew_syms++;
4683 saves[i] = inew_syms;
4689 * Last put the unchanged global symbols into the new symbol table
4690 * and symbols changed into private externs.
4692 for(i = 0; i < nsyms; i++){
4693 if(object->mh != NULL){
4694 n_strx = symbols[i].n_un.n_strx;
4695 n_type = symbols[i].n_type;
4697 else{
4698 n_strx = symbols64[i].n_un.n_strx;
4699 n_type = symbols64[i].n_type;
4701 if((n_type & N_EXT) != 0){
4702 if(nmedits[i] == FALSE || pflag == TRUE){
4703 if(object->mh != NULL)
4704 new_symbols[inew_syms] = symbols[i];
4705 else
4706 new_symbols64[inew_syms] = symbols64[i];
4707 if(nmedits[i] == TRUE && pflag == TRUE){
4709 * Change the new symbol to be a private extern
4710 * symbol by turning on the private extern bit.
4712 if(object->mh != NULL)
4713 new_symbols[inew_syms].n_type |= N_PEXT;
4714 else
4715 new_symbols64[inew_syms].n_type |= N_PEXT;
4717 if(n_strx != 0){
4718 strcpy(p, strings + n_strx);
4719 if(object->mh != NULL)
4720 new_symbols[inew_syms].n_un.n_strx =
4721 p - new_strings;
4722 else
4723 new_symbols64[inew_syms].n_un.n_strx =
4724 p - new_strings;
4725 p += strlen(p) + 1;
4727 inew_syms++;
4728 saves[i] = inew_syms;
4734 if(sections != NULL);
4735 free(sections);
4736 if(sections64 != NULL);
4737 free(sections64);
4739 if(errors == 0)
4740 return(TRUE);
4741 else
4742 return(FALSE);
4746 * Function for qsort for comparing global symbol names.
4748 static
4750 cmp_qsort_global(
4751 const struct nlist **sym1,
4752 const struct nlist **sym2)
4754 return(strcmp(global_strings + (*sym1)->n_un.n_strx,
4755 global_strings + (*sym2)->n_un.n_strx));
4758 static
4760 cmp_qsort_global_64(
4761 const struct nlist_64 **sym1,
4762 const struct nlist_64 **sym2)
4764 return(strcmp(global_strings + (*sym1)->n_un.n_strx,
4765 global_strings + (*sym2)->n_un.n_strx));
4769 * Function for bsearch for finding a global symbol that matches a stab name.
4771 static
4773 cmp_bsearch_global_stab(
4774 const char *name,
4775 const struct nlist **sym)
4778 * The +1 is for the '_' on the global symbol that is not on the
4779 * stab string that is trying to be matched.
4781 return(strcmp(name, global_strings + (*sym)->n_un.n_strx + 1));
4784 static
4786 cmp_bsearch_global_stab_64(
4787 const char *name,
4788 const struct nlist_64 **sym)
4791 * The +1 is for the '_' on the global symbol that is not on the
4792 * stab string that is trying to be matched.
4794 return(strcmp(name, global_strings + (*sym)->n_un.n_strx + 1));
4798 * Function for bsearch for finding a global symbol that matches a stab name
4799 * in the debug map.
4801 static
4803 cmp_bsearch_global(
4804 const char *name,
4805 const struct nlist **sym)
4807 return(strcmp(name, global_strings + (*sym)->n_un.n_strx));
4810 static
4812 cmp_bsearch_global_64(
4813 const char *name,
4814 const struct nlist_64 **sym)
4816 return(strcmp(name, global_strings + (*sym)->n_un.n_strx));
4818 #endif /* defined(NMEDIT) */