Find ld in the PATH when make_ld_r_object is called
[striptease.git] / tease.c
blob181fec449f60f329d6639d6bbca3ec88dfd73df4
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/rnd.h"
44 #include "stuff/reloc.h"
45 #include "stuff/reloc.h"
46 #include "stuff/symbol_list.h"
47 #include "stuff/unix_standard_mode.h"
48 #include "stuff/execute.h"
49 #ifdef TRIE_SUPPORT
50 #include <mach-o/prune_trie.h>
51 #endif /* TRIE_SUPPORT */
53 typedef struct dylib_name_s {
54 struct dylib_name_s *next;
55 char *name;
56 } dylib_name;
58 /* These are set from the command line arguments */
59 __private_extern__
60 char *progname = NULL; /* name of the program for error messages (argv[0]) */
61 static char *output_file;/* name of the output file */
62 static char *sfile; /* filename of global symbol names to keep */
63 static char *Rfile; /* filename of global symbol names to remove */
64 static uint32_t Aflag; /* save only absolute symbols with non-zero value and
65 .objc_class_name_* symbols */
66 static uint32_t aflag; /* -a save all symbols, just regenerate symbol table */
67 static uint32_t iflag; /* -i ignore symbols in -s file not in object */
68 #ifdef NMEDIT
69 static uint32_t pflag; /* make all defined global symbols private extern */
70 #else /* !defined(NMEDIT) */
71 static char *dfile; /* filename of filenames of debugger symbols to keep */
72 static uint32_t uflag; /* save undefined symbols */
73 static uint32_t rflag; /* save symbols referenced dynamically */
74 static uint32_t nflag; /* save N_SECT global symbols */
75 static uint32_t Sflag; /* -S strip only debugger symbols N_STAB */
76 static uint32_t xflag; /* -x strip non-globals */
77 static uint32_t Xflag; /* -X strip local symbols with 'L' names */
78 static uint32_t tflag; /* -t strip local symbols except those in the text
79 section with names that don't begin with 'L' */
80 static uint32_t cflag; /* -c strip section contents from dynamic libraries
81 files to create stub libraries */
82 static uint32_t no_uuid;/* -no_uuid strip LC_UUID load commands */
83 static uint32_t no_code_signature;
84 /* -no_code_signature strip LC_CODE_SIGNATURE cmds */
85 static dylib_name *no_dylib;
86 /* -no_dylib options (zero or more) */
87 static uint32_t no_dylib_unused;
88 /* strip unused dylib references */
89 static uint32_t vflag; /* -v for verbose debugging ld -r executions */
90 static uint32_t lflag; /* -l do ld -r executions even if it has bugs */
91 static uint32_t strip_all = 1;
93 * This is set on an object by object basis if the strip_all flag is still set
94 * and the object is an executable that is for use with the dynamic linker.
95 * This has the same effect as -r and -u.
97 static enum bool default_dyld_executable = FALSE;
98 #endif /* NMEDIT */
101 * Data structures to perform selective stripping of symbol table entries.
102 * save_symbols is the names of the symbols from the -s <file> argument.
103 * remove_symbols is the names of the symbols from the -R <file> argument.
105 static struct symbol_list *save_symbols = NULL;
106 static uint32_t nsave_symbols = 0;
107 static struct symbol_list *remove_symbols = NULL;
108 static uint32_t nremove_symbols = 0;
111 * saves points to an array of uint32_t's that is allocated. This array is a
112 * map of old symbol indexes to new symbol indexes. The new symbol indexes are
113 * plus 1 and zero value means that old symbol is not in the new symbol table.
114 * ref_saves is used in the same way but for the reference table.
115 * nmedits is an array and indexed by the symbol index the value indicates if
116 * the symbol was edited and turned into a non-global.
118 static int32_t *saves = NULL;
119 #ifndef NMEDIT
120 static int32_t *ref_saves = NULL;
121 #else
122 static enum bool *nmedits = NULL;
123 #endif
126 * These hold pointers to the symbol, string and indirect tables being worked on
127 * by strip_object and strip_symtab() from an input object file or possiblity
128 * changed to an ld -r (-S or -x) file by make_ld_r_object().
130 static struct nlist *symbols = NULL;
131 static struct nlist_64 *symbols64 = NULL;
132 static uint32_t nsyms = 0;
133 static char *strings = NULL;
134 static uint32_t strsize = 0;
135 static uint32_t *indirectsyms = NULL;
136 static uint32_t nindirectsyms = 0;
139 * These hold the new symbol and string table created by strip_symtab()
140 * and the new counts of local, defined external and undefined symbols.
142 static struct nlist *new_symbols = NULL;
143 static struct nlist_64 *new_symbols64 = NULL;
144 static uint32_t new_nsyms = 0;
145 static char *new_strings = NULL;
146 static uint32_t new_strsize = 0;
147 static uint32_t new_nlocalsym = 0;
148 static uint32_t new_nextdefsym = 0;
149 static uint32_t new_nundefsym = 0;
150 #if defined(TRIE_SUPPORT) && !defined(NMEDIT)
152 * The index into the new symbols where the defined external start.
154 static uint32_t inew_nextdefsym = 0;
155 #endif
158 * These hold the new table of contents, reference table and module table for
159 * dylibs.
161 static struct dylib_table_of_contents *new_tocs = NULL;
162 static uint32_t new_ntoc = 0;
163 static struct dylib_reference *new_refs = NULL;
164 static uint32_t new_nextrefsyms = 0;
165 #ifdef NMEDIT
166 static struct dylib_module *new_mods = NULL;
167 static struct dylib_module_64 *new_mods64 = NULL;
168 static uint32_t new_nmodtab = 0;
169 #endif
171 #ifndef NMEDIT
173 * The list of file names to save debugging symbols from.
175 static char **debug_filenames = NULL;
176 static uint32_t ndebug_filenames = 0;
177 struct undef_map {
178 uint32_t index;
179 struct nlist symbol;
181 struct undef_map64 {
182 uint32_t index;
183 struct nlist_64 symbol64;
185 static char *qsort_strings = NULL;
186 #endif /* !defined(NMEDIT) */
189 /* Internal routines */
190 static void usage(
191 void);
193 static void strip_file(
194 char *input_file,
195 struct arch_flag *arch_flags,
196 uint32_t narch_flags,
197 enum bool all_archs);
199 static void strip_arch(
200 struct arch *archs,
201 uint32_t narchs,
202 struct arch_flag *arch_flags,
203 uint32_t narch_flags,
204 enum bool all_archs);
206 static void strip_object(
207 struct arch *arch,
208 struct member *member,
209 struct object *object);
211 static uint32_t get_starting_syminfo_offset(
212 struct object *object);
214 static void check_object_relocs(
215 struct arch *arch,
216 struct member *member,
217 struct object *object,
218 char *segname,
219 char *sectname,
220 uint64_t sectsize,
221 char *contents,
222 struct relocation_info *relocs,
223 uint32_t nreloc,
224 struct nlist *symbols,
225 struct nlist_64 *symbols64,
226 uint32_t nsyms,
227 char *strings,
228 int32_t *missing_reloc_symbols,
229 enum byte_sex host_byte_sex);
231 static void check_indirect_symtab(
232 struct arch *arch,
233 struct member *member,
234 struct object *object,
235 uint32_t nitems,
236 uint32_t reserved1,
237 uint32_t section_type,
238 char *contents,
239 struct nlist *symbols,
240 struct nlist_64 *symbols64,
241 uint32_t nsyms,
242 char *strings,
243 int32_t *missing_reloc_symbols,
244 enum byte_sex host_byte_sex);
246 #ifndef NMEDIT
247 static enum bool strip_symtab(
248 struct arch *arch,
249 struct member *member,
250 struct object *object,
251 struct dylib_table_of_contents *tocs,
252 uint32_t ntoc,
253 struct dylib_module *mods,
254 struct dylib_module_64 *mods64,
255 uint32_t nmodtab,
256 struct dylib_reference *refs,
257 uint32_t nextrefsyms);
259 #ifdef TRIE_SUPPORT
260 static int prune(
261 const char *name);
262 #endif /* TRIE_SUPPORT */
264 static void make_ld_r_object(
265 struct arch *arch,
266 struct member *member,
267 struct object *object);
269 static void strip_LC_UUID_commands(
270 struct arch *arch,
271 struct member *member,
272 struct object *object);
274 static void strip_LC_DYLIB_commands(
275 struct arch *arch,
276 struct member *member,
277 struct object *object);
279 #ifndef NMEDIT
280 static void strip_LC_CODE_SIGNATURE_commands(
281 struct arch *arch,
282 struct member *member,
283 struct object *object);
284 #endif /* !(NMEDIT) */
286 static enum bool private_extern_reference_by_module(
287 uint32_t symbol_index,
288 struct dylib_reference *refs,
289 uint32_t nextrefsyms);
291 static enum bool symbol_pointer_used(
292 uint32_t symbol_index,
293 uint32_t *indirectsyms,
294 uint32_t nindirectsyms);
296 static int cmp_qsort_undef_map(
297 const struct undef_map *sym1,
298 const struct undef_map *sym2);
300 static int cmp_qsort_undef_map_64(
301 const struct undef_map64 *sym1,
302 const struct undef_map64 *sym2);
303 #endif /* !defined(NMEDIT) */
305 #ifdef NMEDIT
306 static enum bool edit_symtab(
307 struct arch *arch,
308 struct member *member,
309 struct object *object,
310 struct nlist *symbols,
311 struct nlist_64 *symbols64,
312 uint32_t nsyms,
313 char *strings,
314 uint32_t strsize,
315 struct dylib_table_of_contents *tocs,
316 uint32_t ntoc,
317 struct dylib_module *mods,
318 struct dylib_module_64 *mods64,
319 uint32_t nmodtab,
320 struct dylib_reference *refs,
321 uint32_t nextrefsyms);
322 #endif /* NMEDIT */
324 #ifndef NMEDIT
325 static void setup_debug_filenames(
326 char *dfile);
328 static int cmp_qsort_filename(
329 const char **name1,
330 const char **name2);
332 static int cmp_bsearch_filename(
333 const char *name1,
334 const char **name2);
335 #endif /* NMEDIT */
337 #ifdef NMEDIT
339 * This variable and routines are used for nmedit(1) only.
341 static char *global_strings = NULL;
343 static int cmp_qsort_global(
344 const struct nlist **sym1,
345 const struct nlist **sym2);
347 static int cmp_qsort_global_64(
348 const struct nlist_64 **sym1,
349 const struct nlist_64 **sym2);
351 static int cmp_bsearch_global_stab(
352 const char *name,
353 const struct nlist **sym);
355 static int cmp_bsearch_global_stab_64(
356 const char *name,
357 const struct nlist_64 **sym);
359 static int cmp_bsearch_global(
360 const char *name,
361 const struct nlist **sym);
363 static int cmp_bsearch_global_64(
364 const char *name,
365 const struct nlist_64 **sym);
366 #endif /* NMEDIT */
368 /* apple_version is created by the libstuff/Makefile */
369 extern char apple_version[];
370 char *version = apple_version;
373 main(
374 int argc,
375 char *argv[],
376 char *envp[])
378 int i;
379 uint32_t j, args_left, files_specified;
380 struct arch_flag *arch_flags;
381 uint32_t narch_flags;
382 enum bool all_archs;
383 struct symbol_list *sp;
385 progname = argv[0];
387 arch_flags = NULL;
388 narch_flags = 0;
389 all_archs = FALSE;
391 files_specified = 0;
392 args_left = 1;
393 for (i = 1; i < argc; i++){
394 if(argv[i][0] == '-'){
395 if(argv[i][1] == '\0'){
396 args_left = 0;
397 break;
399 if(strcmp(argv[i], "-o") == 0){
400 if(i + 1 >= argc)
401 fatal("-o requires an argument");
402 if(output_file != NULL)
403 fatal("only one -o option allowed");
404 output_file = argv[i + 1];
405 i++;
407 else if(strcmp(argv[i], "-s") == 0){
408 if(i + 1 >= argc)
409 fatal("-s requires an argument");
410 if(sfile != NULL)
411 fatal("only one -s option allowed");
412 sfile = argv[i + 1];
413 i++;
415 else if(strcmp(argv[i], "-R") == 0){
416 if(i + 1 >= argc)
417 fatal("-R requires an argument");
418 if(Rfile != NULL)
419 fatal("only one -R option allowed");
420 Rfile = argv[i + 1];
421 i++;
423 #ifndef NMEDIT
424 else if(strcmp(argv[i], "-d") == 0){
425 if(i + 1 >= argc)
426 fatal("-d requires an argument");
427 if(dfile != NULL)
428 fatal("only one -d option allowed");
429 dfile = argv[i + 1];
430 i++;
432 else if(strcmp(argv[i], "-no_uuid") == 0){
433 no_uuid = 1;
435 else if(strcmp(argv[i], "-no_dylib") == 0){
436 dylib_name *dname;
437 if(i + 1 >= argc)
438 fatal("-no_dylib requires an argument");
439 dname = (dylib_name *)malloc(sizeof(dylib_name));
440 if(!dname)
441 fatal("out of memory (malloc failed)");
442 dname->next = no_dylib;
443 dname->name = argv[i + 1];
444 no_dylib = dname;
445 i++;
447 else if(strcmp(argv[i], "-no_dylib_unused") == 0){
448 no_dylib_unused = 1;
450 else if(strcmp(argv[i], "-no_code_signature") == 0){
451 no_code_signature = 1;
453 #endif /* !defined(NMEDIT) */
454 else if(strcmp(argv[i], "-arch") == 0){
455 if(i + 1 == argc){
456 error("missing argument(s) to %s option", argv[i]);
457 usage();
459 if(strcmp("all", argv[i+1]) == 0){
460 all_archs = TRUE;
462 else{
463 arch_flags = reallocate(arch_flags,
464 (narch_flags + 1) * sizeof(struct arch_flag));
465 if(get_arch_from_flag(argv[i+1],
466 arch_flags + narch_flags) == 0){
467 error("unknown architecture specification flag: "
468 "%s %s", argv[i], argv[i+1]);
469 arch_usage();
470 usage();
472 for(j = 0; j < narch_flags; j++){
473 if(arch_flags[j].cputype ==
474 arch_flags[narch_flags].cputype &&
475 (arch_flags[j].cpusubtype & ~CPU_SUBTYPE_MASK) ==
476 (arch_flags[narch_flags].cpusubtype &
477 ~CPU_SUBTYPE_MASK) &&
478 strcmp(arch_flags[j].name,
479 arch_flags[narch_flags].name) == 0)
480 break;
482 if(j == narch_flags)
483 narch_flags++;
485 i++;
487 else{
488 for(j = 1; argv[i][j] != '\0'; j++){
489 switch(argv[i][j]){
490 #ifdef NMEDIT
491 case 'p':
492 pflag = 1;
493 break;
494 #else /* !defined(NMEDIT) */
495 case 'S':
496 Sflag = 1;
497 strip_all = 0;
498 break;
499 case 'X':
500 Xflag = 1;
501 strip_all = 0;
502 break;
503 case 'x':
504 xflag = 1;
505 strip_all = 0;
506 break;
507 case 't':
508 tflag = 1;
509 strip_all = 0;
510 break;
511 case 'i':
512 iflag = 1;
513 break;
514 case 'u':
515 uflag = 1;
516 strip_all = 0;
517 break;
518 case 'r':
519 rflag = 1;
520 strip_all = 0;
521 break;
522 case 'n':
523 nflag = 1;
524 strip_all = 0;
525 break;
526 #endif /* !defined(NMEDIT) */
527 case 'A':
528 Aflag = 1;
529 #ifndef NMEDIT
530 strip_all = 0;
531 #endif /* !defined(NMEDIT) */
532 break;
533 #ifndef NMEDIT
534 case 'a':
535 aflag = 1;
536 strip_all = 0;
537 break;
538 case 'c':
539 cflag = 1;
540 strip_all = 0;
541 break;
542 case 'v':
543 vflag = 1;
544 break;
545 case 'l':
546 lflag = 1;
547 break;
548 #endif /* NMEDIT */
549 default:
550 error("unrecognized option: %s", argv[i]);
551 usage();
556 else
557 files_specified++;
559 if(args_left == 0)
560 files_specified += argc - (i + 1);
562 if(files_specified > 1 && output_file != NULL){
563 error("-o <filename> can only be used when one file is specified");
564 usage();
567 if(sfile){
568 setup_symbol_list(sfile, &save_symbols, &nsave_symbols);
570 #ifdef NMEDIT
571 else{
572 if(Rfile == NULL && pflag == 0){
573 error("-s <filename>, -R <filename> or -p argument required");
574 usage();
577 #endif /* NMEDIT */
579 if(Rfile){
580 setup_symbol_list(Rfile, &remove_symbols, &nremove_symbols);
581 if(sfile){
582 for(j = 0; j < nremove_symbols ; j++){
583 sp = bsearch(remove_symbols[j].name,
584 save_symbols, nsave_symbols,
585 sizeof(struct symbol_list),
586 (int (*)(const void *, const void *))
587 symbol_list_bsearch);
588 if(sp != NULL){
589 error("symbol name: %s is listed in both -s %s and -R "
590 "%s files (can't be both saved and removed)",
591 remove_symbols[j].name, sfile, Rfile);
594 if(errors)
595 exit(EXIT_FAILURE);
599 /* the default when no -arch flags is present is to strip all archs */
600 if(narch_flags == 0)
601 all_archs = TRUE;
603 #ifndef NMEDIT
604 if(dfile){
605 setup_debug_filenames(dfile);
607 #endif /* !defined(NMEDIT) */
609 files_specified = 0;
610 args_left = 1;
611 for (i = 1; i < argc; i++) {
612 if(args_left && argv[i][0] == '-'){
613 if(argv[i][1] == '\0')
614 args_left = 0;
615 else if(strcmp(argv[i], "-o") == 0 ||
616 strcmp(argv[i], "-s") == 0 ||
617 strcmp(argv[i], "-R") == 0 ||
618 #ifndef NMEDIT
619 strcmp(argv[i], "-d") == 0 ||
620 strcmp(argv[i], "-no_dylib") == 0 ||
621 #endif /* !defined(NMEDIT) */
622 strcmp(argv[i], "-arch") == 0)
623 i++;
625 else{
626 char resolved_path[PATH_MAX + 1];
628 if(realpath(argv[i], resolved_path) == NULL)
629 strip_file(argv[i], arch_flags, narch_flags, all_archs);
630 else
631 strip_file(resolved_path, arch_flags,narch_flags,all_archs);
632 files_specified++;
635 if(files_specified == 0)
636 fatal("no files specified");
638 if(errors)
639 return(EXIT_FAILURE);
640 else
641 return(EXIT_SUCCESS);
644 static
645 void
646 usage(
647 void)
649 #ifndef NMEDIT
650 fprintf(stderr, "Usage: %s [-AanuStXx] [-no_uuid] [-no_code_signature] "
651 "[-no_dylib filename] [-no_dylib_unused] [-] [-d filename] "
652 "[-s filename] [-R filename] [-o output] file [...]\n",
653 progname);
654 #else /* defined(NMEDIT) */
655 fprintf(stderr, "Usage: %s -s filename [-R filename] [-p] [-A] [-] "
656 "[-o output] file [...] \n",
657 progname);
658 #endif /* NMEDIT */
659 exit(EXIT_FAILURE);
662 static
663 void
664 strip_file(
665 char *input_file,
666 struct arch_flag *arch_flags,
667 uint32_t narch_flags,
668 enum bool all_archs)
670 struct ofile *ofile;
671 struct arch *archs;
672 uint32_t narchs;
673 struct stat stat_buf;
674 uint32_t previous_errors;
675 enum bool unix_standard_mode;
676 int cwd_fd;
677 char *rename_file;
678 #ifndef NMEDIT
679 char *p;
680 #endif
682 archs = NULL;
683 narchs = 0;
684 previous_errors = errors;
685 errors = 0;
687 /* breakout the file for processing */
688 ofile = breakout(input_file, &archs, &narchs, FALSE);
689 if(errors)
690 return;
692 /* checkout the file for symbol table replacement processing */
693 checkout(archs, narchs);
695 /* process the symbols in the input file */
696 strip_arch(archs, narchs, arch_flags, narch_flags, all_archs);
697 if(errors){
698 free_archs(archs, narchs);
699 ofile_unmap(ofile);
700 return;
703 /* create the output file */
704 if(stat(input_file, &stat_buf) == -1)
705 system_error("can't stat input file: %s", input_file);
706 if(output_file != NULL){
707 writeout(archs, narchs, output_file, stat_buf.st_mode & 0777,
708 TRUE, FALSE, FALSE, NULL);
710 else{
711 unix_standard_mode = get_unix_standard_mode();
712 rename_file = NULL;
713 cwd_fd = -1;
714 #ifdef NMEDIT
715 output_file = makestr(input_file, ".nmedit", NULL);
716 #else /* !defined(NMEDIT) */
718 * In UNIX standard conformance mode we are not allowed to replace
719 * a file that is not writeable.
721 if(unix_standard_mode == TRUE &&
722 access(input_file, W_OK) == -1){
723 system_error("file: %s is not writable", input_file);
724 goto strip_file_return;
726 output_file = makestr(input_file, ".strip", NULL);
729 * The UNIX standard conformance test suite expects files of
730 * MAXPATHLEN to work.
732 if(strlen(output_file) >= MAXPATHLEN){
734 * If there is a directory path in the name try to change
735 * the current working directory to that path.
737 if((p = rindex(output_file, '/')) != NULL){
738 if((cwd_fd = open(".", O_RDONLY, 0)) == -1){
739 system_error("can't open current working directory");
740 goto strip_file_return;
742 *p = '\0';
743 if(chdir(output_file) == -1){
744 system_error("can't change current working directory "
745 "to: %s", output_file);
746 goto strip_file_return;
748 p = rindex(input_file, '/');
749 rename_file = makestr(p + 1, NULL);
752 * Create what might be a short enough name.
754 free(output_file);
755 output_file = makestr("strip.XXXXXX", NULL);
756 output_file = mktemp(output_file);
758 #endif /* NMEDIT */
759 writeout(archs, narchs, output_file, stat_buf.st_mode & 0777,
760 TRUE, FALSE, FALSE, NULL);
761 if(rename_file != NULL){
762 if(rename(output_file, rename_file) == -1)
763 system_error("can't move temporary file: %s to file: %s",
764 output_file, rename_file);
765 free(rename_file);
767 else{
768 if(rename(output_file, input_file) == -1)
769 system_error("can't move temporary file: %s to input "
770 "file: %s", output_file, input_file);
772 free(output_file);
773 output_file = NULL;
776 * If we changed the current working directory change back to
777 * the previous working directory.
779 if(cwd_fd != -1){
780 if(fchdir(cwd_fd) == -1)
781 system_error("can't change back to previous working "
782 "directory");
783 if(close(cwd_fd) == -1)
784 system_error("can't close previous working directory");
788 #ifndef NMEDIT
789 strip_file_return:
790 #endif /* !defined(NMEDIT) */
791 /* clean-up data structures */
792 free_archs(archs, narchs);
793 ofile_unmap(ofile);
795 errors += previous_errors;
798 static
799 void
800 strip_arch(
801 struct arch *archs,
802 uint32_t narchs,
803 struct arch_flag *arch_flags,
804 uint32_t narch_flags,
805 enum bool all_archs)
807 uint32_t i, j, k, offset, size, missing_syms;
808 cpu_type_t cputype;
809 cpu_subtype_t cpusubtype;
810 struct arch_flag host_arch_flag;
811 enum bool arch_process, any_processing, *arch_flag_processed, family;
812 const struct arch_flag *family_arch_flag;
815 * Using the specified arch_flags process specified objects for those
816 * architecures.
818 any_processing = FALSE;
819 arch_flag_processed = NULL;
820 if(narch_flags != 0)
821 arch_flag_processed = allocate(narch_flags * sizeof(enum bool));
822 memset(arch_flag_processed, '\0', narch_flags * sizeof(enum bool));
823 for(i = 0; i < narchs; i++){
825 * Determine the architecture (cputype and cpusubtype) of arch[i]
827 cputype = 0;
828 cpusubtype = 0;
829 if(archs[i].type == OFILE_ARCHIVE){
830 for(j = 0; j < archs[i].nmembers; j++){
831 if(archs[i].members[j].type == OFILE_Mach_O){
832 cputype = archs[i].members[j].object->mh_cputype;
833 cpusubtype = archs[i].members[j].object->mh_cpusubtype;
834 break;
838 else if(archs[i].type == OFILE_Mach_O){
839 cputype = archs[i].object->mh_cputype;
840 cpusubtype = archs[i].object->mh_cpusubtype;
842 else if(archs[i].fat_arch != NULL){
843 cputype = archs[i].fat_arch->cputype;
844 cpusubtype = archs[i].fat_arch->cpusubtype;
846 arch_process = FALSE;
847 if(all_archs == TRUE){
848 arch_process = TRUE;
850 else if(narch_flags != 0){
851 family = FALSE;
852 if(narch_flags == 1){
853 family_arch_flag =
854 get_arch_family_from_cputype(arch_flags[0].cputype);
855 if(family_arch_flag != NULL)
856 family = (enum bool)
857 ((family_arch_flag->cpusubtype & ~CPU_SUBTYPE_MASK) ==
858 (arch_flags[0].cpusubtype & ~CPU_SUBTYPE_MASK));
860 for(j = 0; j < narch_flags; j++){
861 if(arch_flags[j].cputype == cputype &&
862 ((arch_flags[j].cpusubtype & ~CPU_SUBTYPE_MASK) ==
863 (cpusubtype & ~CPU_SUBTYPE_MASK) ||
864 family == TRUE)){
865 arch_process = TRUE;
866 arch_flag_processed[j] = TRUE;
867 break;
871 else{
872 (void)get_arch_from_host(&host_arch_flag, NULL);
873 if(host_arch_flag.cputype == cputype &&
874 (host_arch_flag.cpusubtype & ~CPU_SUBTYPE_MASK) ==
875 (cpusubtype & ~CPU_SUBTYPE_MASK))
876 arch_process = TRUE;
878 if(narchs != 1 && arch_process == FALSE)
879 continue;
880 any_processing = TRUE;
883 * Now this arch[i] has been selected to be processed so process it
884 * according to its type.
886 if(archs[i].type == OFILE_ARCHIVE){
887 for(j = 0; j < archs[i].nmembers; j++){
888 if(archs[i].members[j].type == OFILE_Mach_O){
889 strip_object(archs + i, archs[i].members + j,
890 archs[i].members[j].object);
893 missing_syms = 0;
894 if(iflag == 0){
895 for(k = 0; k < nsave_symbols; k++){
896 if(save_symbols[k].seen == FALSE){
897 if(missing_syms == 0){
898 error_arch(archs + i, NULL, "symbols names "
899 "listed in: %s not in: ", sfile);
900 missing_syms = 1;
902 fprintf(stderr, "%s\n", save_symbols[k].name);
906 for(k = 0; k < nsave_symbols; k++){
907 save_symbols[k].seen = FALSE;
909 missing_syms = 0;
910 if(iflag == 0){
911 for(k = 0; k < nremove_symbols; k++){
912 if(remove_symbols[k].seen == FALSE){
913 if(missing_syms == 0){
914 error_arch(archs + i, NULL, "symbols names "
915 "listed in: %s not defined in: ",
916 Rfile);
917 missing_syms = 1;
919 fprintf(stderr, "%s\n", remove_symbols[k].name);
923 for(k = 0; k < nremove_symbols; k++){
924 remove_symbols[k].seen = FALSE;
927 * Reset the library offsets and size.
929 offset = 0;
930 for(j = 0; j < archs[i].nmembers; j++){
931 archs[i].members[j].offset = offset;
932 size = 0;
933 if(archs[i].members[j].member_long_name == TRUE){
934 size = rnd(archs[i].members[j].member_name_size, 8) +
935 (rnd(sizeof(struct ar_hdr), 8) -
936 sizeof(struct ar_hdr));
937 archs[i].toc_long_name = TRUE;
939 if(archs[i].members[j].object != NULL){
940 size +=
941 rnd(archs[i].members[j].object->object_size -
942 archs[i].members[j].object->input_sym_info_size +
943 archs[i].members[j].object->output_sym_info_size,
945 sprintf(archs[i].members[j].ar_hdr->ar_size, "%-*ld",
946 (int)sizeof(archs[i].members[j].ar_hdr->ar_size),
947 (long)(size));
949 * This has to be done by hand because sprintf puts a
950 * null at the end of the buffer.
952 memcpy(archs[i].members[j].ar_hdr->ar_fmag, ARFMAG,
953 (int)sizeof(archs[i].members[j].ar_hdr->ar_fmag));
955 else{
956 size += archs[i].members[j].unknown_size;
958 offset += sizeof(struct ar_hdr) + size;
960 archs[i].library_size = offset;
962 else if(archs[i].type == OFILE_Mach_O){
963 strip_object(archs + i, NULL, archs[i].object);
965 else {
966 warning_arch(archs + i, NULL, "can't process non-object and "
967 "non-archive file: ");
968 return;
971 if(all_archs == FALSE && narch_flags != 0){
972 for(i = 0; i < narch_flags; i++){
973 if(arch_flag_processed[i] == FALSE)
974 error("file: %s does not contain architecture: %s",
975 archs[0].file_name, arch_flags[i].name);
977 free(arch_flag_processed);
979 if(any_processing == FALSE)
980 fatal("no processing done on input file: %s (specify a -arch flag)",
981 archs[0].file_name);
984 static
985 void
986 strip_object(
987 struct arch *arch,
988 struct member *member,
989 struct object *object)
991 enum byte_sex host_byte_sex;
992 uint32_t offset;
993 struct dylib_table_of_contents *tocs;
994 uint32_t ntoc;
995 struct dylib_module *mods;
996 struct dylib_module_64 *mods64;
997 uint32_t nmodtab;
998 struct dylib_reference *refs;
999 uint32_t nextrefsyms;
1000 uint32_t i, j;
1001 struct load_command *lc;
1002 struct segment_command *sg;
1003 struct segment_command_64 *sg64;
1004 struct section *s;
1005 struct section_64 *s64;
1006 struct relocation_info *relocs;
1007 struct scattered_relocation_info *sreloc;
1008 int32_t missing_reloc_symbols;
1009 uint32_t stride, section_type, nitems;
1010 char *contents;
1011 uint32_t dyld_info_start;
1012 uint32_t dyld_info_end;
1013 #ifndef NMEDIT
1014 uint32_t flags;
1015 uint32_t k;
1016 #endif
1017 uint32_t ncmds;
1019 host_byte_sex = get_host_byte_sex();
1021 /* Don't do anything to stub dylibs which have no load commands. */
1022 if(object->mh_filetype == MH_DYLIB_STUB){
1023 if((object->mh != NULL && object->mh->ncmds == 0) ||
1024 (object->mh64 != NULL && object->mh64->ncmds == 0)){
1025 return;
1028 if(object->mh_filetype == MH_DSYM)
1029 fatal_arch(arch, member, "can't process dSYM companion file: ");
1030 if(object->st == NULL || object->st->nsyms == 0){
1031 warning_arch(arch, member, "input object file stripped: ");
1032 return;
1035 nsyms = object->st->nsyms;
1036 if(object->mh != NULL){
1037 symbols = (struct nlist *)
1038 (object->object_addr + object->st->symoff);
1039 if(object->object_byte_sex != host_byte_sex)
1040 swap_nlist(symbols, nsyms, host_byte_sex);
1041 symbols64 = NULL;
1043 else{
1044 symbols = NULL;
1045 symbols64 = (struct nlist_64 *)
1046 (object->object_addr + object->st->symoff);
1047 if(object->object_byte_sex != host_byte_sex)
1048 swap_nlist_64(symbols64, nsyms, host_byte_sex);
1050 strings = object->object_addr + object->st->stroff;
1051 strsize = object->st->strsize;
1053 #ifndef NMEDIT
1054 if(object->mh != NULL)
1055 flags = object->mh->flags;
1056 else
1057 flags = object->mh64->flags;
1058 if(object->mh_filetype == MH_DYLIB &&
1059 (flags & MH_PREBOUND) != MH_PREBOUND){
1060 arch->dont_update_LC_ID_DYLIB_timestamp = TRUE;
1062 if(object->mh_filetype != MH_DYLIB && cflag)
1063 fatal_arch(arch, member, "-c can't be used on non-dynamic "
1064 "library: ");
1065 #endif /* !(NMEDIT) */
1066 if(object->mh_filetype == MH_DYLIB_STUB)
1067 fatal_arch(arch, member, "dynamic stub library can't be changed "
1068 "once created: ");
1070 if(object->mh_filetype == MH_DYLIB){
1071 tocs = (struct dylib_table_of_contents *)
1072 (object->object_addr + object->dyst->tocoff);
1073 ntoc = object->dyst->ntoc;
1074 nmodtab = object->dyst->nmodtab;
1075 if(object->mh != NULL){
1076 mods = (struct dylib_module *)
1077 (object->object_addr + object->dyst->modtaboff);
1078 if(object->object_byte_sex != host_byte_sex)
1079 swap_dylib_module(mods, nmodtab, host_byte_sex);
1080 mods64 = NULL;
1082 else{
1083 mods = NULL;
1084 mods64 = (struct dylib_module_64 *)
1085 (object->object_addr + object->dyst->modtaboff);
1086 if(object->object_byte_sex != host_byte_sex)
1087 swap_dylib_module_64(mods64, nmodtab, host_byte_sex);
1089 refs = (struct dylib_reference *)
1090 (object->object_addr + object->dyst->extrefsymoff);
1091 nextrefsyms = object->dyst->nextrefsyms;
1092 if(object->object_byte_sex != host_byte_sex){
1093 swap_dylib_table_of_contents(tocs, ntoc, host_byte_sex);
1094 swap_dylib_reference(refs, nextrefsyms, host_byte_sex);
1096 #ifndef NMEDIT
1098 * In the -c flag is specified then strip the section contents of
1099 * this dynamic library and change it into a stub library. When
1100 * creating a stub library the timestamp is not changed.
1102 if(cflag){
1103 arch->dont_update_LC_ID_DYLIB_timestamp = TRUE;
1105 lc = object->load_commands;
1106 if(object->mh != NULL){
1107 ncmds = object->mh->ncmds;
1108 object->mh_filetype = MH_DYLIB_STUB;
1109 object->mh->filetype = MH_DYLIB_STUB;
1111 else{
1112 ncmds = object->mh64->ncmds;
1113 object->mh_filetype = MH_DYLIB_STUB;
1114 object->mh64->filetype = MH_DYLIB_STUB;
1116 for(i = 0; i < ncmds; i++){
1117 if(lc->cmd == LC_SEGMENT){
1118 sg = (struct segment_command *)lc;
1119 if(strcmp(sg->segname, SEG_LINKEDIT) != 0){
1121 * Zero out the section offset, reloff, and size
1122 * fields as the section contents are being removed.
1124 s = (struct section *)
1125 ((char *)sg + sizeof(struct segment_command));
1126 for(j = 0; j < sg->nsects; j++){
1128 * For section types with indirect tables we
1129 * do not zero out the section size in a stub
1130 * library. As the section size is needed to
1131 * know now many indirect table entries the
1132 * section has. This is a bit odd but programs
1133 * dealing with MH_DYLIB_STUB filetypes special
1134 * case this.
1136 section_type = s[j].flags & SECTION_TYPE;
1137 if(section_type != S_SYMBOL_STUBS &&
1138 section_type != S_LAZY_SYMBOL_POINTERS &&
1139 section_type != S_LAZY_DYLIB_SYMBOL_POINTERS &&
1140 section_type != S_NON_LAZY_SYMBOL_POINTERS){
1141 s[j].size = 0;
1143 s[j].addr = 0;
1144 s[j].offset = 0;
1145 s[j].reloff = 0;
1147 /* zero out file offset and size in the segment */
1148 sg->fileoff = 0;
1149 sg->filesize = 0;
1152 else if(lc->cmd == LC_SEGMENT_64){
1153 sg64 = (struct segment_command_64 *)lc;
1154 if(strcmp(sg64->segname, SEG_LINKEDIT) != 0){
1156 * Zero out the section offset, reloff, and size
1157 * fields as the section contents are being removed.
1159 s64 = (struct section_64 *)
1160 ((char *)sg64 +
1161 sizeof(struct segment_command_64));
1162 for(j = 0; j < sg64->nsects; j++){
1164 * For section types with indirect tables we
1165 * do not zero out the section size in a stub
1166 * library. As the section size is needed to
1167 * know now many indirect table entries the
1168 * section has. This is a bit odd but programs
1169 * dealing with MH_DYLIB_STUB filetypes special
1170 * case this.
1172 section_type = s64[j].flags & SECTION_TYPE;
1173 if(section_type != S_SYMBOL_STUBS &&
1174 section_type != S_LAZY_SYMBOL_POINTERS &&
1175 section_type != S_LAZY_DYLIB_SYMBOL_POINTERS &&
1176 section_type != S_NON_LAZY_SYMBOL_POINTERS){
1177 s64[j].size = 0;
1179 s64[j].addr = 0;
1180 s64[j].offset = 0;
1181 s64[j].reloff = 0;
1183 /* zero out file offset and size in the segment */
1184 sg64->fileoff = 0;
1185 sg64->filesize = 0;
1188 lc = (struct load_command *)((char *)lc + lc->cmdsize);
1191 * To get the right amount of the file copied out by writeout()
1192 * for the case when we are stripping out the section contents
1193 * we reduce the object size by the size of the section contents
1194 * including the padding after the load commands. Then this
1195 * size minus the size of the input symbolic information is
1196 * copied out.
1198 if(object->mh != NULL){
1199 object->object_size -= (object->seg_linkedit->fileoff -
1200 (sizeof(struct mach_header) +
1201 object->mh->sizeofcmds));
1203 * Set the file offset to the link edit information to be
1204 * right after the load commands.
1206 object->seg_linkedit->fileoff =
1207 sizeof(struct mach_header) +
1208 object->mh->sizeofcmds;
1210 else{
1211 object->object_size -= (object->seg_linkedit64->fileoff -
1212 (sizeof(struct mach_header_64) +
1213 object->mh64->sizeofcmds));
1215 * Set the file offset to the link edit information to be
1216 * right after the load commands.
1218 object->seg_linkedit64->fileoff =
1219 sizeof(struct mach_header_64) +
1220 object->mh64->sizeofcmds;
1223 #endif /* !(NMEDIT) */
1225 else{
1226 tocs = NULL;
1227 ntoc = 0;
1228 mods = NULL;
1229 mods64 = NULL;
1230 nmodtab = 0;
1231 refs = NULL;
1232 nextrefsyms = 0;
1236 * coalesced symbols can be stripped only if they are not used via an
1237 * symbol pointer. So to know that strip_symtab() needs to be passed
1238 * the indirect symbol table.
1240 if(object->dyst != NULL && object->dyst->nindirectsyms != 0){
1241 nindirectsyms = object->dyst->nindirectsyms;
1242 indirectsyms = (uint32_t *)
1243 (object->object_addr + object->dyst->indirectsymoff);
1244 if(object->object_byte_sex != host_byte_sex)
1245 swap_indirect_symbols(indirectsyms, nindirectsyms,
1246 host_byte_sex);
1248 else{
1249 indirectsyms = NULL;
1250 nindirectsyms = 0;
1253 if(object->mh != NULL)
1254 object->input_sym_info_size =
1255 nsyms * sizeof(struct nlist) +
1256 strsize;
1257 else
1258 object->input_sym_info_size =
1259 nsyms * sizeof(struct nlist_64) +
1260 strsize;
1261 #ifndef NMEDIT
1262 if(object->mh != NULL)
1263 flags = object->mh->flags;
1264 else
1265 flags = object->mh64->flags;
1266 if(strip_all &&
1267 (flags & MH_DYLDLINK) == MH_DYLDLINK &&
1268 object->mh_filetype == MH_EXECUTE)
1269 default_dyld_executable = TRUE;
1270 else
1271 default_dyld_executable = FALSE;
1272 #endif /* !defined(NMEDIT) */
1274 #ifndef NMEDIT
1275 if(sfile != NULL || Rfile != NULL || dfile != NULL || Aflag || aflag ||
1276 uflag || Sflag || xflag || Xflag || tflag || nflag || rflag ||
1277 default_dyld_executable || object->mh_filetype == MH_DYLIB ||
1278 object->mh_filetype == MH_DYLINKER)
1279 #endif /* !defined(NMEDIT) */
1281 #ifdef NMEDIT
1282 if(edit_symtab(arch, member, object, symbols, symbols64, nsyms,
1283 strings, strsize, tocs, ntoc, mods, mods64, nmodtab, refs,
1284 nextrefsyms) == FALSE)
1285 return;
1286 #else /* !defined(NMEDIT) */
1287 if(strip_symtab(arch, member, object, tocs, ntoc, mods, mods64,
1288 nmodtab, refs, nextrefsyms) == FALSE)
1289 return;
1290 if(no_uuid == TRUE)
1291 strip_LC_UUID_commands(arch, member, object);
1292 if(no_dylib || no_dylib_unused)
1293 strip_LC_DYLIB_commands(arch, member, object);
1294 #endif /* !defined(NMEDIT) */
1296 * The parts that make up output_sym_info_size must be added up in
1297 * the output order so that when the sizes of things are rounded up
1298 * before parts that must be aligned the final output_sym_info_size
1299 * is correct.
1301 * Also the parts that make up input_sym_info_size must be added up
1302 * in the same way. And must be done here as the input file may
1303 * have been changed to and "ld -r" file and may not be the
1304 * the original input file.
1306 object->output_sym_info_size = 0;
1307 object->input_sym_info_size = 0;
1308 if(object->dyld_info != NULL){
1309 /* there are five parts to the dyld info, but
1310 strip does not alter them, so copy as a block */
1311 dyld_info_start = 0;
1312 if (object->dyld_info->rebase_off != 0)
1313 dyld_info_start = object->dyld_info->rebase_off;
1314 else if (object->dyld_info->bind_off != 0)
1315 dyld_info_start = object->dyld_info->bind_off;
1316 else if (object->dyld_info->weak_bind_off != 0)
1317 dyld_info_start = object->dyld_info->weak_bind_off;
1318 else if (object->dyld_info->lazy_bind_off != 0)
1319 dyld_info_start = object->dyld_info->lazy_bind_off;
1320 else if (object->dyld_info->export_off != 0)
1321 dyld_info_start = object->dyld_info->export_off;
1322 dyld_info_end = 0;
1323 if (object->dyld_info->export_size != 0)
1324 dyld_info_end = object->dyld_info->export_off
1325 + object->dyld_info->export_size;
1326 else if (object->dyld_info->lazy_bind_size != 0)
1327 dyld_info_end = object->dyld_info->lazy_bind_off
1328 + object->dyld_info->lazy_bind_size;
1329 else if (object->dyld_info->weak_bind_size != 0)
1330 dyld_info_end = object->dyld_info->weak_bind_off
1331 + object->dyld_info->weak_bind_size;
1332 else if (object->dyld_info->bind_size != 0)
1333 dyld_info_end = object->dyld_info->bind_off
1334 + object->dyld_info->bind_size;
1335 else if (object->dyld_info->rebase_size != 0)
1336 dyld_info_end = object->dyld_info->rebase_off
1337 + object->dyld_info->rebase_size;
1338 object->output_dyld_info = object->object_addr +dyld_info_start;
1339 object->output_dyld_info_size = dyld_info_end - dyld_info_start;
1340 object->output_sym_info_size += object->output_dyld_info_size;
1342 * Warn about strip -s or -R on a final linked image with
1343 * dyld_info.
1345 if(nsave_symbols != 0){
1346 warning_arch(arch, NULL, "removing global symbols from a "
1347 "final linked no longer supported. Use "
1348 "-exported_symbols_list at link time when "
1349 "building: ");
1351 object->input_sym_info_size += object->dyld_info->rebase_size
1352 + object->dyld_info->bind_size
1353 + object->dyld_info->weak_bind_size
1354 + object->dyld_info->lazy_bind_size
1355 + object->dyld_info->export_size;
1358 if(object->dyst != NULL){
1359 #ifndef NMEDIT
1361 * When stripping out the section contents to create a
1362 * dynamic library stub the relocation info also gets
1363 * stripped.
1365 if(!cflag)
1366 #endif /* !(NMEDIT) */
1368 object->output_sym_info_size +=
1369 object->dyst->nlocrel * sizeof(struct relocation_info);
1371 object->input_sym_info_size +=
1372 object->dyst->nlocrel * sizeof(struct relocation_info);
1375 if(object->split_info_cmd != NULL){
1376 object->output_split_info_data = object->object_addr +
1377 object->split_info_cmd->dataoff;
1378 object->output_split_info_data_size =
1379 object->split_info_cmd->datasize;
1380 object->input_sym_info_size += object->split_info_cmd->datasize;
1381 object->output_sym_info_size +=
1382 object->split_info_cmd->datasize;
1385 if(object->func_starts_info_cmd != NULL){
1386 object->output_func_start_info_data = object->object_addr +
1387 object->func_starts_info_cmd->dataoff;
1388 object->output_func_start_info_data_size =
1389 object->func_starts_info_cmd->datasize;
1390 object->input_sym_info_size +=
1391 object->func_starts_info_cmd->datasize;
1392 object->output_sym_info_size +=
1393 object->func_starts_info_cmd->datasize;
1396 if(object->data_in_code_cmd != NULL){
1397 object->output_data_in_code_info_data = object->object_addr +
1398 object->data_in_code_cmd->dataoff;
1399 object->output_data_in_code_info_data_size =
1400 object->data_in_code_cmd->datasize;
1401 object->input_sym_info_size +=
1402 object->data_in_code_cmd->datasize;
1403 object->output_sym_info_size +=
1404 object->data_in_code_cmd->datasize;
1407 if(object->code_sign_drs_cmd != NULL){
1408 object->output_code_sign_drs_info_data = object->object_addr +
1409 object->code_sign_drs_cmd->dataoff;
1410 object->output_code_sign_drs_info_data_size =
1411 object->code_sign_drs_cmd->datasize;
1412 object->input_sym_info_size +=
1413 object->code_sign_drs_cmd->datasize;
1414 object->output_sym_info_size +=
1415 object->code_sign_drs_cmd->datasize;
1418 if(object->mh != NULL){
1419 object->input_sym_info_size += nsyms * sizeof(struct nlist);
1420 object->output_symbols = new_symbols;
1421 object->output_sym_info_size +=
1422 new_nsyms * sizeof(struct nlist);
1424 else{
1425 object->input_sym_info_size += nsyms * sizeof(struct nlist_64);
1426 object->output_symbols64 = new_symbols64;
1427 object->output_sym_info_size +=
1428 new_nsyms * sizeof(struct nlist_64);
1430 object->output_nsymbols = new_nsyms;
1431 object->st->nsyms = new_nsyms;
1433 if(object->hints_cmd != NULL){
1434 object->input_sym_info_size +=
1435 object->hints_cmd->nhints *
1436 sizeof(struct twolevel_hint);
1437 object->output_sym_info_size +=
1438 object->hints_cmd->nhints *
1439 sizeof(struct twolevel_hint);
1442 if(object->dyst != NULL){
1443 #ifndef NMEDIT
1445 * When stripping out the section contents to create a
1446 * dynamic library stub the relocation info also gets
1447 * stripped.
1449 if(!cflag)
1450 #endif /* !(NMEDIT) */
1452 object->output_sym_info_size +=
1453 object->dyst->nextrel * sizeof(struct relocation_info);
1455 object->input_sym_info_size +=
1456 object->dyst->nextrel * sizeof(struct relocation_info);
1459 if(object->dyst != NULL){
1460 object->output_sym_info_size +=
1461 object->dyst->nindirectsyms * sizeof(uint32_t) +
1462 object->input_indirectsym_pad;
1463 if(object->mh != NULL){
1464 object->input_sym_info_size +=
1465 object->dyst->nindirectsyms * sizeof(uint32_t);
1467 else{
1468 object->input_sym_info_size +=
1469 object->dyst->nindirectsyms * sizeof(uint32_t) +
1470 object->input_indirectsym_pad;
1474 if(object->dyst != NULL){
1475 object->output_sym_info_size +=
1476 new_ntoc * sizeof(struct dylib_table_of_contents);
1477 object->input_sym_info_size +=
1478 object->dyst->ntoc * sizeof(struct dylib_table_of_contents);
1481 if(object->dyst != NULL){
1482 if(object->mh != NULL){
1483 object->output_sym_info_size +=
1484 object->dyst->nmodtab * sizeof(struct dylib_module);
1485 object->input_sym_info_size +=
1486 object->dyst->nmodtab * sizeof(struct dylib_module);
1488 else{
1489 object->output_sym_info_size +=
1490 object->dyst->nmodtab * sizeof(struct dylib_module_64);
1491 object->input_sym_info_size +=
1492 object->dyst->nmodtab * sizeof(struct dylib_module_64);
1496 if(object->dyst != NULL){
1497 object->output_sym_info_size +=
1498 new_nextrefsyms * sizeof(struct dylib_reference);
1499 object->input_sym_info_size +=
1500 object->dyst->nextrefsyms * sizeof(struct dylib_reference);
1503 object->output_strings = new_strings;
1504 object->output_strings_size = new_strsize;
1505 object->output_sym_info_size += new_strsize;
1506 object->input_sym_info_size += strsize;
1507 object->st->strsize = new_strsize;
1509 if(object->code_sig_cmd != NULL){
1510 #ifndef NMEDIT
1511 if(!cflag && !no_code_signature)
1512 #endif /* !(NMEDIT) */
1514 object->output_code_sig_data = object->object_addr +
1515 object->code_sig_cmd->dataoff;
1516 object->output_code_sig_data_size =
1517 object->code_sig_cmd->datasize;
1519 object->input_sym_info_size =
1520 rnd(object->input_sym_info_size, 16);
1521 object->input_sym_info_size +=
1522 object->code_sig_cmd->datasize;
1523 #ifndef NMEDIT
1524 if(cflag || no_code_signature){
1525 strip_LC_CODE_SIGNATURE_commands(arch, member, object);
1527 else
1528 #endif /* !(NMEDIT) */
1530 object->output_sym_info_size =
1531 rnd(object->output_sym_info_size, 16);
1532 object->output_sym_info_size +=
1533 object->code_sig_cmd->datasize;
1537 if(object->dyst != NULL){
1538 object->dyst->ilocalsym = 0;
1539 object->dyst->nlocalsym = new_nlocalsym;
1540 object->dyst->iextdefsym = new_nlocalsym;
1541 object->dyst->nextdefsym = new_nextdefsym;
1542 object->dyst->iundefsym = new_nlocalsym + new_nextdefsym;
1543 object->dyst->nundefsym = new_nundefsym;
1544 if(object->dyst->nindirectsyms != 0){
1545 object->output_indirect_symtab = indirectsyms;
1546 if(object->object_byte_sex != host_byte_sex)
1547 swap_indirect_symbols(indirectsyms, nindirectsyms,
1548 object->object_byte_sex);
1552 * If the -c option is specified the object's filetype will
1553 * have been changed from MH_DYLIB to MH_DYLIB_STUB above.
1555 if(object->mh_filetype == MH_DYLIB ||
1556 object->mh_filetype == MH_DYLIB_STUB){
1557 object->output_tocs = new_tocs;
1558 object->output_ntoc = new_ntoc;
1559 #ifdef NMEDIT
1560 if(object->mh != NULL)
1561 object->output_mods = new_mods;
1562 else
1563 object->output_mods64 = new_mods64;
1564 object->output_nmodtab = new_nmodtab;
1565 #else
1566 object->output_mods = mods;
1567 object->output_nmodtab = nmodtab;
1568 #endif
1569 object->output_refs = new_refs;
1570 object->output_nextrefsyms = new_nextrefsyms;
1571 if(object->object_byte_sex != host_byte_sex){
1572 swap_dylib_table_of_contents(new_tocs, new_ntoc,
1573 object->object_byte_sex);
1574 #ifdef NMEDIT
1575 if(object->mh != NULL)
1576 swap_dylib_module(new_mods, new_nmodtab,
1577 object->object_byte_sex);
1578 else
1579 swap_dylib_module_64(new_mods64, new_nmodtab,
1580 object->object_byte_sex);
1581 #else
1582 if(object->mh != NULL)
1583 swap_dylib_module(mods, nmodtab,
1584 object->object_byte_sex);
1585 else
1586 swap_dylib_module_64(mods64, nmodtab,
1587 object->object_byte_sex);
1588 #endif
1589 swap_dylib_reference(new_refs, new_nextrefsyms,
1590 object->object_byte_sex);
1593 object->dyst->ntoc = new_ntoc;
1594 object->dyst->nextrefsyms = new_nextrefsyms;
1596 offset = get_starting_syminfo_offset(object);
1598 if(object->dyld_info != 0){
1599 if (object->dyld_info->rebase_off != 0){
1600 object->dyld_info->rebase_off = offset;
1601 offset += object->dyld_info->rebase_size;
1603 if (object->dyld_info->bind_off != 0){
1604 object->dyld_info->bind_off = offset;
1605 offset += object->dyld_info->bind_size;
1607 if (object->dyld_info->weak_bind_off != 0){
1608 object->dyld_info->weak_bind_off = offset;
1609 offset += object->dyld_info->weak_bind_size;
1611 if (object->dyld_info->lazy_bind_off != 0){
1612 object->dyld_info->lazy_bind_off = offset;
1613 offset += object->dyld_info->lazy_bind_size;
1615 if (object->dyld_info->export_off != 0){
1616 object->dyld_info->export_off = offset;
1617 offset += object->dyld_info->export_size;
1621 if(object->dyst->nlocrel != 0){
1622 object->output_loc_relocs = (struct relocation_info *)
1623 (object->object_addr + object->dyst->locreloff);
1624 #ifndef NMEDIT
1626 * When stripping out the section contents to create a
1627 * dynamic library stub the relocation info also gets
1628 * stripped.
1630 if(cflag){
1631 object->dyst->nlocrel = 0;
1632 object->dyst->locreloff = 0;
1634 else
1635 #endif /* defined(NMEDIT) */
1637 object->dyst->locreloff = offset;
1638 offset += object->dyst->nlocrel *
1639 sizeof(struct relocation_info);
1642 else
1643 object->dyst->locreloff = 0;
1645 if(object->split_info_cmd != NULL){
1646 object->split_info_cmd->dataoff = offset;
1647 offset += object->split_info_cmd->datasize;
1650 if(object->func_starts_info_cmd != NULL){
1651 object->func_starts_info_cmd->dataoff = offset;
1652 offset += object->func_starts_info_cmd->datasize;
1655 if(object->data_in_code_cmd != NULL){
1656 object->data_in_code_cmd->dataoff = offset;
1657 offset += object->data_in_code_cmd->datasize;
1660 if(object->code_sign_drs_cmd != NULL){
1661 object->code_sign_drs_cmd->dataoff = offset;
1662 offset += object->code_sign_drs_cmd->datasize;
1665 if(object->st->nsyms != 0){
1666 object->st->symoff = offset;
1667 if(object->mh != NULL)
1668 offset += object->st->nsyms * sizeof(struct nlist);
1669 else
1670 offset += object->st->nsyms * sizeof(struct nlist_64);
1672 else
1673 object->st->symoff = 0;
1675 if(object->hints_cmd != NULL){
1676 if(object->hints_cmd->nhints != 0){
1677 object->output_hints = (struct twolevel_hint *)
1678 (object->object_addr + object->hints_cmd->offset);
1679 object->hints_cmd->offset = offset;
1680 offset += object->hints_cmd->nhints *
1681 sizeof(struct twolevel_hint);
1683 else
1684 object->hints_cmd->offset = 0;
1687 if(object->dyst->nextrel != 0){
1688 object->output_ext_relocs = (struct relocation_info *)
1689 (object->object_addr + object->dyst->extreloff);
1690 #ifndef NMEDIT
1692 * When stripping out the section contents to create a
1693 * dynamic library stub the relocation info also gets
1694 * stripped.
1696 if(cflag){
1697 object->dyst->nextrel = 0;
1698 object->dyst->extreloff = 0;
1700 else
1701 #endif /* defined(NMEDIT) */
1703 object->dyst->extreloff = offset;
1704 offset += object->dyst->nextrel *
1705 sizeof(struct relocation_info);
1708 else
1709 object->dyst->extreloff = 0;
1711 if(object->dyst->nindirectsyms != 0){
1712 object->dyst->indirectsymoff = offset;
1713 offset += object->dyst->nindirectsyms * sizeof(uint32_t) +
1714 object->input_indirectsym_pad;
1716 else
1717 object->dyst->indirectsymoff = 0;;
1719 if(object->dyst->ntoc != 0){
1720 object->dyst->tocoff = offset;
1721 offset += object->dyst->ntoc *
1722 sizeof(struct dylib_table_of_contents);
1724 else
1725 object->dyst->tocoff = 0;
1727 if(object->dyst->nmodtab != 0){
1728 #ifndef NMEDIT
1730 * When stripping out the section contents to create a
1731 * dynamic library stub zero out the fields in the module
1732 * table for the sections and relocation information and
1733 * clear Objective-C address and size from modules.
1735 if(cflag){
1736 if(object->mh != NULL){
1737 for(k = 0; k < object->dyst->nmodtab; k++){
1738 mods[k].iinit_iterm = 0;
1739 mods[k].ninit_nterm = 0;
1740 mods[k].iextrel = 0;
1741 mods[k].nextrel = 0;
1742 mods[k].objc_module_info_addr = 0;
1743 mods[k].objc_module_info_size = 0;
1746 else{
1747 for(k = 0; k < object->dyst->nmodtab; k++){
1748 mods64[k].iinit_iterm = 0;
1749 mods64[k].ninit_nterm = 0;
1750 mods64[k].iextrel = 0;
1751 mods64[k].nextrel = 0;
1752 mods64[k].objc_module_info_addr = 0;
1753 mods64[k].objc_module_info_size = 0;
1757 #endif /* !(NMEDIT) */
1758 object->dyst->modtaboff = offset;
1759 if(object->mh != NULL)
1760 offset += object->dyst->nmodtab *
1761 sizeof(struct dylib_module);
1762 else
1763 offset += object->dyst->nmodtab *
1764 sizeof(struct dylib_module_64);
1766 else
1767 object->dyst->modtaboff = 0;
1769 if(object->dyst->nextrefsyms != 0){
1770 object->dyst->extrefsymoff = offset;
1771 offset += object->dyst->nextrefsyms *
1772 sizeof(struct dylib_reference);
1774 else
1775 object->dyst->extrefsymoff = 0;
1777 if(object->st->strsize != 0){
1778 object->st->stroff = offset;
1779 offset += object->st->strsize;
1781 else
1782 object->st->stroff = 0;
1784 if(object->code_sig_cmd != NULL){
1785 offset = rnd(offset, 16);
1786 object->code_sig_cmd->dataoff = offset;
1787 offset += object->code_sig_cmd->datasize;
1790 else{
1791 if(new_strsize != 0){
1792 if(object->mh != NULL)
1793 object->st->stroff = object->st->symoff +
1794 new_nsyms * sizeof(struct nlist);
1795 else
1796 object->st->stroff = object->st->symoff +
1797 new_nsyms * sizeof(struct nlist_64);
1799 else
1800 object->st->stroff = 0;
1801 if(new_nsyms == 0)
1802 object->st->symoff = 0;
1805 #ifndef NMEDIT
1806 else{
1808 * Here we are doing a full symbol strip. In some cases it may
1809 * leave the local relocation entries as well as LOCAL indirect
1810 * symbol table entries.
1812 if(saves != NULL)
1813 free(saves);
1814 saves = (int32_t *)allocate(object->st->nsyms * sizeof(int32_t));
1815 bzero(saves, object->st->nsyms * sizeof(int32_t));
1818 * Account for the symbolic info in the input file.
1820 if(object->dyst != NULL){
1821 object->input_sym_info_size +=
1822 object->dyst->nlocrel * sizeof(struct relocation_info) +
1823 object->dyst->nextrel * sizeof(struct relocation_info) +
1824 object->dyst->ntoc * sizeof(struct dylib_table_of_contents)+
1825 object->dyst->nextrefsyms * sizeof(struct dylib_reference);
1826 if(object->mh != NULL){
1827 object->input_sym_info_size +=
1828 object->dyst->nmodtab * sizeof(struct dylib_module) +
1829 object->dyst->nindirectsyms * sizeof(uint32_t);
1831 else{
1832 object->input_sym_info_size +=
1833 object->dyst->nmodtab * sizeof(struct dylib_module_64) +
1834 object->dyst->nindirectsyms * sizeof(uint32_t) +
1835 object->input_indirectsym_pad;
1840 * Determine the offset where the remaining symbolic info will start
1841 * in the output file (if any).
1843 offset = get_starting_syminfo_offset(object);
1846 * For a full symbol strip all these values in the output file are
1847 * set to zero.
1849 object->st->symoff = 0;
1850 object->st->nsyms = 0;
1851 object->st->stroff = 0;
1852 object->st->strsize = 0;
1853 if(object->dyst != NULL){
1854 object->dyst->ilocalsym = 0;
1855 object->dyst->nlocalsym = 0;
1856 object->dyst->iextdefsym = 0;
1857 object->dyst->nextdefsym = 0;
1858 object->dyst->iundefsym = 0;
1859 object->dyst->nundefsym = 0;
1863 * This will accumulate any remaining symbolic info size in the
1864 * output file.
1866 object->output_sym_info_size = 0;
1869 * We set these so that checking can be done below to report the
1870 * symbols that can't be stripped because of relocation entries
1871 * or indirect symbol table entries. Normally if these table have a
1872 * non-zero number of entries it will be an error as we are trying
1873 * to strip everything. But it maybe that there are only LOCAL
1874 * indirect entries which is odd but will be OK.
1876 if(object->dyst != NULL){
1877 if(object->dyst->nextrel != 0){
1878 object->output_ext_relocs = (struct relocation_info *)
1879 (object->object_addr + object->dyst->extreloff);
1882 * Since this file has a dynamic symbol table and if this file
1883 * has local relocation entries on input make sure they are
1884 * there on output. This is a rare case that it will not have
1885 * external relocs or indirect symbols but can happen as is the
1886 * case with the dynamic linker itself.
1888 if(object->dyst->nlocrel != 0){
1889 object->output_loc_relocs = (struct relocation_info *)
1890 (object->object_addr + object->dyst->locreloff);
1891 object->output_sym_info_size +=
1892 object->dyst->nlocrel * sizeof(struct relocation_info);
1894 object->dyst->locreloff = offset;
1895 offset += object->dyst->nlocrel *
1896 sizeof(struct relocation_info);
1899 if(object->dyst->nindirectsyms != 0){
1900 object->output_indirect_symtab = (uint32_t *)
1901 (object->object_addr +
1902 object->dyst->indirectsymoff);
1903 if(object->object_byte_sex != host_byte_sex)
1904 swap_indirect_symbols(
1905 object->output_indirect_symtab,
1906 object->dyst->nindirectsyms,
1907 object->object_byte_sex);
1909 object->output_sym_info_size +=
1910 object->dyst->nindirectsyms * sizeof(uint32_t) +
1911 object->input_indirectsym_pad;
1913 object->dyst->indirectsymoff = offset;
1914 offset += object->dyst->nindirectsyms * sizeof(uint32_t) +
1915 object->input_indirectsym_pad;
1919 #endif /* !defined(NMEDIT) */
1922 * Always clear the prebind checksum if any when creating a new file.
1924 if(object->cs != NULL)
1925 object->cs->cksum = 0;
1927 if(object->seg_linkedit != NULL){
1928 object->seg_linkedit->filesize += object->output_sym_info_size -
1929 object->input_sym_info_size;
1930 object->seg_linkedit->vmsize = object->seg_linkedit->filesize;
1932 else if(object->seg_linkedit64 != NULL){
1933 /* Do this in two steps to avoid 32/64-bit casting problems. */
1934 object->seg_linkedit64->filesize -= object->input_sym_info_size;
1935 object->seg_linkedit64->filesize += object->output_sym_info_size;
1936 object->seg_linkedit64->vmsize = object->seg_linkedit64->filesize;
1940 * Check and update the external relocation entries to make sure
1941 * referenced symbols are not stripped and refer to the new symbol
1942 * table indexes.
1944 * The external relocation entries can be located in one of two places,
1945 * first off of the sections or second off of the dynamic symtab.
1947 missing_reloc_symbols = 0;
1948 lc = object->load_commands;
1949 if(object->mh != NULL)
1950 ncmds = object->mh->ncmds;
1951 else
1952 ncmds = object->mh64->ncmds;
1953 for(i = 0; i < ncmds; i++){
1954 if(lc->cmd == LC_SEGMENT &&
1955 object->seg_linkedit != (struct segment_command *)lc){
1956 sg = (struct segment_command *)lc;
1957 s = (struct section *)((char *)sg +
1958 sizeof(struct segment_command));
1959 for(j = 0; j < sg->nsects; j++){
1960 if(s->nreloc != 0){
1961 if(s->reloff + s->nreloc *
1962 sizeof(struct relocation_info) >
1963 object->object_size){
1964 fatal_arch(arch, member, "truncated or malformed "
1965 "object (relocation entries for section (%.16s,"
1966 "%.16s) extends past the end of the file)",
1967 s->segname, s->sectname);
1969 relocs = (struct relocation_info *)
1970 (object->object_addr + s->reloff);
1971 if(object->object_byte_sex != host_byte_sex)
1972 swap_relocation_info(relocs, s->nreloc,
1973 host_byte_sex);
1974 if(s->offset + s->size > object->object_size){
1975 fatal_arch(arch, member, "truncated or malformed "
1976 "object (contents of section (%.16s,"
1977 "%.16s) extends past the end of the file)",
1978 s->segname, s->sectname);
1980 contents = object->object_addr + s->offset;
1981 check_object_relocs(arch, member, object, s->segname,
1982 s->sectname, s->size, contents, relocs, s->nreloc,
1983 symbols, symbols64, nsyms, strings,
1984 &missing_reloc_symbols, host_byte_sex);
1985 if(object->object_byte_sex != host_byte_sex)
1986 swap_relocation_info(relocs, s->nreloc,
1987 object->object_byte_sex);
1989 s++;
1992 else if(lc->cmd == LC_SEGMENT_64 &&
1993 object->seg_linkedit64 != (struct segment_command_64 *)lc){
1994 sg64 = (struct segment_command_64 *)lc;
1995 s64 = (struct section_64 *)((char *)sg64 +
1996 sizeof(struct segment_command_64));
1997 for(j = 0; j < sg64->nsects; j++){
1998 if(s64->nreloc != 0){
1999 if(s64->reloff + s64->nreloc *
2000 sizeof(struct relocation_info) >
2001 object->object_size){
2002 fatal_arch(arch, member, "truncated or malformed "
2003 "object (relocation entries for section (%.16s,"
2004 "%.16s) extends past the end of the file)",
2005 s64->segname, s64->sectname);
2007 relocs = (struct relocation_info *)
2008 (object->object_addr + s64->reloff);
2009 if(object->object_byte_sex != host_byte_sex)
2010 swap_relocation_info(relocs, s64->nreloc,
2011 host_byte_sex);
2012 if(s64->offset + s64->size > object->object_size){
2013 fatal_arch(arch, member, "truncated or malformed "
2014 "object (contents of section (%.16s,"
2015 "%.16s) extends past the end of the file)",
2016 s64->segname, s64->sectname);
2018 contents = object->object_addr + s64->offset;
2019 check_object_relocs(arch, member, object, s64->segname,
2020 s64->sectname, s64->size, contents, relocs,
2021 s64->nreloc, symbols, symbols64, nsyms, strings,
2022 &missing_reloc_symbols, host_byte_sex);
2023 if(object->object_byte_sex != host_byte_sex)
2024 swap_relocation_info(relocs, s64->nreloc,
2025 object->object_byte_sex);
2027 s64++;
2030 lc = (struct load_command *)((char *)lc + lc->cmdsize);
2032 if(object->dyst != NULL && object->dyst->nextrel != 0){
2033 relocs = object->output_ext_relocs;
2034 if(object->object_byte_sex != host_byte_sex)
2035 swap_relocation_info(relocs, object->dyst->nextrel,
2036 host_byte_sex);
2038 for(i = 0; i < object->dyst->nextrel; i++){
2039 if((relocs[i].r_address & R_SCATTERED) == 0 &&
2040 relocs[i].r_extern == 1){
2041 if(relocs[i].r_symbolnum > nsyms){
2042 fatal_arch(arch, member, "bad r_symbolnum for external "
2043 "relocation entry %d in: ", i);
2045 if(saves[relocs[i].r_symbolnum] == 0){
2046 if(missing_reloc_symbols == 0){
2047 error_arch(arch, member, "symbols referenced by "
2048 "relocation entries that can't be stripped in: ");
2049 missing_reloc_symbols = 1;
2051 if(object->mh != NULL){
2052 fprintf(stderr, "%s\n", strings + symbols
2053 [relocs[i].r_symbolnum].n_un.n_strx);
2055 else {
2056 fprintf(stderr, "%s\n", strings + symbols64
2057 [relocs[i].r_symbolnum].n_un.n_strx);
2059 saves[relocs[i].r_symbolnum] = -1;
2061 if(saves[relocs[i].r_symbolnum] != -1){
2062 relocs[i].r_symbolnum =
2063 saves[relocs[i].r_symbolnum] - 1;
2066 else{
2067 fatal_arch(arch, member, "bad external relocation entry "
2068 "%d (not external) in: ", i);
2070 if((relocs[i].r_address & R_SCATTERED) == 0){
2071 if(reloc_has_pair(object->mh_cputype, relocs[i].r_type))
2072 i++;
2074 else{
2075 sreloc = (struct scattered_relocation_info *)relocs + i;
2076 if(reloc_has_pair(object->mh_cputype, sreloc->r_type))
2077 i++;
2080 if(object->object_byte_sex != host_byte_sex)
2081 swap_relocation_info(relocs, object->dyst->nextrel,
2082 object->object_byte_sex);
2086 * Check and update the indirect symbol table entries to make sure
2087 * referenced symbols are not stripped and refer to the new symbol
2088 * table indexes.
2090 if(object->dyst != NULL && object->dyst->nindirectsyms != 0){
2091 if(object->object_byte_sex != host_byte_sex)
2092 swap_indirect_symbols(object->output_indirect_symtab,
2093 object->dyst->nindirectsyms, host_byte_sex);
2095 lc = object->load_commands;
2096 if(object->mh != NULL)
2097 ncmds = object->mh->ncmds;
2098 else
2099 ncmds = object->mh64->ncmds;
2100 for(i = 0; i < ncmds; i++){
2101 if(lc->cmd == LC_SEGMENT &&
2102 object->seg_linkedit != (struct segment_command *)lc){
2103 sg = (struct segment_command *)lc;
2104 s = (struct section *)((char *)sg +
2105 sizeof(struct segment_command));
2106 for(j = 0; j < sg->nsects; j++){
2107 section_type = s->flags & SECTION_TYPE;
2108 if(section_type == S_LAZY_SYMBOL_POINTERS ||
2109 section_type == S_LAZY_DYLIB_SYMBOL_POINTERS ||
2110 section_type == S_NON_LAZY_SYMBOL_POINTERS)
2111 stride = 4;
2112 else if(section_type == S_SYMBOL_STUBS)
2113 stride = s->reserved2;
2114 else{
2115 s++;
2116 continue;
2118 nitems = s->size / stride;
2119 contents = object->object_addr + s->offset;
2120 check_indirect_symtab(arch, member, object, nitems,
2121 s->reserved1, section_type, contents, symbols,
2122 symbols64, nsyms, strings, &missing_reloc_symbols,
2123 host_byte_sex);
2124 s++;
2127 else if(lc->cmd == LC_SEGMENT_64 &&
2128 object->seg_linkedit64 != (struct segment_command_64 *)lc){
2129 sg64 = (struct segment_command_64 *)lc;
2130 s64 = (struct section_64 *)((char *)sg64 +
2131 sizeof(struct segment_command_64));
2132 for(j = 0; j < sg64->nsects; j++){
2133 section_type = s64->flags & SECTION_TYPE;
2134 if(section_type == S_LAZY_SYMBOL_POINTERS ||
2135 section_type == S_LAZY_DYLIB_SYMBOL_POINTERS ||
2136 section_type == S_NON_LAZY_SYMBOL_POINTERS)
2137 stride = 8;
2138 else if(section_type == S_SYMBOL_STUBS)
2139 stride = s64->reserved2;
2140 else{
2141 s64++;
2142 continue;
2144 nitems = s64->size / stride;
2145 contents = object->object_addr + s64->offset;
2146 check_indirect_symtab(arch, member, object, nitems,
2147 s64->reserved1, section_type, contents, symbols,
2148 symbols64, nsyms, strings, &missing_reloc_symbols,
2149 host_byte_sex);
2150 s64++;
2153 lc = (struct load_command *)((char *)lc + lc->cmdsize);
2156 if(object->object_byte_sex != host_byte_sex)
2157 swap_indirect_symbols(object->output_indirect_symtab,
2158 object->dyst->nindirectsyms, object->object_byte_sex);
2162 * Issue a warning if object file has a code signature that the
2163 * operation will invalidate it.
2165 if(object->code_sig_cmd != NULL)
2166 warning_arch(arch, member, "changes being made to the file will "
2167 "invalidate the code signature in: ");
2171 * get_starting_syminfo_offset() returns the starting offset of the symbolic
2172 * info in the object file.
2174 static
2175 uint32_t
2176 get_starting_syminfo_offset(
2177 struct object *object)
2179 uint32_t offset;
2181 if(object->seg_linkedit != NULL ||
2182 object->seg_linkedit64 != NULL){
2183 if(object->mh != NULL)
2184 offset = object->seg_linkedit->fileoff;
2185 else
2186 offset = object->seg_linkedit64->fileoff;
2188 else{
2189 offset = UINT_MAX;
2190 if(object->dyst != NULL &&
2191 object->dyst->nlocrel != 0 &&
2192 object->dyst->locreloff < offset)
2193 offset = object->dyst->locreloff;
2194 if(object->st->nsyms != 0 &&
2195 object->st->symoff < offset)
2196 offset = object->st->symoff;
2197 if(object->dyst != NULL &&
2198 object->dyst->nextrel != 0 &&
2199 object->dyst->extreloff < offset)
2200 offset = object->dyst->extreloff;
2201 if(object->dyst != NULL &&
2202 object->dyst->nindirectsyms != 0 &&
2203 object->dyst->indirectsymoff < offset)
2204 offset = object->dyst->indirectsymoff;
2205 if(object->dyst != NULL &&
2206 object->dyst->ntoc != 0 &&
2207 object->dyst->tocoff < offset)
2208 offset = object->dyst->tocoff;
2209 if(object->dyst != NULL &&
2210 object->dyst->nmodtab != 0 &&
2211 object->dyst->modtaboff < offset)
2212 offset = object->dyst->modtaboff;
2213 if(object->dyst != NULL &&
2214 object->dyst->nextrefsyms != 0 &&
2215 object->dyst->extrefsymoff < offset)
2216 offset = object->dyst->extrefsymoff;
2217 if(object->st->strsize != 0 &&
2218 object->st->stroff < offset)
2219 offset = object->st->stroff;
2221 return(offset);
2225 * check_object_relocs() is used to check and update the external relocation
2226 * entries from a section in an object file, to make sure referenced symbols
2227 * are not stripped and are changed to refer to the new symbol table indexes.
2229 static
2230 void
2231 check_object_relocs(
2232 struct arch *arch,
2233 struct member *member,
2234 struct object *object,
2235 char *segname,
2236 char *sectname,
2237 uint64_t sectsize,
2238 char *contents,
2239 struct relocation_info *relocs,
2240 uint32_t nreloc,
2241 struct nlist *symbols,
2242 struct nlist_64 *symbols64,
2243 uint32_t nsyms,
2244 char *strings,
2245 int32_t *missing_reloc_symbols,
2246 enum byte_sex host_byte_sex)
2248 uint32_t k, n_strx;
2249 uint64_t n_value;
2250 #ifdef NMEDIT
2251 uint32_t value, n_ext;
2252 uint64_t value64;
2253 #endif
2254 struct scattered_relocation_info *sreloc;
2256 for(k = 0; k < nreloc; k++){
2257 if((relocs[k].r_address & R_SCATTERED) == 0 &&
2258 relocs[k].r_extern == 1){
2259 if(relocs[k].r_symbolnum > nsyms){
2260 fatal_arch(arch, member, "bad r_symbolnum for relocation "
2261 "entry %d in section (%.16s,%.16s) in: ", k, segname,
2262 sectname);
2264 if(object->mh != NULL){
2265 n_strx = symbols[relocs[k].r_symbolnum].n_un.n_strx;
2266 n_value = symbols[relocs[k].r_symbolnum].n_value;
2268 else{
2269 n_strx = symbols64[relocs[k].r_symbolnum].n_un.n_strx;
2270 n_value = symbols64[relocs[k].r_symbolnum].n_value;
2272 #ifndef NMEDIT
2273 if(saves[relocs[k].r_symbolnum] == 0){
2274 if(*missing_reloc_symbols == 0){
2275 error_arch(arch, member, "symbols referenced by "
2276 "relocation entries that can't be stripped in: ");
2277 *missing_reloc_symbols = 1;
2279 fprintf(stderr, "%s\n", strings + n_strx);
2280 saves[relocs[k].r_symbolnum] = -1;
2282 #else /* defined(NMEDIT) */
2284 * We are letting nmedit change global coalesed symbols into
2285 * statics in MH_OBJECT file types only. Relocation entries to
2286 * global coalesced symbols are external relocs.
2288 if(object->mh != NULL)
2289 n_ext = new_symbols[saves[relocs[k].r_symbolnum] - 1].
2290 n_type & N_EXT;
2291 else
2292 n_ext = new_symbols64[saves[relocs[k].r_symbolnum] - 1].
2293 n_type & N_EXT;
2294 if(n_ext != N_EXT &&
2295 object->mh_cputype != CPU_TYPE_X86_64){
2297 * We need to do the relocation for this external relocation
2298 * entry so the item to be relocated is correct for a local
2299 * relocation entry. We don't need to do this for x86-64.
2301 if(relocs[k].r_address + sizeof(int32_t) > sectsize){
2302 fatal_arch(arch, member, "truncated or malformed "
2303 "object (r_address of relocation entry %u of "
2304 "section (%.16s,%.16s) extends past the end "
2305 "of the section)", k, segname, sectname);
2307 if(object->mh != NULL){
2308 value = *(uint32_t *)
2309 (contents + relocs[k].r_address);
2310 if(object->object_byte_sex != host_byte_sex)
2311 value = SWAP_INT(value);
2313 * We handle a very limited form here. Only VANILLA
2314 * (r_type == 0) long (r_length==2) absolute or pcrel
2315 * that won't need a scattered relocation entry.
2317 if(relocs[k].r_type != 0 ||
2318 relocs[k].r_length != 2){
2319 fatal_arch(arch, member, "don't have "
2320 "code to convert external relocation "
2321 "entry %d in section (%.16s,%.16s) "
2322 "for global coalesced symbol: %s "
2323 "in: ", k, segname, sectname,
2324 strings + n_strx);
2326 value += n_value;
2327 if(object->object_byte_sex != host_byte_sex)
2328 value = SWAP_INT(value);
2329 *(uint32_t *)(contents + relocs[k].r_address) =
2330 value;
2332 else{
2333 value64 = *(uint64_t *)(contents + relocs[k].r_address);
2334 if(object->object_byte_sex != host_byte_sex)
2335 value64 = SWAP_LONG_LONG(value64);
2337 * We handle a very limited form here. Only VANILLA
2338 * (r_type == 0) quad (r_length==3) absolute or pcrel
2339 * that won't need a scattered relocation entry.
2341 if(relocs[k].r_type != 0 ||
2342 relocs[k].r_length != 3){
2343 fatal_arch(arch, member, "don't have "
2344 "code to convert external relocation "
2345 "entry %d in section (%.16s,%.16s) "
2346 "for global coalesced symbol: %s "
2347 "in: ", k, segname, sectname,
2348 strings + n_strx);
2350 value64 += n_value;
2351 if(object->object_byte_sex != host_byte_sex)
2352 value64 = SWAP_LONG_LONG(value64);
2353 *(uint64_t *)(contents + relocs[k].r_address) = value64;
2356 * Turn the extern reloc into a local.
2358 if(object->mh != NULL)
2359 relocs[k].r_symbolnum =
2360 new_symbols[saves[relocs[k].r_symbolnum] - 1].n_sect;
2361 else
2362 relocs[k].r_symbolnum =
2363 new_symbols64[saves[relocs[k].r_symbolnum] - 1].n_sect;
2364 relocs[k].r_extern = 0;
2366 #endif /* NMEDIT */
2367 if(relocs[k].r_extern == 1 &&
2368 saves[relocs[k].r_symbolnum] != -1){
2369 relocs[k].r_symbolnum = saves[relocs[k].r_symbolnum] - 1;
2372 if((relocs[k].r_address & R_SCATTERED) == 0){
2373 if(reloc_has_pair(object->mh_cputype, relocs[k].r_type) == TRUE)
2374 k++;
2376 else{
2377 sreloc = (struct scattered_relocation_info *)relocs + k;
2378 if(reloc_has_pair(object->mh_cputype, sreloc->r_type) == TRUE)
2379 k++;
2385 * check_indirect_symtab() checks and updates the indirect symbol table entries
2386 * to make sure referenced symbols are not stripped and refer to the new symbol
2387 * table indexes.
2389 static
2390 void
2391 check_indirect_symtab(
2392 struct arch *arch,
2393 struct member *member,
2394 struct object *object,
2395 uint32_t nitems,
2396 uint32_t reserved1,
2397 uint32_t section_type,
2398 char *contents,
2399 struct nlist *symbols,
2400 struct nlist_64 *symbols64,
2401 uint32_t nsyms,
2402 char *strings,
2403 int32_t *missing_reloc_symbols,
2404 enum byte_sex host_byte_sex)
2406 uint32_t k, index;
2407 uint8_t n_type;
2408 uint32_t n_strx, value;
2409 uint64_t value64;
2410 enum bool made_local;
2412 for(k = 0; k < nitems; k++){
2413 made_local = FALSE;
2414 index = object->output_indirect_symtab[reserved1 + k];
2415 if(index == INDIRECT_SYMBOL_LOCAL ||
2416 index == INDIRECT_SYMBOL_ABS ||
2417 index == (INDIRECT_SYMBOL_LOCAL | INDIRECT_SYMBOL_ABS))
2418 continue;
2419 if(index > nsyms)
2420 fatal_arch(arch, member,"indirect symbol table entry %d (past " "the end of the symbol table) in: ", reserved1 + k);
2421 #ifdef NMEDIT
2422 if(pflag == 0 && nmedits[index] == TRUE && saves[index] != -1)
2423 #else
2424 if(saves[index] == 0)
2425 #endif
2428 * Indirect symbol table entries for defined symbols in a
2429 * non-lazy pointer section that are not saved are changed to
2430 * INDIRECT_SYMBOL_LOCAL which their values just have to be
2431 * slid if the are not absolute symbols.
2433 if(object->mh != NULL){
2434 n_type = symbols[index].n_type;
2435 n_strx = symbols[index].n_un.n_strx;
2437 else{
2438 n_type = symbols64[index].n_type;
2439 n_strx = symbols64[index].n_un.n_strx;
2441 if((n_type & N_TYPE) != N_UNDF &&
2442 (n_type & N_TYPE) != N_PBUD &&
2443 section_type == S_NON_LAZY_SYMBOL_POINTERS){
2444 object->output_indirect_symtab[reserved1 + k] =
2445 INDIRECT_SYMBOL_LOCAL;
2446 if((n_type & N_TYPE) == N_ABS)
2447 object->output_indirect_symtab[reserved1 + k] |=
2448 INDIRECT_SYMBOL_ABS;
2449 made_local = TRUE;
2451 * When creating a stub shared library the section contents
2452 * are not updated since they will be stripped.
2454 if(object->mh_filetype != MH_DYLIB_STUB){
2455 if(object->mh != NULL){
2456 value = symbols[index].n_value;
2457 if (symbols[index].n_desc & N_ARM_THUMB_DEF)
2458 value |= 1;
2459 if(object->object_byte_sex != host_byte_sex)
2460 value = SWAP_INT(value);
2461 *(uint32_t *)(contents + k * 4) = value;
2463 else{
2464 value64 = symbols64[index].n_value;
2465 if(object->object_byte_sex != host_byte_sex)
2466 value64 = SWAP_LONG_LONG(value64);
2467 *(uint64_t *)(contents + k * 8) = value64;
2471 #ifdef NMEDIT
2472 else {
2473 object->output_indirect_symtab[reserved1 + k] =
2474 saves[index] - 1;
2476 #else /* !defined(NMEDIT) */
2477 else{
2478 if(*missing_reloc_symbols == 0){
2479 error_arch(arch, member, "symbols referenced by "
2480 "indirect symbol table entries that can't be "
2481 "stripped in: ");
2482 *missing_reloc_symbols = 1;
2484 fprintf(stderr, "%s\n", strings + n_strx);
2485 saves[index] = -1;
2487 #endif /* !defined(NMEDIT) */
2489 #ifdef NMEDIT
2490 else
2491 #else /* !defined(NMEDIT) */
2492 if(made_local == FALSE && saves[index] != -1)
2493 #endif /* !defined(NMEDIT) */
2495 object->output_indirect_symtab[reserved1+k] = saves[index] - 1;
2500 #ifndef NMEDIT
2502 * This is called if there is a -d option specified. It reads the file with
2503 * the strings in it and places them in the array debug_filenames and sorts
2504 * them by name. The file that contains the file names must have names one
2505 * per line with no white space (except the newlines).
2507 static
2508 void
2509 setup_debug_filenames(
2510 char *dfile)
2512 int fd, i, strings_size;
2513 struct stat stat_buf;
2514 char *strings, *p;
2516 if((fd = open(dfile, O_RDONLY)) < 0){
2517 system_error("can't open: %s", dfile);
2518 return;
2520 if(fstat(fd, &stat_buf) == -1){
2521 system_error("can't stat: %s", dfile);
2522 close(fd);
2523 return;
2525 strings_size = stat_buf.st_size;
2526 strings = (char *)allocate(strings_size + 1);
2527 strings[strings_size] = '\0';
2528 if(read(fd, strings, strings_size) != strings_size){
2529 system_error("can't read: %s", dfile);
2530 close(fd);
2531 return;
2533 p = strings;
2534 for(i = 0; i < strings_size; i++){
2535 if(*p == '\n'){
2536 *p = '\0';
2537 ndebug_filenames++;
2539 p++;
2541 debug_filenames = (char **)allocate(ndebug_filenames * sizeof(char *));
2542 p = strings;
2543 for(i = 0; i < ndebug_filenames; i++){
2544 debug_filenames[i] = p;
2545 p += strlen(p) + 1;
2547 qsort(debug_filenames, ndebug_filenames, sizeof(char *),
2548 (int (*)(const void *, const void *))cmp_qsort_filename);
2550 #ifdef DEBUG
2551 printf("Debug filenames:\n");
2552 for(i = 0; i < ndebug_filenames; i++){
2553 printf("filename = %s\n", debug_filenames[i]);
2555 #endif /* DEBUG */
2559 * Strip the symbol table to the level specified by the command line arguments.
2560 * The new symbol table is built and new_symbols is left pointing to it. The
2561 * number of new symbols is left in new_nsyms, the new string table is built
2562 * and new_stings is left pointing to it and new_strsize is left containing it.
2563 * This routine returns zero if successfull and non-zero otherwise.
2565 static
2566 enum bool
2567 strip_symtab(
2568 struct arch *arch,
2569 struct member *member,
2570 struct object *object,
2571 struct dylib_table_of_contents *tocs,
2572 uint32_t ntoc,
2573 struct dylib_module *mods,
2574 struct dylib_module_64 *mods64,
2575 uint32_t nmodtab,
2576 struct dylib_reference *refs,
2577 uint32_t nextrefsyms)
2579 uint32_t i, j, k, n, inew_syms, save_debug, missing_syms;
2580 uint32_t missing_symbols;
2581 char *p, *q, **pp, *basename;
2582 struct symbol_list *sp;
2583 uint32_t new_ext_strsize, len, *changes, inew_undefsyms;
2584 unsigned char nsects;
2585 struct load_command *lc;
2586 struct segment_command *sg;
2587 struct segment_command_64 *sg64;
2588 struct section *s, **sections;
2589 struct section_64 *s64, **sections64;
2590 uint32_t ncmds, mh_flags, s_flags, n_strx;
2591 struct nlist *sym;
2592 struct undef_map *undef_map;
2593 struct undef_map64 *undef_map64;
2594 uint8_t n_type, n_sect;
2595 uint16_t n_desc;
2596 uint64_t n_value;
2597 uint32_t module_name, iextdefsym, nextdefsym, ilocalsym, nlocalsym;
2598 uint32_t irefsym, nrefsym;
2599 unsigned char text_nsect;
2600 enum bool has_dwarf, hack_5614542;
2602 save_debug = 0;
2603 if(saves != NULL)
2604 free(saves);
2605 changes = NULL;
2606 for(i = 0; i < nsave_symbols; i++)
2607 save_symbols[i].sym = NULL;
2608 for(i = 0; i < nremove_symbols; i++)
2609 remove_symbols[i].sym = NULL;
2610 if(member == NULL){
2611 for(i = 0; i < nsave_symbols; i++)
2612 save_symbols[i].seen = FALSE;
2613 for(i = 0; i < nremove_symbols; i++)
2614 remove_symbols[i].seen = FALSE;
2617 new_nsyms = 0;
2618 if(object->mh != NULL)
2619 new_strsize = sizeof(int32_t);
2620 else
2621 new_strsize = sizeof(int64_t);
2622 new_nlocalsym = 0;
2623 new_nextdefsym = 0;
2624 new_nundefsym = 0;
2625 new_ext_strsize = 0;
2628 * If this an object file that has DWARF debugging sections to strip
2629 * then we have to run ld -r on it.
2631 if(object->mh_filetype == MH_OBJECT && (Sflag || xflag)){
2632 has_dwarf = FALSE;
2633 lc = object->load_commands;
2634 if(object->mh != NULL)
2635 ncmds = object->mh->ncmds;
2636 else
2637 ncmds = object->mh64->ncmds;
2638 for(i = 0; i < ncmds && has_dwarf == FALSE; i++){
2639 if(lc->cmd == LC_SEGMENT){
2640 sg = (struct segment_command *)lc;
2641 s = (struct section *)((char *)sg +
2642 sizeof(struct segment_command));
2643 for(j = 0; j < sg->nsects; j++){
2644 if(s->flags & S_ATTR_DEBUG){
2645 has_dwarf = TRUE;
2646 break;
2648 s++;
2651 else if(lc->cmd == LC_SEGMENT_64){
2652 sg64 = (struct segment_command_64 *)lc;
2653 s64 = (struct section_64 *)((char *)sg64 +
2654 sizeof(struct segment_command_64));
2655 for(j = 0; j < sg64->nsects; j++){
2656 if(s64->flags & S_ATTR_DEBUG){
2657 has_dwarf = TRUE;
2658 break;
2660 s64++;
2663 lc = (struct load_command *)((char *)lc + lc->cmdsize);
2665 if(has_dwarf == TRUE)
2666 make_ld_r_object(arch, member, object);
2669 * Because of the "design" of 64-bit object files and the lack of
2670 * local relocation entries it is not possible for strip(1) to do its
2671 * job without becoming a static link editor. The "design" does not
2672 * actually strip the symbols it simply renames them to things like
2673 * "l1000". And they become static symbols but still have external
2674 * relocation entries. Thus can never actually be stripped. Also some
2675 * symbols, *.eh, symbols are not even changed to these names if there
2676 * corresponding global symbol is not stripped. So strip(1) only
2677 * recourse is to use the unified linker to create an ld -r object then
2678 * save all resulting symbols (both static and global) and hope the user
2679 * does not notice the stripping is not what they asked for.
2681 if(object->mh_filetype == MH_OBJECT &&
2682 (object->mh64 != NULL && object->ld_r_ofile == NULL))
2683 make_ld_r_object(arch, member, object);
2686 * Since make_ld_r_object() may create an object with more symbols
2687 * this has to be done after make_ld_r_object() and nsyms is updated.
2689 saves = (int32_t *)allocate(nsyms * sizeof(int32_t));
2690 bzero(saves, nsyms * sizeof(int32_t));
2693 * Gather an array of section struct pointers so we can later determine
2694 * if we run into a global symbol in a coalesced section and not strip
2695 * those symbols.
2696 * statics.
2698 nsects = 0;
2699 text_nsect = NO_SECT;
2700 lc = object->load_commands;
2701 if(object->mh != NULL)
2702 ncmds = object->mh->ncmds;
2703 else
2704 ncmds = object->mh64->ncmds;
2705 for(i = 0; i < ncmds; i++){
2706 if(lc->cmd == LC_SEGMENT){
2707 sg = (struct segment_command *)lc;
2708 nsects += sg->nsects;
2710 else if(lc->cmd == LC_SEGMENT_64){
2711 sg64 = (struct segment_command_64 *)lc;
2712 nsects += sg64->nsects;
2714 lc = (struct load_command *)((char *)lc + lc->cmdsize);
2716 if(object->mh != NULL){
2717 sections = allocate(nsects * sizeof(struct section *));
2718 sections64 = NULL;
2720 else{
2721 sections = NULL;
2722 sections64 = allocate(nsects * sizeof(struct section_64 *));
2724 nsects = 0;
2725 lc = object->load_commands;
2726 for(i = 0; i < ncmds; i++){
2727 if(lc->cmd == LC_SEGMENT){
2728 sg = (struct segment_command *)lc;
2729 s = (struct section *)((char *)sg +
2730 sizeof(struct segment_command));
2731 for(j = 0; j < sg->nsects; j++){
2732 if(strcmp((s + j)->sectname, SECT_TEXT) == 0 &&
2733 strcmp((s + j)->segname, SEG_TEXT) == 0)
2734 text_nsect = nsects + 1;
2735 sections[nsects++] = s++;
2738 else if(lc->cmd == LC_SEGMENT_64){
2739 sg64 = (struct segment_command_64 *)lc;
2740 s64 = (struct section_64 *)((char *)sg64 +
2741 sizeof(struct segment_command_64));
2742 for(j = 0; j < sg64->nsects; j++){
2743 if(strcmp((s64 + j)->sectname, SECT_TEXT) == 0 &&
2744 strcmp((s64 + j)->segname, SEG_TEXT) == 0)
2745 text_nsect = nsects + 1;
2746 sections64[nsects++] = s64++;
2749 lc = (struct load_command *)((char *)lc + lc->cmdsize);
2752 for(i = 0; i < nsyms; i++){
2753 s_flags = 0;
2754 if(object->mh != NULL){
2755 mh_flags = object->mh->flags;
2756 n_strx = symbols[i].n_un.n_strx;
2757 n_type = symbols[i].n_type;
2758 n_sect = symbols[i].n_sect;
2759 if((n_type & N_TYPE) == N_SECT){
2760 if(n_sect == 0 || n_sect > nsects){
2761 error_arch(arch, member, "bad n_sect for symbol "
2762 "table entry %d in: ", i);
2763 return(FALSE);
2765 s_flags = sections[n_sect - 1]->flags;
2767 n_desc = symbols[i].n_desc;
2768 n_value = symbols[i].n_value;
2770 else{
2771 mh_flags = object->mh64->flags;
2772 n_strx = symbols64[i].n_un.n_strx;
2773 n_type = symbols64[i].n_type;
2774 n_sect = symbols64[i].n_sect;
2775 if((n_type & N_TYPE) == N_SECT){
2776 if(n_sect == 0 || n_sect > nsects){
2777 error_arch(arch, member, "bad n_sect for symbol "
2778 "table entry %d in: ", i);
2779 return(FALSE);
2781 s_flags = sections64[n_sect - 1]->flags;
2783 n_desc = symbols64[i].n_desc;
2784 n_value = symbols64[i].n_value;
2786 if(n_strx != 0){
2787 if(n_strx > strsize){
2788 error_arch(arch, member, "bad string index for symbol "
2789 "table entry %d in: ", i);
2790 return(FALSE);
2793 if((n_type & N_TYPE) == N_INDR){
2794 if(n_value != 0){
2795 if(n_value > strsize){
2796 error_arch(arch, member, "bad string index for "
2797 "indirect symbol table entry %d in: ", i);
2798 return(FALSE);
2802 if((n_type & N_EXT) == 0){ /* local symbol */
2803 if(aflag){
2804 if(n_strx != 0)
2805 new_strsize += strlen(strings + n_strx) + 1;
2806 new_nlocalsym++;
2807 new_nsyms++;
2808 saves[i] = new_nsyms;
2811 * For x86_64 .o files we have run ld -r on them and are stuck
2812 * keeping all resulting symbols.
2814 else if(object->mh == NULL && (
2815 object->mh64->cputype == CPU_TYPE_X86_64) &&
2816 object->mh64->filetype == MH_OBJECT){
2817 if(n_strx != 0)
2818 new_strsize += strlen(strings + n_strx) + 1;
2819 new_nlocalsym++;
2820 new_nsyms++;
2821 saves[i] = new_nsyms;
2824 * The cases a local symbol might be saved are with -X, -S, -t,
2825 * or with -d filename.
2827 else if((!strip_all && (Xflag || tflag || Sflag)) || dfile){
2828 if(n_type & N_STAB){ /* debug symbol */
2829 if(dfile && n_type == N_SO){
2830 if(n_strx != 0){
2831 basename = strrchr(strings + n_strx, '/');
2832 if(basename != NULL)
2833 basename++;
2834 else
2835 basename = strings + n_strx;
2836 pp = bsearch(basename, debug_filenames,
2837 ndebug_filenames, sizeof(char *),
2838 (int (*)(const void *, const void *)
2839 )cmp_bsearch_filename);
2841 * Save the bracketing N_SO. For each N_SO that
2842 * has a filename there is an N_SO that has a
2843 * name of "" which ends the stabs for that file
2845 if(*basename != '\0'){
2846 if(pp != NULL)
2847 save_debug = 1;
2848 else
2849 save_debug = 0;
2851 else{
2853 * This is a bracketing SO so if we are
2854 * currently saving debug symbols save this
2855 * last one and turn off saving debug syms.
2857 if(save_debug){
2858 if(n_strx != 0)
2859 new_strsize += strlen(strings +
2860 n_strx) + 1;
2861 new_nlocalsym++;
2862 new_nsyms++;
2863 saves[i] = new_nsyms;
2865 save_debug = 0;
2868 else{
2869 save_debug = 0;
2872 if(saves[i] == 0 && (!Sflag || save_debug)){
2873 if(n_strx != 0)
2874 new_strsize += strlen(strings + n_strx) + 1;
2875 new_nlocalsym++;
2876 new_nsyms++;
2877 saves[i] = new_nsyms;
2880 else{ /* non-debug local symbol */
2881 if(xflag == 0 && (Sflag || Xflag || tflag)){
2883 * No -x (strip all local), and one of -S (strip
2884 * debug), -X (strip 'L' local), or -t (strip
2885 * local except non-'L' text) was given.
2887 if((Xflag && n_strx != 0 &&
2888 strings[n_strx] != 'L') ||
2889 (tflag && (n_type & N_TYPE) == N_SECT &&
2890 n_sect == text_nsect && n_strx != 0 &&
2891 strings[n_strx] != 'L') ||
2892 (Sflag && !Xflag && !tflag)) {
2894 * If this file is a for the dynamic linker and
2895 * this symbol is in a section marked so that
2896 * static symbols are stripped then don't
2897 * keep this symbol.
2899 if((mh_flags & MH_DYLDLINK) != MH_DYLDLINK ||
2900 (n_type & N_TYPE) != N_SECT ||
2901 (s_flags & S_ATTR_STRIP_STATIC_SYMS) !=
2902 S_ATTR_STRIP_STATIC_SYMS){
2903 new_strsize += strlen(strings + n_strx) + 1;
2904 new_nlocalsym++;
2905 new_nsyms++;
2906 saves[i] = new_nsyms;
2911 * Treat a local symbol that was a private extern as if
2912 * were global if it is referenced by a module and save
2913 * it.
2915 if((n_type & N_PEXT) == N_PEXT){
2916 if(saves[i] == 0 &&
2917 private_extern_reference_by_module(
2918 i, refs ,nextrefsyms) == TRUE){
2919 if(n_strx != 0)
2920 new_strsize += strlen(strings + n_strx) + 1;
2921 new_nlocalsym++;
2922 new_nsyms++;
2923 saves[i] = new_nsyms;
2926 * We need to save symbols that were private externs
2927 * that are used with indirect symbols.
2929 if(saves[i] == 0 &&
2930 symbol_pointer_used(i, indirectsyms,
2931 nindirectsyms) == TRUE){
2932 if(n_strx != 0){
2933 len = strlen(strings + n_strx) + 1;
2934 new_strsize += len;
2936 new_nlocalsym++;
2937 new_nsyms++;
2938 saves[i] = new_nsyms;
2944 * Treat a local symbol that was a private extern as if were
2945 * global if it is not referenced by a module.
2947 else if((n_type & N_PEXT) == N_PEXT){
2948 if(saves[i] == 0 && sfile){
2949 sp = bsearch(strings + n_strx,
2950 save_symbols, nsave_symbols,
2951 sizeof(struct symbol_list),
2952 (int (*)(const void *, const void *))
2953 symbol_list_bsearch);
2954 if(sp != NULL){
2955 if(sp->sym == NULL){
2956 if(object->mh != NULL)
2957 sp->sym = &(symbols[i]);
2958 else
2959 sp->sym = &(symbols64[i]);
2960 sp->seen = TRUE;
2962 if(n_strx != 0)
2963 new_strsize += strlen(strings + n_strx) + 1;
2964 new_nlocalsym++;
2965 new_nsyms++;
2966 saves[i] = new_nsyms;
2969 if(saves[i] == 0 &&
2970 private_extern_reference_by_module(
2971 i, refs ,nextrefsyms) == TRUE){
2972 if(n_strx != 0)
2973 new_strsize += strlen(strings + n_strx) + 1;
2974 new_nlocalsym++;
2975 new_nsyms++;
2976 saves[i] = new_nsyms;
2979 * We need to save symbols that were private externs that
2980 * are used with indirect symbols.
2982 if(saves[i] == 0 &&
2983 symbol_pointer_used(i, indirectsyms, nindirectsyms) ==
2984 TRUE){
2985 if(n_strx != 0){
2986 len = strlen(strings + n_strx) + 1;
2987 new_strsize += len;
2989 new_nlocalsym++;
2990 new_nsyms++;
2991 saves[i] = new_nsyms;
2995 else{ /* global symbol */
2997 * strip -R on an x86_64 .o file should do nothing.
2999 if(Rfile &&
3000 (object->mh != NULL ||
3001 object->mh64->cputype != CPU_TYPE_X86_64 ||
3002 object->mh64->filetype != MH_OBJECT)){
3003 sp = bsearch(strings + n_strx,
3004 remove_symbols, nremove_symbols,
3005 sizeof(struct symbol_list),
3006 (int (*)(const void *, const void *))
3007 symbol_list_bsearch);
3008 if(sp != NULL){
3009 if((n_type & N_TYPE) == N_UNDF ||
3010 (n_type & N_TYPE) == N_PBUD){
3011 error_arch(arch, member, "symbol: %s undefined"
3012 " and can't be stripped from: ",
3013 sp->name);
3015 else if(sp->sym != NULL){
3016 sym = (struct nlist *)sp->sym;
3017 if((sym->n_type & N_PEXT) != N_PEXT)
3018 error_arch(arch, member, "more than one symbol "
3019 "for: %s found in: ", sp->name);
3021 else{
3022 if(object->mh != NULL)
3023 sp->sym = &(symbols[i]);
3024 else
3025 sp->sym = &(symbols64[i]);
3026 sp->seen = TRUE;
3028 if(n_desc & REFERENCED_DYNAMICALLY){
3029 error_arch(arch, member, "symbol: %s is dynamically"
3030 " referenced and can't be stripped "
3031 "from: ", sp->name);
3033 if((n_type & N_TYPE) == N_SECT &&
3034 (s_flags & SECTION_TYPE) == S_COALESCED){
3035 error_arch(arch, member, "symbol: %s is a global "
3036 "coalesced symbol and can't be "
3037 "stripped from: ", sp->name);
3039 /* don't save this symbol */
3040 continue;
3043 if(Aflag && (n_type & N_TYPE) == N_ABS &&
3044 (n_value != 0 ||
3045 (n_strx != 0 &&
3046 strncmp(strings + n_strx,
3047 ".objc_class_name_",
3048 sizeof(".objc_class_name_") - 1) == 0))){
3049 len = strlen(strings + n_strx) + 1;
3050 new_strsize += len;
3051 new_ext_strsize += len;
3052 new_nextdefsym++;
3053 new_nsyms++;
3054 saves[i] = new_nsyms;
3056 if(saves[i] == 0 && (uflag || default_dyld_executable) &&
3057 ((((n_type & N_TYPE) == N_UNDF) &&
3058 n_value == 0) ||
3059 (n_type & N_TYPE) == N_PBUD)){
3060 if(n_strx != 0){
3061 len = strlen(strings + n_strx) + 1;
3062 new_strsize += len;
3063 new_ext_strsize += len;
3065 new_nundefsym++;
3066 new_nsyms++;
3067 saves[i] = new_nsyms;
3069 if(saves[i] == 0 && nflag &&
3070 (n_type & N_TYPE) == N_SECT){
3071 if(n_strx != 0){
3072 len = strlen(strings + n_strx) + 1;
3073 new_strsize += len;
3074 new_ext_strsize += len;
3076 new_nextdefsym++;
3077 new_nsyms++;
3078 saves[i] = new_nsyms;
3080 if(saves[i] == 0 && sfile){
3081 sp = bsearch(strings + n_strx,
3082 save_symbols, nsave_symbols,
3083 sizeof(struct symbol_list),
3084 (int (*)(const void *, const void *))
3085 symbol_list_bsearch);
3086 if(sp != NULL){
3087 if(sp->sym != NULL){
3088 sym = (struct nlist *)sp->sym;
3089 if((sym->n_type & N_PEXT) != N_PEXT)
3090 error_arch(arch, member, "more than one symbol "
3091 "for: %s found in: ", sp->name);
3093 else{
3094 if(object->mh != NULL)
3095 sp->sym = &(symbols[i]);
3096 else
3097 sp->sym = &(symbols64[i]);
3098 sp->seen = TRUE;
3099 len = strlen(strings + n_strx) + 1;
3100 new_strsize += len;
3101 new_ext_strsize += len;
3102 if((n_type & N_TYPE) == N_UNDF ||
3103 (n_type & N_TYPE) == N_PBUD)
3104 new_nundefsym++;
3105 else
3106 new_nextdefsym++;
3107 new_nsyms++;
3108 saves[i] = new_nsyms;
3113 * We only need to save coalesced symbols that are used as
3114 * indirect symbols in 32-bit applications.
3116 * In 64-bit applications, we only need to save coalesced
3117 * symbols that are used as weak definitions.
3119 if(object->mh != NULL &&
3120 saves[i] == 0 &&
3121 (n_type & N_TYPE) == N_SECT &&
3122 (s_flags & SECTION_TYPE) == S_COALESCED &&
3123 symbol_pointer_used(i, indirectsyms, nindirectsyms) == TRUE){
3124 if(n_strx != 0){
3125 len = strlen(strings + n_strx) + 1;
3126 new_strsize += len;
3127 new_ext_strsize += len;
3129 new_nextdefsym++;
3130 new_nsyms++;
3131 saves[i] = new_nsyms;
3133 if(saves[i] == 0 &&
3134 (n_type & N_TYPE) == N_SECT &&
3135 (n_desc & N_WEAK_DEF) != 0){
3136 if(n_strx != 0){
3137 len = strlen(strings + n_strx) + 1;
3138 new_strsize += len;
3139 new_ext_strsize += len;
3141 new_nextdefsym++;
3142 new_nsyms++;
3143 saves[i] = new_nsyms;
3145 if(saves[i] == 0 &&
3146 ((Xflag || Sflag || xflag || tflag || aflag) ||
3147 ((rflag || default_dyld_executable) &&
3148 n_desc & REFERENCED_DYNAMICALLY))){
3149 len = strlen(strings + n_strx) + 1;
3150 new_strsize += len;
3151 new_ext_strsize += len;
3152 if((n_type & N_TYPE) == N_INDR){
3153 len = strlen(strings + n_value) + 1;
3154 new_strsize += len;
3155 new_ext_strsize += len;
3157 if((n_type & N_TYPE) == N_UNDF ||
3158 (n_type & N_TYPE) == N_PBUD)
3159 new_nundefsym++;
3160 else
3161 new_nextdefsym++;
3162 new_nsyms++;
3163 saves[i] = new_nsyms;
3166 * For x86_64 .o files we have run ld -r on them and are stuck
3167 * keeping all resulting symbols.
3169 if(saves[i] == 0 &&
3170 object->mh == NULL &&
3171 object->mh64->cputype == CPU_TYPE_X86_64 &&
3172 object->mh64->filetype == MH_OBJECT){
3173 len = strlen(strings + n_strx) + 1;
3174 new_strsize += len;
3175 new_ext_strsize += len;
3176 if((n_type & N_TYPE) == N_INDR){
3177 len = strlen(strings + n_value) + 1;
3178 new_strsize += len;
3179 new_ext_strsize += len;
3181 if((n_type & N_TYPE) == N_UNDF ||
3182 (n_type & N_TYPE) == N_PBUD)
3183 new_nundefsym++;
3184 else
3185 new_nextdefsym++;
3186 new_nsyms++;
3187 saves[i] = new_nsyms;
3192 * The module table's module names are placed with the external strings.
3193 * So size them and add this to the external string size.
3195 for(i = 0; i < nmodtab; i++){
3196 if(object->mh != NULL)
3197 module_name = mods[i].module_name;
3198 else
3199 module_name = mods64[i].module_name;
3200 if(module_name == 0 || module_name > strsize){
3201 error_arch(arch, member, "bad string index for module_name "
3202 "of module table entry %d in: ", i);
3203 return(FALSE);
3205 len = strlen(strings + module_name) + 1;
3206 new_strsize += len;
3207 new_ext_strsize += len;
3211 * Updating the reference table may require a symbol not yet listed as
3212 * as saved to be present in the output file. If a defined external
3213 * symbol is removed and there is a undefined reference to it in the
3214 * reference table an undefined symbol needs to be created for it in
3215 * the output file. If this happens the number of new symbols and size
3216 * of the new strings are adjusted. And the array changes[] is set to
3217 * map the old symbol index to the new symbol index for the symbol that
3218 * is changed to an undefined symbol.
3220 missing_symbols = 0;
3221 if(ref_saves != NULL)
3222 free(ref_saves);
3223 ref_saves = (int32_t *)allocate(nextrefsyms * sizeof(int32_t));
3224 bzero(ref_saves, nextrefsyms * sizeof(int32_t));
3225 changes = (uint32_t *)allocate(nsyms * sizeof(int32_t));
3226 bzero(changes, nsyms * sizeof(int32_t));
3227 new_nextrefsyms = 0;
3228 for(i = 0; i < nextrefsyms; i++){
3229 if(refs[i].isym > nsyms){
3230 error_arch(arch, member, "bad symbol table index for "
3231 "reference table entry %d in: ", i);
3232 return(FALSE);
3234 if(saves[refs[i].isym]){
3235 new_nextrefsyms++;
3236 ref_saves[i] = new_nextrefsyms;
3238 else{
3239 if(refs[i].flags == REFERENCE_FLAG_UNDEFINED_NON_LAZY ||
3240 refs[i].flags == REFERENCE_FLAG_UNDEFINED_LAZY){
3241 if(changes[refs[i].isym] == 0){
3242 if(object->mh != NULL)
3243 n_strx = symbols[refs[i].isym].n_un.n_strx;
3244 else
3245 n_strx = symbols64[refs[i].isym].n_un.n_strx;
3246 len = strlen(strings + n_strx) + 1;
3247 new_strsize += len;
3248 new_ext_strsize += len;
3249 new_nundefsym++;
3250 new_nsyms++;
3251 changes[refs[i].isym] = new_nsyms;
3252 new_nextrefsyms++;
3253 ref_saves[i] = new_nextrefsyms;
3256 else{
3257 if(refs[i].flags ==
3258 REFERENCE_FLAG_PRIVATE_UNDEFINED_NON_LAZY ||
3259 refs[i].flags == REFERENCE_FLAG_PRIVATE_UNDEFINED_LAZY){
3260 if(missing_symbols == 0){
3261 error_arch(arch, member, "private extern symbols "
3262 "referenced by modules can't be stripped in: ");
3263 missing_symbols = 1;
3265 if(object->mh != NULL)
3266 n_strx = symbols[refs[i].isym].n_un.n_strx;
3267 else
3268 n_strx = symbols64[refs[i].isym].n_un.n_strx;
3269 fprintf(stderr, "%s\n", strings + n_strx);
3270 saves[refs[i].isym] = -1;
3275 if(missing_symbols == 1)
3276 return(FALSE);
3278 if(member == NULL){
3279 missing_syms = 0;
3280 if(iflag == 0){
3281 for(i = 0; i < nsave_symbols; i++){
3282 if(save_symbols[i].sym == NULL){
3283 if(missing_syms == 0){
3284 error_arch(arch, member, "symbols names listed "
3285 "in: %s not in: ", sfile);
3286 missing_syms = 1;
3288 fprintf(stderr, "%s\n", save_symbols[i].name);
3292 missing_syms = 0;
3294 * strip -R on an x86_64 .o file should do nothing.
3296 if(iflag == 0 &&
3297 (object->mh != NULL ||
3298 object->mh64->cputype != CPU_TYPE_X86_64 ||
3299 object->mh64->filetype != MH_OBJECT)){
3300 for(i = 0; i < nremove_symbols; i++){
3301 if(remove_symbols[i].sym == NULL){
3302 if(missing_syms == 0){
3303 error_arch(arch, member, "symbols names listed "
3304 "in: %s not in: ", Rfile);
3305 missing_syms = 1;
3307 fprintf(stderr, "%s\n", remove_symbols[i].name);
3314 * If there is a chance that we could end up with an indirect symbol
3315 * with an index of zero we need to avoid that due to a work around
3316 * in the dynamic linker for a bug it is working around that was in
3317 * the old classic static linker. See radar bug 5614542 and the
3318 * related bugs 3685312 and 3534709.
3320 * A reasonable way to do this to know that local symbols are first in
3321 * the symbol table. So if we have any local symbols this won't happen
3322 * and if there are no indirect symbols it will also not happen. Past
3323 * that we'll just add a local symbol so it will end up at symbol index
3324 * zero and avoid any indirect symbol having that index.
3326 * If one really wanted they could build up the new symbol table then
3327 * look at all the indirect symbol table entries to see if any of them
3328 * have an index of zero then in that case throw that new symbol table
3329 * away and rebuild the symbol and string table once again after adding
3330 * a local symbol. This seems not all that resonable to save one symbol
3331 * table entry and a few bytes in the string table for the complexity it
3332 * would add and what it would save.
3334 if(new_nlocalsym == 0 && nindirectsyms != 0){
3335 len = strlen("radr://5614542") + 1;
3336 new_strsize += len;
3337 new_nlocalsym++;
3338 new_nsyms++;
3339 hack_5614542 = TRUE;
3341 else{
3342 hack_5614542 = FALSE;
3345 if(object->mh != NULL){
3346 new_symbols = (struct nlist *)
3347 allocate(new_nsyms * sizeof(struct nlist));
3348 new_symbols64 = NULL;
3350 else{
3351 new_symbols = NULL;
3352 new_symbols64 = (struct nlist_64 *)
3353 allocate(new_nsyms * sizeof(struct nlist_64));
3355 if(object->mh != NULL)
3356 new_strsize = rnd(new_strsize, sizeof(int32_t));
3357 else
3358 new_strsize = rnd(new_strsize, sizeof(int64_t));
3359 new_strings = (char *)allocate(new_strsize);
3360 if(object->mh != NULL){
3361 new_strings[new_strsize - 3] = '\0';
3362 new_strings[new_strsize - 2] = '\0';
3363 new_strings[new_strsize - 1] = '\0';
3365 else{
3366 new_strings[new_strsize - 7] = '\0';
3367 new_strings[new_strsize - 6] = '\0';
3368 new_strings[new_strsize - 5] = '\0';
3369 new_strings[new_strsize - 4] = '\0';
3370 new_strings[new_strsize - 3] = '\0';
3371 new_strings[new_strsize - 2] = '\0';
3372 new_strings[new_strsize - 1] = '\0';
3375 memset(new_strings, '\0', sizeof(int32_t));
3376 p = new_strings + sizeof(int32_t);
3377 q = p + new_ext_strsize;
3380 * If all strings were stripped set the size to zero but only for 32-bit
3381 * because the unified linker seems to set the filesize of empty .o
3382 * files to include the string table.
3384 if(object->mh != NULL && new_strsize == sizeof(int32_t))
3385 new_strsize = 0;
3388 * Now create a symbol table and string table in this order
3389 * symbol table
3390 * local symbols
3391 * external defined symbols
3392 * undefined symbols
3393 * string table
3394 * external strings
3395 * local strings
3397 inew_syms = 0;
3400 * If we are doing the hack for radar bug 5614542 (see above) add the
3401 * one local symbol and string.
3403 * We use an N_OPT stab which should be safe to use and not mess any
3404 * thing up. In Mac OS X, gcc(1) writes one N_OPT stab saying the file
3405 * is compiled with gcc(1). Then gdb(1) looks for that stab, but it
3406 * also looks at the name. If the name string is "gcc_compiled" or
3407 * "gcc2_compiled" gdb(1) sets its "compiled by gcc flag. If the N_OPT
3408 * is emitted INSIDE an N_SO section, then gdb(1) thinks that object
3409 * module was compiled by Sun's compiler, which apparently sticks one
3410 * outermost N_LBRAC/N_RBRAC pair, which gdb(1) strips off. But if the
3411 * N_OPT comes before any N_SO stabs, then gdb(1) will just ignore it.
3412 * Since this N_OPT is the first local symbol, it will always come
3413 * before any N_SO stabs that might be around and should be fine.
3415 if(hack_5614542 == TRUE){
3416 if(object->mh != NULL){
3417 new_symbols[inew_syms].n_type = N_OPT;
3418 new_symbols[inew_syms].n_sect = NO_SECT;
3419 new_symbols[inew_syms].n_desc = 0;
3420 new_symbols[inew_syms].n_value = 0x05614542;
3422 else{
3423 new_symbols64[inew_syms].n_type = N_OPT;
3424 new_symbols64[inew_syms].n_sect = NO_SECT;
3425 new_symbols64[inew_syms].n_desc = 0;
3426 new_symbols64[inew_syms].n_value = 0x05614542;
3428 strcpy(q, "radr://5614542");
3429 if(object->mh != NULL)
3430 new_symbols[inew_syms].n_un.n_strx =
3431 q - new_strings;
3432 else
3433 new_symbols64[inew_syms].n_un.n_strx =
3434 q - new_strings;
3435 q += strlen(q) + 1;
3436 inew_syms++;
3439 for(i = 0; i < nsyms; i++){
3440 if(saves[i]){
3441 if(object->mh != NULL){
3442 n_strx = symbols[i].n_un.n_strx;
3443 n_type = symbols[i].n_type;
3445 else{
3446 n_strx = symbols64[i].n_un.n_strx;
3447 n_type = symbols64[i].n_type;
3449 if((n_type & N_EXT) == 0){
3450 if(object->mh != NULL)
3451 new_symbols[inew_syms] = symbols[i];
3452 else
3453 new_symbols64[inew_syms] = symbols64[i];
3454 if(n_strx != 0){
3455 strcpy(q, strings + n_strx);
3456 if(object->mh != NULL)
3457 new_symbols[inew_syms].n_un.n_strx =
3458 q - new_strings;
3459 else
3460 new_symbols64[inew_syms].n_un.n_strx =
3461 q - new_strings;
3462 q += strlen(q) + 1;
3464 inew_syms++;
3465 saves[i] = inew_syms;
3469 #ifdef TRIE_SUPPORT
3470 inew_nextdefsym = inew_syms;
3471 #endif /* TRIE_SUPPORT */
3472 for(i = 0; i < nsyms; i++){
3473 if(saves[i]){
3474 if(object->mh != NULL){
3475 n_strx = symbols[i].n_un.n_strx;
3476 n_type = symbols[i].n_type;
3477 n_value = symbols[i].n_value;
3479 else{
3480 n_strx = symbols64[i].n_un.n_strx;
3481 n_type = symbols64[i].n_type;
3482 n_value = symbols64[i].n_value;
3484 if((n_type & N_EXT) == N_EXT &&
3485 ((n_type & N_TYPE) != N_UNDF &&
3486 (n_type & N_TYPE) != N_PBUD)){
3487 if(object->mh != NULL)
3488 new_symbols[inew_syms] = symbols[i];
3489 else
3490 new_symbols64[inew_syms] = symbols64[i];
3491 if(n_strx != 0){
3492 strcpy(p, strings + n_strx);
3493 if(object->mh != NULL)
3494 new_symbols[inew_syms].n_un.n_strx =
3495 p - new_strings;
3496 else
3497 new_symbols64[inew_syms].n_un.n_strx =
3498 p - new_strings;
3499 p += strlen(p) + 1;
3501 if((n_type & N_TYPE) == N_INDR){
3502 if(n_value != 0){
3503 strcpy(p, strings + n_value);
3504 if(object->mh != NULL)
3505 new_symbols[inew_syms].n_value =
3506 p - new_strings;
3507 else
3508 new_symbols64[inew_syms].n_value =
3509 p - new_strings;
3510 p += strlen(p) + 1;
3513 inew_syms++;
3514 saves[i] = inew_syms;
3519 * Build the new undefined symbols into a map and sort it.
3521 inew_undefsyms = 0;
3522 if(object->mh != NULL){
3523 undef_map = (struct undef_map *)allocate(new_nundefsym *
3524 sizeof(struct undef_map));
3525 undef_map64 = NULL;
3527 else{
3528 undef_map = NULL;
3529 undef_map64 = (struct undef_map64 *)allocate(new_nundefsym *
3530 sizeof(struct undef_map64));
3532 for(i = 0; i < nsyms; i++){
3533 if(saves[i]){
3534 if(object->mh != NULL){
3535 n_strx = symbols[i].n_un.n_strx;
3536 n_type = symbols[i].n_type;
3538 else{
3539 n_strx = symbols64[i].n_un.n_strx;
3540 n_type = symbols64[i].n_type;
3542 if((n_type & N_EXT) == N_EXT &&
3543 ((n_type & N_TYPE) == N_UNDF ||
3544 (n_type & N_TYPE) == N_PBUD)){
3545 if(object->mh != NULL)
3546 undef_map[inew_undefsyms].symbol = symbols[i];
3547 else
3548 undef_map64[inew_undefsyms].symbol64 = symbols64[i];
3549 if(n_strx != 0){
3550 strcpy(p, strings + n_strx);
3551 if(object->mh != NULL)
3552 undef_map[inew_undefsyms].symbol.n_un.n_strx =
3553 p - new_strings;
3554 else
3555 undef_map64[inew_undefsyms].symbol64.n_un.n_strx =
3556 p - new_strings;
3557 p += strlen(p) + 1;
3559 if(object->mh != NULL)
3560 undef_map[inew_undefsyms].index = i;
3561 else
3562 undef_map64[inew_undefsyms].index = i;
3563 inew_undefsyms++;
3567 for(i = 0; i < nsyms; i++){
3568 if(changes[i]){
3569 if(object->mh != NULL)
3570 n_strx = symbols[i].n_un.n_strx;
3571 else
3572 n_strx = symbols64[i].n_un.n_strx;
3573 if(n_strx != 0){
3574 strcpy(p, strings + n_strx);
3575 if(object->mh != NULL)
3576 undef_map[inew_undefsyms].symbol.n_un.n_strx =
3577 p - new_strings;
3578 else
3579 undef_map64[inew_undefsyms].symbol64.n_un.n_strx =
3580 p - new_strings;
3581 p += strlen(p) + 1;
3583 if(object->mh != NULL){
3584 undef_map[inew_undefsyms].symbol.n_type = N_UNDF | N_EXT;
3585 undef_map[inew_undefsyms].symbol.n_sect = NO_SECT;
3586 undef_map[inew_undefsyms].symbol.n_desc = 0;
3587 undef_map[inew_undefsyms].symbol.n_value = 0;
3588 undef_map[inew_undefsyms].index = i;
3590 else{
3591 undef_map64[inew_undefsyms].symbol64.n_type = N_UNDF |N_EXT;
3592 undef_map64[inew_undefsyms].symbol64.n_sect = NO_SECT;
3593 undef_map64[inew_undefsyms].symbol64.n_desc = 0;
3594 undef_map64[inew_undefsyms].symbol64.n_value = 0;
3595 undef_map64[inew_undefsyms].index = i;
3597 inew_undefsyms++;
3600 /* Sort the undefined symbols by name */
3601 qsort_strings = new_strings;
3602 if(object->mh != NULL)
3603 qsort(undef_map, new_nundefsym, sizeof(struct undef_map),
3604 (int (*)(const void *, const void *))cmp_qsort_undef_map);
3605 else
3606 qsort(undef_map64, new_nundefsym, sizeof(struct undef_map64),
3607 (int (*)(const void *, const void *))cmp_qsort_undef_map_64);
3608 /* Copy the symbols now in sorted order into new_symbols */
3609 for(i = 0; i < new_nundefsym; i++){
3610 if(object->mh != NULL){
3611 new_symbols[inew_syms] = undef_map[i].symbol;
3612 inew_syms++;
3613 saves[undef_map[i].index] = inew_syms;
3615 else{
3616 new_symbols64[inew_syms] = undef_map64[i].symbol64;
3617 inew_syms++;
3618 saves[undef_map64[i].index] = inew_syms;
3623 * Fixup the module table's module name strings adding them to the
3624 * string table. Also fix the indexes into the symbol table for
3625 * external and local symbols. And fix up the indexes into the
3626 * reference table.
3628 for(i = 0; i < nmodtab; i++){
3629 if(object->mh != NULL){
3630 strcpy(p, strings + mods[i].module_name);
3631 mods[i].module_name = p - new_strings;
3632 iextdefsym = mods[i].iextdefsym;
3633 nextdefsym = mods[i].nextdefsym;
3634 ilocalsym = mods[i].ilocalsym;
3635 nlocalsym = mods[i].nlocalsym;
3636 irefsym = mods[i].irefsym;
3637 nrefsym = mods[i].nrefsym;
3639 else{
3640 strcpy(p, strings + mods64[i].module_name);
3641 mods64[i].module_name = p - new_strings;
3642 iextdefsym = mods64[i].iextdefsym;
3643 nextdefsym = mods64[i].nextdefsym;
3644 ilocalsym = mods64[i].ilocalsym;
3645 nlocalsym = mods64[i].nlocalsym;
3646 irefsym = mods64[i].irefsym;
3647 nrefsym = mods64[i].nrefsym;
3649 p += strlen(p) + 1;
3651 if(iextdefsym > nsyms){
3652 error_arch(arch, member, "bad index into externally defined "
3653 "symbols of module table entry %d in: ", i);
3654 return(FALSE);
3656 if(iextdefsym + nextdefsym > nsyms){
3657 error_arch(arch, member, "bad number of externally defined "
3658 "symbols of module table entry %d in: ", i);
3659 return(FALSE);
3661 for(j = iextdefsym; j < iextdefsym + nextdefsym; j++){
3662 if(saves[j] != 0 && changes[j] == 0)
3663 break;
3665 n = 0;
3666 for(k = j; k < iextdefsym + nextdefsym; k++){
3667 if(saves[k] != 0 && changes[k] == 0)
3668 n++;
3670 if(n == 0){
3671 if(object->mh != NULL){
3672 mods[i].iextdefsym = 0;
3673 mods[i].nextdefsym = 0;
3675 else{
3676 mods64[i].iextdefsym = 0;
3677 mods64[i].nextdefsym = 0;
3680 else{
3681 if(object->mh != NULL){
3682 mods[i].iextdefsym = saves[j] - 1;
3683 mods[i].nextdefsym = n;
3685 else{
3686 mods64[i].iextdefsym = saves[j] - 1;
3687 mods64[i].nextdefsym = n;
3691 if(ilocalsym > nsyms){
3692 error_arch(arch, member, "bad index into symbols for local "
3693 "symbols of module table entry %d in: ", i);
3694 return(FALSE);
3696 if(ilocalsym + nlocalsym > nsyms){
3697 error_arch(arch, member, "bad number of local "
3698 "symbols of module table entry %d in: ", i);
3699 return(FALSE);
3701 for(j = ilocalsym; j < ilocalsym + nlocalsym; j++){
3702 if(saves[j] != 0)
3703 break;
3705 n = 0;
3706 for(k = j; k < ilocalsym + nlocalsym; k++){
3707 if(saves[k] != 0)
3708 n++;
3710 if(n == 0){
3711 if(object->mh != NULL){
3712 mods[i].ilocalsym = 0;
3713 mods[i].nlocalsym = 0;
3715 else{
3716 mods64[i].ilocalsym = 0;
3717 mods64[i].nlocalsym = 0;
3720 else{
3721 if(object->mh != NULL){
3722 mods[i].ilocalsym = saves[j] - 1;
3723 mods[i].nlocalsym = n;
3725 else{
3726 mods64[i].ilocalsym = saves[j] - 1;
3727 mods64[i].nlocalsym = n;
3731 if(irefsym > nextrefsyms){
3732 error_arch(arch, member, "bad index into reference table "
3733 "of module table entry %d in: ", i);
3734 return(FALSE);
3736 if(irefsym + nrefsym > nextrefsyms){
3737 error_arch(arch, member, "bad number of reference table "
3738 "entries of module table entry %d in: ", i);
3739 return(FALSE);
3741 for(j = irefsym; j < irefsym + nrefsym; j++){
3742 if(ref_saves[j] != 0)
3743 break;
3745 n = 0;
3746 for(k = j; k < irefsym + nrefsym; k++){
3747 if(ref_saves[k] != 0)
3748 n++;
3750 if(n == 0){
3751 if(object->mh != NULL){
3752 mods[i].irefsym = 0;
3753 mods[i].nrefsym = 0;
3755 else{
3756 mods64[i].irefsym = 0;
3757 mods64[i].nrefsym = 0;
3760 else{
3761 if(object->mh != NULL){
3762 mods[i].irefsym = ref_saves[j] - 1;
3763 mods[i].nrefsym = n;
3765 else{
3766 mods64[i].irefsym = ref_saves[j] - 1;
3767 mods64[i].nrefsym = n;
3773 * Create a new reference table.
3775 new_refs = allocate(new_nextrefsyms * sizeof(struct dylib_reference));
3776 j = 0;
3777 for(i = 0; i < nextrefsyms; i++){
3778 if(ref_saves[i]){
3779 if(saves[refs[i].isym]){
3780 new_refs[j].isym = saves[refs[i].isym] - 1;
3781 new_refs[j].flags = refs[i].flags;
3783 else{
3784 if(refs[i].flags == REFERENCE_FLAG_UNDEFINED_NON_LAZY ||
3785 refs[i].flags == REFERENCE_FLAG_UNDEFINED_LAZY){
3786 new_refs[j].isym = changes[refs[i].isym] - 1;
3787 new_refs[j].flags = refs[i].flags;
3790 j++;
3795 * Create a new dylib table of contents.
3797 new_ntoc = 0;
3798 for(i = 0; i < ntoc; i++){
3799 if(tocs[i].symbol_index >= nsyms){
3800 error_arch(arch, member, "bad symbol index for table of "
3801 "contents table entry %d in: ", i);
3802 return(FALSE);
3804 if(saves[tocs[i].symbol_index] != 0 &&
3805 changes[tocs[i].symbol_index] == 0)
3806 new_ntoc++;
3808 new_tocs = allocate(new_ntoc * sizeof(struct dylib_table_of_contents));
3809 j = 0;
3810 for(i = 0; i < ntoc; i++){
3811 if(saves[tocs[i].symbol_index] != 0 &&
3812 changes[tocs[i].symbol_index] == 0){
3813 new_tocs[j].symbol_index = saves[tocs[i].symbol_index] - 1;
3814 new_tocs[j].module_index = tocs[i].module_index;
3815 j++;
3818 #ifdef TRIE_SUPPORT
3820 * Update the export trie if it has one but only call the the
3821 * prune_trie() routine when we are removing global symbols as is
3822 * done with default stripping of a dyld executable or with the -s
3823 * or -R options.
3825 if(object->dyld_info != NULL &&
3826 object->dyld_info->export_size != 0 &&
3827 (default_dyld_executable || sfile != NULL || Rfile != NULL)){
3828 const char *error_string;
3829 uint32_t trie_new_size;
3831 error_string = prune_trie((uint8_t *)(object->object_addr +
3832 object->dyld_info->export_off),
3833 object->dyld_info->export_size,
3834 prune,
3835 &trie_new_size);
3836 if(error_string != NULL){
3837 error_arch(arch, member, "%s", error_string);
3838 return(FALSE);
3841 #endif /* TRIE_SUPPORT */
3843 if(undef_map != NULL)
3844 free(undef_map);
3845 if(undef_map64 != NULL)
3846 free(undef_map64);
3847 if(changes != NULL)
3848 free(changes);
3849 if(sections != NULL)
3850 free(sections);
3851 if(sections64 != NULL)
3852 free(sections64);
3854 if(errors == 0)
3855 return(TRUE);
3856 else
3857 return(FALSE);
3860 #ifdef TRIE_SUPPORT
3862 * prune() is called by prune_trie() and passed a name of an external symbol
3863 * in the trie. It returns 1 if the symbols is to be pruned out and 0 if the
3864 * symbol is to be kept.
3866 * Note that it may seem like a linear search of the new symbols would not be
3867 * the best approach but in 10.6 the only defined global symbol left in a
3868 * stripped executable is __mh_execute_header and new_nextdefsym is usually 1
3869 * so this never actually loops in practice.
3871 static
3873 prune(
3874 const char *name)
3876 uint32_t i;
3878 for(i = 0; i < new_nextdefsym; i++){
3879 if(new_symbols != NULL){
3880 if(strcmp(name, new_strings + new_symbols[inew_nextdefsym + i]
3881 .n_un.n_strx) == 0)
3882 return(0);
3884 else{
3885 if(strcmp(name, new_strings + new_symbols64[inew_nextdefsym + i]
3886 .n_un.n_strx) == 0)
3887 return(0);
3890 return(1);
3892 #endif /* TRIE_SUPPORT */
3895 * make_ld_r_object() takes the object file contents referenced by the passed
3896 * data structures, writes that to a temporary file, runs "ld -r" plus the
3897 * specified stripping option creating a second temporary file, reads that file
3898 * in and replaces the object file contents with that and resets the variables
3899 * pointing to the symbol, string and indirect tables.
3901 static
3902 void
3903 make_ld_r_object(
3904 struct arch *arch,
3905 struct member *member,
3906 struct object *object)
3908 enum byte_sex host_byte_sex;
3909 char *input_file, *output_file;
3910 int fd;
3911 struct ofile *ld_r_ofile;
3912 struct arch *ld_r_archs;
3913 uint32_t ld_r_narchs, save_errors;
3915 host_byte_sex = get_host_byte_sex();
3918 * Swap the object file back into its bytesex before writing it to the
3919 * temporary file if needed.
3921 if(object->object_byte_sex != host_byte_sex){
3922 if(object->mh != NULL){
3923 if(swap_object_headers(object->mh, object->load_commands) ==
3924 FALSE)
3925 fatal("internal error: swap_object_headers() failed");
3926 swap_nlist(symbols, nsyms, object->object_byte_sex);
3928 else{
3929 if(swap_object_headers(object->mh64, object->load_commands) ==
3930 FALSE)
3931 fatal("internal error: swap_object_headers() failed");
3932 swap_nlist_64(symbols64, nsyms, object->object_byte_sex);
3934 swap_indirect_symbols(indirectsyms, nindirectsyms,
3935 object->object_byte_sex);
3939 * Create an input object file for the ld -r command from the bytes
3940 * of this arch's object file.
3942 input_file = makestr("/tmp/strip.XXXXXX", NULL);
3943 input_file = mktemp(input_file);
3945 if((fd = open(input_file, O_WRONLY|O_CREAT, 0600)) < 0)
3946 system_fatal("can't open temporary file: %s", input_file);
3948 if(write(fd, object->object_addr, object->object_size) !=
3949 object->object_size)
3950 system_fatal("can't write temporary file: %s", input_file);
3952 if(close(fd) == -1)
3953 system_fatal("can't close temporary file: %s", input_file);
3956 * Create a temporary name for the output file of the ld -r
3958 output_file = makestr("/tmp/strip.XXXXXX", NULL);
3959 output_file = mktemp(output_file);
3962 * Create the ld -r command line and execute it.
3964 reset_execute_list();
3965 add_execute_list("ld");
3966 add_execute_list("-keep_private_externs");
3967 add_execute_list("-r");
3968 if(Sflag)
3969 add_execute_list("-S");
3970 if(xflag)
3971 add_execute_list("-x");
3972 add_execute_list(input_file);
3973 add_execute_list("-o");
3974 add_execute_list(output_file);
3975 if(sfile != NULL){
3976 add_execute_list("-x");
3977 add_execute_list("-exported_symbols_list");
3978 add_execute_list(sfile);
3980 if(Rfile != NULL){
3981 add_execute_list("-unexported_symbols_list");
3982 add_execute_list(Rfile);
3984 if(execute_list(vflag) == 0)
3985 fatal("internal link edit command failed");
3987 save_errors = errors;
3988 errors = 0;
3989 /* breakout the output file of the ld -f for processing */
3990 ld_r_ofile = breakout(output_file, &ld_r_archs, &ld_r_narchs, FALSE);
3991 if(errors)
3992 goto make_ld_r_object_cleanup;
3994 /* checkout the file for symbol table replacement processing */
3995 checkout(ld_r_archs, ld_r_narchs);
3998 * Make sure the output of the ld -r is an object file with one arch.
4000 if(ld_r_narchs != 1 ||
4001 ld_r_archs->type != OFILE_Mach_O ||
4002 ld_r_archs->object == NULL ||
4003 ld_r_archs->object->mh_filetype != MH_OBJECT)
4004 fatal("internal link edit command failed to produce a thin Mach-O "
4005 "object file");
4008 * Now reset all the data of the input object with the ld -r output
4009 * object file.
4011 nsyms = ld_r_archs->object->st->nsyms;
4012 if(ld_r_archs->object->mh != NULL){
4013 symbols = (struct nlist *)
4014 (ld_r_archs->object->object_addr +
4015 ld_r_archs->object->st->symoff);
4016 if(ld_r_archs->object->object_byte_sex != host_byte_sex)
4017 swap_nlist(symbols, nsyms, host_byte_sex);
4018 symbols64 = NULL;
4020 else{
4021 symbols = NULL;
4022 symbols64 = (struct nlist_64 *)
4023 (ld_r_archs->object->object_addr +
4024 ld_r_archs->object->st->symoff);
4025 if(ld_r_archs->object->object_byte_sex != host_byte_sex)
4026 swap_nlist_64(symbols64, nsyms, host_byte_sex);
4028 strings = ld_r_archs->object->object_addr +
4029 ld_r_archs->object->st->stroff;
4030 strsize = ld_r_archs->object->st->strsize;
4032 if(ld_r_archs->object->dyst != NULL &&
4033 ld_r_archs->object->dyst->nindirectsyms != 0){
4034 nindirectsyms = ld_r_archs->object->dyst->nindirectsyms;
4035 indirectsyms = (uint32_t *)
4036 (ld_r_archs->object->object_addr +
4037 ld_r_archs->object->dyst->indirectsymoff);
4038 if(ld_r_archs->object->object_byte_sex != host_byte_sex)
4039 swap_indirect_symbols(indirectsyms, nindirectsyms,
4040 host_byte_sex);
4042 else{
4043 indirectsyms = NULL;
4044 nindirectsyms = 0;
4047 if(ld_r_archs->object->mh != NULL)
4048 ld_r_archs->object->input_sym_info_size =
4049 nsyms * sizeof(struct nlist) +
4050 strsize;
4051 else
4052 ld_r_archs->object->input_sym_info_size =
4053 nsyms * sizeof(struct nlist_64) +
4054 strsize;
4057 * Copy over the object struct from the ld -r object file onto the
4058 * input object file.
4060 *object = *ld_r_archs->object;
4063 * Save the ofile struct for the ld -r output so it can be umapped when
4064 * we are done. And free up the ld_r_archs now that we are done with
4065 * them.
4067 object->ld_r_ofile = ld_r_ofile;
4068 free_archs(ld_r_archs, ld_r_narchs);
4070 make_ld_r_object_cleanup:
4071 errors += save_errors;
4073 * Remove the input and output files and clean up.
4075 if(unlink(input_file) == -1)
4076 system_fatal("can't remove temporary file: %s", input_file);
4077 if(unlink(output_file) == -1)
4078 system_fatal("can't remove temporary file: %s", output_file);
4079 free(input_file);
4080 free(output_file);
4084 * strip_LC_UUID_commands() is called when -no_uuid is specified to remove any
4085 * LC_UUID load commands from the object's load commands.
4087 static
4088 void
4089 strip_LC_UUID_commands(
4090 struct arch *arch,
4091 struct member *member,
4092 struct object *object)
4094 uint32_t i, ncmds, nuuids, mh_sizeofcmds, sizeofcmds;
4095 struct load_command *lc1, *lc2, *new_load_commands;
4096 struct segment_command *sg;
4099 * See if there are any LC_UUID load commands.
4101 nuuids = 0;
4102 lc1 = arch->object->load_commands;
4103 if(arch->object->mh != NULL){
4104 ncmds = arch->object->mh->ncmds;
4105 mh_sizeofcmds = arch->object->mh->sizeofcmds;
4107 else{
4108 ncmds = arch->object->mh64->ncmds;
4109 mh_sizeofcmds = arch->object->mh64->sizeofcmds;
4111 for(i = 0; i < ncmds; i++){
4112 if(lc1->cmd == LC_UUID){
4113 nuuids++;
4115 lc1 = (struct load_command *)((char *)lc1 + lc1->cmdsize);
4117 /* if no LC_UUID load commands just return */
4118 if(nuuids == 0)
4119 return;
4122 * Allocate space for the new load commands as zero it out so any holes
4123 * will be zero bytes.
4125 new_load_commands = allocate(mh_sizeofcmds);
4126 memset(new_load_commands, '\0', mh_sizeofcmds);
4129 * Copy all the load commands except the LC_UUID load commands into the
4130 * allocated space for the new load commands.
4132 lc1 = arch->object->load_commands;
4133 lc2 = new_load_commands;
4134 sizeofcmds = 0;
4135 for(i = 0; i < ncmds; i++){
4136 if(lc1->cmd != LC_UUID){
4137 memcpy(lc2, lc1, lc1->cmdsize);
4138 sizeofcmds += lc2->cmdsize;
4139 lc2 = (struct load_command *)((char *)lc2 + lc2->cmdsize);
4141 lc1 = (struct load_command *)((char *)lc1 + lc1->cmdsize);
4145 * Finally copy the updated load commands over the existing load
4146 * commands.
4148 memcpy(arch->object->load_commands, new_load_commands, sizeofcmds);
4149 if(mh_sizeofcmds > sizeofcmds){
4150 memset((char *)arch->object->load_commands + sizeofcmds, '\0',
4151 (mh_sizeofcmds - sizeofcmds));
4153 ncmds -= nuuids;
4154 if(arch->object->mh != NULL) {
4155 arch->object->mh->sizeofcmds = sizeofcmds;
4156 arch->object->mh->ncmds = ncmds;
4157 } else {
4158 arch->object->mh64->sizeofcmds = sizeofcmds;
4159 arch->object->mh64->ncmds = ncmds;
4161 free(new_load_commands);
4163 /* reset the pointers into the load commands */
4164 lc1 = arch->object->load_commands;
4165 for(i = 0; i < ncmds; i++){
4166 switch(lc1->cmd){
4167 case LC_SYMTAB:
4168 arch->object->st = (struct symtab_command *)lc1;
4169 break;
4170 case LC_DYSYMTAB:
4171 arch->object->dyst = (struct dysymtab_command *)lc1;
4172 break;
4173 case LC_TWOLEVEL_HINTS:
4174 arch->object->hints_cmd = (struct twolevel_hints_command *)lc1;
4175 break;
4176 case LC_PREBIND_CKSUM:
4177 arch->object->cs = (struct prebind_cksum_command *)lc1;
4178 break;
4179 case LC_SEGMENT:
4180 sg = (struct segment_command *)lc1;
4181 if(strcmp(sg->segname, SEG_LINKEDIT) == 0)
4182 arch->object->seg_linkedit = sg;
4183 break;
4184 case LC_SEGMENT_SPLIT_INFO:
4185 object->split_info_cmd = (struct linkedit_data_command *)lc1;
4186 break;
4187 case LC_FUNCTION_STARTS:
4188 object->func_starts_info_cmd =
4189 (struct linkedit_data_command *)lc1;
4190 break;
4191 case LC_DATA_IN_CODE:
4192 object->data_in_code_cmd =
4193 (struct linkedit_data_command *)lc1;
4194 break;
4195 case LC_DYLIB_CODE_SIGN_DRS:
4196 object->code_sign_drs_cmd =
4197 (struct linkedit_data_command *)lc1;
4198 break;
4199 case LC_CODE_SIGNATURE:
4200 object->code_sig_cmd = (struct linkedit_data_command *)lc1;
4201 break;
4202 case LC_DYLD_INFO_ONLY:
4203 case LC_DYLD_INFO:
4204 object->dyld_info = (struct dyld_info_command *)lc1;
4206 lc1 = (struct load_command *)((char *)lc1 + lc1->cmdsize);
4211 * strip_LC_DYLIB_commands() is called when -no_dylib is specified to remove any
4212 * LC_LOAD_DYLIB, LC_LOAD_WEAK_DYLIB or LC_REEXPORT_DYLIB load commands from the
4213 * object's load commands that reference any of the -no_dylib shared libraries.
4215 static
4216 void
4217 strip_LC_DYLIB_commands(
4218 struct arch *arch,
4219 struct member *member,
4220 struct object *object)
4222 uint32_t i, ncmds, ndylibs, dyidx, newnum, mh_sizeofcmds, sizeofcmds;
4223 struct load_command *lc1, *lc2, *new_load_commands;
4224 struct segment_command *sg;
4225 uint8_t inuse[256], renum[256];
4228 * See if there are any DYLIB load commands.
4230 ndylibs = 0;
4231 lc1 = arch->object->load_commands;
4232 if(arch->object->mh != NULL){
4233 ncmds = arch->object->mh->ncmds;
4234 mh_sizeofcmds = arch->object->mh->sizeofcmds;
4236 else{
4237 ncmds = arch->object->mh64->ncmds;
4238 mh_sizeofcmds = arch->object->mh64->sizeofcmds;
4240 for(i = 0; i < ncmds; i++){
4241 if(lc1->cmd == LC_LOAD_DYLIB ||
4242 lc1->cmd == LC_LOAD_WEAK_DYLIB ||
4243 lc1->cmd == LC_REEXPORT_DYLIB ||
4244 lc1->cmd == LC_LAZY_LOAD_DYLIB ||
4245 lc1->cmd == LC_LOAD_UPWARD_DYLIB){
4246 ndylibs++;
4248 lc1 = (struct load_command *)((char *)lc1 + lc1->cmdsize);
4250 /* if no DYLIB load commands just return */
4251 if(ndylibs == 0)
4252 return;
4255 * Allocate space for the new load commands as zero it out so any holes
4256 * will be zero bytes.
4258 new_load_commands = allocate(mh_sizeofcmds);
4259 memset(new_load_commands, '\0', mh_sizeofcmds);
4262 * Find dylib references currently in use by undefined symbols
4264 memset(inuse, 0, sizeof(inuse));
4265 memset(renum, 0, sizeof(renum));
4266 if (new_symbols) {
4267 for (i=0; i<new_nsyms; ++i) {
4268 if ((new_symbols[i].n_type & N_TYPE) == N_UNDF) {
4269 uint8_t ordn = GET_LIBRARY_ORDINAL(new_symbols[i].n_desc);
4270 if (1 <= ordn && ordn <= MAX_LIBRARY_ORDINAL)
4271 inuse[ordn] = 1;
4275 else if (new_symbols64) {
4276 for (i=0; i<new_nsyms; ++i) {
4277 if ((new_symbols64[i].n_type & N_TYPE) == N_UNDF) {
4278 uint8_t ordn = GET_LIBRARY_ORDINAL(new_symbols64[i].n_desc);
4279 if (1 <= ordn && ordn <= MAX_LIBRARY_ORDINAL)
4280 inuse[ordn] = 1;
4286 * Copy all the load commands except the matching DYLIB load commands
4287 * into the allocated space for the new load commands.
4289 lc1 = arch->object->load_commands;
4290 lc2 = new_load_commands;
4291 sizeofcmds = 0;
4292 ndylibs = 0;
4293 dyidx = 0;
4294 newnum = 0;
4295 for(i = 0; i < ncmds; i++){
4296 int ignore = 0;
4297 if(lc1->cmd == LC_LOAD_DYLIB ||
4298 lc1->cmd == LC_LOAD_WEAK_DYLIB ||
4299 lc1->cmd == LC_REEXPORT_DYLIB ||
4300 lc1->cmd == LC_LAZY_LOAD_DYLIB ||
4301 lc1->cmd == LC_LOAD_UPWARD_DYLIB){
4302 struct dylib_command *dlc = (struct dylib_command *)lc1;
4303 char *name = (char *)lc1 + dlc->dylib.name.offset;
4304 dylib_name *ptr;
4305 ++dyidx;
4306 if (no_dylib_unused)
4307 ignore = !inuse[dyidx];
4308 for (ptr = no_dylib; !ignore && ptr; ptr = ptr->next) {
4309 if (strcmp(ptr->name, name) == 0) {
4310 if (inuse[dyidx]) {
4311 fatal_arch(arch, member, "can't remove inuse "
4312 "dylib reference %s from: ", name);
4314 else {
4315 ignore = 1;
4317 break;
4320 if (ignore)
4321 ++ndylibs;
4322 else
4323 renum[dyidx] = ++newnum;
4325 if(!ignore){
4326 memcpy(lc2, lc1, lc1->cmdsize);
4327 sizeofcmds += lc2->cmdsize;
4328 lc2 = (struct load_command *)((char *)lc2 + lc2->cmdsize);
4330 lc1 = (struct load_command *)((char *)lc1 + lc1->cmdsize);
4334 * Finally copy the updated load commands over the existing load
4335 * commands.
4337 memcpy(arch->object->load_commands, new_load_commands, sizeofcmds);
4338 if(mh_sizeofcmds > sizeofcmds){
4339 memset((char *)arch->object->load_commands + sizeofcmds, '\0',
4340 (mh_sizeofcmds - sizeofcmds));
4342 ncmds -= ndylibs;
4343 if(arch->object->mh != NULL) {
4344 arch->object->mh->sizeofcmds = sizeofcmds;
4345 arch->object->mh->ncmds = ncmds;
4346 } else {
4347 arch->object->mh64->sizeofcmds = sizeofcmds;
4348 arch->object->mh64->ncmds = ncmds;
4350 free(new_load_commands);
4352 /* reset the pointers into the load commands */
4353 lc1 = arch->object->load_commands;
4354 for(i = 0; i < ncmds; i++){
4355 switch(lc1->cmd){
4356 case LC_SYMTAB:
4357 arch->object->st = (struct symtab_command *)lc1;
4358 break;
4359 case LC_DYSYMTAB:
4360 arch->object->dyst = (struct dysymtab_command *)lc1;
4361 break;
4362 case LC_TWOLEVEL_HINTS:
4363 arch->object->hints_cmd = (struct twolevel_hints_command *)lc1;
4364 break;
4365 case LC_PREBIND_CKSUM:
4366 arch->object->cs = (struct prebind_cksum_command *)lc1;
4367 break;
4368 case LC_SEGMENT:
4369 sg = (struct segment_command *)lc1;
4370 if(strcmp(sg->segname, SEG_LINKEDIT) == 0)
4371 arch->object->seg_linkedit = sg;
4372 break;
4373 case LC_SEGMENT_SPLIT_INFO:
4374 object->split_info_cmd = (struct linkedit_data_command *)lc1;
4375 break;
4376 case LC_FUNCTION_STARTS:
4377 object->func_starts_info_cmd =
4378 (struct linkedit_data_command *)lc1;
4379 break;
4380 case LC_DATA_IN_CODE:
4381 object->data_in_code_cmd =
4382 (struct linkedit_data_command *)lc1;
4383 break;
4384 case LC_DYLIB_CODE_SIGN_DRS:
4385 object->code_sign_drs_cmd =
4386 (struct linkedit_data_command *)lc1;
4387 break;
4388 case LC_CODE_SIGNATURE:
4389 object->code_sig_cmd = (struct linkedit_data_command *)lc1;
4390 break;
4391 case LC_DYLD_INFO_ONLY:
4392 case LC_DYLD_INFO:
4393 object->dyld_info = (struct dyld_info_command *)lc1;
4395 lc1 = (struct load_command *)((char *)lc1 + lc1->cmdsize);
4399 * Renumber symbol dylib references
4401 if (new_symbols) {
4402 for (i=0; i<new_nsyms; ++i) {
4403 if ((new_symbols[i].n_type & N_TYPE) == N_UNDF) {
4404 uint8_t n = GET_LIBRARY_ORDINAL(new_symbols[i].n_desc);
4405 if (1 <= n && n <= MAX_LIBRARY_ORDINAL)
4406 SET_LIBRARY_ORDINAL(new_symbols[i].n_desc, renum[n]);
4410 else if (new_symbols64) {
4411 for (i=0; i<new_nsyms; ++i) {
4412 if ((new_symbols64[i].n_type & N_TYPE) == N_UNDF) {
4413 uint8_t n = GET_LIBRARY_ORDINAL(new_symbols64[i].n_desc);
4414 if (1 <= n && n <= MAX_LIBRARY_ORDINAL)
4415 SET_LIBRARY_ORDINAL(new_symbols64[i].n_desc, renum[n]);
4421 #ifndef NMEDIT
4423 * strip_LC_CODE_SIGNATURE_commands() is called when -c is specified to remove
4424 * any LC_CODE_SIGNATURE load commands from the object's load commands.
4426 static
4427 void
4428 strip_LC_CODE_SIGNATURE_commands(
4429 struct arch *arch,
4430 struct member *member,
4431 struct object *object)
4433 uint32_t i, ncmds, mh_sizeofcmds, sizeofcmds;
4434 struct load_command *lc1, *lc2, *new_load_commands;
4435 struct segment_command *sg;
4438 * See if there is an LC_CODE_SIGNATURE load command and if no command
4439 * just return.
4441 if(object->code_sig_cmd == NULL)
4442 return;
4445 * Allocate space for the new load commands and zero it out so any holes
4446 * will be zero bytes.
4448 if(arch->object->mh != NULL){
4449 ncmds = arch->object->mh->ncmds;
4450 mh_sizeofcmds = arch->object->mh->sizeofcmds;
4452 else{
4453 ncmds = arch->object->mh64->ncmds;
4454 mh_sizeofcmds = arch->object->mh64->sizeofcmds;
4456 new_load_commands = allocate(mh_sizeofcmds);
4457 memset(new_load_commands, '\0', mh_sizeofcmds);
4460 * Copy all the load commands except the LC_CODE_SIGNATURE load commands
4461 * into the allocated space for the new load commands.
4463 lc1 = arch->object->load_commands;
4464 lc2 = new_load_commands;
4465 sizeofcmds = 0;
4466 for(i = 0; i < ncmds; i++){
4467 if(lc1->cmd != LC_CODE_SIGNATURE){
4468 memcpy(lc2, lc1, lc1->cmdsize);
4469 sizeofcmds += lc2->cmdsize;
4470 lc2 = (struct load_command *)((char *)lc2 + lc2->cmdsize);
4472 lc1 = (struct load_command *)((char *)lc1 + lc1->cmdsize);
4476 * Finally copy the updated load commands over the existing load
4477 * commands.
4479 memcpy(arch->object->load_commands, new_load_commands, sizeofcmds);
4480 if(mh_sizeofcmds > sizeofcmds){
4481 memset((char *)arch->object->load_commands + sizeofcmds, '\0',
4482 (mh_sizeofcmds - sizeofcmds));
4484 ncmds -= 1;
4485 if(arch->object->mh != NULL) {
4486 arch->object->mh->sizeofcmds = sizeofcmds;
4487 arch->object->mh->ncmds = ncmds;
4488 } else {
4489 arch->object->mh64->sizeofcmds = sizeofcmds;
4490 arch->object->mh64->ncmds = ncmds;
4492 free(new_load_commands);
4494 /* reset the pointers into the load commands */
4495 object->code_sig_cmd = NULL;
4496 lc1 = arch->object->load_commands;
4497 for(i = 0; i < ncmds; i++){
4498 switch(lc1->cmd){
4499 case LC_SYMTAB:
4500 arch->object->st = (struct symtab_command *)lc1;
4501 break;
4502 case LC_DYSYMTAB:
4503 arch->object->dyst = (struct dysymtab_command *)lc1;
4504 break;
4505 case LC_TWOLEVEL_HINTS:
4506 arch->object->hints_cmd = (struct twolevel_hints_command *)lc1;
4507 break;
4508 case LC_PREBIND_CKSUM:
4509 arch->object->cs = (struct prebind_cksum_command *)lc1;
4510 break;
4511 case LC_SEGMENT:
4512 sg = (struct segment_command *)lc1;
4513 if(strcmp(sg->segname, SEG_LINKEDIT) == 0)
4514 arch->object->seg_linkedit = sg;
4515 break;
4516 case LC_SEGMENT_SPLIT_INFO:
4517 object->split_info_cmd = (struct linkedit_data_command *)lc1;
4518 break;
4519 case LC_FUNCTION_STARTS:
4520 object->func_starts_info_cmd =
4521 (struct linkedit_data_command *)lc1;
4522 break;
4523 case LC_DATA_IN_CODE:
4524 object->data_in_code_cmd =
4525 (struct linkedit_data_command *)lc1;
4526 break;
4527 case LC_DYLIB_CODE_SIGN_DRS:
4528 object->code_sign_drs_cmd =
4529 (struct linkedit_data_command *)lc1;
4530 break;
4531 case LC_DYLD_INFO_ONLY:
4532 case LC_DYLD_INFO:
4533 object->dyld_info = (struct dyld_info_command *)lc1;
4535 lc1 = (struct load_command *)((char *)lc1 + lc1->cmdsize);
4538 if(cflag){
4540 * To get the right amount of the file copied out by writeout() for
4541 * the case when we are stripping out the section contents we
4542 * already reduce the object size by the size of the section
4543 * contents including the padding after the load commands. So here
4544 * we need to further reduce it by the load command for the
4545 * LC_CODE_SIGNATURE (a struct linkedit_data_command) we are
4546 * removing.
4548 object->object_size -= sizeof(struct linkedit_data_command);
4550 * Then this size minus the size of the input symbolic information
4551 * is what is copied out from the file by writeout(). Which in this
4552 * case is just the new headers.
4556 * Finally for -c the file offset to the link edit information is to
4557 * be right after the load commands. So reset this for the updated
4558 * size of the load commands without the LC_CODE_SIGNATURE.
4560 if(object->mh != NULL)
4561 object->seg_linkedit->fileoff = sizeof(struct mach_header) +
4562 sizeofcmds;
4563 else
4564 object->seg_linkedit64->fileoff =
4565 sizeof(struct mach_header_64) + sizeofcmds;
4568 #endif /* !(NMEDIT) */
4571 * private_extern_reference_by_module() is passed a symbol_index of a private
4572 * extern symbol and the module table. If the symbol_index appears in the
4573 * module symbol table this returns TRUE else it returns FALSE.
4575 static
4576 enum bool
4577 private_extern_reference_by_module(
4578 uint32_t symbol_index,
4579 struct dylib_reference *refs,
4580 uint32_t nextrefsyms)
4582 uint32_t i;
4584 for(i = 0; i < nextrefsyms; i++){
4585 if(refs[i].isym == symbol_index){
4586 if(refs[i].flags == REFERENCE_FLAG_PRIVATE_UNDEFINED_NON_LAZY ||
4587 refs[i].flags == REFERENCE_FLAG_PRIVATE_UNDEFINED_LAZY){
4588 return(TRUE);
4592 return(FALSE);
4596 * symbol_pointer_used() is passed a symbol_index and the indirect table. If
4597 * the symbol_index appears in the indirect symbol table this returns TRUE else
4598 * it returns FALSE.
4600 static
4601 enum bool
4602 symbol_pointer_used(
4603 uint32_t symbol_index,
4604 uint32_t *indirectsyms,
4605 uint32_t nindirectsyms)
4607 uint32_t i;
4609 for(i = 0; i < nindirectsyms; i++){
4610 if(indirectsyms[i] == symbol_index)
4611 return(TRUE);
4613 return(FALSE);
4617 * Function for qsort for comparing undefined map entries.
4619 static
4621 cmp_qsort_undef_map(
4622 const struct undef_map *sym1,
4623 const struct undef_map *sym2)
4625 return(strcmp(qsort_strings + sym1->symbol.n_un.n_strx,
4626 qsort_strings + sym2->symbol.n_un.n_strx));
4629 static
4631 cmp_qsort_undef_map_64(
4632 const struct undef_map64 *sym1,
4633 const struct undef_map64 *sym2)
4635 return(strcmp(qsort_strings + sym1->symbol64.n_un.n_strx,
4636 qsort_strings + sym2->symbol64.n_un.n_strx));
4638 #endif /* !defined(NMEDIT) */
4640 #ifndef NMEDIT
4642 * Function for qsort for comparing object names.
4644 static
4646 cmp_qsort_filename(
4647 const char **name1,
4648 const char **name2)
4650 return(strcmp(*name1, *name2));
4654 * Function for bsearch for finding a object name.
4656 static
4658 cmp_bsearch_filename(
4659 const char *name1,
4660 const char **name2)
4662 return(strcmp(name1, *name2));
4664 #endif /* !defined(NMEDIT) */
4666 #ifdef NMEDIT
4667 static
4668 enum bool
4669 edit_symtab(
4670 struct arch *arch,
4671 struct member *member,
4672 struct object *object,
4673 struct nlist *symbols,
4674 struct nlist_64 *symbols64,
4675 uint32_t nsyms,
4676 char *strings,
4677 uint32_t strsize,
4678 struct dylib_table_of_contents *tocs,
4679 uint32_t ntoc,
4680 struct dylib_module *mods,
4681 struct dylib_module_64 *mods64,
4682 uint32_t nmodtab,
4683 struct dylib_reference *refs,
4684 uint32_t nextrefsyms)
4686 uint32_t i, j, k;
4687 unsigned char data_n_sect, nsects;
4688 struct load_command *lc;
4689 struct segment_command *sg;
4690 struct segment_command_64 *sg64;
4691 struct section *s, **sections;
4692 struct section_64 *s64, **sections64;
4694 uint32_t missing_syms;
4695 struct symbol_list *sp;
4696 struct nlist **global_symbol;
4697 struct nlist_64 **global_symbol64;
4698 enum bool global_symbol_found;
4699 char *global_name, save_char;
4700 enum bool dwarf_debug_map;
4701 enum byte_sex host_byte_sex;
4702 int32_t missing_reloc_symbols;
4703 enum bool edit_symtab_return;
4705 char *p, *q;
4706 uint32_t new_ext_strsize, len, inew_syms;
4708 struct nlist **changed_globals;
4709 struct nlist_64 **changed_globals64;
4710 uint32_t nchanged_globals;
4711 uint32_t ncmds, s_flags, n_strx, module_name, ilocalsym, nlocalsym;
4712 uint32_t iextdefsym, nextdefsym;
4713 uint8_t n_type, n_sect, global_symbol_n_sect;
4714 uint64_t n_value;
4715 enum bool warned_about_global_coalesced_symbols;
4717 edit_symtab_return = TRUE;
4718 host_byte_sex = get_host_byte_sex();
4719 missing_reloc_symbols = 0;
4720 warned_about_global_coalesced_symbols = FALSE;
4722 if(nmedits != NULL)
4723 free(nmedits);
4724 nmedits = allocate(nsyms * sizeof(enum bool));
4725 for(i = 0; i < nsyms; i++)
4726 nmedits[i] = FALSE;
4729 * If nmedit is operating on a dynamic library then symbols are turned
4730 * into private externs with the extern bit off not into static symbols.
4732 if(object->mh_filetype == MH_DYLIB && pflag == TRUE){
4733 error_arch(arch, member, "can't use -p with dynamic libraries");
4734 return(FALSE);
4738 * As part of the MAJOR guess for the second pass to fix stabs for the
4739 * globals symbols that get turned into non-global symbols. We need to
4740 * change the stabs. To do this we to know if a N_GSYM is for a data
4741 * symbol or not to know to turn it into an N_STSYM or a N_FUN.
4742 * This logic as determined by compiling test cases with and without
4743 * the key word 'static' and looking at the difference between the STABS
4744 * the compiler generates and trying to match that here.
4746 * We also use this loop and the next to gather an array of section
4747 * struct pointers so we can later determine if we run into a global
4748 * symbol in a coalesced section and not turn those symbols into
4749 * statics.
4751 j = 0;
4752 nsects = 0;
4753 n_sect = 1;
4754 data_n_sect = NO_SECT;
4755 lc = object->load_commands;
4756 if(object->mh != NULL)
4757 ncmds = object->mh->ncmds;
4758 else
4759 ncmds = object->mh64->ncmds;
4760 for(i = 0; i < ncmds; i++){
4761 if(lc->cmd == LC_SEGMENT){
4762 sg = (struct segment_command *)lc;
4763 s = (struct section *)((char *)sg +
4764 sizeof(struct segment_command));
4765 nsects += sg->nsects;
4766 for(j = 0; j < sg->nsects; j++){
4767 if(strcmp(s->segname, SEG_DATA) == 0 &&
4768 strcmp(s->sectname, SECT_DATA) == 0 &&
4769 data_n_sect == NO_SECT){
4770 data_n_sect = n_sect;
4771 break;
4773 n_sect++;
4774 s++;
4777 else if(lc->cmd == LC_SEGMENT_64){
4778 sg64 = (struct segment_command_64 *)lc;
4779 s64 = (struct section_64 *)((char *)sg64 +
4780 sizeof(struct segment_command_64));
4781 nsects += sg64->nsects;
4782 for(j = 0; j < sg64->nsects; j++){
4783 if(strcmp(s64->segname, SEG_DATA) == 0 &&
4784 strcmp(s64->sectname, SECT_DATA) == 0 &&
4785 data_n_sect == NO_SECT){
4786 data_n_sect = n_sect;
4787 break;
4789 n_sect++;
4790 s64++;
4793 lc = (struct load_command *)((char *)lc + lc->cmdsize);
4795 if(object->mh != NULL){
4796 sections = allocate(nsects * sizeof(struct section *));
4797 sections64 = NULL;
4799 else{
4800 sections = NULL;
4801 sections64 = allocate(nsects * sizeof(struct section_64 *));
4803 nsects = 0;
4804 lc = object->load_commands;
4805 for(i = 0; i < ncmds; i++){
4806 if(lc->cmd == LC_SEGMENT){
4807 sg = (struct segment_command *)lc;
4808 s = (struct section *)((char *)sg +
4809 sizeof(struct segment_command));
4810 for(j = 0; j < sg->nsects; j++){
4811 sections[nsects++] = s++;
4814 else if(lc->cmd == LC_SEGMENT_64){
4815 sg64 = (struct segment_command_64 *)lc;
4816 s64 = (struct section_64 *)((char *)sg64 +
4817 sizeof(struct segment_command_64));
4818 for(j = 0; j < sg64->nsects; j++){
4819 sections64[nsects++] = s64++;
4822 lc = (struct load_command *)((char *)lc + lc->cmdsize);
4826 * Zero out the saved symbols so they can be recorded for this file.
4828 for(i = 0; i < nsave_symbols; i++)
4829 save_symbols[i].sym = NULL;
4830 for(i = 0; i < nremove_symbols; i++)
4831 remove_symbols[i].sym = NULL;
4832 if(member == NULL){
4833 for(i = 0; i < nsave_symbols; i++)
4834 save_symbols[i].seen = FALSE;
4835 for(i = 0; i < nremove_symbols; i++)
4836 remove_symbols[i].seen = FALSE;
4839 nchanged_globals = 0;
4840 if(object->mh != NULL){
4841 changed_globals = allocate(nsyms * sizeof(struct nlist *));
4842 changed_globals64 = NULL;
4843 for(i = 0; i < nsyms; i++)
4844 changed_globals[i] = NULL;
4846 else{
4847 changed_globals = NULL;
4848 changed_globals64 = allocate(nsyms * sizeof(struct nlist_64 *));
4849 for(i = 0; i < nsyms; i++)
4850 changed_globals64[i] = NULL;
4854 * These are the variables for the new symbol table and new string
4855 * table. Since this routine only turns globals into non-globals the
4856 * number of symbols does not change. But the count of local, defined
4857 * external symbols does change.
4859 new_nsyms = nsyms;
4860 new_nlocalsym = 0;
4861 new_nextdefsym = 0;
4862 new_nundefsym = 0;
4864 new_strsize = sizeof(int32_t);
4865 new_ext_strsize = 0;
4868 * First pass: turn the globals symbols into non-global symbols.
4870 for(i = 0; i < nsyms; i++){
4871 len = 0;
4872 s_flags = 0;
4873 if(object->mh != NULL){
4874 n_strx = symbols[i].n_un.n_strx;
4875 n_type = symbols[i].n_type;
4876 n_sect = symbols[i].n_sect;
4877 if((n_type & N_TYPE) == N_SECT)
4878 s_flags = sections[n_sect - 1]->flags;
4879 n_value = symbols[i].n_value;
4881 else{
4882 n_strx = symbols64[i].n_un.n_strx;
4883 n_type = symbols64[i].n_type;
4884 n_sect = symbols64[i].n_sect;
4885 if((n_type & N_TYPE) == N_SECT)
4886 s_flags = sections64[n_sect - 1]->flags;
4887 n_value = symbols64[i].n_value;
4889 if(n_strx != 0){
4890 if(n_strx > strsize){
4891 error_arch(arch, member, "bad string index for symbol "
4892 "table entry %u in: ", i);
4893 return(FALSE);
4895 len = strlen(strings + n_strx) + 1;
4897 if(n_type & N_EXT){
4898 if((n_type & N_TYPE) != N_UNDF &&
4899 (n_type & N_TYPE) != N_PBUD){
4900 if((n_type & N_TYPE) == N_SECT){
4901 if(n_sect > nsects){
4902 error_arch(arch, member, "bad n_sect for symbol "
4903 "table entry %u in: ", i);
4904 return(FALSE);
4906 if(((s_flags & SECTION_TYPE) == S_COALESCED) &&
4907 pflag == FALSE &&
4908 object->mh_filetype != MH_OBJECT){
4909 /* this remains a global defined symbol */
4910 if(warned_about_global_coalesced_symbols == FALSE){
4911 warning_arch(arch, member, "can't make global "
4912 "coalesced symbols (like %s) into static "
4913 "symbols (use ld(1)'s "
4914 "-exported_symbols_list option) in a final "
4915 "linked image: ", strings + n_strx);
4916 warned_about_global_coalesced_symbols = TRUE;
4918 new_nextdefsym++;
4919 new_ext_strsize += len;
4920 new_strsize += len;
4921 sp = bsearch(strings + n_strx,
4922 remove_symbols, nremove_symbols,
4923 sizeof(struct symbol_list),
4924 (int (*)(const void *, const void *))
4925 symbol_list_bsearch);
4926 if(sp != NULL){
4927 if(sp->sym != NULL){
4928 error_arch(arch, member, "more than one "
4929 "symbol for: %s found in: ", sp->name);
4930 return(FALSE);
4932 else{
4933 if(object->mh != NULL)
4934 sp->sym = &(symbols[i]);
4935 else
4936 sp->sym = &(symbols64[i]);
4937 sp->seen = TRUE;
4938 warning_arch(arch, member, "can't make "
4939 "global coalesced symbol: %s into a "
4940 "static symbol in: ", sp->name);
4944 * In case the user has listed this coalesced
4945 * symbol in the save list look for it and mark it
4946 * as seen so we don't complain about not seeing it.
4948 sp = bsearch(strings + n_strx,
4949 save_symbols, nsave_symbols,
4950 sizeof(struct symbol_list),
4951 (int (*)(const void *, const void *))
4952 symbol_list_bsearch);
4953 if(sp != NULL){
4954 if(sp->sym != NULL){
4955 error_arch(arch, member, "more than one "
4956 "symbol for: %s found in: ", sp->name);
4957 return(FALSE);
4959 else{
4960 if(object->mh != NULL)
4961 sp->sym = &(symbols[i]);
4962 else
4963 sp->sym = &(symbols64[i]);
4964 sp->seen = TRUE;
4967 continue; /* leave this symbol unchanged */
4970 sp = bsearch(strings + n_strx,
4971 remove_symbols, nremove_symbols,
4972 sizeof(struct symbol_list),
4973 (int (*)(const void *, const void *))
4974 symbol_list_bsearch);
4975 if(sp != NULL){
4976 if(sp->sym != NULL){
4977 error_arch(arch, member, "more than one symbol "
4978 "for: %s found in: ", sp->name);
4979 return(FALSE);
4981 else{
4982 if(object->mh != NULL)
4983 sp->sym = &(symbols[i]);
4984 else
4985 sp->sym = &(symbols64[i]);
4986 sp->seen = TRUE;
4987 goto change_symbol;
4990 else{
4992 * If there is no list of saved symbols, then all
4993 * symbols will be saved unless listed in the remove
4994 * list.
4996 if(sfile == NULL){
4998 * There is no save list, so if there is also no
4999 * remove list but the -p flag is specified or it is
5000 * a dynamic library then change all symbols.
5002 if((pflag || object->mh_filetype == MH_DYLIB)
5003 && nremove_symbols == 0)
5004 goto change_symbol;
5005 /* this remains a global defined symbol */
5006 new_nextdefsym++;
5007 new_ext_strsize += len;
5008 new_strsize += len;
5009 continue; /* leave this symbol unchanged */
5012 sp = bsearch(strings + n_strx,
5013 save_symbols, nsave_symbols,
5014 sizeof(struct symbol_list),
5015 (int (*)(const void *, const void *))
5016 symbol_list_bsearch);
5017 if(sp != NULL){
5018 if(sp->sym != NULL){
5019 error_arch(arch, member, "more than one symbol "
5020 "for: %s found in: ", sp->name);
5021 return(FALSE);
5023 else{
5024 if(object->mh != NULL)
5025 sp->sym = &(symbols[i]);
5026 else
5027 sp->sym = &(symbols64[i]);
5028 sp->seen = TRUE;
5029 /* this remains a global defined symbol */
5030 new_nextdefsym++;
5031 new_ext_strsize += len;
5032 new_strsize += len;
5035 else{
5036 if(Aflag && n_type == (N_EXT | N_ABS) &&
5037 (n_value != 0 ||
5038 (n_strx != 0 &&
5039 strncmp(strings + n_strx,
5040 ".objc_class_name_",
5041 sizeof(".objc_class_name_") - 1) == 0))){
5042 /* this remains a global defined symbol */
5043 new_nextdefsym++;
5044 new_ext_strsize += len;
5045 new_strsize += len;
5047 else{
5048 change_symbol:
5049 if((n_type & N_TYPE) != N_INDR){
5050 nmedits[i] = TRUE;
5051 if(object->mh != NULL)
5052 changed_globals[nchanged_globals++] =
5053 symbols + i;
5054 else
5055 changed_globals64[nchanged_globals++] =
5056 symbols64 + i;
5057 if(pflag){
5058 /* this remains a global defined symbol */
5059 new_nextdefsym++;
5060 new_ext_strsize += len;
5061 new_strsize += len;
5063 else{
5064 /* this will become a non-global symbol */
5065 new_nlocalsym++;
5066 new_strsize += len;
5069 else{
5070 /* this remains a global defined symbol */
5071 new_nextdefsym++;
5072 new_ext_strsize += len;
5073 new_strsize += len;
5078 else{
5079 /* this is an undefined symbol */
5080 new_nundefsym++;
5081 new_ext_strsize += len;
5082 new_strsize += len;
5085 else{
5086 /* this is a local symbol */
5087 new_nlocalsym++;
5088 new_strsize += len;
5093 * The module table's module names are placed with the external
5094 * strings. So size them and add this to the external string size.
5096 for(i = 0; i < nmodtab; i++){
5097 if(object->mh != NULL)
5098 module_name = mods[i].module_name;
5099 else
5100 module_name = mods64[i].module_name;
5101 if(module_name == 0 || module_name > strsize){
5102 error_arch(arch, member, "bad string index for module_name "
5103 "of module table entry %d in: ", i);
5104 return(FALSE);
5106 len = strlen(strings + module_name) + 1;
5107 new_strsize += len;
5108 new_ext_strsize += len;
5112 * Warn about symbols to be saved that were missing.
5114 if(member == NULL){
5115 missing_syms = 0;
5116 if(iflag == 0){
5117 for(i = 0; i < nsave_symbols; i++){
5118 if(save_symbols[i].sym == NULL){
5119 if(missing_syms == 0){
5120 error_arch(arch, member, "symbols names listed "
5121 "in: %s not in: ", sfile);
5122 missing_syms = 1;
5124 fprintf(stderr, "%s\n", save_symbols[i].name);
5127 for(i = 0; i < nremove_symbols; i++){
5128 if(remove_symbols[i].sym == NULL){
5129 if(missing_syms == 0){
5130 error_arch(arch, member, "symbols names listed "
5131 "in: %s not in: ", Rfile);
5132 missing_syms = 1;
5134 fprintf(stderr, "%s\n", remove_symbols[i].name);
5141 * Second pass: fix stabs for the globals symbols that got turned into
5142 * non-global symbols. This is a MAJOR guess. The specific changes
5143 * to do here were determined by compiling test cases with and without
5144 * the key word 'static' and looking at the difference between the STABS
5145 * the compiler generates and trying to match that here.
5147 global_strings = strings;
5148 if(object->mh != NULL)
5149 qsort(changed_globals, nchanged_globals, sizeof(struct nlist *),
5150 (int (*)(const void *, const void *))cmp_qsort_global);
5151 else
5152 qsort(changed_globals64, nchanged_globals,sizeof(struct nlist_64 *),
5153 (int (*)(const void *, const void *))cmp_qsort_global_64);
5154 dwarf_debug_map = FALSE;
5155 for(i = 0; i < nsyms; i++){
5156 uint16_t n_desc;
5157 if(object->mh != NULL){
5158 n_strx = symbols[i].n_un.n_strx;
5159 n_type = symbols[i].n_type;
5160 n_desc = symbols[i].n_desc;
5162 else{
5163 n_strx = symbols64[i].n_un.n_strx;
5164 n_type = symbols64[i].n_type;
5165 n_desc = symbols64[i].n_desc;
5167 if(n_type == N_SO)
5168 dwarf_debug_map = FALSE;
5169 else if (n_type == N_OSO)
5170 dwarf_debug_map = n_desc != 0;
5171 else if (dwarf_debug_map && n_type == N_GSYM){
5172 global_name = strings + n_strx;
5173 if(object->mh != NULL){
5174 global_symbol = bsearch(global_name, changed_globals,
5175 nchanged_globals,sizeof(struct nlist *),
5176 (int (*)(const void *, const void *))
5177 cmp_bsearch_global);
5178 if(global_symbol != NULL){
5179 symbols[i].n_type = N_STSYM;
5180 symbols[i].n_sect = (*global_symbol)->n_sect;
5181 symbols[i].n_value = (*global_symbol)->n_value;
5184 else{
5185 global_symbol64 = bsearch(global_name, changed_globals64,
5186 nchanged_globals,
5187 sizeof(struct nlist_64 *),
5188 (int (*)(const void *, const void *))
5189 cmp_bsearch_global_64);
5190 if(global_symbol64 != NULL){
5191 symbols64[i].n_type = N_STSYM;
5192 symbols64[i].n_sect = (*global_symbol64)->n_sect;
5193 symbols64[i].n_value = (*global_symbol64)->n_value;
5197 else if(! dwarf_debug_map &&
5198 (n_type == N_GSYM || n_type == N_FUN) &&
5199 (n_strx != 0 && strings[n_strx] != '\0')){
5200 global_name = strings + n_strx;
5201 if((global_name[0] == '+' || global_name[0] == '-') &&
5202 global_name[1] == '['){
5203 j = 2;
5204 while(j + n_strx < strsize && global_name[j] != ']')
5205 j++;
5206 if(j + n_strx < strsize && global_name[j] == ']')
5207 j++;
5209 else
5210 j = 0;
5211 while(j + n_strx < strsize && global_name[j] != ':')
5212 j++;
5213 if(j + n_strx >= strsize){
5214 error_arch(arch, member, "bad N_STAB symbol name for entry "
5215 "%u (does not contain ':' separating name from type) "
5216 "in: ", i);
5217 return(FALSE);
5219 save_char = global_name[j];
5220 global_name[j] = '\0';
5222 global_symbol_found = FALSE;
5223 global_symbol_n_sect = 0;
5224 if(object->mh != NULL){
5225 global_symbol = bsearch(global_name, changed_globals,
5226 nchanged_globals,sizeof(struct nlist *),
5227 (int (*)(const void *, const void *))
5228 cmp_bsearch_global_stab);
5229 global_symbol64 = NULL;
5230 if(global_symbol != NULL){
5231 global_symbol_found = TRUE;
5232 global_symbol_n_sect = (*global_symbol)->n_sect;
5235 else{
5236 global_symbol64 = bsearch(global_name, changed_globals64,
5237 nchanged_globals,
5238 sizeof(struct nlist_64 *),
5239 (int (*)(const void *, const void *))
5240 cmp_bsearch_global_stab_64);
5241 global_symbol = NULL;
5242 if(global_symbol64 != NULL){
5243 global_symbol_found = TRUE;
5244 global_symbol_n_sect = (*global_symbol64)->n_sect;
5247 global_name[j] = save_char;
5248 if(global_symbol_found == TRUE){
5249 if(n_type == N_GSYM){
5250 if(global_symbol_n_sect == data_n_sect){
5251 if(object->mh != NULL)
5252 symbols[i].n_type = N_STSYM;
5253 else
5254 symbols64[i].n_type = N_STSYM;
5256 else{
5257 if(object->mh != NULL)
5258 symbols[i].n_type = N_FUN;
5259 else
5260 symbols64[i].n_type = N_FUN;
5262 if(object->mh != NULL){
5263 symbols[i].n_sect = (*global_symbol)->n_sect;
5264 symbols[i].n_value = (*global_symbol)->n_value;
5265 symbols[i].n_desc = (*global_symbol)->n_desc;
5267 else{
5268 symbols64[i].n_sect = (*global_symbol64)->n_sect;
5269 symbols64[i].n_value = (*global_symbol64)->n_value;
5270 symbols64[i].n_desc = (*global_symbol64)->n_desc;
5272 if(j + 1 + n_strx >= strsize ||
5273 global_name[j+1] != 'G'){
5274 error_arch(arch, member, "bad N_GSYM symbol name "
5275 "for entry %u (does not have type 'G' after "
5276 "':' in name) in: ", i);
5277 return(FALSE);
5279 global_name[j+1] = 'S';
5281 else{ /* n_type == N_FUN */
5282 if(j + 1 + n_strx >= strsize ||
5283 global_name[j+1] == 'F'){
5284 global_name[j+1] = 'f';
5290 global_strings = NULL;
5293 * Now what needs to be done is to create the new symbol table moving
5294 * those global symbols being changed into non-globals into the areas
5295 * in the symbol table for local symbols. The symbol table and string
5296 * table must be in this order:
5298 * symbol table
5299 * local symbols
5300 * external defined symbols
5301 * undefined symbols
5302 * string table
5303 * external strings
5304 * local strings
5306 if(saves != NULL)
5307 free(saves);
5308 saves = (int32_t *)allocate(nsyms * sizeof(int32_t));
5309 bzero(saves, nsyms * sizeof(int32_t));
5311 if(object->mh != NULL){
5312 new_symbols = (struct nlist *)
5313 allocate(new_nsyms * sizeof(struct nlist));
5314 new_symbols64 = NULL;
5316 else{
5317 new_symbols = NULL;
5318 new_symbols64 = (struct nlist_64 *)
5319 allocate(new_nsyms * sizeof(struct nlist_64));
5321 new_strsize = rnd(new_strsize, sizeof(int32_t));
5322 new_strings = (char *)allocate(new_strsize);
5323 new_strings[new_strsize - 3] = '\0';
5324 new_strings[new_strsize - 2] = '\0';
5325 new_strings[new_strsize - 1] = '\0';
5327 memset(new_strings, '\0', sizeof(int32_t));
5328 p = new_strings + sizeof(int32_t);
5329 q = p + new_ext_strsize;
5332 * If this is a dynamic library the movement of the symbols has to be
5333 * done with respect to the modules. As the local symbols, and external
5334 * defined symbols are grouped together for each module. Then a new
5335 * module table needs to be created with the new indexes into the symbol
5336 * table for each module.
5338 new_nmodtab = nmodtab;
5339 new_ntoc = ntoc;
5340 new_nextrefsyms = nextrefsyms;
5341 if(object->mh_filetype == MH_DYLIB && nmodtab != 0){
5342 if(object->mh != NULL){
5343 new_mods = allocate(nmodtab * sizeof(struct dylib_module));
5344 new_mods64 = NULL;
5346 else{
5347 new_mods = NULL;
5348 new_mods64 = allocate(nmodtab * sizeof(struct dylib_module_64));
5351 inew_syms = 0;
5353 * This first loop through the module table sets the index and
5354 * counts of the local symbols for each module.
5356 for(i = 0; i < nmodtab; i++){
5358 * First put the existing local symbols into the new symbol
5359 * table.
5361 if(object->mh != NULL){
5362 new_mods[i].ilocalsym = inew_syms;
5363 new_mods[i].nlocalsym = 0;
5364 ilocalsym = mods[i].ilocalsym;
5365 nlocalsym = mods[i].nlocalsym;
5367 else{
5368 new_mods64[i].ilocalsym = inew_syms;
5369 new_mods64[i].nlocalsym = 0;
5370 ilocalsym = mods64[i].ilocalsym;
5371 nlocalsym = mods64[i].nlocalsym;
5373 for(j = ilocalsym; j < ilocalsym + nlocalsym; j++){
5374 if(object->mh != NULL){
5375 n_strx = symbols[j].n_un.n_strx;
5376 n_type = symbols[j].n_type;
5378 else{
5379 n_strx = symbols64[j].n_un.n_strx;
5380 n_type = symbols64[j].n_type;
5382 if((n_type & N_EXT) == 0){
5383 if(object->mh != NULL)
5384 new_symbols[inew_syms] = symbols[j];
5385 else
5386 new_symbols64[inew_syms] = symbols64[j];
5387 if(n_strx != 0){
5388 strcpy(q, strings + n_strx);
5389 if(object->mh != NULL)
5390 new_symbols[inew_syms].n_un.n_strx =
5391 q - new_strings;
5392 else
5393 new_symbols64[inew_syms].n_un.n_strx =
5394 q - new_strings;
5395 q += strlen(q) + 1;
5397 inew_syms++;
5398 saves[j] = inew_syms;
5399 if(object->mh != NULL)
5400 new_mods[i].nlocalsym++;
5401 else
5402 new_mods64[i].nlocalsym++;
5406 * Next put the global symbols that were changed into
5407 * non-global symbols into the new symbol table and moved their
5408 * counts to the local symbol counts.
5410 if(object->mh != NULL){
5411 iextdefsym = mods[i].iextdefsym;
5412 nextdefsym = mods[i].nextdefsym;
5414 else{
5415 iextdefsym = mods64[i].iextdefsym;
5416 nextdefsym = mods64[i].nextdefsym;
5418 for(j = iextdefsym; j < iextdefsym + nextdefsym; j++){
5419 if(object->mh != NULL){
5420 n_strx = symbols[j].n_un.n_strx;
5421 n_type = symbols[j].n_type;
5423 else{
5424 n_strx = symbols64[j].n_un.n_strx;
5425 n_type = symbols64[j].n_type;
5427 if((n_type & N_EXT) != 0){
5428 if(nmedits[j] == TRUE){
5430 * Change the new symbol to a private extern symbol
5431 * with the extern bit off.
5433 if(object->mh != NULL){
5434 new_symbols[inew_syms] = symbols[j];
5435 new_symbols[inew_syms].n_type |= N_PEXT;
5436 new_symbols[inew_syms].n_type &= ~N_EXT;
5438 else{
5439 new_symbols64[inew_syms] = symbols64[j];
5440 new_symbols64[inew_syms].n_type |= N_PEXT;
5441 new_symbols64[inew_syms].n_type &= ~N_EXT;
5443 if(n_strx != 0){
5444 strcpy(q, strings + n_strx);
5445 if(object->mh != NULL)
5446 new_symbols[inew_syms].n_un.n_strx =
5447 q - new_strings;
5448 else
5449 new_symbols64[inew_syms].n_un.n_strx =
5450 q - new_strings;
5451 q += strlen(q) + 1;
5453 inew_syms++;
5454 saves[j] = inew_syms;
5455 if(object->mh != NULL)
5456 new_mods[i].nlocalsym++;
5457 else
5458 new_mods64[i].nlocalsym++;
5464 * Next put the unchanged defined global symbols into the new
5465 * symbol table.
5467 for(i = 0; i < nmodtab; i++){
5468 if(object->mh != NULL){
5469 new_mods[i].iextdefsym = inew_syms;
5470 new_mods[i].nextdefsym = 0;
5471 iextdefsym = mods[i].iextdefsym;
5472 nextdefsym = mods[i].nextdefsym;
5474 else{
5475 new_mods64[i].iextdefsym = inew_syms;
5476 new_mods64[i].nextdefsym = 0;
5477 iextdefsym = mods64[i].iextdefsym;
5478 nextdefsym = mods64[i].nextdefsym;
5480 for(j = iextdefsym; j < iextdefsym + nextdefsym; j++){
5481 if(object->mh != NULL){
5482 n_strx = symbols[j].n_un.n_strx;
5483 n_type = symbols[j].n_type;
5485 else{
5486 n_strx = symbols64[j].n_un.n_strx;
5487 n_type = symbols64[j].n_type;
5489 if((n_type & N_EXT) != 0){
5490 if(nmedits[j] == FALSE){
5491 if(object->mh != NULL)
5492 new_symbols[inew_syms] = symbols[j];
5493 else
5494 new_symbols64[inew_syms] = symbols64[j];
5495 if(n_strx != 0){
5496 strcpy(p, strings + n_strx);
5497 if(object->mh != NULL)
5498 new_symbols[inew_syms].n_un.n_strx =
5499 p - new_strings;
5500 else
5501 new_symbols64[inew_syms].n_un.n_strx =
5502 p - new_strings;
5503 p += strlen(p) + 1;
5505 inew_syms++;
5506 saves[j] = inew_syms;
5507 if(object->mh != NULL)
5508 new_mods[i].nextdefsym++;
5509 else
5510 new_mods64[i].nextdefsym++;
5516 * Last put the undefined symbols into the new symbol table.
5518 for(i = 0; i < nsyms; i++){
5519 if(object->mh != NULL){
5520 n_strx = symbols[i].n_un.n_strx;
5521 n_type = symbols[i].n_type;
5523 else{
5524 n_strx = symbols64[i].n_un.n_strx;
5525 n_type = symbols64[i].n_type;
5527 if((n_type & N_EXT) != 0 &&
5528 ((n_type & N_TYPE) == N_UNDF ||
5529 (n_type & N_TYPE) == N_PBUD)){
5530 if(object->mh != NULL)
5531 new_symbols[inew_syms] = symbols[i];
5532 else
5533 new_symbols64[inew_syms] = symbols64[i];
5534 if(n_strx != 0){
5535 strcpy(p, strings + n_strx);
5536 if(object->mh != NULL)
5537 new_symbols[inew_syms].n_un.n_strx =
5538 p - new_strings;
5539 else
5540 new_symbols64[inew_syms].n_un.n_strx =
5541 p - new_strings;
5542 p += strlen(p) + 1;
5544 inew_syms++;
5545 saves[i] = inew_syms;
5550 * Place the module table's module names with the external strings
5551 * and set the names in the new module table. And then copy the
5552 * other unchanged fields.
5554 for(i = 0; i < nmodtab; i++){
5555 if(object->mh != NULL){
5556 strcpy(p, strings + mods[i].module_name);
5557 new_mods[i].module_name = p - new_strings;
5558 p += strlen(p) + 1;
5560 new_mods[i].irefsym = mods[i].irefsym;
5561 new_mods[i].nrefsym = mods[i].nrefsym;
5562 new_mods[i].iextrel = mods[i].iextrel;
5563 new_mods[i].nextrel = mods[i].nextrel;
5564 new_mods[i].iinit_iterm = mods[i].iinit_iterm;
5565 new_mods[i].ninit_nterm = mods[i].ninit_nterm;
5566 new_mods[i].objc_module_info_addr =
5567 mods[i].objc_module_info_addr;
5568 new_mods[i].objc_module_info_size =
5569 mods[i].objc_module_info_size;
5571 else{
5572 strcpy(p, strings + mods64[i].module_name);
5573 new_mods64[i].module_name = p - new_strings;
5574 p += strlen(p) + 1;
5576 new_mods64[i].irefsym = mods64[i].irefsym;
5577 new_mods64[i].nrefsym = mods64[i].nrefsym;
5578 new_mods64[i].iextrel = mods64[i].iextrel;
5579 new_mods64[i].nextrel = mods64[i].nextrel;
5580 new_mods64[i].iinit_iterm = mods64[i].iinit_iterm;
5581 new_mods64[i].ninit_nterm = mods64[i].ninit_nterm;
5582 new_mods64[i].objc_module_info_addr =
5583 mods64[i].objc_module_info_addr;
5584 new_mods64[i].objc_module_info_size =
5585 mods64[i].objc_module_info_size;
5590 * Update the reference table with the new symbol indexes for all
5591 * entries and change type of reference (the flags field) for those
5592 * symbols that got changed from globals to non-globals.
5594 new_nextrefsyms = nextrefsyms;
5595 new_refs = allocate(new_nextrefsyms *
5596 sizeof(struct dylib_reference));
5597 j = 0;
5598 for(i = 0; i < nextrefsyms; i++){
5599 if(nmedits[refs[i].isym] == TRUE){
5600 if(refs[i].flags == REFERENCE_FLAG_DEFINED)
5601 new_refs[i].flags =
5602 REFERENCE_FLAG_PRIVATE_DEFINED;
5603 else if(refs[i].flags == REFERENCE_FLAG_UNDEFINED_NON_LAZY)
5604 new_refs[i].flags =
5605 REFERENCE_FLAG_PRIVATE_UNDEFINED_NON_LAZY;
5606 else if(refs[i].flags == REFERENCE_FLAG_UNDEFINED_LAZY)
5607 new_refs[i].flags =
5608 REFERENCE_FLAG_PRIVATE_UNDEFINED_LAZY;
5609 else
5610 new_refs[i].flags = refs[i].flags;
5612 else{
5613 new_refs[i].flags = refs[i].flags;
5615 new_refs[i].isym = saves[refs[i].isym] - 1;
5619 * Create a new dylib table of contents without the global symbols
5620 * that got turned into non-globals.
5622 new_ntoc = ntoc - nchanged_globals;
5623 new_tocs = allocate(new_ntoc *
5624 sizeof(struct dylib_table_of_contents));
5625 k = 0;
5626 for(i = 0; i < ntoc; i++){
5627 if(tocs[i].symbol_index >= nsyms){
5628 error_arch(arch, member, "bad symbol index for table of "
5629 "contents table entry %d in: ", i);
5630 return(FALSE);
5632 if(nmedits[tocs[i].symbol_index] == FALSE){
5633 new_tocs[k].symbol_index = saves[tocs[i].symbol_index] - 1;
5634 new_tocs[k].module_index = tocs[i].module_index;
5635 k++;
5640 * If is not a dynamic library so all global symbols changed into
5641 * statics can be moved to the end of the local symbols. If the pflag
5642 * is set then the changed symbols remain global and just get the
5643 * private extern bit set.
5645 else{
5647 * First put the existing local symbols into the new symbol table.
5649 inew_syms = 0;
5650 for(i = 0; i < nsyms; i++){
5651 if(object->mh != NULL){
5652 n_strx = symbols[i].n_un.n_strx;
5653 n_type = symbols[i].n_type;
5655 else{
5656 n_strx = symbols64[i].n_un.n_strx;
5657 n_type = symbols64[i].n_type;
5659 if((n_type & N_EXT) == 0){
5660 if(object->mh != NULL)
5661 new_symbols[inew_syms] = symbols[i];
5662 else
5663 new_symbols64[inew_syms] = symbols64[i];
5664 if(n_strx != 0){
5665 strcpy(q, strings + n_strx);
5666 if(object->mh != NULL)
5667 new_symbols[inew_syms].n_un.n_strx =
5668 q - new_strings;
5669 else
5670 new_symbols64[inew_syms].n_un.n_strx =
5671 q - new_strings;
5672 q += strlen(q) + 1;
5674 inew_syms++;
5675 saves[i] = inew_syms;
5679 * Next put the global symbols that were changed into statics
5680 * symbols into the new symbol table.
5682 if(pflag == FALSE){
5683 for(i = 0; i < nsyms; i++){
5684 if(object->mh != NULL){
5685 n_strx = symbols[i].n_un.n_strx;
5686 n_type = symbols[i].n_type;
5688 else{
5689 n_strx = symbols64[i].n_un.n_strx;
5690 n_type = symbols64[i].n_type;
5692 if((n_type & N_EXT) != 0){
5693 if(nmedits[i] == TRUE){
5695 * Change the new symbol to not be an extern symbol
5696 * by turning off the extern bit.
5698 if(object->mh != NULL){
5699 new_symbols[inew_syms] = symbols[i];
5700 new_symbols[inew_syms].n_type &= ~N_EXT;
5701 new_symbols[inew_syms].n_desc &= ~N_WEAK_DEF;
5703 else{
5704 new_symbols64[inew_syms] = symbols64[i];
5705 new_symbols64[inew_syms].n_type &= ~N_EXT;
5706 new_symbols64[inew_syms].n_desc &= ~N_WEAK_DEF;
5708 if(n_strx != 0){
5709 strcpy(q, strings + n_strx);
5710 if(object->mh != NULL)
5711 new_symbols[inew_syms].n_un.n_strx =
5712 q - new_strings;
5713 else
5714 new_symbols64[inew_syms].n_un.n_strx =
5715 q - new_strings;
5716 q += strlen(q) + 1;
5718 inew_syms++;
5719 saves[i] = inew_syms;
5725 * Last put the unchanged global symbols into the new symbol table
5726 * and symbols changed into private externs.
5728 for(i = 0; i < nsyms; i++){
5729 if(object->mh != NULL){
5730 n_strx = symbols[i].n_un.n_strx;
5731 n_type = symbols[i].n_type;
5733 else{
5734 n_strx = symbols64[i].n_un.n_strx;
5735 n_type = symbols64[i].n_type;
5737 if((n_type & N_EXT) != 0){
5738 if(nmedits[i] == FALSE || pflag == TRUE){
5739 if(object->mh != NULL)
5740 new_symbols[inew_syms] = symbols[i];
5741 else
5742 new_symbols64[inew_syms] = symbols64[i];
5743 if(nmedits[i] == TRUE && pflag == TRUE){
5745 * Change the new symbol to be a private extern
5746 * symbol by turning on the private extern bit.
5748 if(object->mh != NULL)
5749 new_symbols[inew_syms].n_type |= N_PEXT;
5750 else
5751 new_symbols64[inew_syms].n_type |= N_PEXT;
5753 if(n_strx != 0){
5754 strcpy(p, strings + n_strx);
5755 if(object->mh != NULL)
5756 new_symbols[inew_syms].n_un.n_strx =
5757 p - new_strings;
5758 else
5759 new_symbols64[inew_syms].n_un.n_strx =
5760 p - new_strings;
5761 p += strlen(p) + 1;
5763 inew_syms++;
5764 saves[i] = inew_syms;
5770 if(sections != NULL)
5771 free(sections);
5772 if(sections64 != NULL)
5773 free(sections64);
5775 if(errors == 0)
5776 return(TRUE);
5777 else
5778 return(FALSE);
5782 * Function for qsort for comparing global symbol names.
5784 static
5786 cmp_qsort_global(
5787 const struct nlist **sym1,
5788 const struct nlist **sym2)
5790 return(strcmp(global_strings + (*sym1)->n_un.n_strx,
5791 global_strings + (*sym2)->n_un.n_strx));
5794 static
5796 cmp_qsort_global_64(
5797 const struct nlist_64 **sym1,
5798 const struct nlist_64 **sym2)
5800 return(strcmp(global_strings + (*sym1)->n_un.n_strx,
5801 global_strings + (*sym2)->n_un.n_strx));
5805 * Function for bsearch for finding a global symbol that matches a stab name.
5807 static
5809 cmp_bsearch_global_stab(
5810 const char *name,
5811 const struct nlist **sym)
5814 * The +1 is for the '_' on the global symbol that is not on the
5815 * stab string that is trying to be matched.
5817 return(strcmp(name, global_strings + (*sym)->n_un.n_strx + 1));
5820 static
5822 cmp_bsearch_global_stab_64(
5823 const char *name,
5824 const struct nlist_64 **sym)
5827 * The +1 is for the '_' on the global symbol that is not on the
5828 * stab string that is trying to be matched.
5830 return(strcmp(name, global_strings + (*sym)->n_un.n_strx + 1));
5834 * Function for bsearch for finding a global symbol that matches a stab name
5835 * in the debug map.
5837 static
5839 cmp_bsearch_global(
5840 const char *name,
5841 const struct nlist **sym)
5843 return(strcmp(name, global_strings + (*sym)->n_un.n_strx));
5846 static
5848 cmp_bsearch_global_64(
5849 const char *name,
5850 const struct nlist_64 **sym)
5852 return(strcmp(name, global_strings + (*sym)->n_un.n_strx));
5854 #endif /* defined(NMEDIT) */