Integrate cctools-822 changes
[striptease.git] / tease.c
blob416ab4f9f4ed70e9dcf9204d86410e2476dd1750
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 /* These are set from the command line arguments */
54 __private_extern__
55 char *progname = NULL; /* name of the program for error messages (argv[0]) */
56 static char *output_file;/* name of the output file */
57 static char *sfile; /* filename of global symbol names to keep */
58 static char *Rfile; /* filename of global symbol names to remove */
59 static uint32_t Aflag; /* save only absolute symbols with non-zero value and
60 .objc_class_name_* symbols */
61 static uint32_t aflag; /* -a save all symbols, just regenerate symbol table */
62 static uint32_t iflag; /* -i ignore symbols in -s file not in object */
63 #ifdef NMEDIT
64 static uint32_t pflag; /* make all defined global symbols private extern */
65 #else /* !defined(NMEDIT) */
66 static char *dfile; /* filename of filenames of debugger symbols to keep */
67 static uint32_t uflag; /* save undefined symbols */
68 static uint32_t rflag; /* save symbols referenced dynamically */
69 static uint32_t nflag; /* save N_SECT global symbols */
70 static uint32_t Sflag; /* -S strip only debugger symbols N_STAB */
71 static uint32_t xflag; /* -x strip non-globals */
72 static uint32_t Xflag; /* -X strip local symbols with 'L' names */
73 static uint32_t tflag; /* -t strip local symbols except those in the text
74 section with names that don't begin with 'L' */
75 static uint32_t cflag; /* -c strip section contents from dynamic libraries
76 files to create stub libraries */
77 static uint32_t no_uuid;/* -no_uuid strip LC_UUID load commands */
78 static uint32_t no_code_signature;
79 /* -no_code_signature strip LC_CODE_SIGNATURE cmds */
80 static uint32_t vflag; /* -v for verbose debugging ld -r executions */
81 static uint32_t lflag; /* -l do ld -r executions even if it has bugs */
82 static uint32_t strip_all = 1;
84 * This is set on an object by object basis if the strip_all flag is still set
85 * and the object is an executable that is for use with the dynamic linker.
86 * This has the same effect as -r and -u.
88 static enum bool default_dyld_executable = FALSE;
89 #endif /* NMEDIT */
92 * Data structures to perform selective stripping of symbol table entries.
93 * save_symbols is the names of the symbols from the -s <file> argument.
94 * remove_symbols is the names of the symbols from the -R <file> argument.
96 static struct symbol_list *save_symbols = NULL;
97 static uint32_t nsave_symbols = 0;
98 static struct symbol_list *remove_symbols = NULL;
99 static uint32_t nremove_symbols = 0;
102 * saves points to an array of uint32_t's that is allocated. This array is a
103 * map of old symbol indexes to new symbol indexes. The new symbol indexes are
104 * plus 1 and zero value means that old symbol is not in the new symbol table.
105 * ref_saves is used in the same way but for the reference table.
106 * nmedits is an array and indexed by the symbol index the value indicates if
107 * the symbol was edited and turned into a non-global.
109 static int32_t *saves = NULL;
110 #ifndef NMEDIT
111 static int32_t *ref_saves = NULL;
112 #else
113 static enum bool *nmedits = NULL;
114 #endif
117 * These hold pointers to the symbol, string and indirect tables being worked on
118 * by strip_object and strip_symtab() from an input object file or possiblity
119 * changed to an ld -r (-S or -x) file by make_ld_r_object().
121 static struct nlist *symbols = NULL;
122 static struct nlist_64 *symbols64 = NULL;
123 static uint32_t nsyms = 0;
124 static char *strings = NULL;
125 static uint32_t strsize = 0;
126 static uint32_t *indirectsyms = NULL;
127 static uint32_t nindirectsyms = 0;
130 * These hold the new symbol and string table created by strip_symtab()
131 * and the new counts of local, defined external and undefined symbols.
133 static struct nlist *new_symbols = NULL;
134 static struct nlist_64 *new_symbols64 = NULL;
135 static uint32_t new_nsyms = 0;
136 static char *new_strings = NULL;
137 static uint32_t new_strsize = 0;
138 static uint32_t new_nlocalsym = 0;
139 static uint32_t new_nextdefsym = 0;
140 static uint32_t new_nundefsym = 0;
141 #if defined(TRIE_SUPPORT) && !defined(NMEDIT)
143 * The index into the new symbols where the defined external start.
145 static uint32_t inew_nextdefsym = 0;
146 #endif
149 * These hold the new table of contents, reference table and module table for
150 * dylibs.
152 static struct dylib_table_of_contents *new_tocs = NULL;
153 static uint32_t new_ntoc = 0;
154 static struct dylib_reference *new_refs = NULL;
155 static uint32_t new_nextrefsyms = 0;
156 #ifdef NMEDIT
157 static struct dylib_module *new_mods = NULL;
158 static struct dylib_module_64 *new_mods64 = NULL;
159 static uint32_t new_nmodtab = 0;
160 #endif
162 #ifndef NMEDIT
164 * The list of file names to save debugging symbols from.
166 static char **debug_filenames = NULL;
167 static uint32_t ndebug_filenames = 0;
168 struct undef_map {
169 uint32_t index;
170 struct nlist symbol;
172 struct undef_map64 {
173 uint32_t index;
174 struct nlist_64 symbol64;
176 static char *qsort_strings = NULL;
177 #endif /* !defined(NMEDIT) */
180 /* Internal routines */
181 static void usage(
182 void);
184 static void strip_file(
185 char *input_file,
186 struct arch_flag *arch_flags,
187 uint32_t narch_flags,
188 enum bool all_archs);
190 static void strip_arch(
191 struct arch *archs,
192 uint32_t narchs,
193 struct arch_flag *arch_flags,
194 uint32_t narch_flags,
195 enum bool all_archs);
197 static void strip_object(
198 struct arch *arch,
199 struct member *member,
200 struct object *object);
202 static uint32_t get_starting_syminfo_offset(
203 struct object *object);
205 static void check_object_relocs(
206 struct arch *arch,
207 struct member *member,
208 struct object *object,
209 char *segname,
210 char *sectname,
211 uint64_t sectsize,
212 char *contents,
213 struct relocation_info *relocs,
214 uint32_t nreloc,
215 struct nlist *symbols,
216 struct nlist_64 *symbols64,
217 uint32_t nsyms,
218 char *strings,
219 int32_t *missing_reloc_symbols,
220 enum byte_sex host_byte_sex);
222 static void check_indirect_symtab(
223 struct arch *arch,
224 struct member *member,
225 struct object *object,
226 uint32_t nitems,
227 uint32_t reserved1,
228 uint32_t section_type,
229 char *contents,
230 struct nlist *symbols,
231 struct nlist_64 *symbols64,
232 uint32_t nsyms,
233 char *strings,
234 int32_t *missing_reloc_symbols,
235 enum byte_sex host_byte_sex);
237 #ifndef NMEDIT
238 static enum bool strip_symtab(
239 struct arch *arch,
240 struct member *member,
241 struct object *object,
242 struct dylib_table_of_contents *tocs,
243 uint32_t ntoc,
244 struct dylib_module *mods,
245 struct dylib_module_64 *mods64,
246 uint32_t nmodtab,
247 struct dylib_reference *refs,
248 uint32_t nextrefsyms);
250 #ifdef TRIE_SUPPORT
251 static int prune(
252 const char *name);
253 #endif /* TRIE_SUPPORT */
255 static void make_ld_r_object(
256 struct arch *arch,
257 struct member *member,
258 struct object *object);
260 static void strip_LC_UUID_commands(
261 struct arch *arch,
262 struct member *member,
263 struct object *object);
265 #ifndef NMEDIT
266 static void strip_LC_CODE_SIGNATURE_commands(
267 struct arch *arch,
268 struct member *member,
269 struct object *object);
270 #endif /* !(NMEDIT) */
272 static enum bool private_extern_reference_by_module(
273 uint32_t symbol_index,
274 struct dylib_reference *refs,
275 uint32_t nextrefsyms);
277 static enum bool symbol_pointer_used(
278 uint32_t symbol_index,
279 uint32_t *indirectsyms,
280 uint32_t nindirectsyms);
282 static int cmp_qsort_undef_map(
283 const struct undef_map *sym1,
284 const struct undef_map *sym2);
286 static int cmp_qsort_undef_map_64(
287 const struct undef_map64 *sym1,
288 const struct undef_map64 *sym2);
289 #endif /* !defined(NMEDIT) */
291 #ifdef NMEDIT
292 static enum bool edit_symtab(
293 struct arch *arch,
294 struct member *member,
295 struct object *object,
296 struct nlist *symbols,
297 struct nlist_64 *symbols64,
298 uint32_t nsyms,
299 char *strings,
300 uint32_t strsize,
301 struct dylib_table_of_contents *tocs,
302 uint32_t ntoc,
303 struct dylib_module *mods,
304 struct dylib_module_64 *mods64,
305 uint32_t nmodtab,
306 struct dylib_reference *refs,
307 uint32_t nextrefsyms);
308 #endif /* NMEDIT */
310 #ifndef NMEDIT
311 static void setup_debug_filenames(
312 char *dfile);
314 static int cmp_qsort_filename(
315 const char **name1,
316 const char **name2);
318 static int cmp_bsearch_filename(
319 const char *name1,
320 const char **name2);
321 #endif /* NMEDIT */
323 #ifdef NMEDIT
325 * This variable and routines are used for nmedit(1) only.
327 static char *global_strings = NULL;
329 static int cmp_qsort_global(
330 const struct nlist **sym1,
331 const struct nlist **sym2);
333 static int cmp_qsort_global_64(
334 const struct nlist_64 **sym1,
335 const struct nlist_64 **sym2);
337 static int cmp_bsearch_global_stab(
338 const char *name,
339 const struct nlist **sym);
341 static int cmp_bsearch_global_stab_64(
342 const char *name,
343 const struct nlist_64 **sym);
345 static int cmp_bsearch_global(
346 const char *name,
347 const struct nlist **sym);
349 static int cmp_bsearch_global_64(
350 const char *name,
351 const struct nlist_64 **sym);
352 #endif /* NMEDIT */
354 /* apple_version is created by the libstuff/Makefile */
355 extern char apple_version[];
356 char *version = apple_version;
359 main(
360 int argc,
361 char *argv[],
362 char *envp[])
364 int i;
365 uint32_t j, args_left, files_specified;
366 struct arch_flag *arch_flags;
367 uint32_t narch_flags;
368 enum bool all_archs;
369 struct symbol_list *sp;
371 progname = argv[0];
373 arch_flags = NULL;
374 narch_flags = 0;
375 all_archs = FALSE;
377 files_specified = 0;
378 args_left = 1;
379 for (i = 1; i < argc; i++){
380 if(argv[i][0] == '-'){
381 if(argv[i][1] == '\0'){
382 args_left = 0;
383 break;
385 if(strcmp(argv[i], "-o") == 0){
386 if(i + 1 >= argc)
387 fatal("-o requires an argument");
388 if(output_file != NULL)
389 fatal("only one -o option allowed");
390 output_file = argv[i + 1];
391 i++;
393 else if(strcmp(argv[i], "-s") == 0){
394 if(i + 1 >= argc)
395 fatal("-s requires an argument");
396 if(sfile != NULL)
397 fatal("only one -s option allowed");
398 sfile = argv[i + 1];
399 i++;
401 else if(strcmp(argv[i], "-R") == 0){
402 if(i + 1 >= argc)
403 fatal("-R requires an argument");
404 if(Rfile != NULL)
405 fatal("only one -R option allowed");
406 Rfile = argv[i + 1];
407 i++;
409 #ifndef NMEDIT
410 else if(strcmp(argv[i], "-d") == 0){
411 if(i + 1 >= argc)
412 fatal("-d requires an argument");
413 if(dfile != NULL)
414 fatal("only one -d option allowed");
415 dfile = argv[i + 1];
416 i++;
418 else if(strcmp(argv[i], "-no_uuid") == 0){
419 no_uuid = 1;
421 else if(strcmp(argv[i], "-no_code_signature") == 0){
422 no_code_signature = 1;
424 #endif /* !defined(NMEDIT) */
425 else if(strcmp(argv[i], "-arch") == 0){
426 if(i + 1 == argc){
427 error("missing argument(s) to %s option", argv[i]);
428 usage();
430 if(strcmp("all", argv[i+1]) == 0){
431 all_archs = TRUE;
433 else{
434 arch_flags = reallocate(arch_flags,
435 (narch_flags + 1) * sizeof(struct arch_flag));
436 if(get_arch_from_flag(argv[i+1],
437 arch_flags + narch_flags) == 0){
438 error("unknown architecture specification flag: "
439 "%s %s", argv[i], argv[i+1]);
440 arch_usage();
441 usage();
443 for(j = 0; j < narch_flags; j++){
444 if(arch_flags[j].cputype ==
445 arch_flags[narch_flags].cputype &&
446 (arch_flags[j].cpusubtype & ~CPU_SUBTYPE_MASK) ==
447 (arch_flags[narch_flags].cpusubtype &
448 ~CPU_SUBTYPE_MASK) &&
449 strcmp(arch_flags[j].name,
450 arch_flags[narch_flags].name) == 0)
451 break;
453 if(j == narch_flags)
454 narch_flags++;
456 i++;
458 else{
459 for(j = 1; argv[i][j] != '\0'; j++){
460 switch(argv[i][j]){
461 #ifdef NMEDIT
462 case 'p':
463 pflag = 1;
464 break;
465 #else /* !defined(NMEDIT) */
466 case 'S':
467 Sflag = 1;
468 strip_all = 0;
469 break;
470 case 'X':
471 Xflag = 1;
472 strip_all = 0;
473 break;
474 case 'x':
475 xflag = 1;
476 strip_all = 0;
477 break;
478 case 't':
479 tflag = 1;
480 strip_all = 0;
481 break;
482 case 'i':
483 iflag = 1;
484 break;
485 case 'u':
486 uflag = 1;
487 strip_all = 0;
488 break;
489 case 'r':
490 rflag = 1;
491 strip_all = 0;
492 break;
493 case 'n':
494 nflag = 1;
495 strip_all = 0;
496 break;
497 #endif /* !defined(NMEDIT) */
498 case 'A':
499 Aflag = 1;
500 #ifndef NMEDIT
501 strip_all = 0;
502 #endif /* !defined(NMEDIT) */
503 break;
504 #ifndef NMEDIT
505 case 'a':
506 aflag = 1;
507 strip_all = 0;
508 break;
509 case 'c':
510 cflag = 1;
511 strip_all = 0;
512 break;
513 case 'v':
514 vflag = 1;
515 break;
516 case 'l':
517 lflag = 1;
518 break;
519 #endif /* NMEDIT */
520 default:
521 error("unrecognized option: %s", argv[i]);
522 usage();
527 else
528 files_specified++;
530 if(args_left == 0)
531 files_specified += argc - (i + 1);
533 if(files_specified > 1 && output_file != NULL){
534 error("-o <filename> can only be used when one file is specified");
535 usage();
538 if(sfile){
539 setup_symbol_list(sfile, &save_symbols, &nsave_symbols);
541 #ifdef NMEDIT
542 else{
543 if(Rfile == NULL && pflag == 0){
544 error("-s <filename>, -R <filename> or -p argument required");
545 usage();
548 #endif /* NMEDIT */
550 if(Rfile){
551 setup_symbol_list(Rfile, &remove_symbols, &nremove_symbols);
552 if(sfile){
553 for(j = 0; j < nremove_symbols ; j++){
554 sp = bsearch(remove_symbols[j].name,
555 save_symbols, nsave_symbols,
556 sizeof(struct symbol_list),
557 (int (*)(const void *, const void *))
558 symbol_list_bsearch);
559 if(sp != NULL){
560 error("symbol name: %s is listed in both -s %s and -R "
561 "%s files (can't be both saved and removed)",
562 remove_symbols[j].name, sfile, Rfile);
565 if(errors)
566 exit(EXIT_FAILURE);
570 /* the default when no -arch flags is present is to strip all archs */
571 if(narch_flags == 0)
572 all_archs = TRUE;
574 #ifndef NMEDIT
575 if(dfile){
576 setup_debug_filenames(dfile);
578 #endif /* !defined(NMEDIT) */
580 files_specified = 0;
581 args_left = 1;
582 for (i = 1; i < argc; i++) {
583 if(args_left && argv[i][0] == '-'){
584 if(argv[i][1] == '\0')
585 args_left = 0;
586 else if(strcmp(argv[i], "-o") == 0 ||
587 strcmp(argv[i], "-s") == 0 ||
588 strcmp(argv[i], "-R") == 0 ||
589 #ifndef NMEDIT
590 strcmp(argv[i], "-d") == 0 ||
591 #endif /* !defined(NMEDIT) */
592 strcmp(argv[i], "-arch") == 0)
593 i++;
595 else{
596 char resolved_path[PATH_MAX + 1];
598 if(realpath(argv[i], resolved_path) == NULL)
599 strip_file(argv[i], arch_flags, narch_flags, all_archs);
600 else
601 strip_file(resolved_path, arch_flags,narch_flags,all_archs);
602 files_specified++;
605 if(files_specified == 0)
606 fatal("no files specified");
608 if(errors)
609 return(EXIT_FAILURE);
610 else
611 return(EXIT_SUCCESS);
614 static
615 void
616 usage(
617 void)
619 #ifndef NMEDIT
620 fprintf(stderr, "Usage: %s [-AanuStXx] [-no_uuid] [-no_code_signature] "
621 "[-] [-d filename] [-s filename] [-R filename] [-o output] "
622 "file [...]\n", progname);
623 #else /* defined(NMEDIT) */
624 fprintf(stderr, "Usage: %s -s filename [-R filename] [-p] [-A] [-] "
625 "[-o output] file [...] \n",
626 progname);
627 #endif /* NMEDIT */
628 exit(EXIT_FAILURE);
631 static
632 void
633 strip_file(
634 char *input_file,
635 struct arch_flag *arch_flags,
636 uint32_t narch_flags,
637 enum bool all_archs)
639 struct ofile *ofile;
640 struct arch *archs;
641 uint32_t narchs;
642 struct stat stat_buf;
643 uint32_t previous_errors;
644 enum bool unix_standard_mode;
645 int cwd_fd;
646 char *rename_file;
647 #ifndef NMEDIT
648 char *p;
649 #endif
651 archs = NULL;
652 narchs = 0;
653 previous_errors = errors;
654 errors = 0;
656 /* breakout the file for processing */
657 ofile = breakout(input_file, &archs, &narchs, FALSE);
658 if(errors)
659 return;
661 /* checkout the file for symbol table replacement processing */
662 checkout(archs, narchs);
664 /* process the symbols in the input file */
665 strip_arch(archs, narchs, arch_flags, narch_flags, all_archs);
666 if(errors){
667 free_archs(archs, narchs);
668 ofile_unmap(ofile);
669 return;
672 /* create the output file */
673 if(stat(input_file, &stat_buf) == -1)
674 system_error("can't stat input file: %s", input_file);
675 if(output_file != NULL){
676 writeout(archs, narchs, output_file, stat_buf.st_mode & 0777,
677 TRUE, FALSE, FALSE, NULL);
679 else{
680 unix_standard_mode = get_unix_standard_mode();
681 rename_file = NULL;
682 cwd_fd = -1;
683 #ifdef NMEDIT
684 output_file = makestr(input_file, ".nmedit", NULL);
685 #else /* !defined(NMEDIT) */
687 * In UNIX standard conformance mode we are not allowed to replace
688 * a file that is not writeable.
690 if(unix_standard_mode == TRUE &&
691 access(input_file, W_OK) == -1){
692 system_error("file: %s is not writable", input_file);
693 goto strip_file_return;
695 output_file = makestr(input_file, ".strip", NULL);
698 * The UNIX standard conformance test suite expects files of
699 * MAXPATHLEN to work.
701 if(strlen(output_file) >= MAXPATHLEN){
703 * If there is a directory path in the name try to change
704 * the current working directory to that path.
706 if((p = rindex(output_file, '/')) != NULL){
707 if((cwd_fd = open(".", O_RDONLY, 0)) == -1){
708 system_error("can't open current working directory");
709 goto strip_file_return;
711 *p = '\0';
712 if(chdir(output_file) == -1){
713 system_error("can't change current working directory "
714 "to: %s", output_file);
715 goto strip_file_return;
717 p = rindex(input_file, '/');
718 rename_file = makestr(p + 1, NULL);
721 * Create what might be a short enough name.
723 free(output_file);
724 output_file = makestr("strip.XXXXXX", NULL);
725 output_file = mktemp(output_file);
727 #endif /* NMEDIT */
728 writeout(archs, narchs, output_file, stat_buf.st_mode & 0777,
729 TRUE, FALSE, FALSE, NULL);
730 if(rename_file != NULL){
731 if(rename(output_file, rename_file) == -1)
732 system_error("can't move temporary file: %s to file: %s",
733 output_file, rename_file);
734 free(rename_file);
736 else{
737 if(rename(output_file, input_file) == -1)
738 system_error("can't move temporary file: %s to input "
739 "file: %s", output_file, input_file);
741 free(output_file);
742 output_file = NULL;
745 * If we changed the current working directory change back to
746 * the previous working directory.
748 if(cwd_fd != -1){
749 if(fchdir(cwd_fd) == -1)
750 system_error("can't change back to previous working "
751 "directory");
752 if(close(cwd_fd) == -1)
753 system_error("can't close previous working directory");
757 #ifndef NMEDIT
758 strip_file_return:
759 #endif /* !defined(NMEDIT) */
760 /* clean-up data structures */
761 free_archs(archs, narchs);
762 ofile_unmap(ofile);
764 errors += previous_errors;
767 static
768 void
769 strip_arch(
770 struct arch *archs,
771 uint32_t narchs,
772 struct arch_flag *arch_flags,
773 uint32_t narch_flags,
774 enum bool all_archs)
776 uint32_t i, j, k, offset, size, missing_syms;
777 cpu_type_t cputype;
778 cpu_subtype_t cpusubtype;
779 struct arch_flag host_arch_flag;
780 enum bool arch_process, any_processing, *arch_flag_processed, family;
781 const struct arch_flag *family_arch_flag;
784 * Using the specified arch_flags process specified objects for those
785 * architecures.
787 any_processing = FALSE;
788 arch_flag_processed = NULL;
789 if(narch_flags != 0)
790 arch_flag_processed = allocate(narch_flags * sizeof(enum bool));
791 memset(arch_flag_processed, '\0', narch_flags * sizeof(enum bool));
792 for(i = 0; i < narchs; i++){
794 * Determine the architecture (cputype and cpusubtype) of arch[i]
796 cputype = 0;
797 cpusubtype = 0;
798 if(archs[i].type == OFILE_ARCHIVE){
799 for(j = 0; j < archs[i].nmembers; j++){
800 if(archs[i].members[j].type == OFILE_Mach_O){
801 cputype = archs[i].members[j].object->mh_cputype;
802 cpusubtype = archs[i].members[j].object->mh_cpusubtype;
803 break;
807 else if(archs[i].type == OFILE_Mach_O){
808 cputype = archs[i].object->mh_cputype;
809 cpusubtype = archs[i].object->mh_cpusubtype;
811 else if(archs[i].fat_arch != NULL){
812 cputype = archs[i].fat_arch->cputype;
813 cpusubtype = archs[i].fat_arch->cpusubtype;
815 arch_process = FALSE;
816 if(all_archs == TRUE){
817 arch_process = TRUE;
819 else if(narch_flags != 0){
820 family = FALSE;
821 if(narch_flags == 1){
822 family_arch_flag =
823 get_arch_family_from_cputype(arch_flags[0].cputype);
824 if(family_arch_flag != NULL)
825 family = (enum bool)
826 ((family_arch_flag->cpusubtype & ~CPU_SUBTYPE_MASK) ==
827 (arch_flags[0].cpusubtype & ~CPU_SUBTYPE_MASK));
829 for(j = 0; j < narch_flags; j++){
830 if(arch_flags[j].cputype == cputype &&
831 ((arch_flags[j].cpusubtype & ~CPU_SUBTYPE_MASK) ==
832 (cpusubtype & ~CPU_SUBTYPE_MASK) ||
833 family == TRUE)){
834 arch_process = TRUE;
835 arch_flag_processed[j] = TRUE;
836 break;
840 else{
841 (void)get_arch_from_host(&host_arch_flag, NULL);
842 if(host_arch_flag.cputype == cputype &&
843 (host_arch_flag.cpusubtype & ~CPU_SUBTYPE_MASK) ==
844 (cpusubtype & ~CPU_SUBTYPE_MASK))
845 arch_process = TRUE;
847 if(narchs != 1 && arch_process == FALSE)
848 continue;
849 any_processing = TRUE;
852 * Now this arch[i] has been selected to be processed so process it
853 * according to its type.
855 if(archs[i].type == OFILE_ARCHIVE){
856 for(j = 0; j < archs[i].nmembers; j++){
857 if(archs[i].members[j].type == OFILE_Mach_O){
858 strip_object(archs + i, archs[i].members + j,
859 archs[i].members[j].object);
862 missing_syms = 0;
863 if(iflag == 0){
864 for(k = 0; k < nsave_symbols; k++){
865 if(save_symbols[k].seen == FALSE){
866 if(missing_syms == 0){
867 error_arch(archs + i, NULL, "symbols names "
868 "listed in: %s not in: ", sfile);
869 missing_syms = 1;
871 fprintf(stderr, "%s\n", save_symbols[k].name);
875 for(k = 0; k < nsave_symbols; k++){
876 save_symbols[k].seen = FALSE;
878 missing_syms = 0;
879 if(iflag == 0){
880 for(k = 0; k < nremove_symbols; k++){
881 if(remove_symbols[k].seen == FALSE){
882 if(missing_syms == 0){
883 error_arch(archs + i, NULL, "symbols names "
884 "listed in: %s not defined in: ",
885 Rfile);
886 missing_syms = 1;
888 fprintf(stderr, "%s\n", remove_symbols[k].name);
892 for(k = 0; k < nremove_symbols; k++){
893 remove_symbols[k].seen = FALSE;
896 * Reset the library offsets and size.
898 offset = 0;
899 for(j = 0; j < archs[i].nmembers; j++){
900 archs[i].members[j].offset = offset;
901 size = 0;
902 if(archs[i].members[j].member_long_name == TRUE){
903 size = rnd(archs[i].members[j].member_name_size, 8) +
904 (rnd(sizeof(struct ar_hdr), 8) -
905 sizeof(struct ar_hdr));
906 archs[i].toc_long_name = TRUE;
908 if(archs[i].members[j].object != NULL){
909 size +=
910 rnd(archs[i].members[j].object->object_size -
911 archs[i].members[j].object->input_sym_info_size +
912 archs[i].members[j].object->output_sym_info_size,
914 sprintf(archs[i].members[j].ar_hdr->ar_size, "%-*ld",
915 (int)sizeof(archs[i].members[j].ar_hdr->ar_size),
916 (long)(size));
918 * This has to be done by hand because sprintf puts a
919 * null at the end of the buffer.
921 memcpy(archs[i].members[j].ar_hdr->ar_fmag, ARFMAG,
922 (int)sizeof(archs[i].members[j].ar_hdr->ar_fmag));
924 else{
925 size += archs[i].members[j].unknown_size;
927 offset += sizeof(struct ar_hdr) + size;
929 archs[i].library_size = offset;
931 else if(archs[i].type == OFILE_Mach_O){
932 strip_object(archs + i, NULL, archs[i].object);
934 else {
935 warning_arch(archs + i, NULL, "can't process non-object and "
936 "non-archive file: ");
937 return;
940 if(all_archs == FALSE && narch_flags != 0){
941 for(i = 0; i < narch_flags; i++){
942 if(arch_flag_processed[i] == FALSE)
943 error("file: %s does not contain architecture: %s",
944 archs[0].file_name, arch_flags[i].name);
946 free(arch_flag_processed);
948 if(any_processing == FALSE)
949 fatal("no processing done on input file: %s (specify a -arch flag)",
950 archs[0].file_name);
953 static
954 void
955 strip_object(
956 struct arch *arch,
957 struct member *member,
958 struct object *object)
960 enum byte_sex host_byte_sex;
961 uint32_t offset;
962 struct dylib_table_of_contents *tocs;
963 uint32_t ntoc;
964 struct dylib_module *mods;
965 struct dylib_module_64 *mods64;
966 uint32_t nmodtab;
967 struct dylib_reference *refs;
968 uint32_t nextrefsyms;
969 uint32_t i, j;
970 struct load_command *lc;
971 struct segment_command *sg;
972 struct segment_command_64 *sg64;
973 struct section *s;
974 struct section_64 *s64;
975 struct relocation_info *relocs;
976 struct scattered_relocation_info *sreloc;
977 int32_t missing_reloc_symbols;
978 uint32_t stride, section_type, nitems;
979 char *contents;
980 uint32_t dyld_info_start;
981 uint32_t dyld_info_end;
982 #ifndef NMEDIT
983 uint32_t flags;
984 uint32_t k;
985 #endif
986 uint32_t ncmds;
988 host_byte_sex = get_host_byte_sex();
990 /* Don't do anything to stub dylibs which have no load commands. */
991 if(object->mh_filetype == MH_DYLIB_STUB){
992 if((object->mh != NULL && object->mh->ncmds == 0) ||
993 (object->mh64 != NULL && object->mh64->ncmds == 0)){
994 return;
997 if(object->mh_filetype == MH_DSYM)
998 fatal_arch(arch, member, "can't process dSYM companion file: ");
999 if(object->st == NULL || object->st->nsyms == 0){
1000 warning_arch(arch, member, "input object file stripped: ");
1001 return;
1004 nsyms = object->st->nsyms;
1005 if(object->mh != NULL){
1006 symbols = (struct nlist *)
1007 (object->object_addr + object->st->symoff);
1008 if(object->object_byte_sex != host_byte_sex)
1009 swap_nlist(symbols, nsyms, host_byte_sex);
1010 symbols64 = NULL;
1012 else{
1013 symbols = NULL;
1014 symbols64 = (struct nlist_64 *)
1015 (object->object_addr + object->st->symoff);
1016 if(object->object_byte_sex != host_byte_sex)
1017 swap_nlist_64(symbols64, nsyms, host_byte_sex);
1019 strings = object->object_addr + object->st->stroff;
1020 strsize = object->st->strsize;
1022 #ifndef NMEDIT
1023 if(object->mh != NULL)
1024 flags = object->mh->flags;
1025 else
1026 flags = object->mh64->flags;
1027 if(object->mh_filetype == MH_DYLIB &&
1028 (flags & MH_PREBOUND) != MH_PREBOUND){
1029 arch->dont_update_LC_ID_DYLIB_timestamp = TRUE;
1031 if(object->mh_filetype != MH_DYLIB && cflag)
1032 fatal_arch(arch, member, "-c can't be used on non-dynamic "
1033 "library: ");
1034 #endif /* !(NMEDIT) */
1035 if(object->mh_filetype == MH_DYLIB_STUB)
1036 fatal_arch(arch, member, "dynamic stub library can't be changed "
1037 "once created: ");
1039 if(object->mh_filetype == MH_DYLIB){
1040 tocs = (struct dylib_table_of_contents *)
1041 (object->object_addr + object->dyst->tocoff);
1042 ntoc = object->dyst->ntoc;
1043 nmodtab = object->dyst->nmodtab;
1044 if(object->mh != NULL){
1045 mods = (struct dylib_module *)
1046 (object->object_addr + object->dyst->modtaboff);
1047 if(object->object_byte_sex != host_byte_sex)
1048 swap_dylib_module(mods, nmodtab, host_byte_sex);
1049 mods64 = NULL;
1051 else{
1052 mods = NULL;
1053 mods64 = (struct dylib_module_64 *)
1054 (object->object_addr + object->dyst->modtaboff);
1055 if(object->object_byte_sex != host_byte_sex)
1056 swap_dylib_module_64(mods64, nmodtab, host_byte_sex);
1058 refs = (struct dylib_reference *)
1059 (object->object_addr + object->dyst->extrefsymoff);
1060 nextrefsyms = object->dyst->nextrefsyms;
1061 if(object->object_byte_sex != host_byte_sex){
1062 swap_dylib_table_of_contents(tocs, ntoc, host_byte_sex);
1063 swap_dylib_reference(refs, nextrefsyms, host_byte_sex);
1065 #ifndef NMEDIT
1067 * In the -c flag is specified then strip the section contents of
1068 * this dynamic library and change it into a stub library. When
1069 * creating a stub library the timestamp is not changed.
1071 if(cflag){
1072 arch->dont_update_LC_ID_DYLIB_timestamp = TRUE;
1074 lc = object->load_commands;
1075 if(object->mh != NULL){
1076 ncmds = object->mh->ncmds;
1077 object->mh_filetype = MH_DYLIB_STUB;
1078 object->mh->filetype = MH_DYLIB_STUB;
1080 else{
1081 ncmds = object->mh64->ncmds;
1082 object->mh_filetype = MH_DYLIB_STUB;
1083 object->mh64->filetype = MH_DYLIB_STUB;
1085 for(i = 0; i < ncmds; i++){
1086 if(lc->cmd == LC_SEGMENT){
1087 sg = (struct segment_command *)lc;
1088 if(strcmp(sg->segname, SEG_LINKEDIT) != 0){
1090 * Zero out the section offset, reloff, and size
1091 * fields as the section contents are being removed.
1093 s = (struct section *)
1094 ((char *)sg + sizeof(struct segment_command));
1095 for(j = 0; j < sg->nsects; j++){
1097 * For section types with indirect tables we
1098 * do not zero out the section size in a stub
1099 * library. As the section size is needed to
1100 * know now many indirect table entries the
1101 * section has. This is a bit odd but programs
1102 * dealing with MH_DYLIB_STUB filetypes special
1103 * case this.
1105 section_type = s[j].flags & SECTION_TYPE;
1106 if(section_type != S_SYMBOL_STUBS &&
1107 section_type != S_LAZY_SYMBOL_POINTERS &&
1108 section_type != S_LAZY_DYLIB_SYMBOL_POINTERS &&
1109 section_type != S_NON_LAZY_SYMBOL_POINTERS){
1110 s[j].size = 0;
1112 s[j].addr = 0;
1113 s[j].offset = 0;
1114 s[j].reloff = 0;
1116 /* zero out file offset and size in the segment */
1117 sg->fileoff = 0;
1118 sg->filesize = 0;
1121 else if(lc->cmd == LC_SEGMENT_64){
1122 sg64 = (struct segment_command_64 *)lc;
1123 if(strcmp(sg64->segname, SEG_LINKEDIT) != 0){
1125 * Zero out the section offset, reloff, and size
1126 * fields as the section contents are being removed.
1128 s64 = (struct section_64 *)
1129 ((char *)sg64 +
1130 sizeof(struct segment_command_64));
1131 for(j = 0; j < sg64->nsects; j++){
1133 * For section types with indirect tables we
1134 * do not zero out the section size in a stub
1135 * library. As the section size is needed to
1136 * know now many indirect table entries the
1137 * section has. This is a bit odd but programs
1138 * dealing with MH_DYLIB_STUB filetypes special
1139 * case this.
1141 section_type = s64[j].flags & SECTION_TYPE;
1142 if(section_type != S_SYMBOL_STUBS &&
1143 section_type != S_LAZY_SYMBOL_POINTERS &&
1144 section_type != S_LAZY_DYLIB_SYMBOL_POINTERS &&
1145 section_type != S_NON_LAZY_SYMBOL_POINTERS){
1146 s64[j].size = 0;
1148 s64[j].addr = 0;
1149 s64[j].offset = 0;
1150 s64[j].reloff = 0;
1152 /* zero out file offset and size in the segment */
1153 sg64->fileoff = 0;
1154 sg64->filesize = 0;
1157 lc = (struct load_command *)((char *)lc + lc->cmdsize);
1160 * To get the right amount of the file copied out by writeout()
1161 * for the case when we are stripping out the section contents
1162 * we reduce the object size by the size of the section contents
1163 * including the padding after the load commands. Then this
1164 * size minus the size of the input symbolic information is
1165 * copied out.
1167 if(object->mh != NULL){
1168 object->object_size -= (object->seg_linkedit->fileoff -
1169 (sizeof(struct mach_header) +
1170 object->mh->sizeofcmds));
1172 * Set the file offset to the link edit information to be
1173 * right after the load commands.
1175 object->seg_linkedit->fileoff =
1176 sizeof(struct mach_header) +
1177 object->mh->sizeofcmds;
1179 else{
1180 object->object_size -= (object->seg_linkedit64->fileoff -
1181 (sizeof(struct mach_header_64) +
1182 object->mh64->sizeofcmds));
1184 * Set the file offset to the link edit information to be
1185 * right after the load commands.
1187 object->seg_linkedit64->fileoff =
1188 sizeof(struct mach_header_64) +
1189 object->mh64->sizeofcmds;
1192 #endif /* !(NMEDIT) */
1194 else{
1195 tocs = NULL;
1196 ntoc = 0;
1197 mods = NULL;
1198 mods64 = NULL;
1199 nmodtab = 0;
1200 refs = NULL;
1201 nextrefsyms = 0;
1205 * coalesced symbols can be stripped only if they are not used via an
1206 * symbol pointer. So to know that strip_symtab() needs to be passed
1207 * the indirect symbol table.
1209 if(object->dyst != NULL && object->dyst->nindirectsyms != 0){
1210 nindirectsyms = object->dyst->nindirectsyms;
1211 indirectsyms = (uint32_t *)
1212 (object->object_addr + object->dyst->indirectsymoff);
1213 if(object->object_byte_sex != host_byte_sex)
1214 swap_indirect_symbols(indirectsyms, nindirectsyms,
1215 host_byte_sex);
1217 else{
1218 indirectsyms = NULL;
1219 nindirectsyms = 0;
1222 if(object->mh != NULL)
1223 object->input_sym_info_size =
1224 nsyms * sizeof(struct nlist) +
1225 strsize;
1226 else
1227 object->input_sym_info_size =
1228 nsyms * sizeof(struct nlist_64) +
1229 strsize;
1230 #ifndef NMEDIT
1231 if(object->mh != NULL)
1232 flags = object->mh->flags;
1233 else
1234 flags = object->mh64->flags;
1235 if(strip_all &&
1236 (flags & MH_DYLDLINK) == MH_DYLDLINK &&
1237 object->mh_filetype == MH_EXECUTE)
1238 default_dyld_executable = TRUE;
1239 else
1240 default_dyld_executable = FALSE;
1241 #endif /* !defined(NMEDIT) */
1243 #ifndef NMEDIT
1244 if(sfile != NULL || Rfile != NULL || dfile != NULL || Aflag || aflag ||
1245 uflag || Sflag || xflag || Xflag || tflag || nflag || rflag ||
1246 default_dyld_executable || object->mh_filetype == MH_DYLIB ||
1247 object->mh_filetype == MH_DYLINKER)
1248 #endif /* !defined(NMEDIT) */
1250 #ifdef NMEDIT
1251 if(edit_symtab(arch, member, object, symbols, symbols64, nsyms,
1252 strings, strsize, tocs, ntoc, mods, mods64, nmodtab, refs,
1253 nextrefsyms) == FALSE)
1254 return;
1255 #else /* !defined(NMEDIT) */
1256 if(strip_symtab(arch, member, object, tocs, ntoc, mods, mods64,
1257 nmodtab, refs, nextrefsyms) == FALSE)
1258 return;
1259 if(no_uuid == TRUE)
1260 strip_LC_UUID_commands(arch, member, object);
1261 #endif /* !defined(NMEDIT) */
1263 * The parts that make up output_sym_info_size must be added up in
1264 * the output order so that when the sizes of things are rounded up
1265 * before parts that must be aligned the final output_sym_info_size
1266 * is correct.
1268 * Also the parts that make up input_sym_info_size must be added up
1269 * in the same way. And must be done here as the input file may
1270 * have been changed to and "ld -r" file and may not be the
1271 * the original input file.
1273 object->output_sym_info_size = 0;
1274 object->input_sym_info_size = 0;
1275 if(object->dyld_info != NULL){
1276 /* there are five parts to the dyld info, but
1277 strip does not alter them, so copy as a block */
1278 dyld_info_start = 0;
1279 if (object->dyld_info->rebase_off != 0)
1280 dyld_info_start = object->dyld_info->rebase_off;
1281 else if (object->dyld_info->bind_off != 0)
1282 dyld_info_start = object->dyld_info->bind_off;
1283 else if (object->dyld_info->weak_bind_off != 0)
1284 dyld_info_start = object->dyld_info->weak_bind_off;
1285 else if (object->dyld_info->lazy_bind_off != 0)
1286 dyld_info_start = object->dyld_info->lazy_bind_off;
1287 else if (object->dyld_info->export_off != 0)
1288 dyld_info_start = object->dyld_info->export_off;
1289 dyld_info_end = 0;
1290 if (object->dyld_info->export_size != 0)
1291 dyld_info_end = object->dyld_info->export_off
1292 + object->dyld_info->export_size;
1293 else if (object->dyld_info->lazy_bind_size != 0)
1294 dyld_info_end = object->dyld_info->lazy_bind_off
1295 + object->dyld_info->lazy_bind_size;
1296 else if (object->dyld_info->weak_bind_size != 0)
1297 dyld_info_end = object->dyld_info->weak_bind_off
1298 + object->dyld_info->weak_bind_size;
1299 else if (object->dyld_info->bind_size != 0)
1300 dyld_info_end = object->dyld_info->bind_off
1301 + object->dyld_info->bind_size;
1302 else if (object->dyld_info->rebase_size != 0)
1303 dyld_info_end = object->dyld_info->rebase_off
1304 + object->dyld_info->rebase_size;
1305 object->output_dyld_info = object->object_addr +dyld_info_start;
1306 object->output_dyld_info_size = dyld_info_end - dyld_info_start;
1307 object->output_sym_info_size += object->output_dyld_info_size;
1309 * Warn about strip -s or -R on a final linked image with
1310 * dyld_info.
1312 if(nsave_symbols != 0){
1313 warning_arch(arch, NULL, "removing global symbols from a "
1314 "final linked no longer supported. Use "
1315 "-exported_symbols_list at link time when "
1316 "building: ");
1318 object->input_sym_info_size += object->dyld_info->rebase_size
1319 + object->dyld_info->bind_size
1320 + object->dyld_info->weak_bind_size
1321 + object->dyld_info->lazy_bind_size
1322 + object->dyld_info->export_size;
1325 if(object->dyst != NULL){
1326 #ifndef NMEDIT
1328 * When stripping out the section contents to create a
1329 * dynamic library stub the relocation info also gets
1330 * stripped.
1332 if(!cflag)
1333 #endif /* !(NMEDIT) */
1335 object->output_sym_info_size +=
1336 object->dyst->nlocrel * sizeof(struct relocation_info);
1338 object->input_sym_info_size +=
1339 object->dyst->nlocrel * sizeof(struct relocation_info);
1342 if(object->split_info_cmd != NULL){
1343 object->output_split_info_data = object->object_addr +
1344 object->split_info_cmd->dataoff;
1345 object->output_split_info_data_size =
1346 object->split_info_cmd->datasize;
1347 object->input_sym_info_size += object->split_info_cmd->datasize;
1348 object->output_sym_info_size +=
1349 object->split_info_cmd->datasize;
1352 if(object->func_starts_info_cmd != NULL){
1353 object->output_func_start_info_data = object->object_addr +
1354 object->func_starts_info_cmd->dataoff;
1355 object->output_func_start_info_data_size =
1356 object->func_starts_info_cmd->datasize;
1357 object->input_sym_info_size +=
1358 object->func_starts_info_cmd->datasize;
1359 object->output_sym_info_size +=
1360 object->func_starts_info_cmd->datasize;
1363 if(object->data_in_code_cmd != NULL){
1364 object->output_data_in_code_info_data = object->object_addr +
1365 object->data_in_code_cmd->dataoff;
1366 object->output_data_in_code_info_data_size =
1367 object->data_in_code_cmd->datasize;
1368 object->input_sym_info_size +=
1369 object->data_in_code_cmd->datasize;
1370 object->output_sym_info_size +=
1371 object->data_in_code_cmd->datasize;
1374 if(object->code_sign_drs_cmd != NULL){
1375 object->output_code_sign_drs_info_data = object->object_addr +
1376 object->code_sign_drs_cmd->dataoff;
1377 object->output_code_sign_drs_info_data_size =
1378 object->code_sign_drs_cmd->datasize;
1379 object->input_sym_info_size +=
1380 object->code_sign_drs_cmd->datasize;
1381 object->output_sym_info_size +=
1382 object->code_sign_drs_cmd->datasize;
1385 if(object->mh != NULL){
1386 object->input_sym_info_size += nsyms * sizeof(struct nlist);
1387 object->output_symbols = new_symbols;
1388 object->output_sym_info_size +=
1389 new_nsyms * sizeof(struct nlist);
1391 else{
1392 object->input_sym_info_size += nsyms * sizeof(struct nlist_64);
1393 object->output_symbols64 = new_symbols64;
1394 object->output_sym_info_size +=
1395 new_nsyms * sizeof(struct nlist_64);
1397 object->output_nsymbols = new_nsyms;
1398 object->st->nsyms = new_nsyms;
1400 if(object->hints_cmd != NULL){
1401 object->input_sym_info_size +=
1402 object->hints_cmd->nhints *
1403 sizeof(struct twolevel_hint);
1404 object->output_sym_info_size +=
1405 object->hints_cmd->nhints *
1406 sizeof(struct twolevel_hint);
1409 if(object->dyst != NULL){
1410 #ifndef NMEDIT
1412 * When stripping out the section contents to create a
1413 * dynamic library stub the relocation info also gets
1414 * stripped.
1416 if(!cflag)
1417 #endif /* !(NMEDIT) */
1419 object->output_sym_info_size +=
1420 object->dyst->nextrel * sizeof(struct relocation_info);
1422 object->input_sym_info_size +=
1423 object->dyst->nextrel * sizeof(struct relocation_info);
1426 if(object->dyst != NULL){
1427 object->output_sym_info_size +=
1428 object->dyst->nindirectsyms * sizeof(uint32_t) +
1429 object->input_indirectsym_pad;
1430 if(object->mh != NULL){
1431 object->input_sym_info_size +=
1432 object->dyst->nindirectsyms * sizeof(uint32_t);
1434 else{
1435 object->input_sym_info_size +=
1436 object->dyst->nindirectsyms * sizeof(uint32_t) +
1437 object->input_indirectsym_pad;
1441 if(object->dyst != NULL){
1442 object->output_sym_info_size +=
1443 new_ntoc * sizeof(struct dylib_table_of_contents);
1444 object->input_sym_info_size +=
1445 object->dyst->ntoc * sizeof(struct dylib_table_of_contents);
1448 if(object->dyst != NULL){
1449 if(object->mh != NULL){
1450 object->output_sym_info_size +=
1451 object->dyst->nmodtab * sizeof(struct dylib_module);
1452 object->input_sym_info_size +=
1453 object->dyst->nmodtab * sizeof(struct dylib_module);
1455 else{
1456 object->output_sym_info_size +=
1457 object->dyst->nmodtab * sizeof(struct dylib_module_64);
1458 object->input_sym_info_size +=
1459 object->dyst->nmodtab * sizeof(struct dylib_module_64);
1463 if(object->dyst != NULL){
1464 object->output_sym_info_size +=
1465 new_nextrefsyms * sizeof(struct dylib_reference);
1466 object->input_sym_info_size +=
1467 object->dyst->nextrefsyms * sizeof(struct dylib_reference);
1470 object->output_strings = new_strings;
1471 object->output_strings_size = new_strsize;
1472 object->output_sym_info_size += new_strsize;
1473 object->input_sym_info_size += strsize;
1474 object->st->strsize = new_strsize;
1476 if(object->code_sig_cmd != NULL){
1477 #ifndef NMEDIT
1478 if(!cflag && !no_code_signature)
1479 #endif /* !(NMEDIT) */
1481 object->output_code_sig_data = object->object_addr +
1482 object->code_sig_cmd->dataoff;
1483 object->output_code_sig_data_size =
1484 object->code_sig_cmd->datasize;
1486 object->input_sym_info_size =
1487 rnd(object->input_sym_info_size, 16);
1488 object->input_sym_info_size +=
1489 object->code_sig_cmd->datasize;
1490 #ifndef NMEDIT
1491 if(cflag || no_code_signature){
1492 strip_LC_CODE_SIGNATURE_commands(arch, member, object);
1494 else
1495 #endif /* !(NMEDIT) */
1497 object->output_sym_info_size =
1498 rnd(object->output_sym_info_size, 16);
1499 object->output_sym_info_size +=
1500 object->code_sig_cmd->datasize;
1504 if(object->dyst != NULL){
1505 object->dyst->ilocalsym = 0;
1506 object->dyst->nlocalsym = new_nlocalsym;
1507 object->dyst->iextdefsym = new_nlocalsym;
1508 object->dyst->nextdefsym = new_nextdefsym;
1509 object->dyst->iundefsym = new_nlocalsym + new_nextdefsym;
1510 object->dyst->nundefsym = new_nundefsym;
1511 if(object->dyst->nindirectsyms != 0){
1512 object->output_indirect_symtab = indirectsyms;
1513 if(object->object_byte_sex != host_byte_sex)
1514 swap_indirect_symbols(indirectsyms, nindirectsyms,
1515 object->object_byte_sex);
1519 * If the -c option is specified the object's filetype will
1520 * have been changed from MH_DYLIB to MH_DYLIB_STUB above.
1522 if(object->mh_filetype == MH_DYLIB ||
1523 object->mh_filetype == MH_DYLIB_STUB){
1524 object->output_tocs = new_tocs;
1525 object->output_ntoc = new_ntoc;
1526 #ifdef NMEDIT
1527 if(object->mh != NULL)
1528 object->output_mods = new_mods;
1529 else
1530 object->output_mods64 = new_mods64;
1531 object->output_nmodtab = new_nmodtab;
1532 #else
1533 object->output_mods = mods;
1534 object->output_nmodtab = nmodtab;
1535 #endif
1536 object->output_refs = new_refs;
1537 object->output_nextrefsyms = new_nextrefsyms;
1538 if(object->object_byte_sex != host_byte_sex){
1539 swap_dylib_table_of_contents(new_tocs, new_ntoc,
1540 object->object_byte_sex);
1541 #ifdef NMEDIT
1542 if(object->mh != NULL)
1543 swap_dylib_module(new_mods, new_nmodtab,
1544 object->object_byte_sex);
1545 else
1546 swap_dylib_module_64(new_mods64, new_nmodtab,
1547 object->object_byte_sex);
1548 #else
1549 if(object->mh != NULL)
1550 swap_dylib_module(mods, nmodtab,
1551 object->object_byte_sex);
1552 else
1553 swap_dylib_module_64(mods64, nmodtab,
1554 object->object_byte_sex);
1555 #endif
1556 swap_dylib_reference(new_refs, new_nextrefsyms,
1557 object->object_byte_sex);
1560 object->dyst->ntoc = new_ntoc;
1561 object->dyst->nextrefsyms = new_nextrefsyms;
1563 offset = get_starting_syminfo_offset(object);
1565 if(object->dyld_info != 0){
1566 if (object->dyld_info->rebase_off != 0){
1567 object->dyld_info->rebase_off = offset;
1568 offset += object->dyld_info->rebase_size;
1570 if (object->dyld_info->bind_off != 0){
1571 object->dyld_info->bind_off = offset;
1572 offset += object->dyld_info->bind_size;
1574 if (object->dyld_info->weak_bind_off != 0){
1575 object->dyld_info->weak_bind_off = offset;
1576 offset += object->dyld_info->weak_bind_size;
1578 if (object->dyld_info->lazy_bind_off != 0){
1579 object->dyld_info->lazy_bind_off = offset;
1580 offset += object->dyld_info->lazy_bind_size;
1582 if (object->dyld_info->export_off != 0){
1583 object->dyld_info->export_off = offset;
1584 offset += object->dyld_info->export_size;
1588 if(object->dyst->nlocrel != 0){
1589 object->output_loc_relocs = (struct relocation_info *)
1590 (object->object_addr + object->dyst->locreloff);
1591 #ifndef NMEDIT
1593 * When stripping out the section contents to create a
1594 * dynamic library stub the relocation info also gets
1595 * stripped.
1597 if(cflag){
1598 object->dyst->nlocrel = 0;
1599 object->dyst->locreloff = 0;
1601 else
1602 #endif /* defined(NMEDIT) */
1604 object->dyst->locreloff = offset;
1605 offset += object->dyst->nlocrel *
1606 sizeof(struct relocation_info);
1609 else
1610 object->dyst->locreloff = 0;
1612 if(object->split_info_cmd != NULL){
1613 object->split_info_cmd->dataoff = offset;
1614 offset += object->split_info_cmd->datasize;
1617 if(object->func_starts_info_cmd != NULL){
1618 object->func_starts_info_cmd->dataoff = offset;
1619 offset += object->func_starts_info_cmd->datasize;
1622 if(object->data_in_code_cmd != NULL){
1623 object->data_in_code_cmd->dataoff = offset;
1624 offset += object->data_in_code_cmd->datasize;
1627 if(object->code_sign_drs_cmd != NULL){
1628 object->code_sign_drs_cmd->dataoff = offset;
1629 offset += object->code_sign_drs_cmd->datasize;
1632 if(object->st->nsyms != 0){
1633 object->st->symoff = offset;
1634 if(object->mh != NULL)
1635 offset += object->st->nsyms * sizeof(struct nlist);
1636 else
1637 offset += object->st->nsyms * sizeof(struct nlist_64);
1639 else
1640 object->st->symoff = 0;
1642 if(object->hints_cmd != NULL){
1643 if(object->hints_cmd->nhints != 0){
1644 object->output_hints = (struct twolevel_hint *)
1645 (object->object_addr + object->hints_cmd->offset);
1646 object->hints_cmd->offset = offset;
1647 offset += object->hints_cmd->nhints *
1648 sizeof(struct twolevel_hint);
1650 else
1651 object->hints_cmd->offset = 0;
1654 if(object->dyst->nextrel != 0){
1655 object->output_ext_relocs = (struct relocation_info *)
1656 (object->object_addr + object->dyst->extreloff);
1657 #ifndef NMEDIT
1659 * When stripping out the section contents to create a
1660 * dynamic library stub the relocation info also gets
1661 * stripped.
1663 if(cflag){
1664 object->dyst->nextrel = 0;
1665 object->dyst->extreloff = 0;
1667 else
1668 #endif /* defined(NMEDIT) */
1670 object->dyst->extreloff = offset;
1671 offset += object->dyst->nextrel *
1672 sizeof(struct relocation_info);
1675 else
1676 object->dyst->extreloff = 0;
1678 if(object->dyst->nindirectsyms != 0){
1679 object->dyst->indirectsymoff = offset;
1680 offset += object->dyst->nindirectsyms * sizeof(uint32_t) +
1681 object->input_indirectsym_pad;
1683 else
1684 object->dyst->indirectsymoff = 0;;
1686 if(object->dyst->ntoc != 0){
1687 object->dyst->tocoff = offset;
1688 offset += object->dyst->ntoc *
1689 sizeof(struct dylib_table_of_contents);
1691 else
1692 object->dyst->tocoff = 0;
1694 if(object->dyst->nmodtab != 0){
1695 #ifndef NMEDIT
1697 * When stripping out the section contents to create a
1698 * dynamic library stub zero out the fields in the module
1699 * table for the sections and relocation information and
1700 * clear Objective-C address and size from modules.
1702 if(cflag){
1703 if(object->mh != NULL){
1704 for(k = 0; k < object->dyst->nmodtab; k++){
1705 mods[k].iinit_iterm = 0;
1706 mods[k].ninit_nterm = 0;
1707 mods[k].iextrel = 0;
1708 mods[k].nextrel = 0;
1709 mods[k].objc_module_info_addr = 0;
1710 mods[k].objc_module_info_size = 0;
1713 else{
1714 for(k = 0; k < object->dyst->nmodtab; k++){
1715 mods64[k].iinit_iterm = 0;
1716 mods64[k].ninit_nterm = 0;
1717 mods64[k].iextrel = 0;
1718 mods64[k].nextrel = 0;
1719 mods64[k].objc_module_info_addr = 0;
1720 mods64[k].objc_module_info_size = 0;
1724 #endif /* !(NMEDIT) */
1725 object->dyst->modtaboff = offset;
1726 if(object->mh != NULL)
1727 offset += object->dyst->nmodtab *
1728 sizeof(struct dylib_module);
1729 else
1730 offset += object->dyst->nmodtab *
1731 sizeof(struct dylib_module_64);
1733 else
1734 object->dyst->modtaboff = 0;
1736 if(object->dyst->nextrefsyms != 0){
1737 object->dyst->extrefsymoff = offset;
1738 offset += object->dyst->nextrefsyms *
1739 sizeof(struct dylib_reference);
1741 else
1742 object->dyst->extrefsymoff = 0;
1744 if(object->st->strsize != 0){
1745 object->st->stroff = offset;
1746 offset += object->st->strsize;
1748 else
1749 object->st->stroff = 0;
1751 if(object->code_sig_cmd != NULL){
1752 offset = rnd(offset, 16);
1753 object->code_sig_cmd->dataoff = offset;
1754 offset += object->code_sig_cmd->datasize;
1757 else{
1758 if(new_strsize != 0){
1759 if(object->mh != NULL)
1760 object->st->stroff = object->st->symoff +
1761 new_nsyms * sizeof(struct nlist);
1762 else
1763 object->st->stroff = object->st->symoff +
1764 new_nsyms * sizeof(struct nlist_64);
1766 else
1767 object->st->stroff = 0;
1768 if(new_nsyms == 0)
1769 object->st->symoff = 0;
1772 #ifndef NMEDIT
1773 else{
1775 * Here we are doing a full symbol strip. In some cases it may
1776 * leave the local relocation entries as well as LOCAL indirect
1777 * symbol table entries.
1779 if(saves != NULL)
1780 free(saves);
1781 saves = (int32_t *)allocate(object->st->nsyms * sizeof(int32_t));
1782 bzero(saves, object->st->nsyms * sizeof(int32_t));
1785 * Account for the symbolic info in the input file.
1787 if(object->dyst != NULL){
1788 object->input_sym_info_size +=
1789 object->dyst->nlocrel * sizeof(struct relocation_info) +
1790 object->dyst->nextrel * sizeof(struct relocation_info) +
1791 object->dyst->ntoc * sizeof(struct dylib_table_of_contents)+
1792 object->dyst->nextrefsyms * sizeof(struct dylib_reference);
1793 if(object->mh != NULL){
1794 object->input_sym_info_size +=
1795 object->dyst->nmodtab * sizeof(struct dylib_module) +
1796 object->dyst->nindirectsyms * sizeof(uint32_t);
1798 else{
1799 object->input_sym_info_size +=
1800 object->dyst->nmodtab * sizeof(struct dylib_module_64) +
1801 object->dyst->nindirectsyms * sizeof(uint32_t) +
1802 object->input_indirectsym_pad;
1807 * Determine the offset where the remaining symbolic info will start
1808 * in the output file (if any).
1810 offset = get_starting_syminfo_offset(object);
1813 * For a full symbol strip all these values in the output file are
1814 * set to zero.
1816 object->st->symoff = 0;
1817 object->st->nsyms = 0;
1818 object->st->stroff = 0;
1819 object->st->strsize = 0;
1820 if(object->dyst != NULL){
1821 object->dyst->ilocalsym = 0;
1822 object->dyst->nlocalsym = 0;
1823 object->dyst->iextdefsym = 0;
1824 object->dyst->nextdefsym = 0;
1825 object->dyst->iundefsym = 0;
1826 object->dyst->nundefsym = 0;
1830 * This will accumulate any remaining symbolic info size in the
1831 * output file.
1833 object->output_sym_info_size = 0;
1836 * We set these so that checking can be done below to report the
1837 * symbols that can't be stripped because of relocation entries
1838 * or indirect symbol table entries. Normally if these table have a
1839 * non-zero number of entries it will be an error as we are trying
1840 * to strip everything. But it maybe that there are only LOCAL
1841 * indirect entries which is odd but will be OK.
1843 if(object->dyst != NULL){
1844 if(object->dyst->nextrel != 0){
1845 object->output_ext_relocs = (struct relocation_info *)
1846 (object->object_addr + object->dyst->extreloff);
1849 * Since this file has a dynamic symbol table and if this file
1850 * has local relocation entries on input make sure they are
1851 * there on output. This is a rare case that it will not have
1852 * external relocs or indirect symbols but can happen as is the
1853 * case with the dynamic linker itself.
1855 if(object->dyst->nlocrel != 0){
1856 object->output_loc_relocs = (struct relocation_info *)
1857 (object->object_addr + object->dyst->locreloff);
1858 object->output_sym_info_size +=
1859 object->dyst->nlocrel * sizeof(struct relocation_info);
1861 object->dyst->locreloff = offset;
1862 offset += object->dyst->nlocrel *
1863 sizeof(struct relocation_info);
1866 if(object->dyst->nindirectsyms != 0){
1867 object->output_indirect_symtab = (uint32_t *)
1868 (object->object_addr +
1869 object->dyst->indirectsymoff);
1870 if(object->object_byte_sex != host_byte_sex)
1871 swap_indirect_symbols(
1872 object->output_indirect_symtab,
1873 object->dyst->nindirectsyms,
1874 object->object_byte_sex);
1876 object->output_sym_info_size +=
1877 object->dyst->nindirectsyms * sizeof(uint32_t) +
1878 object->input_indirectsym_pad;
1880 object->dyst->indirectsymoff = offset;
1881 offset += object->dyst->nindirectsyms * sizeof(uint32_t) +
1882 object->input_indirectsym_pad;
1886 #endif /* !defined(NMEDIT) */
1889 * Always clear the prebind checksum if any when creating a new file.
1891 if(object->cs != NULL)
1892 object->cs->cksum = 0;
1894 if(object->seg_linkedit != NULL){
1895 object->seg_linkedit->filesize += object->output_sym_info_size -
1896 object->input_sym_info_size;
1897 object->seg_linkedit->vmsize = object->seg_linkedit->filesize;
1899 else if(object->seg_linkedit64 != NULL){
1900 /* Do this in two steps to avoid 32/64-bit casting problems. */
1901 object->seg_linkedit64->filesize -= object->input_sym_info_size;
1902 object->seg_linkedit64->filesize += object->output_sym_info_size;
1903 object->seg_linkedit64->vmsize = object->seg_linkedit64->filesize;
1907 * Check and update the external relocation entries to make sure
1908 * referenced symbols are not stripped and refer to the new symbol
1909 * table indexes.
1911 * The external relocation entries can be located in one of two places,
1912 * first off of the sections or second off of the dynamic symtab.
1914 missing_reloc_symbols = 0;
1915 lc = object->load_commands;
1916 if(object->mh != NULL)
1917 ncmds = object->mh->ncmds;
1918 else
1919 ncmds = object->mh64->ncmds;
1920 for(i = 0; i < ncmds; i++){
1921 if(lc->cmd == LC_SEGMENT &&
1922 object->seg_linkedit != (struct segment_command *)lc){
1923 sg = (struct segment_command *)lc;
1924 s = (struct section *)((char *)sg +
1925 sizeof(struct segment_command));
1926 for(j = 0; j < sg->nsects; j++){
1927 if(s->nreloc != 0){
1928 if(s->reloff + s->nreloc *
1929 sizeof(struct relocation_info) >
1930 object->object_size){
1931 fatal_arch(arch, member, "truncated or malformed "
1932 "object (relocation entries for section (%.16s,"
1933 "%.16s) extends past the end of the file)",
1934 s->segname, s->sectname);
1936 relocs = (struct relocation_info *)
1937 (object->object_addr + s->reloff);
1938 if(object->object_byte_sex != host_byte_sex)
1939 swap_relocation_info(relocs, s->nreloc,
1940 host_byte_sex);
1941 if(s->offset + s->size > object->object_size){
1942 fatal_arch(arch, member, "truncated or malformed "
1943 "object (contents of section (%.16s,"
1944 "%.16s) extends past the end of the file)",
1945 s->segname, s->sectname);
1947 contents = object->object_addr + s->offset;
1948 check_object_relocs(arch, member, object, s->segname,
1949 s->sectname, s->size, contents, relocs, s->nreloc,
1950 symbols, symbols64, nsyms, strings,
1951 &missing_reloc_symbols, host_byte_sex);
1952 if(object->object_byte_sex != host_byte_sex)
1953 swap_relocation_info(relocs, s->nreloc,
1954 object->object_byte_sex);
1956 s++;
1959 else if(lc->cmd == LC_SEGMENT_64 &&
1960 object->seg_linkedit64 != (struct segment_command_64 *)lc){
1961 sg64 = (struct segment_command_64 *)lc;
1962 s64 = (struct section_64 *)((char *)sg64 +
1963 sizeof(struct segment_command_64));
1964 for(j = 0; j < sg64->nsects; j++){
1965 if(s64->nreloc != 0){
1966 if(s64->reloff + s64->nreloc *
1967 sizeof(struct relocation_info) >
1968 object->object_size){
1969 fatal_arch(arch, member, "truncated or malformed "
1970 "object (relocation entries for section (%.16s,"
1971 "%.16s) extends past the end of the file)",
1972 s64->segname, s64->sectname);
1974 relocs = (struct relocation_info *)
1975 (object->object_addr + s64->reloff);
1976 if(object->object_byte_sex != host_byte_sex)
1977 swap_relocation_info(relocs, s64->nreloc,
1978 host_byte_sex);
1979 if(s64->offset + s64->size > object->object_size){
1980 fatal_arch(arch, member, "truncated or malformed "
1981 "object (contents of section (%.16s,"
1982 "%.16s) extends past the end of the file)",
1983 s64->segname, s64->sectname);
1985 contents = object->object_addr + s64->offset;
1986 check_object_relocs(arch, member, object, s64->segname,
1987 s64->sectname, s64->size, contents, relocs,
1988 s64->nreloc, symbols, symbols64, nsyms, strings,
1989 &missing_reloc_symbols, host_byte_sex);
1990 if(object->object_byte_sex != host_byte_sex)
1991 swap_relocation_info(relocs, s64->nreloc,
1992 object->object_byte_sex);
1994 s64++;
1997 lc = (struct load_command *)((char *)lc + lc->cmdsize);
1999 if(object->dyst != NULL && object->dyst->nextrel != 0){
2000 relocs = object->output_ext_relocs;
2001 if(object->object_byte_sex != host_byte_sex)
2002 swap_relocation_info(relocs, object->dyst->nextrel,
2003 host_byte_sex);
2005 for(i = 0; i < object->dyst->nextrel; i++){
2006 if((relocs[i].r_address & R_SCATTERED) == 0 &&
2007 relocs[i].r_extern == 1){
2008 if(relocs[i].r_symbolnum > nsyms){
2009 fatal_arch(arch, member, "bad r_symbolnum for external "
2010 "relocation entry %d in: ", i);
2012 if(saves[relocs[i].r_symbolnum] == 0){
2013 if(missing_reloc_symbols == 0){
2014 error_arch(arch, member, "symbols referenced by "
2015 "relocation entries that can't be stripped in: ");
2016 missing_reloc_symbols = 1;
2018 if(object->mh != NULL){
2019 fprintf(stderr, "%s\n", strings + symbols
2020 [relocs[i].r_symbolnum].n_un.n_strx);
2022 else {
2023 fprintf(stderr, "%s\n", strings + symbols64
2024 [relocs[i].r_symbolnum].n_un.n_strx);
2026 saves[relocs[i].r_symbolnum] = -1;
2028 if(saves[relocs[i].r_symbolnum] != -1){
2029 relocs[i].r_symbolnum =
2030 saves[relocs[i].r_symbolnum] - 1;
2033 else{
2034 fatal_arch(arch, member, "bad external relocation entry "
2035 "%d (not external) in: ", i);
2037 if((relocs[i].r_address & R_SCATTERED) == 0){
2038 if(reloc_has_pair(object->mh_cputype, relocs[i].r_type))
2039 i++;
2041 else{
2042 sreloc = (struct scattered_relocation_info *)relocs + i;
2043 if(reloc_has_pair(object->mh_cputype, sreloc->r_type))
2044 i++;
2047 if(object->object_byte_sex != host_byte_sex)
2048 swap_relocation_info(relocs, object->dyst->nextrel,
2049 object->object_byte_sex);
2053 * Check and update the indirect symbol table entries to make sure
2054 * referenced symbols are not stripped and refer to the new symbol
2055 * table indexes.
2057 if(object->dyst != NULL && object->dyst->nindirectsyms != 0){
2058 if(object->object_byte_sex != host_byte_sex)
2059 swap_indirect_symbols(object->output_indirect_symtab,
2060 object->dyst->nindirectsyms, host_byte_sex);
2062 lc = object->load_commands;
2063 if(object->mh != NULL)
2064 ncmds = object->mh->ncmds;
2065 else
2066 ncmds = object->mh64->ncmds;
2067 for(i = 0; i < ncmds; i++){
2068 if(lc->cmd == LC_SEGMENT &&
2069 object->seg_linkedit != (struct segment_command *)lc){
2070 sg = (struct segment_command *)lc;
2071 s = (struct section *)((char *)sg +
2072 sizeof(struct segment_command));
2073 for(j = 0; j < sg->nsects; j++){
2074 section_type = s->flags & SECTION_TYPE;
2075 if(section_type == S_LAZY_SYMBOL_POINTERS ||
2076 section_type == S_LAZY_DYLIB_SYMBOL_POINTERS ||
2077 section_type == S_NON_LAZY_SYMBOL_POINTERS)
2078 stride = 4;
2079 else if(section_type == S_SYMBOL_STUBS)
2080 stride = s->reserved2;
2081 else{
2082 s++;
2083 continue;
2085 nitems = s->size / stride;
2086 contents = object->object_addr + s->offset;
2087 check_indirect_symtab(arch, member, object, nitems,
2088 s->reserved1, section_type, contents, symbols,
2089 symbols64, nsyms, strings, &missing_reloc_symbols,
2090 host_byte_sex);
2091 s++;
2094 else if(lc->cmd == LC_SEGMENT_64 &&
2095 object->seg_linkedit64 != (struct segment_command_64 *)lc){
2096 sg64 = (struct segment_command_64 *)lc;
2097 s64 = (struct section_64 *)((char *)sg64 +
2098 sizeof(struct segment_command_64));
2099 for(j = 0; j < sg64->nsects; j++){
2100 section_type = s64->flags & SECTION_TYPE;
2101 if(section_type == S_LAZY_SYMBOL_POINTERS ||
2102 section_type == S_LAZY_DYLIB_SYMBOL_POINTERS ||
2103 section_type == S_NON_LAZY_SYMBOL_POINTERS)
2104 stride = 8;
2105 else if(section_type == S_SYMBOL_STUBS)
2106 stride = s64->reserved2;
2107 else{
2108 s64++;
2109 continue;
2111 nitems = s64->size / stride;
2112 contents = object->object_addr + s64->offset;
2113 check_indirect_symtab(arch, member, object, nitems,
2114 s64->reserved1, section_type, contents, symbols,
2115 symbols64, nsyms, strings, &missing_reloc_symbols,
2116 host_byte_sex);
2117 s64++;
2120 lc = (struct load_command *)((char *)lc + lc->cmdsize);
2123 if(object->object_byte_sex != host_byte_sex)
2124 swap_indirect_symbols(object->output_indirect_symtab,
2125 object->dyst->nindirectsyms, object->object_byte_sex);
2129 * Issue a warning if object file has a code signature that the
2130 * operation will invalidate it.
2132 if(object->code_sig_cmd != NULL)
2133 warning_arch(arch, member, "changes being made to the file will "
2134 "invalidate the code signature in: ");
2138 * get_starting_syminfo_offset() returns the starting offset of the symbolic
2139 * info in the object file.
2141 static
2142 uint32_t
2143 get_starting_syminfo_offset(
2144 struct object *object)
2146 uint32_t offset;
2148 if(object->seg_linkedit != NULL ||
2149 object->seg_linkedit64 != NULL){
2150 if(object->mh != NULL)
2151 offset = object->seg_linkedit->fileoff;
2152 else
2153 offset = object->seg_linkedit64->fileoff;
2155 else{
2156 offset = UINT_MAX;
2157 if(object->dyst != NULL &&
2158 object->dyst->nlocrel != 0 &&
2159 object->dyst->locreloff < offset)
2160 offset = object->dyst->locreloff;
2161 if(object->st->nsyms != 0 &&
2162 object->st->symoff < offset)
2163 offset = object->st->symoff;
2164 if(object->dyst != NULL &&
2165 object->dyst->nextrel != 0 &&
2166 object->dyst->extreloff < offset)
2167 offset = object->dyst->extreloff;
2168 if(object->dyst != NULL &&
2169 object->dyst->nindirectsyms != 0 &&
2170 object->dyst->indirectsymoff < offset)
2171 offset = object->dyst->indirectsymoff;
2172 if(object->dyst != NULL &&
2173 object->dyst->ntoc != 0 &&
2174 object->dyst->tocoff < offset)
2175 offset = object->dyst->tocoff;
2176 if(object->dyst != NULL &&
2177 object->dyst->nmodtab != 0 &&
2178 object->dyst->modtaboff < offset)
2179 offset = object->dyst->modtaboff;
2180 if(object->dyst != NULL &&
2181 object->dyst->nextrefsyms != 0 &&
2182 object->dyst->extrefsymoff < offset)
2183 offset = object->dyst->extrefsymoff;
2184 if(object->st->strsize != 0 &&
2185 object->st->stroff < offset)
2186 offset = object->st->stroff;
2188 return(offset);
2192 * check_object_relocs() is used to check and update the external relocation
2193 * entries from a section in an object file, to make sure referenced symbols
2194 * are not stripped and are changed to refer to the new symbol table indexes.
2196 static
2197 void
2198 check_object_relocs(
2199 struct arch *arch,
2200 struct member *member,
2201 struct object *object,
2202 char *segname,
2203 char *sectname,
2204 uint64_t sectsize,
2205 char *contents,
2206 struct relocation_info *relocs,
2207 uint32_t nreloc,
2208 struct nlist *symbols,
2209 struct nlist_64 *symbols64,
2210 uint32_t nsyms,
2211 char *strings,
2212 int32_t *missing_reloc_symbols,
2213 enum byte_sex host_byte_sex)
2215 uint32_t k, n_strx;
2216 uint64_t n_value;
2217 #ifdef NMEDIT
2218 uint32_t value, n_ext;
2219 uint64_t value64;
2220 #endif
2221 struct scattered_relocation_info *sreloc;
2223 for(k = 0; k < nreloc; k++){
2224 if((relocs[k].r_address & R_SCATTERED) == 0 &&
2225 relocs[k].r_extern == 1){
2226 if(relocs[k].r_symbolnum > nsyms){
2227 fatal_arch(arch, member, "bad r_symbolnum for relocation "
2228 "entry %d in section (%.16s,%.16s) in: ", k, segname,
2229 sectname);
2231 if(object->mh != NULL){
2232 n_strx = symbols[relocs[k].r_symbolnum].n_un.n_strx;
2233 n_value = symbols[relocs[k].r_symbolnum].n_value;
2235 else{
2236 n_strx = symbols64[relocs[k].r_symbolnum].n_un.n_strx;
2237 n_value = symbols64[relocs[k].r_symbolnum].n_value;
2239 #ifndef NMEDIT
2240 if(saves[relocs[k].r_symbolnum] == 0){
2241 if(*missing_reloc_symbols == 0){
2242 error_arch(arch, member, "symbols referenced by "
2243 "relocation entries that can't be stripped in: ");
2244 *missing_reloc_symbols = 1;
2246 fprintf(stderr, "%s\n", strings + n_strx);
2247 saves[relocs[k].r_symbolnum] = -1;
2249 #else /* defined(NMEDIT) */
2251 * We are letting nmedit change global coalesed symbols into
2252 * statics in MH_OBJECT file types only. Relocation entries to
2253 * global coalesced symbols are external relocs.
2255 if(object->mh != NULL)
2256 n_ext = new_symbols[saves[relocs[k].r_symbolnum] - 1].
2257 n_type & N_EXT;
2258 else
2259 n_ext = new_symbols64[saves[relocs[k].r_symbolnum] - 1].
2260 n_type & N_EXT;
2261 if(n_ext != N_EXT &&
2262 object->mh_cputype != CPU_TYPE_X86_64){
2264 * We need to do the relocation for this external relocation
2265 * entry so the item to be relocated is correct for a local
2266 * relocation entry. We don't need to do this for x86-64.
2268 if(relocs[k].r_address + sizeof(int32_t) > sectsize){
2269 fatal_arch(arch, member, "truncated or malformed "
2270 "object (r_address of relocation entry %u of "
2271 "section (%.16s,%.16s) extends past the end "
2272 "of the section)", k, segname, sectname);
2274 if(object->mh != NULL){
2275 value = *(uint32_t *)
2276 (contents + relocs[k].r_address);
2277 if(object->object_byte_sex != host_byte_sex)
2278 value = SWAP_INT(value);
2280 * We handle a very limited form here. Only VANILLA
2281 * (r_type == 0) long (r_length==2) absolute or pcrel
2282 * that won't need a scattered relocation entry.
2284 if(relocs[k].r_type != 0 ||
2285 relocs[k].r_length != 2){
2286 fatal_arch(arch, member, "don't have "
2287 "code to convert external relocation "
2288 "entry %d in section (%.16s,%.16s) "
2289 "for global coalesced symbol: %s "
2290 "in: ", k, segname, sectname,
2291 strings + n_strx);
2293 value += n_value;
2294 if(object->object_byte_sex != host_byte_sex)
2295 value = SWAP_INT(value);
2296 *(uint32_t *)(contents + relocs[k].r_address) =
2297 value;
2299 else{
2300 value64 = *(uint64_t *)(contents + relocs[k].r_address);
2301 if(object->object_byte_sex != host_byte_sex)
2302 value64 = SWAP_LONG_LONG(value64);
2304 * We handle a very limited form here. Only VANILLA
2305 * (r_type == 0) quad (r_length==3) absolute or pcrel
2306 * that won't need a scattered relocation entry.
2308 if(relocs[k].r_type != 0 ||
2309 relocs[k].r_length != 3){
2310 fatal_arch(arch, member, "don't have "
2311 "code to convert external relocation "
2312 "entry %d in section (%.16s,%.16s) "
2313 "for global coalesced symbol: %s "
2314 "in: ", k, segname, sectname,
2315 strings + n_strx);
2317 value64 += n_value;
2318 if(object->object_byte_sex != host_byte_sex)
2319 value64 = SWAP_LONG_LONG(value64);
2320 *(uint64_t *)(contents + relocs[k].r_address) = value64;
2323 * Turn the extern reloc into a local.
2325 if(object->mh != NULL)
2326 relocs[k].r_symbolnum =
2327 new_symbols[saves[relocs[k].r_symbolnum] - 1].n_sect;
2328 else
2329 relocs[k].r_symbolnum =
2330 new_symbols64[saves[relocs[k].r_symbolnum] - 1].n_sect;
2331 relocs[k].r_extern = 0;
2333 #endif /* NMEDIT */
2334 if(relocs[k].r_extern == 1 &&
2335 saves[relocs[k].r_symbolnum] != -1){
2336 relocs[k].r_symbolnum = saves[relocs[k].r_symbolnum] - 1;
2339 if((relocs[k].r_address & R_SCATTERED) == 0){
2340 if(reloc_has_pair(object->mh_cputype, relocs[k].r_type) == TRUE)
2341 k++;
2343 else{
2344 sreloc = (struct scattered_relocation_info *)relocs + k;
2345 if(reloc_has_pair(object->mh_cputype, sreloc->r_type) == TRUE)
2346 k++;
2352 * check_indirect_symtab() checks and updates the indirect symbol table entries
2353 * to make sure referenced symbols are not stripped and refer to the new symbol
2354 * table indexes.
2356 static
2357 void
2358 check_indirect_symtab(
2359 struct arch *arch,
2360 struct member *member,
2361 struct object *object,
2362 uint32_t nitems,
2363 uint32_t reserved1,
2364 uint32_t section_type,
2365 char *contents,
2366 struct nlist *symbols,
2367 struct nlist_64 *symbols64,
2368 uint32_t nsyms,
2369 char *strings,
2370 int32_t *missing_reloc_symbols,
2371 enum byte_sex host_byte_sex)
2373 uint32_t k, index;
2374 uint8_t n_type;
2375 uint32_t n_strx, value;
2376 uint64_t value64;
2377 enum bool made_local;
2379 for(k = 0; k < nitems; k++){
2380 made_local = FALSE;
2381 index = object->output_indirect_symtab[reserved1 + k];
2382 if(index == INDIRECT_SYMBOL_LOCAL ||
2383 index == INDIRECT_SYMBOL_ABS ||
2384 index == (INDIRECT_SYMBOL_LOCAL | INDIRECT_SYMBOL_ABS))
2385 continue;
2386 if(index > nsyms)
2387 fatal_arch(arch, member,"indirect symbol table entry %d (past " "the end of the symbol table) in: ", reserved1 + k);
2388 #ifdef NMEDIT
2389 if(pflag == 0 && nmedits[index] == TRUE && saves[index] != -1)
2390 #else
2391 if(saves[index] == 0)
2392 #endif
2395 * Indirect symbol table entries for defined symbols in a
2396 * non-lazy pointer section that are not saved are changed to
2397 * INDIRECT_SYMBOL_LOCAL which their values just have to be
2398 * slid if the are not absolute symbols.
2400 if(object->mh != NULL){
2401 n_type = symbols[index].n_type;
2402 n_strx = symbols[index].n_un.n_strx;
2404 else{
2405 n_type = symbols64[index].n_type;
2406 n_strx = symbols64[index].n_un.n_strx;
2408 if((n_type & N_TYPE) != N_UNDF &&
2409 (n_type & N_TYPE) != N_PBUD &&
2410 section_type == S_NON_LAZY_SYMBOL_POINTERS){
2411 object->output_indirect_symtab[reserved1 + k] =
2412 INDIRECT_SYMBOL_LOCAL;
2413 if((n_type & N_TYPE) == N_ABS)
2414 object->output_indirect_symtab[reserved1 + k] |=
2415 INDIRECT_SYMBOL_ABS;
2416 made_local = TRUE;
2418 * When creating a stub shared library the section contents
2419 * are not updated since they will be stripped.
2421 if(object->mh_filetype != MH_DYLIB_STUB){
2422 if(object->mh != NULL){
2423 value = symbols[index].n_value;
2424 if (symbols[index].n_desc & N_ARM_THUMB_DEF)
2425 value |= 1;
2426 if(object->object_byte_sex != host_byte_sex)
2427 value = SWAP_INT(value);
2428 *(uint32_t *)(contents + k * 4) = value;
2430 else{
2431 value64 = symbols64[index].n_value;
2432 if(object->object_byte_sex != host_byte_sex)
2433 value64 = SWAP_LONG_LONG(value64);
2434 *(uint64_t *)(contents + k * 8) = value64;
2438 #ifdef NMEDIT
2439 else {
2440 object->output_indirect_symtab[reserved1 + k] =
2441 saves[index] - 1;
2443 #else /* !defined(NMEDIT) */
2444 else{
2445 if(*missing_reloc_symbols == 0){
2446 error_arch(arch, member, "symbols referenced by "
2447 "indirect symbol table entries that can't be "
2448 "stripped in: ");
2449 *missing_reloc_symbols = 1;
2451 fprintf(stderr, "%s\n", strings + n_strx);
2452 saves[index] = -1;
2454 #endif /* !defined(NMEDIT) */
2456 #ifdef NMEDIT
2457 else
2458 #else /* !defined(NMEDIT) */
2459 if(made_local == FALSE && saves[index] != -1)
2460 #endif /* !defined(NMEDIT) */
2462 object->output_indirect_symtab[reserved1+k] = saves[index] - 1;
2467 #ifndef NMEDIT
2469 * This is called if there is a -d option specified. It reads the file with
2470 * the strings in it and places them in the array debug_filenames and sorts
2471 * them by name. The file that contains the file names must have names one
2472 * per line with no white space (except the newlines).
2474 static
2475 void
2476 setup_debug_filenames(
2477 char *dfile)
2479 int fd, i, strings_size;
2480 struct stat stat_buf;
2481 char *strings, *p;
2483 if((fd = open(dfile, O_RDONLY)) < 0){
2484 system_error("can't open: %s", dfile);
2485 return;
2487 if(fstat(fd, &stat_buf) == -1){
2488 system_error("can't stat: %s", dfile);
2489 close(fd);
2490 return;
2492 strings_size = stat_buf.st_size;
2493 strings = (char *)allocate(strings_size + 1);
2494 strings[strings_size] = '\0';
2495 if(read(fd, strings, strings_size) != strings_size){
2496 system_error("can't read: %s", dfile);
2497 close(fd);
2498 return;
2500 p = strings;
2501 for(i = 0; i < strings_size; i++){
2502 if(*p == '\n'){
2503 *p = '\0';
2504 ndebug_filenames++;
2506 p++;
2508 debug_filenames = (char **)allocate(ndebug_filenames * sizeof(char *));
2509 p = strings;
2510 for(i = 0; i < ndebug_filenames; i++){
2511 debug_filenames[i] = p;
2512 p += strlen(p) + 1;
2514 qsort(debug_filenames, ndebug_filenames, sizeof(char *),
2515 (int (*)(const void *, const void *))cmp_qsort_filename);
2517 #ifdef DEBUG
2518 printf("Debug filenames:\n");
2519 for(i = 0; i < ndebug_filenames; i++){
2520 printf("filename = %s\n", debug_filenames[i]);
2522 #endif /* DEBUG */
2526 * Strip the symbol table to the level specified by the command line arguments.
2527 * The new symbol table is built and new_symbols is left pointing to it. The
2528 * number of new symbols is left in new_nsyms, the new string table is built
2529 * and new_stings is left pointing to it and new_strsize is left containing it.
2530 * This routine returns zero if successfull and non-zero otherwise.
2532 static
2533 enum bool
2534 strip_symtab(
2535 struct arch *arch,
2536 struct member *member,
2537 struct object *object,
2538 struct dylib_table_of_contents *tocs,
2539 uint32_t ntoc,
2540 struct dylib_module *mods,
2541 struct dylib_module_64 *mods64,
2542 uint32_t nmodtab,
2543 struct dylib_reference *refs,
2544 uint32_t nextrefsyms)
2546 uint32_t i, j, k, n, inew_syms, save_debug, missing_syms;
2547 uint32_t missing_symbols;
2548 char *p, *q, **pp, *basename;
2549 struct symbol_list *sp;
2550 uint32_t new_ext_strsize, len, *changes, inew_undefsyms;
2551 unsigned char nsects;
2552 struct load_command *lc;
2553 struct segment_command *sg;
2554 struct segment_command_64 *sg64;
2555 struct section *s, **sections;
2556 struct section_64 *s64, **sections64;
2557 uint32_t ncmds, mh_flags, s_flags, n_strx;
2558 struct nlist *sym;
2559 struct undef_map *undef_map;
2560 struct undef_map64 *undef_map64;
2561 uint8_t n_type, n_sect;
2562 uint16_t n_desc;
2563 uint64_t n_value;
2564 uint32_t module_name, iextdefsym, nextdefsym, ilocalsym, nlocalsym;
2565 uint32_t irefsym, nrefsym;
2566 unsigned char text_nsect;
2567 enum bool has_dwarf, hack_5614542;
2569 save_debug = 0;
2570 if(saves != NULL)
2571 free(saves);
2572 changes = NULL;
2573 for(i = 0; i < nsave_symbols; i++)
2574 save_symbols[i].sym = NULL;
2575 for(i = 0; i < nremove_symbols; i++)
2576 remove_symbols[i].sym = NULL;
2577 if(member == NULL){
2578 for(i = 0; i < nsave_symbols; i++)
2579 save_symbols[i].seen = FALSE;
2580 for(i = 0; i < nremove_symbols; i++)
2581 remove_symbols[i].seen = FALSE;
2584 new_nsyms = 0;
2585 if(object->mh != NULL)
2586 new_strsize = sizeof(int32_t);
2587 else
2588 new_strsize = sizeof(int64_t);
2589 new_nlocalsym = 0;
2590 new_nextdefsym = 0;
2591 new_nundefsym = 0;
2592 new_ext_strsize = 0;
2595 * If this an object file that has DWARF debugging sections to strip
2596 * then we have to run ld -r on it.
2598 if(object->mh_filetype == MH_OBJECT && (Sflag || xflag)){
2599 has_dwarf = FALSE;
2600 lc = object->load_commands;
2601 if(object->mh != NULL)
2602 ncmds = object->mh->ncmds;
2603 else
2604 ncmds = object->mh64->ncmds;
2605 for(i = 0; i < ncmds && has_dwarf == FALSE; i++){
2606 if(lc->cmd == LC_SEGMENT){
2607 sg = (struct segment_command *)lc;
2608 s = (struct section *)((char *)sg +
2609 sizeof(struct segment_command));
2610 for(j = 0; j < sg->nsects; j++){
2611 if(s->flags & S_ATTR_DEBUG){
2612 has_dwarf = TRUE;
2613 break;
2615 s++;
2618 else if(lc->cmd == LC_SEGMENT_64){
2619 sg64 = (struct segment_command_64 *)lc;
2620 s64 = (struct section_64 *)((char *)sg64 +
2621 sizeof(struct segment_command_64));
2622 for(j = 0; j < sg64->nsects; j++){
2623 if(s64->flags & S_ATTR_DEBUG){
2624 has_dwarf = TRUE;
2625 break;
2627 s64++;
2630 lc = (struct load_command *)((char *)lc + lc->cmdsize);
2632 if(has_dwarf == TRUE)
2633 make_ld_r_object(arch, member, object);
2636 * Because of the "design" of 64-bit object files and the lack of
2637 * local relocation entries it is not possible for strip(1) to do its
2638 * job without becoming a static link editor. The "design" does not
2639 * actually strip the symbols it simply renames them to things like
2640 * "l1000". And they become static symbols but still have external
2641 * relocation entries. Thus can never actually be stripped. Also some
2642 * symbols, *.eh, symbols are not even changed to these names if there
2643 * corresponding global symbol is not stripped. So strip(1) only
2644 * recourse is to use the unified linker to create an ld -r object then
2645 * save all resulting symbols (both static and global) and hope the user
2646 * does not notice the stripping is not what they asked for.
2648 if(object->mh_filetype == MH_OBJECT &&
2649 (object->mh64 != NULL && object->ld_r_ofile == NULL))
2650 make_ld_r_object(arch, member, object);
2653 * Since make_ld_r_object() may create an object with more symbols
2654 * this has to be done after make_ld_r_object() and nsyms is updated.
2656 saves = (int32_t *)allocate(nsyms * sizeof(int32_t));
2657 bzero(saves, nsyms * sizeof(int32_t));
2660 * Gather an array of section struct pointers so we can later determine
2661 * if we run into a global symbol in a coalesced section and not strip
2662 * those symbols.
2663 * statics.
2665 nsects = 0;
2666 text_nsect = NO_SECT;
2667 lc = object->load_commands;
2668 if(object->mh != NULL)
2669 ncmds = object->mh->ncmds;
2670 else
2671 ncmds = object->mh64->ncmds;
2672 for(i = 0; i < ncmds; i++){
2673 if(lc->cmd == LC_SEGMENT){
2674 sg = (struct segment_command *)lc;
2675 nsects += sg->nsects;
2677 else if(lc->cmd == LC_SEGMENT_64){
2678 sg64 = (struct segment_command_64 *)lc;
2679 nsects += sg64->nsects;
2681 lc = (struct load_command *)((char *)lc + lc->cmdsize);
2683 if(object->mh != NULL){
2684 sections = allocate(nsects * sizeof(struct section *));
2685 sections64 = NULL;
2687 else{
2688 sections = NULL;
2689 sections64 = allocate(nsects * sizeof(struct section_64 *));
2691 nsects = 0;
2692 lc = object->load_commands;
2693 for(i = 0; i < ncmds; i++){
2694 if(lc->cmd == LC_SEGMENT){
2695 sg = (struct segment_command *)lc;
2696 s = (struct section *)((char *)sg +
2697 sizeof(struct segment_command));
2698 for(j = 0; j < sg->nsects; j++){
2699 if(strcmp((s + j)->sectname, SECT_TEXT) == 0 &&
2700 strcmp((s + j)->segname, SEG_TEXT) == 0)
2701 text_nsect = nsects + 1;
2702 sections[nsects++] = s++;
2705 else if(lc->cmd == LC_SEGMENT_64){
2706 sg64 = (struct segment_command_64 *)lc;
2707 s64 = (struct section_64 *)((char *)sg64 +
2708 sizeof(struct segment_command_64));
2709 for(j = 0; j < sg64->nsects; j++){
2710 if(strcmp((s64 + j)->sectname, SECT_TEXT) == 0 &&
2711 strcmp((s64 + j)->segname, SEG_TEXT) == 0)
2712 text_nsect = nsects + 1;
2713 sections64[nsects++] = s64++;
2716 lc = (struct load_command *)((char *)lc + lc->cmdsize);
2719 for(i = 0; i < nsyms; i++){
2720 s_flags = 0;
2721 if(object->mh != NULL){
2722 mh_flags = object->mh->flags;
2723 n_strx = symbols[i].n_un.n_strx;
2724 n_type = symbols[i].n_type;
2725 n_sect = symbols[i].n_sect;
2726 if((n_type & N_TYPE) == N_SECT){
2727 if(n_sect == 0 || n_sect > nsects){
2728 error_arch(arch, member, "bad n_sect for symbol "
2729 "table entry %d in: ", i);
2730 return(FALSE);
2732 s_flags = sections[n_sect - 1]->flags;
2734 n_desc = symbols[i].n_desc;
2735 n_value = symbols[i].n_value;
2737 else{
2738 mh_flags = object->mh64->flags;
2739 n_strx = symbols64[i].n_un.n_strx;
2740 n_type = symbols64[i].n_type;
2741 n_sect = symbols64[i].n_sect;
2742 if((n_type & N_TYPE) == N_SECT){
2743 if(n_sect == 0 || n_sect > nsects){
2744 error_arch(arch, member, "bad n_sect for symbol "
2745 "table entry %d in: ", i);
2746 return(FALSE);
2748 s_flags = sections64[n_sect - 1]->flags;
2750 n_desc = symbols64[i].n_desc;
2751 n_value = symbols64[i].n_value;
2753 if(n_strx != 0){
2754 if(n_strx > strsize){
2755 error_arch(arch, member, "bad string index for symbol "
2756 "table entry %d in: ", i);
2757 return(FALSE);
2760 if((n_type & N_TYPE) == N_INDR){
2761 if(n_value != 0){
2762 if(n_value > strsize){
2763 error_arch(arch, member, "bad string index for "
2764 "indirect symbol table entry %d in: ", i);
2765 return(FALSE);
2769 if((n_type & N_EXT) == 0){ /* local symbol */
2770 if(aflag){
2771 if(n_strx != 0)
2772 new_strsize += strlen(strings + n_strx) + 1;
2773 new_nlocalsym++;
2774 new_nsyms++;
2775 saves[i] = new_nsyms;
2778 * For x86_64 .o files we have run ld -r on them and are stuck
2779 * keeping all resulting symbols.
2781 else if(object->mh == NULL && (
2782 object->mh64->cputype == CPU_TYPE_X86_64) &&
2783 object->mh64->filetype == MH_OBJECT){
2784 if(n_strx != 0)
2785 new_strsize += strlen(strings + n_strx) + 1;
2786 new_nlocalsym++;
2787 new_nsyms++;
2788 saves[i] = new_nsyms;
2791 * The cases a local symbol might be saved are with -X, -S, -t,
2792 * or with -d filename.
2794 else if((!strip_all && (Xflag || tflag || Sflag)) || dfile){
2795 if(n_type & N_STAB){ /* debug symbol */
2796 if(dfile && n_type == N_SO){
2797 if(n_strx != 0){
2798 basename = strrchr(strings + n_strx, '/');
2799 if(basename != NULL)
2800 basename++;
2801 else
2802 basename = strings + n_strx;
2803 pp = bsearch(basename, debug_filenames,
2804 ndebug_filenames, sizeof(char *),
2805 (int (*)(const void *, const void *)
2806 )cmp_bsearch_filename);
2808 * Save the bracketing N_SO. For each N_SO that
2809 * has a filename there is an N_SO that has a
2810 * name of "" which ends the stabs for that file
2812 if(*basename != '\0'){
2813 if(pp != NULL)
2814 save_debug = 1;
2815 else
2816 save_debug = 0;
2818 else{
2820 * This is a bracketing SO so if we are
2821 * currently saving debug symbols save this
2822 * last one and turn off saving debug syms.
2824 if(save_debug){
2825 if(n_strx != 0)
2826 new_strsize += strlen(strings +
2827 n_strx) + 1;
2828 new_nlocalsym++;
2829 new_nsyms++;
2830 saves[i] = new_nsyms;
2832 save_debug = 0;
2835 else{
2836 save_debug = 0;
2839 if(saves[i] == 0 && (!Sflag || save_debug)){
2840 if(n_strx != 0)
2841 new_strsize += strlen(strings + n_strx) + 1;
2842 new_nlocalsym++;
2843 new_nsyms++;
2844 saves[i] = new_nsyms;
2847 else{ /* non-debug local symbol */
2848 if(xflag == 0 && (Sflag || Xflag || tflag)){
2850 * No -x (strip all local), and one of -S (strip
2851 * debug), -X (strip 'L' local), or -t (strip
2852 * local except non-'L' text) was given.
2854 if((Xflag && n_strx != 0 &&
2855 strings[n_strx] != 'L') ||
2856 (tflag && (n_type & N_TYPE) == N_SECT &&
2857 n_sect == text_nsect && n_strx != 0 &&
2858 strings[n_strx] != 'L') ||
2859 (Sflag && !Xflag && !tflag)) {
2861 * If this file is a for the dynamic linker and
2862 * this symbol is in a section marked so that
2863 * static symbols are stripped then don't
2864 * keep this symbol.
2866 if((mh_flags & MH_DYLDLINK) != MH_DYLDLINK ||
2867 (n_type & N_TYPE) != N_SECT ||
2868 (s_flags & S_ATTR_STRIP_STATIC_SYMS) !=
2869 S_ATTR_STRIP_STATIC_SYMS){
2870 new_strsize += strlen(strings + n_strx) + 1;
2871 new_nlocalsym++;
2872 new_nsyms++;
2873 saves[i] = new_nsyms;
2878 * Treat a local symbol that was a private extern as if
2879 * were global if it is referenced by a module and save
2880 * it.
2882 if((n_type & N_PEXT) == N_PEXT){
2883 if(saves[i] == 0 &&
2884 private_extern_reference_by_module(
2885 i, refs ,nextrefsyms) == TRUE){
2886 if(n_strx != 0)
2887 new_strsize += strlen(strings + n_strx) + 1;
2888 new_nlocalsym++;
2889 new_nsyms++;
2890 saves[i] = new_nsyms;
2893 * We need to save symbols that were private externs
2894 * that are used with indirect symbols.
2896 if(saves[i] == 0 &&
2897 symbol_pointer_used(i, indirectsyms,
2898 nindirectsyms) == TRUE){
2899 if(n_strx != 0){
2900 len = strlen(strings + n_strx) + 1;
2901 new_strsize += len;
2903 new_nlocalsym++;
2904 new_nsyms++;
2905 saves[i] = new_nsyms;
2911 * Treat a local symbol that was a private extern as if were
2912 * global if it is not referenced by a module.
2914 else if((n_type & N_PEXT) == N_PEXT){
2915 if(saves[i] == 0 && sfile){
2916 sp = bsearch(strings + n_strx,
2917 save_symbols, nsave_symbols,
2918 sizeof(struct symbol_list),
2919 (int (*)(const void *, const void *))
2920 symbol_list_bsearch);
2921 if(sp != NULL){
2922 if(sp->sym == NULL){
2923 if(object->mh != NULL)
2924 sp->sym = &(symbols[i]);
2925 else
2926 sp->sym = &(symbols64[i]);
2927 sp->seen = TRUE;
2929 if(n_strx != 0)
2930 new_strsize += strlen(strings + n_strx) + 1;
2931 new_nlocalsym++;
2932 new_nsyms++;
2933 saves[i] = new_nsyms;
2936 if(saves[i] == 0 &&
2937 private_extern_reference_by_module(
2938 i, refs ,nextrefsyms) == TRUE){
2939 if(n_strx != 0)
2940 new_strsize += strlen(strings + n_strx) + 1;
2941 new_nlocalsym++;
2942 new_nsyms++;
2943 saves[i] = new_nsyms;
2946 * We need to save symbols that were private externs that
2947 * are used with indirect symbols.
2949 if(saves[i] == 0 &&
2950 symbol_pointer_used(i, indirectsyms, nindirectsyms) ==
2951 TRUE){
2952 if(n_strx != 0){
2953 len = strlen(strings + n_strx) + 1;
2954 new_strsize += len;
2956 new_nlocalsym++;
2957 new_nsyms++;
2958 saves[i] = new_nsyms;
2962 else{ /* global symbol */
2964 * strip -R on an x86_64 .o file should do nothing.
2966 if(Rfile &&
2967 (object->mh != NULL ||
2968 object->mh64->cputype != CPU_TYPE_X86_64 ||
2969 object->mh64->filetype != MH_OBJECT)){
2970 sp = bsearch(strings + n_strx,
2971 remove_symbols, nremove_symbols,
2972 sizeof(struct symbol_list),
2973 (int (*)(const void *, const void *))
2974 symbol_list_bsearch);
2975 if(sp != NULL){
2976 if((n_type & N_TYPE) == N_UNDF ||
2977 (n_type & N_TYPE) == N_PBUD){
2978 error_arch(arch, member, "symbol: %s undefined"
2979 " and can't be stripped from: ",
2980 sp->name);
2982 else if(sp->sym != NULL){
2983 sym = (struct nlist *)sp->sym;
2984 if((sym->n_type & N_PEXT) != N_PEXT)
2985 error_arch(arch, member, "more than one symbol "
2986 "for: %s found in: ", sp->name);
2988 else{
2989 if(object->mh != NULL)
2990 sp->sym = &(symbols[i]);
2991 else
2992 sp->sym = &(symbols64[i]);
2993 sp->seen = TRUE;
2995 if(n_desc & REFERENCED_DYNAMICALLY){
2996 error_arch(arch, member, "symbol: %s is dynamically"
2997 " referenced and can't be stripped "
2998 "from: ", sp->name);
3000 if((n_type & N_TYPE) == N_SECT &&
3001 (s_flags & SECTION_TYPE) == S_COALESCED){
3002 error_arch(arch, member, "symbol: %s is a global "
3003 "coalesced symbol and can't be "
3004 "stripped from: ", sp->name);
3006 /* don't save this symbol */
3007 continue;
3010 if(Aflag && (n_type & N_TYPE) == N_ABS &&
3011 (n_value != 0 ||
3012 (n_strx != 0 &&
3013 strncmp(strings + n_strx,
3014 ".objc_class_name_",
3015 sizeof(".objc_class_name_") - 1) == 0))){
3016 len = strlen(strings + n_strx) + 1;
3017 new_strsize += len;
3018 new_ext_strsize += len;
3019 new_nextdefsym++;
3020 new_nsyms++;
3021 saves[i] = new_nsyms;
3023 if(saves[i] == 0 && (uflag || default_dyld_executable) &&
3024 ((((n_type & N_TYPE) == N_UNDF) &&
3025 n_value == 0) ||
3026 (n_type & N_TYPE) == N_PBUD)){
3027 if(n_strx != 0){
3028 len = strlen(strings + n_strx) + 1;
3029 new_strsize += len;
3030 new_ext_strsize += len;
3032 new_nundefsym++;
3033 new_nsyms++;
3034 saves[i] = new_nsyms;
3036 if(saves[i] == 0 && nflag &&
3037 (n_type & N_TYPE) == N_SECT){
3038 if(n_strx != 0){
3039 len = strlen(strings + n_strx) + 1;
3040 new_strsize += len;
3041 new_ext_strsize += len;
3043 new_nextdefsym++;
3044 new_nsyms++;
3045 saves[i] = new_nsyms;
3047 if(saves[i] == 0 && sfile){
3048 sp = bsearch(strings + n_strx,
3049 save_symbols, nsave_symbols,
3050 sizeof(struct symbol_list),
3051 (int (*)(const void *, const void *))
3052 symbol_list_bsearch);
3053 if(sp != NULL){
3054 if(sp->sym != NULL){
3055 sym = (struct nlist *)sp->sym;
3056 if((sym->n_type & N_PEXT) != N_PEXT)
3057 error_arch(arch, member, "more than one symbol "
3058 "for: %s found in: ", sp->name);
3060 else{
3061 if(object->mh != NULL)
3062 sp->sym = &(symbols[i]);
3063 else
3064 sp->sym = &(symbols64[i]);
3065 sp->seen = TRUE;
3066 len = strlen(strings + n_strx) + 1;
3067 new_strsize += len;
3068 new_ext_strsize += len;
3069 if((n_type & N_TYPE) == N_UNDF ||
3070 (n_type & N_TYPE) == N_PBUD)
3071 new_nundefsym++;
3072 else
3073 new_nextdefsym++;
3074 new_nsyms++;
3075 saves[i] = new_nsyms;
3080 * We only need to save coalesced symbols that are used as
3081 * indirect symbols in 32-bit applications.
3083 * In 64-bit applications, we only need to save coalesced
3084 * symbols that are used as weak definitions.
3086 if(object->mh != NULL &&
3087 saves[i] == 0 &&
3088 (n_type & N_TYPE) == N_SECT &&
3089 (s_flags & SECTION_TYPE) == S_COALESCED &&
3090 symbol_pointer_used(i, indirectsyms, nindirectsyms) == TRUE){
3091 if(n_strx != 0){
3092 len = strlen(strings + n_strx) + 1;
3093 new_strsize += len;
3094 new_ext_strsize += len;
3096 new_nextdefsym++;
3097 new_nsyms++;
3098 saves[i] = new_nsyms;
3100 if(saves[i] == 0 &&
3101 (n_type & N_TYPE) == N_SECT &&
3102 (n_desc & N_WEAK_DEF) != 0){
3103 if(n_strx != 0){
3104 len = strlen(strings + n_strx) + 1;
3105 new_strsize += len;
3106 new_ext_strsize += len;
3108 new_nextdefsym++;
3109 new_nsyms++;
3110 saves[i] = new_nsyms;
3112 if(saves[i] == 0 &&
3113 ((Xflag || Sflag || xflag || tflag || aflag) ||
3114 ((rflag || default_dyld_executable) &&
3115 n_desc & REFERENCED_DYNAMICALLY))){
3116 len = strlen(strings + n_strx) + 1;
3117 new_strsize += len;
3118 new_ext_strsize += len;
3119 if((n_type & N_TYPE) == N_INDR){
3120 len = strlen(strings + n_value) + 1;
3121 new_strsize += len;
3122 new_ext_strsize += len;
3124 if((n_type & N_TYPE) == N_UNDF ||
3125 (n_type & N_TYPE) == N_PBUD)
3126 new_nundefsym++;
3127 else
3128 new_nextdefsym++;
3129 new_nsyms++;
3130 saves[i] = new_nsyms;
3133 * For x86_64 .o files we have run ld -r on them and are stuck
3134 * keeping all resulting symbols.
3136 if(saves[i] == 0 &&
3137 object->mh == NULL &&
3138 object->mh64->cputype == CPU_TYPE_X86_64 &&
3139 object->mh64->filetype == MH_OBJECT){
3140 len = strlen(strings + n_strx) + 1;
3141 new_strsize += len;
3142 new_ext_strsize += len;
3143 if((n_type & N_TYPE) == N_INDR){
3144 len = strlen(strings + n_value) + 1;
3145 new_strsize += len;
3146 new_ext_strsize += len;
3148 if((n_type & N_TYPE) == N_UNDF ||
3149 (n_type & N_TYPE) == N_PBUD)
3150 new_nundefsym++;
3151 else
3152 new_nextdefsym++;
3153 new_nsyms++;
3154 saves[i] = new_nsyms;
3159 * The module table's module names are placed with the external strings.
3160 * So size them and add this to the external string size.
3162 for(i = 0; i < nmodtab; i++){
3163 if(object->mh != NULL)
3164 module_name = mods[i].module_name;
3165 else
3166 module_name = mods64[i].module_name;
3167 if(module_name == 0 || module_name > strsize){
3168 error_arch(arch, member, "bad string index for module_name "
3169 "of module table entry %d in: ", i);
3170 return(FALSE);
3172 len = strlen(strings + module_name) + 1;
3173 new_strsize += len;
3174 new_ext_strsize += len;
3178 * Updating the reference table may require a symbol not yet listed as
3179 * as saved to be present in the output file. If a defined external
3180 * symbol is removed and there is a undefined reference to it in the
3181 * reference table an undefined symbol needs to be created for it in
3182 * the output file. If this happens the number of new symbols and size
3183 * of the new strings are adjusted. And the array changes[] is set to
3184 * map the old symbol index to the new symbol index for the symbol that
3185 * is changed to an undefined symbol.
3187 missing_symbols = 0;
3188 if(ref_saves != NULL)
3189 free(ref_saves);
3190 ref_saves = (int32_t *)allocate(nextrefsyms * sizeof(int32_t));
3191 bzero(ref_saves, nextrefsyms * sizeof(int32_t));
3192 changes = (uint32_t *)allocate(nsyms * sizeof(int32_t));
3193 bzero(changes, nsyms * sizeof(int32_t));
3194 new_nextrefsyms = 0;
3195 for(i = 0; i < nextrefsyms; i++){
3196 if(refs[i].isym > nsyms){
3197 error_arch(arch, member, "bad symbol table index for "
3198 "reference table entry %d in: ", i);
3199 return(FALSE);
3201 if(saves[refs[i].isym]){
3202 new_nextrefsyms++;
3203 ref_saves[i] = new_nextrefsyms;
3205 else{
3206 if(refs[i].flags == REFERENCE_FLAG_UNDEFINED_NON_LAZY ||
3207 refs[i].flags == REFERENCE_FLAG_UNDEFINED_LAZY){
3208 if(changes[refs[i].isym] == 0){
3209 if(object->mh != NULL)
3210 n_strx = symbols[refs[i].isym].n_un.n_strx;
3211 else
3212 n_strx = symbols64[refs[i].isym].n_un.n_strx;
3213 len = strlen(strings + n_strx) + 1;
3214 new_strsize += len;
3215 new_ext_strsize += len;
3216 new_nundefsym++;
3217 new_nsyms++;
3218 changes[refs[i].isym] = new_nsyms;
3219 new_nextrefsyms++;
3220 ref_saves[i] = new_nextrefsyms;
3223 else{
3224 if(refs[i].flags ==
3225 REFERENCE_FLAG_PRIVATE_UNDEFINED_NON_LAZY ||
3226 refs[i].flags == REFERENCE_FLAG_PRIVATE_UNDEFINED_LAZY){
3227 if(missing_symbols == 0){
3228 error_arch(arch, member, "private extern symbols "
3229 "referenced by modules can't be stripped in: ");
3230 missing_symbols = 1;
3232 if(object->mh != NULL)
3233 n_strx = symbols[refs[i].isym].n_un.n_strx;
3234 else
3235 n_strx = symbols64[refs[i].isym].n_un.n_strx;
3236 fprintf(stderr, "%s\n", strings + n_strx);
3237 saves[refs[i].isym] = -1;
3242 if(missing_symbols == 1)
3243 return(FALSE);
3245 if(member == NULL){
3246 missing_syms = 0;
3247 if(iflag == 0){
3248 for(i = 0; i < nsave_symbols; i++){
3249 if(save_symbols[i].sym == NULL){
3250 if(missing_syms == 0){
3251 error_arch(arch, member, "symbols names listed "
3252 "in: %s not in: ", sfile);
3253 missing_syms = 1;
3255 fprintf(stderr, "%s\n", save_symbols[i].name);
3259 missing_syms = 0;
3261 * strip -R on an x86_64 .o file should do nothing.
3263 if(iflag == 0 &&
3264 (object->mh != NULL ||
3265 object->mh64->cputype != CPU_TYPE_X86_64 ||
3266 object->mh64->filetype != MH_OBJECT)){
3267 for(i = 0; i < nremove_symbols; i++){
3268 if(remove_symbols[i].sym == NULL){
3269 if(missing_syms == 0){
3270 error_arch(arch, member, "symbols names listed "
3271 "in: %s not in: ", Rfile);
3272 missing_syms = 1;
3274 fprintf(stderr, "%s\n", remove_symbols[i].name);
3281 * If there is a chance that we could end up with an indirect symbol
3282 * with an index of zero we need to avoid that due to a work around
3283 * in the dynamic linker for a bug it is working around that was in
3284 * the old classic static linker. See radar bug 5614542 and the
3285 * related bugs 3685312 and 3534709.
3287 * A reasonable way to do this to know that local symbols are first in
3288 * the symbol table. So if we have any local symbols this won't happen
3289 * and if there are no indirect symbols it will also not happen. Past
3290 * that we'll just add a local symbol so it will end up at symbol index
3291 * zero and avoid any indirect symbol having that index.
3293 * If one really wanted they could build up the new symbol table then
3294 * look at all the indirect symbol table entries to see if any of them
3295 * have an index of zero then in that case throw that new symbol table
3296 * away and rebuild the symbol and string table once again after adding
3297 * a local symbol. This seems not all that resonable to save one symbol
3298 * table entry and a few bytes in the string table for the complexity it
3299 * would add and what it would save.
3301 if(new_nlocalsym == 0 && nindirectsyms != 0){
3302 len = strlen("radr://5614542") + 1;
3303 new_strsize += len;
3304 new_nlocalsym++;
3305 new_nsyms++;
3306 hack_5614542 = TRUE;
3308 else{
3309 hack_5614542 = FALSE;
3312 if(object->mh != NULL){
3313 new_symbols = (struct nlist *)
3314 allocate(new_nsyms * sizeof(struct nlist));
3315 new_symbols64 = NULL;
3317 else{
3318 new_symbols = NULL;
3319 new_symbols64 = (struct nlist_64 *)
3320 allocate(new_nsyms * sizeof(struct nlist_64));
3322 if(object->mh != NULL)
3323 new_strsize = rnd(new_strsize, sizeof(int32_t));
3324 else
3325 new_strsize = rnd(new_strsize, sizeof(int64_t));
3326 new_strings = (char *)allocate(new_strsize);
3327 if(object->mh != NULL){
3328 new_strings[new_strsize - 3] = '\0';
3329 new_strings[new_strsize - 2] = '\0';
3330 new_strings[new_strsize - 1] = '\0';
3332 else{
3333 new_strings[new_strsize - 7] = '\0';
3334 new_strings[new_strsize - 6] = '\0';
3335 new_strings[new_strsize - 5] = '\0';
3336 new_strings[new_strsize - 4] = '\0';
3337 new_strings[new_strsize - 3] = '\0';
3338 new_strings[new_strsize - 2] = '\0';
3339 new_strings[new_strsize - 1] = '\0';
3342 memset(new_strings, '\0', sizeof(int32_t));
3343 p = new_strings + sizeof(int32_t);
3344 q = p + new_ext_strsize;
3347 * If all strings were stripped set the size to zero but only for 32-bit
3348 * because the unified linker seems to set the filesize of empty .o
3349 * files to include the string table.
3351 if(object->mh != NULL && new_strsize == sizeof(int32_t))
3352 new_strsize = 0;
3355 * Now create a symbol table and string table in this order
3356 * symbol table
3357 * local symbols
3358 * external defined symbols
3359 * undefined symbols
3360 * string table
3361 * external strings
3362 * local strings
3364 inew_syms = 0;
3367 * If we are doing the hack for radar bug 5614542 (see above) add the
3368 * one local symbol and string.
3370 * We use an N_OPT stab which should be safe to use and not mess any
3371 * thing up. In Mac OS X, gcc(1) writes one N_OPT stab saying the file
3372 * is compiled with gcc(1). Then gdb(1) looks for that stab, but it
3373 * also looks at the name. If the name string is "gcc_compiled" or
3374 * "gcc2_compiled" gdb(1) sets its "compiled by gcc flag. If the N_OPT
3375 * is emitted INSIDE an N_SO section, then gdb(1) thinks that object
3376 * module was compiled by Sun's compiler, which apparently sticks one
3377 * outermost N_LBRAC/N_RBRAC pair, which gdb(1) strips off. But if the
3378 * N_OPT comes before any N_SO stabs, then gdb(1) will just ignore it.
3379 * Since this N_OPT is the first local symbol, it will always come
3380 * before any N_SO stabs that might be around and should be fine.
3382 if(hack_5614542 == TRUE){
3383 if(object->mh != NULL){
3384 new_symbols[inew_syms].n_type = N_OPT;
3385 new_symbols[inew_syms].n_sect = NO_SECT;
3386 new_symbols[inew_syms].n_desc = 0;
3387 new_symbols[inew_syms].n_value = 0x05614542;
3389 else{
3390 new_symbols64[inew_syms].n_type = N_OPT;
3391 new_symbols64[inew_syms].n_sect = NO_SECT;
3392 new_symbols64[inew_syms].n_desc = 0;
3393 new_symbols64[inew_syms].n_value = 0x05614542;
3395 strcpy(q, "radr://5614542");
3396 if(object->mh != NULL)
3397 new_symbols[inew_syms].n_un.n_strx =
3398 q - new_strings;
3399 else
3400 new_symbols64[inew_syms].n_un.n_strx =
3401 q - new_strings;
3402 q += strlen(q) + 1;
3403 inew_syms++;
3406 for(i = 0; i < nsyms; i++){
3407 if(saves[i]){
3408 if(object->mh != NULL){
3409 n_strx = symbols[i].n_un.n_strx;
3410 n_type = symbols[i].n_type;
3412 else{
3413 n_strx = symbols64[i].n_un.n_strx;
3414 n_type = symbols64[i].n_type;
3416 if((n_type & N_EXT) == 0){
3417 if(object->mh != NULL)
3418 new_symbols[inew_syms] = symbols[i];
3419 else
3420 new_symbols64[inew_syms] = symbols64[i];
3421 if(n_strx != 0){
3422 strcpy(q, strings + n_strx);
3423 if(object->mh != NULL)
3424 new_symbols[inew_syms].n_un.n_strx =
3425 q - new_strings;
3426 else
3427 new_symbols64[inew_syms].n_un.n_strx =
3428 q - new_strings;
3429 q += strlen(q) + 1;
3431 inew_syms++;
3432 saves[i] = inew_syms;
3436 #ifdef TRIE_SUPPORT
3437 inew_nextdefsym = inew_syms;
3438 #endif /* TRIE_SUPPORT */
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;
3444 n_value = symbols[i].n_value;
3446 else{
3447 n_strx = symbols64[i].n_un.n_strx;
3448 n_type = symbols64[i].n_type;
3449 n_value = symbols64[i].n_value;
3451 if((n_type & N_EXT) == N_EXT &&
3452 ((n_type & N_TYPE) != N_UNDF &&
3453 (n_type & N_TYPE) != N_PBUD)){
3454 if(object->mh != NULL)
3455 new_symbols[inew_syms] = symbols[i];
3456 else
3457 new_symbols64[inew_syms] = symbols64[i];
3458 if(n_strx != 0){
3459 strcpy(p, strings + n_strx);
3460 if(object->mh != NULL)
3461 new_symbols[inew_syms].n_un.n_strx =
3462 p - new_strings;
3463 else
3464 new_symbols64[inew_syms].n_un.n_strx =
3465 p - new_strings;
3466 p += strlen(p) + 1;
3468 if((n_type & N_TYPE) == N_INDR){
3469 if(n_value != 0){
3470 strcpy(p, strings + n_value);
3471 if(object->mh != NULL)
3472 new_symbols[inew_syms].n_value =
3473 p - new_strings;
3474 else
3475 new_symbols64[inew_syms].n_value =
3476 p - new_strings;
3477 p += strlen(p) + 1;
3480 inew_syms++;
3481 saves[i] = inew_syms;
3486 * Build the new undefined symbols into a map and sort it.
3488 inew_undefsyms = 0;
3489 if(object->mh != NULL){
3490 undef_map = (struct undef_map *)allocate(new_nundefsym *
3491 sizeof(struct undef_map));
3492 undef_map64 = NULL;
3494 else{
3495 undef_map = NULL;
3496 undef_map64 = (struct undef_map64 *)allocate(new_nundefsym *
3497 sizeof(struct undef_map64));
3499 for(i = 0; i < nsyms; i++){
3500 if(saves[i]){
3501 if(object->mh != NULL){
3502 n_strx = symbols[i].n_un.n_strx;
3503 n_type = symbols[i].n_type;
3505 else{
3506 n_strx = symbols64[i].n_un.n_strx;
3507 n_type = symbols64[i].n_type;
3509 if((n_type & N_EXT) == N_EXT &&
3510 ((n_type & N_TYPE) == N_UNDF ||
3511 (n_type & N_TYPE) == N_PBUD)){
3512 if(object->mh != NULL)
3513 undef_map[inew_undefsyms].symbol = symbols[i];
3514 else
3515 undef_map64[inew_undefsyms].symbol64 = symbols64[i];
3516 if(n_strx != 0){
3517 strcpy(p, strings + n_strx);
3518 if(object->mh != NULL)
3519 undef_map[inew_undefsyms].symbol.n_un.n_strx =
3520 p - new_strings;
3521 else
3522 undef_map64[inew_undefsyms].symbol64.n_un.n_strx =
3523 p - new_strings;
3524 p += strlen(p) + 1;
3526 if(object->mh != NULL)
3527 undef_map[inew_undefsyms].index = i;
3528 else
3529 undef_map64[inew_undefsyms].index = i;
3530 inew_undefsyms++;
3534 for(i = 0; i < nsyms; i++){
3535 if(changes[i]){
3536 if(object->mh != NULL)
3537 n_strx = symbols[i].n_un.n_strx;
3538 else
3539 n_strx = symbols64[i].n_un.n_strx;
3540 if(n_strx != 0){
3541 strcpy(p, strings + n_strx);
3542 if(object->mh != NULL)
3543 undef_map[inew_undefsyms].symbol.n_un.n_strx =
3544 p - new_strings;
3545 else
3546 undef_map64[inew_undefsyms].symbol64.n_un.n_strx =
3547 p - new_strings;
3548 p += strlen(p) + 1;
3550 if(object->mh != NULL){
3551 undef_map[inew_undefsyms].symbol.n_type = N_UNDF | N_EXT;
3552 undef_map[inew_undefsyms].symbol.n_sect = NO_SECT;
3553 undef_map[inew_undefsyms].symbol.n_desc = 0;
3554 undef_map[inew_undefsyms].symbol.n_value = 0;
3555 undef_map[inew_undefsyms].index = i;
3557 else{
3558 undef_map64[inew_undefsyms].symbol64.n_type = N_UNDF |N_EXT;
3559 undef_map64[inew_undefsyms].symbol64.n_sect = NO_SECT;
3560 undef_map64[inew_undefsyms].symbol64.n_desc = 0;
3561 undef_map64[inew_undefsyms].symbol64.n_value = 0;
3562 undef_map64[inew_undefsyms].index = i;
3564 inew_undefsyms++;
3567 /* Sort the undefined symbols by name */
3568 qsort_strings = new_strings;
3569 if(object->mh != NULL)
3570 qsort(undef_map, new_nundefsym, sizeof(struct undef_map),
3571 (int (*)(const void *, const void *))cmp_qsort_undef_map);
3572 else
3573 qsort(undef_map64, new_nundefsym, sizeof(struct undef_map64),
3574 (int (*)(const void *, const void *))cmp_qsort_undef_map_64);
3575 /* Copy the symbols now in sorted order into new_symbols */
3576 for(i = 0; i < new_nundefsym; i++){
3577 if(object->mh != NULL){
3578 new_symbols[inew_syms] = undef_map[i].symbol;
3579 inew_syms++;
3580 saves[undef_map[i].index] = inew_syms;
3582 else{
3583 new_symbols64[inew_syms] = undef_map64[i].symbol64;
3584 inew_syms++;
3585 saves[undef_map64[i].index] = inew_syms;
3590 * Fixup the module table's module name strings adding them to the
3591 * string table. Also fix the indexes into the symbol table for
3592 * external and local symbols. And fix up the indexes into the
3593 * reference table.
3595 for(i = 0; i < nmodtab; i++){
3596 if(object->mh != NULL){
3597 strcpy(p, strings + mods[i].module_name);
3598 mods[i].module_name = p - new_strings;
3599 iextdefsym = mods[i].iextdefsym;
3600 nextdefsym = mods[i].nextdefsym;
3601 ilocalsym = mods[i].ilocalsym;
3602 nlocalsym = mods[i].nlocalsym;
3603 irefsym = mods[i].irefsym;
3604 nrefsym = mods[i].nrefsym;
3606 else{
3607 strcpy(p, strings + mods64[i].module_name);
3608 mods64[i].module_name = p - new_strings;
3609 iextdefsym = mods64[i].iextdefsym;
3610 nextdefsym = mods64[i].nextdefsym;
3611 ilocalsym = mods64[i].ilocalsym;
3612 nlocalsym = mods64[i].nlocalsym;
3613 irefsym = mods64[i].irefsym;
3614 nrefsym = mods64[i].nrefsym;
3616 p += strlen(p) + 1;
3618 if(iextdefsym > nsyms){
3619 error_arch(arch, member, "bad index into externally defined "
3620 "symbols of module table entry %d in: ", i);
3621 return(FALSE);
3623 if(iextdefsym + nextdefsym > nsyms){
3624 error_arch(arch, member, "bad number of externally defined "
3625 "symbols of module table entry %d in: ", i);
3626 return(FALSE);
3628 for(j = iextdefsym; j < iextdefsym + nextdefsym; j++){
3629 if(saves[j] != 0 && changes[j] == 0)
3630 break;
3632 n = 0;
3633 for(k = j; k < iextdefsym + nextdefsym; k++){
3634 if(saves[k] != 0 && changes[k] == 0)
3635 n++;
3637 if(n == 0){
3638 if(object->mh != NULL){
3639 mods[i].iextdefsym = 0;
3640 mods[i].nextdefsym = 0;
3642 else{
3643 mods64[i].iextdefsym = 0;
3644 mods64[i].nextdefsym = 0;
3647 else{
3648 if(object->mh != NULL){
3649 mods[i].iextdefsym = saves[j] - 1;
3650 mods[i].nextdefsym = n;
3652 else{
3653 mods64[i].iextdefsym = saves[j] - 1;
3654 mods64[i].nextdefsym = n;
3658 if(ilocalsym > nsyms){
3659 error_arch(arch, member, "bad index into symbols for local "
3660 "symbols of module table entry %d in: ", i);
3661 return(FALSE);
3663 if(ilocalsym + nlocalsym > nsyms){
3664 error_arch(arch, member, "bad number of local "
3665 "symbols of module table entry %d in: ", i);
3666 return(FALSE);
3668 for(j = ilocalsym; j < ilocalsym + nlocalsym; j++){
3669 if(saves[j] != 0)
3670 break;
3672 n = 0;
3673 for(k = j; k < ilocalsym + nlocalsym; k++){
3674 if(saves[k] != 0)
3675 n++;
3677 if(n == 0){
3678 if(object->mh != NULL){
3679 mods[i].ilocalsym = 0;
3680 mods[i].nlocalsym = 0;
3682 else{
3683 mods64[i].ilocalsym = 0;
3684 mods64[i].nlocalsym = 0;
3687 else{
3688 if(object->mh != NULL){
3689 mods[i].ilocalsym = saves[j] - 1;
3690 mods[i].nlocalsym = n;
3692 else{
3693 mods64[i].ilocalsym = saves[j] - 1;
3694 mods64[i].nlocalsym = n;
3698 if(irefsym > nextrefsyms){
3699 error_arch(arch, member, "bad index into reference table "
3700 "of module table entry %d in: ", i);
3701 return(FALSE);
3703 if(irefsym + nrefsym > nextrefsyms){
3704 error_arch(arch, member, "bad number of reference table "
3705 "entries of module table entry %d in: ", i);
3706 return(FALSE);
3708 for(j = irefsym; j < irefsym + nrefsym; j++){
3709 if(ref_saves[j] != 0)
3710 break;
3712 n = 0;
3713 for(k = j; k < irefsym + nrefsym; k++){
3714 if(ref_saves[k] != 0)
3715 n++;
3717 if(n == 0){
3718 if(object->mh != NULL){
3719 mods[i].irefsym = 0;
3720 mods[i].nrefsym = 0;
3722 else{
3723 mods64[i].irefsym = 0;
3724 mods64[i].nrefsym = 0;
3727 else{
3728 if(object->mh != NULL){
3729 mods[i].irefsym = ref_saves[j] - 1;
3730 mods[i].nrefsym = n;
3732 else{
3733 mods64[i].irefsym = ref_saves[j] - 1;
3734 mods64[i].nrefsym = n;
3740 * Create a new reference table.
3742 new_refs = allocate(new_nextrefsyms * sizeof(struct dylib_reference));
3743 j = 0;
3744 for(i = 0; i < nextrefsyms; i++){
3745 if(ref_saves[i]){
3746 if(saves[refs[i].isym]){
3747 new_refs[j].isym = saves[refs[i].isym] - 1;
3748 new_refs[j].flags = refs[i].flags;
3750 else{
3751 if(refs[i].flags == REFERENCE_FLAG_UNDEFINED_NON_LAZY ||
3752 refs[i].flags == REFERENCE_FLAG_UNDEFINED_LAZY){
3753 new_refs[j].isym = changes[refs[i].isym] - 1;
3754 new_refs[j].flags = refs[i].flags;
3757 j++;
3762 * Create a new dylib table of contents.
3764 new_ntoc = 0;
3765 for(i = 0; i < ntoc; i++){
3766 if(tocs[i].symbol_index >= nsyms){
3767 error_arch(arch, member, "bad symbol index for table of "
3768 "contents table entry %d in: ", i);
3769 return(FALSE);
3771 if(saves[tocs[i].symbol_index] != 0 &&
3772 changes[tocs[i].symbol_index] == 0)
3773 new_ntoc++;
3775 new_tocs = allocate(new_ntoc * sizeof(struct dylib_table_of_contents));
3776 j = 0;
3777 for(i = 0; i < ntoc; i++){
3778 if(saves[tocs[i].symbol_index] != 0 &&
3779 changes[tocs[i].symbol_index] == 0){
3780 new_tocs[j].symbol_index = saves[tocs[i].symbol_index] - 1;
3781 new_tocs[j].module_index = tocs[i].module_index;
3782 j++;
3785 #ifdef TRIE_SUPPORT
3787 * Update the export trie if it has one but only call the the
3788 * prune_trie() routine when we are removing global symbols as is
3789 * done with default stripping of a dyld executable or with the -s
3790 * or -R options.
3792 if(object->dyld_info != NULL &&
3793 object->dyld_info->export_size != 0 &&
3794 (default_dyld_executable || sfile != NULL || Rfile != NULL)){
3795 const char *error_string;
3796 uint32_t trie_new_size;
3798 error_string = prune_trie((uint8_t *)(object->object_addr +
3799 object->dyld_info->export_off),
3800 object->dyld_info->export_size,
3801 prune,
3802 &trie_new_size);
3803 if(error_string != NULL){
3804 error_arch(arch, member, "%s", error_string);
3805 return(FALSE);
3808 #endif /* TRIE_SUPPORT */
3810 if(undef_map != NULL)
3811 free(undef_map);
3812 if(undef_map64 != NULL)
3813 free(undef_map64);
3814 if(changes != NULL)
3815 free(changes);
3816 if(sections != NULL)
3817 free(sections);
3818 if(sections64 != NULL)
3819 free(sections64);
3821 if(errors == 0)
3822 return(TRUE);
3823 else
3824 return(FALSE);
3827 #ifdef TRIE_SUPPORT
3829 * prune() is called by prune_trie() and passed a name of an external symbol
3830 * in the trie. It returns 1 if the symbols is to be pruned out and 0 if the
3831 * symbol is to be kept.
3833 * Note that it may seem like a linear search of the new symbols would not be
3834 * the best approach but in 10.6 the only defined global symbol left in a
3835 * stripped executable is __mh_execute_header and new_nextdefsym is usually 1
3836 * so this never actually loops in practice.
3838 static
3840 prune(
3841 const char *name)
3843 uint32_t i;
3845 for(i = 0; i < new_nextdefsym; i++){
3846 if(new_symbols != NULL){
3847 if(strcmp(name, new_strings + new_symbols[inew_nextdefsym + i]
3848 .n_un.n_strx) == 0)
3849 return(0);
3851 else{
3852 if(strcmp(name, new_strings + new_symbols64[inew_nextdefsym + i]
3853 .n_un.n_strx) == 0)
3854 return(0);
3857 return(1);
3859 #endif /* TRIE_SUPPORT */
3862 * make_ld_r_object() takes the object file contents referenced by the passed
3863 * data structures, writes that to a temporary file, runs "ld -r" plus the
3864 * specified stripping option creating a second temporary file, reads that file
3865 * in and replaces the object file contents with that and resets the variables
3866 * pointing to the symbol, string and indirect tables.
3868 static
3869 void
3870 make_ld_r_object(
3871 struct arch *arch,
3872 struct member *member,
3873 struct object *object)
3875 enum byte_sex host_byte_sex;
3876 char *input_file, *output_file;
3877 int fd;
3878 struct ofile *ld_r_ofile;
3879 struct arch *ld_r_archs;
3880 uint32_t ld_r_narchs, save_errors;
3882 host_byte_sex = get_host_byte_sex();
3885 * Swap the object file back into its bytesex before writing it to the
3886 * temporary file if needed.
3888 if(object->object_byte_sex != host_byte_sex){
3889 if(object->mh != NULL){
3890 if(swap_object_headers(object->mh, object->load_commands) ==
3891 FALSE)
3892 fatal("internal error: swap_object_headers() failed");
3893 swap_nlist(symbols, nsyms, object->object_byte_sex);
3895 else{
3896 if(swap_object_headers(object->mh64, object->load_commands) ==
3897 FALSE)
3898 fatal("internal error: swap_object_headers() failed");
3899 swap_nlist_64(symbols64, nsyms, object->object_byte_sex);
3901 swap_indirect_symbols(indirectsyms, nindirectsyms,
3902 object->object_byte_sex);
3906 * Create an input object file for the ld -r command from the bytes
3907 * of this arch's object file.
3909 input_file = makestr("/tmp/strip.XXXXXX", NULL);
3910 input_file = mktemp(input_file);
3912 if((fd = open(input_file, O_WRONLY|O_CREAT, 0600)) < 0)
3913 system_fatal("can't open temporary file: %s", input_file);
3915 if(write(fd, object->object_addr, object->object_size) !=
3916 object->object_size)
3917 system_fatal("can't write temporary file: %s", input_file);
3919 if(close(fd) == -1)
3920 system_fatal("can't close temporary file: %s", input_file);
3923 * Create a temporary name for the output file of the ld -r
3925 output_file = makestr("/tmp/strip.XXXXXX", NULL);
3926 output_file = mktemp(output_file);
3929 * Create the ld -r command line and execute it.
3931 reset_execute_list();
3932 add_execute_list_with_prefix("ld");
3933 add_execute_list("-keep_private_externs");
3934 add_execute_list("-r");
3935 if(Sflag)
3936 add_execute_list("-S");
3937 if(xflag)
3938 add_execute_list("-x");
3939 add_execute_list(input_file);
3940 add_execute_list("-o");
3941 add_execute_list(output_file);
3942 if(sfile != NULL){
3943 add_execute_list("-x");
3944 add_execute_list("-exported_symbols_list");
3945 add_execute_list(sfile);
3947 if(Rfile != NULL){
3948 add_execute_list("-unexported_symbols_list");
3949 add_execute_list(Rfile);
3951 if(execute_list(vflag) == 0)
3952 fatal("internal link edit command failed");
3954 save_errors = errors;
3955 errors = 0;
3956 /* breakout the output file of the ld -f for processing */
3957 ld_r_ofile = breakout(output_file, &ld_r_archs, &ld_r_narchs, FALSE);
3958 if(errors)
3959 goto make_ld_r_object_cleanup;
3961 /* checkout the file for symbol table replacement processing */
3962 checkout(ld_r_archs, ld_r_narchs);
3965 * Make sure the output of the ld -r is an object file with one arch.
3967 if(ld_r_narchs != 1 ||
3968 ld_r_archs->type != OFILE_Mach_O ||
3969 ld_r_archs->object == NULL ||
3970 ld_r_archs->object->mh_filetype != MH_OBJECT)
3971 fatal("internal link edit command failed to produce a thin Mach-O "
3972 "object file");
3975 * Now reset all the data of the input object with the ld -r output
3976 * object file.
3978 nsyms = ld_r_archs->object->st->nsyms;
3979 if(ld_r_archs->object->mh != NULL){
3980 symbols = (struct nlist *)
3981 (ld_r_archs->object->object_addr +
3982 ld_r_archs->object->st->symoff);
3983 if(ld_r_archs->object->object_byte_sex != host_byte_sex)
3984 swap_nlist(symbols, nsyms, host_byte_sex);
3985 symbols64 = NULL;
3987 else{
3988 symbols = NULL;
3989 symbols64 = (struct nlist_64 *)
3990 (ld_r_archs->object->object_addr +
3991 ld_r_archs->object->st->symoff);
3992 if(ld_r_archs->object->object_byte_sex != host_byte_sex)
3993 swap_nlist_64(symbols64, nsyms, host_byte_sex);
3995 strings = ld_r_archs->object->object_addr +
3996 ld_r_archs->object->st->stroff;
3997 strsize = ld_r_archs->object->st->strsize;
3999 if(ld_r_archs->object->dyst != NULL &&
4000 ld_r_archs->object->dyst->nindirectsyms != 0){
4001 nindirectsyms = ld_r_archs->object->dyst->nindirectsyms;
4002 indirectsyms = (uint32_t *)
4003 (ld_r_archs->object->object_addr +
4004 ld_r_archs->object->dyst->indirectsymoff);
4005 if(ld_r_archs->object->object_byte_sex != host_byte_sex)
4006 swap_indirect_symbols(indirectsyms, nindirectsyms,
4007 host_byte_sex);
4009 else{
4010 indirectsyms = NULL;
4011 nindirectsyms = 0;
4014 if(ld_r_archs->object->mh != NULL)
4015 ld_r_archs->object->input_sym_info_size =
4016 nsyms * sizeof(struct nlist) +
4017 strsize;
4018 else
4019 ld_r_archs->object->input_sym_info_size =
4020 nsyms * sizeof(struct nlist_64) +
4021 strsize;
4024 * Copy over the object struct from the ld -r object file onto the
4025 * input object file.
4027 *object = *ld_r_archs->object;
4030 * Save the ofile struct for the ld -r output so it can be umapped when
4031 * we are done. And free up the ld_r_archs now that we are done with
4032 * them.
4034 object->ld_r_ofile = ld_r_ofile;
4035 free_archs(ld_r_archs, ld_r_narchs);
4037 make_ld_r_object_cleanup:
4038 errors += save_errors;
4040 * Remove the input and output files and clean up.
4042 if(unlink(input_file) == -1)
4043 system_fatal("can't remove temporary file: %s", input_file);
4044 if(unlink(output_file) == -1)
4045 system_fatal("can't remove temporary file: %s", output_file);
4046 free(input_file);
4047 free(output_file);
4051 * strip_LC_UUID_commands() is called when -no_uuid is specified to remove any
4052 * LC_UUID load commands from the object's load commands.
4054 static
4055 void
4056 strip_LC_UUID_commands(
4057 struct arch *arch,
4058 struct member *member,
4059 struct object *object)
4061 uint32_t i, ncmds, nuuids, mh_sizeofcmds, sizeofcmds;
4062 struct load_command *lc1, *lc2, *new_load_commands;
4063 struct segment_command *sg;
4066 * See if there are any LC_UUID load commands.
4068 nuuids = 0;
4069 lc1 = arch->object->load_commands;
4070 if(arch->object->mh != NULL){
4071 ncmds = arch->object->mh->ncmds;
4072 mh_sizeofcmds = arch->object->mh->sizeofcmds;
4074 else{
4075 ncmds = arch->object->mh64->ncmds;
4076 mh_sizeofcmds = arch->object->mh64->sizeofcmds;
4078 for(i = 0; i < ncmds; i++){
4079 if(lc1->cmd == LC_UUID){
4080 nuuids++;
4082 lc1 = (struct load_command *)((char *)lc1 + lc1->cmdsize);
4084 /* if no LC_UUID load commands just return */
4085 if(nuuids == 0)
4086 return;
4089 * Allocate space for the new load commands as zero it out so any holes
4090 * will be zero bytes.
4092 new_load_commands = allocate(mh_sizeofcmds);
4093 memset(new_load_commands, '\0', mh_sizeofcmds);
4096 * Copy all the load commands except the LC_UUID load commands into the
4097 * allocated space for the new load commands.
4099 lc1 = arch->object->load_commands;
4100 lc2 = new_load_commands;
4101 sizeofcmds = 0;
4102 for(i = 0; i < ncmds; i++){
4103 if(lc1->cmd != LC_UUID){
4104 memcpy(lc2, lc1, lc1->cmdsize);
4105 sizeofcmds += lc2->cmdsize;
4106 lc2 = (struct load_command *)((char *)lc2 + lc2->cmdsize);
4108 lc1 = (struct load_command *)((char *)lc1 + lc1->cmdsize);
4112 * Finally copy the updated load commands over the existing load
4113 * commands.
4115 memcpy(arch->object->load_commands, new_load_commands, sizeofcmds);
4116 if(mh_sizeofcmds > sizeofcmds){
4117 memset((char *)arch->object->load_commands + sizeofcmds, '\0',
4118 (mh_sizeofcmds - sizeofcmds));
4120 ncmds -= nuuids;
4121 if(arch->object->mh != NULL) {
4122 arch->object->mh->sizeofcmds = sizeofcmds;
4123 arch->object->mh->ncmds = ncmds;
4124 } else {
4125 arch->object->mh64->sizeofcmds = sizeofcmds;
4126 arch->object->mh64->ncmds = ncmds;
4128 free(new_load_commands);
4130 /* reset the pointers into the load commands */
4131 lc1 = arch->object->load_commands;
4132 for(i = 0; i < ncmds; i++){
4133 switch(lc1->cmd){
4134 case LC_SYMTAB:
4135 arch->object->st = (struct symtab_command *)lc1;
4136 break;
4137 case LC_DYSYMTAB:
4138 arch->object->dyst = (struct dysymtab_command *)lc1;
4139 break;
4140 case LC_TWOLEVEL_HINTS:
4141 arch->object->hints_cmd = (struct twolevel_hints_command *)lc1;
4142 break;
4143 case LC_PREBIND_CKSUM:
4144 arch->object->cs = (struct prebind_cksum_command *)lc1;
4145 break;
4146 case LC_SEGMENT:
4147 sg = (struct segment_command *)lc1;
4148 if(strcmp(sg->segname, SEG_LINKEDIT) == 0)
4149 arch->object->seg_linkedit = sg;
4150 break;
4151 case LC_SEGMENT_SPLIT_INFO:
4152 object->split_info_cmd = (struct linkedit_data_command *)lc1;
4153 break;
4154 case LC_FUNCTION_STARTS:
4155 object->func_starts_info_cmd =
4156 (struct linkedit_data_command *)lc1;
4157 break;
4158 case LC_DATA_IN_CODE:
4159 object->data_in_code_cmd =
4160 (struct linkedit_data_command *)lc1;
4161 break;
4162 case LC_DYLIB_CODE_SIGN_DRS:
4163 object->code_sign_drs_cmd =
4164 (struct linkedit_data_command *)lc1;
4165 break;
4166 case LC_CODE_SIGNATURE:
4167 object->code_sig_cmd = (struct linkedit_data_command *)lc1;
4168 break;
4169 case LC_DYLD_INFO_ONLY:
4170 case LC_DYLD_INFO:
4171 object->dyld_info = (struct dyld_info_command *)lc1;
4173 lc1 = (struct load_command *)((char *)lc1 + lc1->cmdsize);
4177 #ifndef NMEDIT
4179 * strip_LC_CODE_SIGNATURE_commands() is called when -c is specified to remove
4180 * any LC_CODE_SIGNATURE load commands from the object's load commands.
4182 static
4183 void
4184 strip_LC_CODE_SIGNATURE_commands(
4185 struct arch *arch,
4186 struct member *member,
4187 struct object *object)
4189 uint32_t i, ncmds, mh_sizeofcmds, sizeofcmds;
4190 struct load_command *lc1, *lc2, *new_load_commands;
4191 struct segment_command *sg;
4194 * See if there is an LC_CODE_SIGNATURE load command and if no command
4195 * just return.
4197 if(object->code_sig_cmd == NULL)
4198 return;
4201 * Allocate space for the new load commands and zero it out so any holes
4202 * will be zero bytes.
4204 if(arch->object->mh != NULL){
4205 ncmds = arch->object->mh->ncmds;
4206 mh_sizeofcmds = arch->object->mh->sizeofcmds;
4208 else{
4209 ncmds = arch->object->mh64->ncmds;
4210 mh_sizeofcmds = arch->object->mh64->sizeofcmds;
4212 new_load_commands = allocate(mh_sizeofcmds);
4213 memset(new_load_commands, '\0', mh_sizeofcmds);
4216 * Copy all the load commands except the LC_CODE_SIGNATURE load commands
4217 * into the allocated space for the new load commands.
4219 lc1 = arch->object->load_commands;
4220 lc2 = new_load_commands;
4221 sizeofcmds = 0;
4222 for(i = 0; i < ncmds; i++){
4223 if(lc1->cmd != LC_CODE_SIGNATURE){
4224 memcpy(lc2, lc1, lc1->cmdsize);
4225 sizeofcmds += lc2->cmdsize;
4226 lc2 = (struct load_command *)((char *)lc2 + lc2->cmdsize);
4228 lc1 = (struct load_command *)((char *)lc1 + lc1->cmdsize);
4232 * Finally copy the updated load commands over the existing load
4233 * commands.
4235 memcpy(arch->object->load_commands, new_load_commands, sizeofcmds);
4236 if(mh_sizeofcmds > sizeofcmds){
4237 memset((char *)arch->object->load_commands + sizeofcmds, '\0',
4238 (mh_sizeofcmds - sizeofcmds));
4240 ncmds -= 1;
4241 if(arch->object->mh != NULL) {
4242 arch->object->mh->sizeofcmds = sizeofcmds;
4243 arch->object->mh->ncmds = ncmds;
4244 } else {
4245 arch->object->mh64->sizeofcmds = sizeofcmds;
4246 arch->object->mh64->ncmds = ncmds;
4248 free(new_load_commands);
4250 /* reset the pointers into the load commands */
4251 object->code_sig_cmd = NULL;
4252 lc1 = arch->object->load_commands;
4253 for(i = 0; i < ncmds; i++){
4254 switch(lc1->cmd){
4255 case LC_SYMTAB:
4256 arch->object->st = (struct symtab_command *)lc1;
4257 break;
4258 case LC_DYSYMTAB:
4259 arch->object->dyst = (struct dysymtab_command *)lc1;
4260 break;
4261 case LC_TWOLEVEL_HINTS:
4262 arch->object->hints_cmd = (struct twolevel_hints_command *)lc1;
4263 break;
4264 case LC_PREBIND_CKSUM:
4265 arch->object->cs = (struct prebind_cksum_command *)lc1;
4266 break;
4267 case LC_SEGMENT:
4268 sg = (struct segment_command *)lc1;
4269 if(strcmp(sg->segname, SEG_LINKEDIT) == 0)
4270 arch->object->seg_linkedit = sg;
4271 break;
4272 case LC_SEGMENT_SPLIT_INFO:
4273 object->split_info_cmd = (struct linkedit_data_command *)lc1;
4274 break;
4275 case LC_FUNCTION_STARTS:
4276 object->func_starts_info_cmd =
4277 (struct linkedit_data_command *)lc1;
4278 break;
4279 case LC_DATA_IN_CODE:
4280 object->data_in_code_cmd =
4281 (struct linkedit_data_command *)lc1;
4282 break;
4283 case LC_DYLIB_CODE_SIGN_DRS:
4284 object->code_sign_drs_cmd =
4285 (struct linkedit_data_command *)lc1;
4286 break;
4287 case LC_DYLD_INFO_ONLY:
4288 case LC_DYLD_INFO:
4289 object->dyld_info = (struct dyld_info_command *)lc1;
4291 lc1 = (struct load_command *)((char *)lc1 + lc1->cmdsize);
4294 if(cflag){
4296 * To get the right amount of the file copied out by writeout() for
4297 * the case when we are stripping out the section contents we
4298 * already reduce the object size by the size of the section
4299 * contents including the padding after the load commands. So here
4300 * we need to further reduce it by the load command for the
4301 * LC_CODE_SIGNATURE (a struct linkedit_data_command) we are
4302 * removing.
4304 object->object_size -= sizeof(struct linkedit_data_command);
4306 * Then this size minus the size of the input symbolic information
4307 * is what is copied out from the file by writeout(). Which in this
4308 * case is just the new headers.
4312 * Finally for -c the file offset to the link edit information is to
4313 * be right after the load commands. So reset this for the updated
4314 * size of the load commands without the LC_CODE_SIGNATURE.
4316 if(object->mh != NULL)
4317 object->seg_linkedit->fileoff = sizeof(struct mach_header) +
4318 sizeofcmds;
4319 else
4320 object->seg_linkedit64->fileoff =
4321 sizeof(struct mach_header_64) + sizeofcmds;
4324 #endif /* !(NMEDIT) */
4327 * private_extern_reference_by_module() is passed a symbol_index of a private
4328 * extern symbol and the module table. If the symbol_index appears in the
4329 * module symbol table this returns TRUE else it returns FALSE.
4331 static
4332 enum bool
4333 private_extern_reference_by_module(
4334 uint32_t symbol_index,
4335 struct dylib_reference *refs,
4336 uint32_t nextrefsyms)
4338 uint32_t i;
4340 for(i = 0; i < nextrefsyms; i++){
4341 if(refs[i].isym == symbol_index){
4342 if(refs[i].flags == REFERENCE_FLAG_PRIVATE_UNDEFINED_NON_LAZY ||
4343 refs[i].flags == REFERENCE_FLAG_PRIVATE_UNDEFINED_LAZY){
4344 return(TRUE);
4348 return(FALSE);
4352 * symbol_pointer_used() is passed a symbol_index and the indirect table. If
4353 * the symbol_index appears in the indirect symbol table this returns TRUE else
4354 * it returns FALSE.
4356 static
4357 enum bool
4358 symbol_pointer_used(
4359 uint32_t symbol_index,
4360 uint32_t *indirectsyms,
4361 uint32_t nindirectsyms)
4363 uint32_t i;
4365 for(i = 0; i < nindirectsyms; i++){
4366 if(indirectsyms[i] == symbol_index)
4367 return(TRUE);
4369 return(FALSE);
4373 * Function for qsort for comparing undefined map entries.
4375 static
4377 cmp_qsort_undef_map(
4378 const struct undef_map *sym1,
4379 const struct undef_map *sym2)
4381 return(strcmp(qsort_strings + sym1->symbol.n_un.n_strx,
4382 qsort_strings + sym2->symbol.n_un.n_strx));
4385 static
4387 cmp_qsort_undef_map_64(
4388 const struct undef_map64 *sym1,
4389 const struct undef_map64 *sym2)
4391 return(strcmp(qsort_strings + sym1->symbol64.n_un.n_strx,
4392 qsort_strings + sym2->symbol64.n_un.n_strx));
4394 #endif /* !defined(NMEDIT) */
4396 #ifndef NMEDIT
4398 * Function for qsort for comparing object names.
4400 static
4402 cmp_qsort_filename(
4403 const char **name1,
4404 const char **name2)
4406 return(strcmp(*name1, *name2));
4410 * Function for bsearch for finding a object name.
4412 static
4414 cmp_bsearch_filename(
4415 const char *name1,
4416 const char **name2)
4418 return(strcmp(name1, *name2));
4420 #endif /* !defined(NMEDIT) */
4422 #ifdef NMEDIT
4423 static
4424 enum bool
4425 edit_symtab(
4426 struct arch *arch,
4427 struct member *member,
4428 struct object *object,
4429 struct nlist *symbols,
4430 struct nlist_64 *symbols64,
4431 uint32_t nsyms,
4432 char *strings,
4433 uint32_t strsize,
4434 struct dylib_table_of_contents *tocs,
4435 uint32_t ntoc,
4436 struct dylib_module *mods,
4437 struct dylib_module_64 *mods64,
4438 uint32_t nmodtab,
4439 struct dylib_reference *refs,
4440 uint32_t nextrefsyms)
4442 uint32_t i, j, k;
4443 unsigned char data_n_sect, nsects;
4444 struct load_command *lc;
4445 struct segment_command *sg;
4446 struct segment_command_64 *sg64;
4447 struct section *s, **sections;
4448 struct section_64 *s64, **sections64;
4450 uint32_t missing_syms;
4451 struct symbol_list *sp;
4452 struct nlist **global_symbol;
4453 struct nlist_64 **global_symbol64;
4454 enum bool global_symbol_found;
4455 char *global_name, save_char;
4456 enum bool dwarf_debug_map;
4457 enum byte_sex host_byte_sex;
4458 int32_t missing_reloc_symbols;
4459 enum bool edit_symtab_return;
4461 char *p, *q;
4462 uint32_t new_ext_strsize, len, inew_syms;
4464 struct nlist **changed_globals;
4465 struct nlist_64 **changed_globals64;
4466 uint32_t nchanged_globals;
4467 uint32_t ncmds, s_flags, n_strx, module_name, ilocalsym, nlocalsym;
4468 uint32_t iextdefsym, nextdefsym;
4469 uint8_t n_type, n_sect, global_symbol_n_sect;
4470 uint64_t n_value;
4471 enum bool warned_about_global_coalesced_symbols;
4473 edit_symtab_return = TRUE;
4474 host_byte_sex = get_host_byte_sex();
4475 missing_reloc_symbols = 0;
4476 warned_about_global_coalesced_symbols = FALSE;
4478 if(nmedits != NULL)
4479 free(nmedits);
4480 nmedits = allocate(nsyms * sizeof(enum bool));
4481 for(i = 0; i < nsyms; i++)
4482 nmedits[i] = FALSE;
4485 * If nmedit is operating on a dynamic library then symbols are turned
4486 * into private externs with the extern bit off not into static symbols.
4488 if(object->mh_filetype == MH_DYLIB && pflag == TRUE){
4489 error_arch(arch, member, "can't use -p with dynamic libraries");
4490 return(FALSE);
4494 * As part of the MAJOR guess for the second pass to fix stabs for the
4495 * globals symbols that get turned into non-global symbols. We need to
4496 * change the stabs. To do this we to know if a N_GSYM is for a data
4497 * symbol or not to know to turn it into an N_STSYM or a N_FUN.
4498 * This logic as determined by compiling test cases with and without
4499 * the key word 'static' and looking at the difference between the STABS
4500 * the compiler generates and trying to match that here.
4502 * We also use this loop and the next to gather an array of section
4503 * struct pointers so we can later determine if we run into a global
4504 * symbol in a coalesced section and not turn those symbols into
4505 * statics.
4507 j = 0;
4508 nsects = 0;
4509 n_sect = 1;
4510 data_n_sect = NO_SECT;
4511 lc = object->load_commands;
4512 if(object->mh != NULL)
4513 ncmds = object->mh->ncmds;
4514 else
4515 ncmds = object->mh64->ncmds;
4516 for(i = 0; i < ncmds; i++){
4517 if(lc->cmd == LC_SEGMENT){
4518 sg = (struct segment_command *)lc;
4519 s = (struct section *)((char *)sg +
4520 sizeof(struct segment_command));
4521 nsects += sg->nsects;
4522 for(j = 0; j < sg->nsects; j++){
4523 if(strcmp(s->segname, SEG_DATA) == 0 &&
4524 strcmp(s->sectname, SECT_DATA) == 0 &&
4525 data_n_sect == NO_SECT){
4526 data_n_sect = n_sect;
4527 break;
4529 n_sect++;
4530 s++;
4533 else if(lc->cmd == LC_SEGMENT_64){
4534 sg64 = (struct segment_command_64 *)lc;
4535 s64 = (struct section_64 *)((char *)sg64 +
4536 sizeof(struct segment_command_64));
4537 nsects += sg64->nsects;
4538 for(j = 0; j < sg64->nsects; j++){
4539 if(strcmp(s64->segname, SEG_DATA) == 0 &&
4540 strcmp(s64->sectname, SECT_DATA) == 0 &&
4541 data_n_sect == NO_SECT){
4542 data_n_sect = n_sect;
4543 break;
4545 n_sect++;
4546 s64++;
4549 lc = (struct load_command *)((char *)lc + lc->cmdsize);
4551 if(object->mh != NULL){
4552 sections = allocate(nsects * sizeof(struct section *));
4553 sections64 = NULL;
4555 else{
4556 sections = NULL;
4557 sections64 = allocate(nsects * sizeof(struct section_64 *));
4559 nsects = 0;
4560 lc = object->load_commands;
4561 for(i = 0; i < ncmds; i++){
4562 if(lc->cmd == LC_SEGMENT){
4563 sg = (struct segment_command *)lc;
4564 s = (struct section *)((char *)sg +
4565 sizeof(struct segment_command));
4566 for(j = 0; j < sg->nsects; j++){
4567 sections[nsects++] = s++;
4570 else if(lc->cmd == LC_SEGMENT_64){
4571 sg64 = (struct segment_command_64 *)lc;
4572 s64 = (struct section_64 *)((char *)sg64 +
4573 sizeof(struct segment_command_64));
4574 for(j = 0; j < sg64->nsects; j++){
4575 sections64[nsects++] = s64++;
4578 lc = (struct load_command *)((char *)lc + lc->cmdsize);
4582 * Zero out the saved symbols so they can be recorded for this file.
4584 for(i = 0; i < nsave_symbols; i++)
4585 save_symbols[i].sym = NULL;
4586 for(i = 0; i < nremove_symbols; i++)
4587 remove_symbols[i].sym = NULL;
4588 if(member == NULL){
4589 for(i = 0; i < nsave_symbols; i++)
4590 save_symbols[i].seen = FALSE;
4591 for(i = 0; i < nremove_symbols; i++)
4592 remove_symbols[i].seen = FALSE;
4595 nchanged_globals = 0;
4596 if(object->mh != NULL){
4597 changed_globals = allocate(nsyms * sizeof(struct nlist *));
4598 changed_globals64 = NULL;
4599 for(i = 0; i < nsyms; i++)
4600 changed_globals[i] = NULL;
4602 else{
4603 changed_globals = NULL;
4604 changed_globals64 = allocate(nsyms * sizeof(struct nlist_64 *));
4605 for(i = 0; i < nsyms; i++)
4606 changed_globals64[i] = NULL;
4610 * These are the variables for the new symbol table and new string
4611 * table. Since this routine only turns globals into non-globals the
4612 * number of symbols does not change. But the count of local, defined
4613 * external symbols does change.
4615 new_nsyms = nsyms;
4616 new_nlocalsym = 0;
4617 new_nextdefsym = 0;
4618 new_nundefsym = 0;
4620 new_strsize = sizeof(int32_t);
4621 new_ext_strsize = 0;
4624 * First pass: turn the globals symbols into non-global symbols.
4626 for(i = 0; i < nsyms; i++){
4627 len = 0;
4628 s_flags = 0;
4629 if(object->mh != NULL){
4630 n_strx = symbols[i].n_un.n_strx;
4631 n_type = symbols[i].n_type;
4632 n_sect = symbols[i].n_sect;
4633 if((n_type & N_TYPE) == N_SECT)
4634 s_flags = sections[n_sect - 1]->flags;
4635 n_value = symbols[i].n_value;
4637 else{
4638 n_strx = symbols64[i].n_un.n_strx;
4639 n_type = symbols64[i].n_type;
4640 n_sect = symbols64[i].n_sect;
4641 if((n_type & N_TYPE) == N_SECT)
4642 s_flags = sections64[n_sect - 1]->flags;
4643 n_value = symbols64[i].n_value;
4645 if(n_strx != 0){
4646 if(n_strx > strsize){
4647 error_arch(arch, member, "bad string index for symbol "
4648 "table entry %u in: ", i);
4649 return(FALSE);
4651 len = strlen(strings + n_strx) + 1;
4653 if(n_type & N_EXT){
4654 if((n_type & N_TYPE) != N_UNDF &&
4655 (n_type & N_TYPE) != N_PBUD){
4656 if((n_type & N_TYPE) == N_SECT){
4657 if(n_sect > nsects){
4658 error_arch(arch, member, "bad n_sect for symbol "
4659 "table entry %u in: ", i);
4660 return(FALSE);
4662 if(((s_flags & SECTION_TYPE) == S_COALESCED) &&
4663 pflag == FALSE &&
4664 object->mh_filetype != MH_OBJECT){
4665 /* this remains a global defined symbol */
4666 if(warned_about_global_coalesced_symbols == FALSE){
4667 warning_arch(arch, member, "can't make global "
4668 "coalesced symbols (like %s) into static "
4669 "symbols (use ld(1)'s "
4670 "-exported_symbols_list option) in a final "
4671 "linked image: ", strings + n_strx);
4672 warned_about_global_coalesced_symbols = TRUE;
4674 new_nextdefsym++;
4675 new_ext_strsize += len;
4676 new_strsize += len;
4677 sp = bsearch(strings + n_strx,
4678 remove_symbols, nremove_symbols,
4679 sizeof(struct symbol_list),
4680 (int (*)(const void *, const void *))
4681 symbol_list_bsearch);
4682 if(sp != NULL){
4683 if(sp->sym != NULL){
4684 error_arch(arch, member, "more than one "
4685 "symbol for: %s found in: ", sp->name);
4686 return(FALSE);
4688 else{
4689 if(object->mh != NULL)
4690 sp->sym = &(symbols[i]);
4691 else
4692 sp->sym = &(symbols64[i]);
4693 sp->seen = TRUE;
4694 warning_arch(arch, member, "can't make "
4695 "global coalesced symbol: %s into a "
4696 "static symbol in: ", sp->name);
4700 * In case the user has listed this coalesced
4701 * symbol in the save list look for it and mark it
4702 * as seen so we don't complain about not seeing it.
4704 sp = bsearch(strings + n_strx,
4705 save_symbols, nsave_symbols,
4706 sizeof(struct symbol_list),
4707 (int (*)(const void *, const void *))
4708 symbol_list_bsearch);
4709 if(sp != NULL){
4710 if(sp->sym != NULL){
4711 error_arch(arch, member, "more than one "
4712 "symbol for: %s found in: ", sp->name);
4713 return(FALSE);
4715 else{
4716 if(object->mh != NULL)
4717 sp->sym = &(symbols[i]);
4718 else
4719 sp->sym = &(symbols64[i]);
4720 sp->seen = TRUE;
4723 continue; /* leave this symbol unchanged */
4726 sp = bsearch(strings + n_strx,
4727 remove_symbols, nremove_symbols,
4728 sizeof(struct symbol_list),
4729 (int (*)(const void *, const void *))
4730 symbol_list_bsearch);
4731 if(sp != NULL){
4732 if(sp->sym != NULL){
4733 error_arch(arch, member, "more than one symbol "
4734 "for: %s found in: ", sp->name);
4735 return(FALSE);
4737 else{
4738 if(object->mh != NULL)
4739 sp->sym = &(symbols[i]);
4740 else
4741 sp->sym = &(symbols64[i]);
4742 sp->seen = TRUE;
4743 goto change_symbol;
4746 else{
4748 * If there is no list of saved symbols, then all
4749 * symbols will be saved unless listed in the remove
4750 * list.
4752 if(sfile == NULL){
4754 * There is no save list, so if there is also no
4755 * remove list but the -p flag is specified or it is
4756 * a dynamic library then change all symbols.
4758 if((pflag || object->mh_filetype == MH_DYLIB)
4759 && nremove_symbols == 0)
4760 goto change_symbol;
4761 /* this remains a global defined symbol */
4762 new_nextdefsym++;
4763 new_ext_strsize += len;
4764 new_strsize += len;
4765 continue; /* leave this symbol unchanged */
4768 sp = bsearch(strings + n_strx,
4769 save_symbols, nsave_symbols,
4770 sizeof(struct symbol_list),
4771 (int (*)(const void *, const void *))
4772 symbol_list_bsearch);
4773 if(sp != NULL){
4774 if(sp->sym != NULL){
4775 error_arch(arch, member, "more than one symbol "
4776 "for: %s found in: ", sp->name);
4777 return(FALSE);
4779 else{
4780 if(object->mh != NULL)
4781 sp->sym = &(symbols[i]);
4782 else
4783 sp->sym = &(symbols64[i]);
4784 sp->seen = TRUE;
4785 /* this remains a global defined symbol */
4786 new_nextdefsym++;
4787 new_ext_strsize += len;
4788 new_strsize += len;
4791 else{
4792 if(Aflag && n_type == (N_EXT | N_ABS) &&
4793 (n_value != 0 ||
4794 (n_strx != 0 &&
4795 strncmp(strings + n_strx,
4796 ".objc_class_name_",
4797 sizeof(".objc_class_name_") - 1) == 0))){
4798 /* this remains a global defined symbol */
4799 new_nextdefsym++;
4800 new_ext_strsize += len;
4801 new_strsize += len;
4803 else{
4804 change_symbol:
4805 if((n_type & N_TYPE) != N_INDR){
4806 nmedits[i] = TRUE;
4807 if(object->mh != NULL)
4808 changed_globals[nchanged_globals++] =
4809 symbols + i;
4810 else
4811 changed_globals64[nchanged_globals++] =
4812 symbols64 + i;
4813 if(pflag){
4814 /* this remains a global defined symbol */
4815 new_nextdefsym++;
4816 new_ext_strsize += len;
4817 new_strsize += len;
4819 else{
4820 /* this will become a non-global symbol */
4821 new_nlocalsym++;
4822 new_strsize += len;
4825 else{
4826 /* this remains a global defined symbol */
4827 new_nextdefsym++;
4828 new_ext_strsize += len;
4829 new_strsize += len;
4834 else{
4835 /* this is an undefined symbol */
4836 new_nundefsym++;
4837 new_ext_strsize += len;
4838 new_strsize += len;
4841 else{
4842 /* this is a local symbol */
4843 new_nlocalsym++;
4844 new_strsize += len;
4849 * The module table's module names are placed with the external
4850 * strings. So size them and add this to the external string size.
4852 for(i = 0; i < nmodtab; i++){
4853 if(object->mh != NULL)
4854 module_name = mods[i].module_name;
4855 else
4856 module_name = mods64[i].module_name;
4857 if(module_name == 0 || module_name > strsize){
4858 error_arch(arch, member, "bad string index for module_name "
4859 "of module table entry %d in: ", i);
4860 return(FALSE);
4862 len = strlen(strings + module_name) + 1;
4863 new_strsize += len;
4864 new_ext_strsize += len;
4868 * Warn about symbols to be saved that were missing.
4870 if(member == NULL){
4871 missing_syms = 0;
4872 if(iflag == 0){
4873 for(i = 0; i < nsave_symbols; i++){
4874 if(save_symbols[i].sym == NULL){
4875 if(missing_syms == 0){
4876 error_arch(arch, member, "symbols names listed "
4877 "in: %s not in: ", sfile);
4878 missing_syms = 1;
4880 fprintf(stderr, "%s\n", save_symbols[i].name);
4883 for(i = 0; i < nremove_symbols; i++){
4884 if(remove_symbols[i].sym == NULL){
4885 if(missing_syms == 0){
4886 error_arch(arch, member, "symbols names listed "
4887 "in: %s not in: ", Rfile);
4888 missing_syms = 1;
4890 fprintf(stderr, "%s\n", remove_symbols[i].name);
4897 * Second pass: fix stabs for the globals symbols that got turned into
4898 * non-global symbols. This is a MAJOR guess. The specific changes
4899 * to do here were determined by compiling test cases with and without
4900 * the key word 'static' and looking at the difference between the STABS
4901 * the compiler generates and trying to match that here.
4903 global_strings = strings;
4904 if(object->mh != NULL)
4905 qsort(changed_globals, nchanged_globals, sizeof(struct nlist *),
4906 (int (*)(const void *, const void *))cmp_qsort_global);
4907 else
4908 qsort(changed_globals64, nchanged_globals,sizeof(struct nlist_64 *),
4909 (int (*)(const void *, const void *))cmp_qsort_global_64);
4910 dwarf_debug_map = FALSE;
4911 for(i = 0; i < nsyms; i++){
4912 uint16_t n_desc;
4913 if(object->mh != NULL){
4914 n_strx = symbols[i].n_un.n_strx;
4915 n_type = symbols[i].n_type;
4916 n_desc = symbols[i].n_desc;
4918 else{
4919 n_strx = symbols64[i].n_un.n_strx;
4920 n_type = symbols64[i].n_type;
4921 n_desc = symbols64[i].n_desc;
4923 if(n_type == N_SO)
4924 dwarf_debug_map = FALSE;
4925 else if (n_type == N_OSO)
4926 dwarf_debug_map = n_desc != 0;
4927 else if (dwarf_debug_map && n_type == N_GSYM){
4928 global_name = strings + n_strx;
4929 if(object->mh != NULL){
4930 global_symbol = bsearch(global_name, changed_globals,
4931 nchanged_globals,sizeof(struct nlist *),
4932 (int (*)(const void *, const void *))
4933 cmp_bsearch_global);
4934 if(global_symbol != NULL){
4935 symbols[i].n_type = N_STSYM;
4936 symbols[i].n_sect = (*global_symbol)->n_sect;
4937 symbols[i].n_value = (*global_symbol)->n_value;
4940 else{
4941 global_symbol64 = bsearch(global_name, changed_globals64,
4942 nchanged_globals,
4943 sizeof(struct nlist_64 *),
4944 (int (*)(const void *, const void *))
4945 cmp_bsearch_global_64);
4946 if(global_symbol64 != NULL){
4947 symbols64[i].n_type = N_STSYM;
4948 symbols64[i].n_sect = (*global_symbol64)->n_sect;
4949 symbols64[i].n_value = (*global_symbol64)->n_value;
4953 else if(! dwarf_debug_map &&
4954 (n_type == N_GSYM || n_type == N_FUN) &&
4955 (n_strx != 0 && strings[n_strx] != '\0')){
4956 global_name = strings + n_strx;
4957 if((global_name[0] == '+' || global_name[0] == '-') &&
4958 global_name[1] == '['){
4959 j = 2;
4960 while(j + n_strx < strsize && global_name[j] != ']')
4961 j++;
4962 if(j + n_strx < strsize && global_name[j] == ']')
4963 j++;
4965 else
4966 j = 0;
4967 while(j + n_strx < strsize && global_name[j] != ':')
4968 j++;
4969 if(j + n_strx >= strsize){
4970 error_arch(arch, member, "bad N_STAB symbol name for entry "
4971 "%u (does not contain ':' separating name from type) "
4972 "in: ", i);
4973 return(FALSE);
4975 save_char = global_name[j];
4976 global_name[j] = '\0';
4978 global_symbol_found = FALSE;
4979 global_symbol_n_sect = 0;
4980 if(object->mh != NULL){
4981 global_symbol = bsearch(global_name, changed_globals,
4982 nchanged_globals,sizeof(struct nlist *),
4983 (int (*)(const void *, const void *))
4984 cmp_bsearch_global_stab);
4985 global_symbol64 = NULL;
4986 if(global_symbol != NULL){
4987 global_symbol_found = TRUE;
4988 global_symbol_n_sect = (*global_symbol)->n_sect;
4991 else{
4992 global_symbol64 = bsearch(global_name, changed_globals64,
4993 nchanged_globals,
4994 sizeof(struct nlist_64 *),
4995 (int (*)(const void *, const void *))
4996 cmp_bsearch_global_stab_64);
4997 global_symbol = NULL;
4998 if(global_symbol64 != NULL){
4999 global_symbol_found = TRUE;
5000 global_symbol_n_sect = (*global_symbol64)->n_sect;
5003 global_name[j] = save_char;
5004 if(global_symbol_found == TRUE){
5005 if(n_type == N_GSYM){
5006 if(global_symbol_n_sect == data_n_sect){
5007 if(object->mh != NULL)
5008 symbols[i].n_type = N_STSYM;
5009 else
5010 symbols64[i].n_type = N_STSYM;
5012 else{
5013 if(object->mh != NULL)
5014 symbols[i].n_type = N_FUN;
5015 else
5016 symbols64[i].n_type = N_FUN;
5018 if(object->mh != NULL){
5019 symbols[i].n_sect = (*global_symbol)->n_sect;
5020 symbols[i].n_value = (*global_symbol)->n_value;
5021 symbols[i].n_desc = (*global_symbol)->n_desc;
5023 else{
5024 symbols64[i].n_sect = (*global_symbol64)->n_sect;
5025 symbols64[i].n_value = (*global_symbol64)->n_value;
5026 symbols64[i].n_desc = (*global_symbol64)->n_desc;
5028 if(j + 1 + n_strx >= strsize ||
5029 global_name[j+1] != 'G'){
5030 error_arch(arch, member, "bad N_GSYM symbol name "
5031 "for entry %u (does not have type 'G' after "
5032 "':' in name) in: ", i);
5033 return(FALSE);
5035 global_name[j+1] = 'S';
5037 else{ /* n_type == N_FUN */
5038 if(j + 1 + n_strx >= strsize ||
5039 global_name[j+1] == 'F'){
5040 global_name[j+1] = 'f';
5046 global_strings = NULL;
5049 * Now what needs to be done is to create the new symbol table moving
5050 * those global symbols being changed into non-globals into the areas
5051 * in the symbol table for local symbols. The symbol table and string
5052 * table must be in this order:
5054 * symbol table
5055 * local symbols
5056 * external defined symbols
5057 * undefined symbols
5058 * string table
5059 * external strings
5060 * local strings
5062 if(saves != NULL)
5063 free(saves);
5064 saves = (int32_t *)allocate(nsyms * sizeof(int32_t));
5065 bzero(saves, nsyms * sizeof(int32_t));
5067 if(object->mh != NULL){
5068 new_symbols = (struct nlist *)
5069 allocate(new_nsyms * sizeof(struct nlist));
5070 new_symbols64 = NULL;
5072 else{
5073 new_symbols = NULL;
5074 new_symbols64 = (struct nlist_64 *)
5075 allocate(new_nsyms * sizeof(struct nlist_64));
5077 new_strsize = rnd(new_strsize, sizeof(int32_t));
5078 new_strings = (char *)allocate(new_strsize);
5079 new_strings[new_strsize - 3] = '\0';
5080 new_strings[new_strsize - 2] = '\0';
5081 new_strings[new_strsize - 1] = '\0';
5083 memset(new_strings, '\0', sizeof(int32_t));
5084 p = new_strings + sizeof(int32_t);
5085 q = p + new_ext_strsize;
5088 * If this is a dynamic library the movement of the symbols has to be
5089 * done with respect to the modules. As the local symbols, and external
5090 * defined symbols are grouped together for each module. Then a new
5091 * module table needs to be created with the new indexes into the symbol
5092 * table for each module.
5094 new_nmodtab = nmodtab;
5095 new_ntoc = ntoc;
5096 new_nextrefsyms = nextrefsyms;
5097 if(object->mh_filetype == MH_DYLIB && nmodtab != 0){
5098 if(object->mh != NULL){
5099 new_mods = allocate(nmodtab * sizeof(struct dylib_module));
5100 new_mods64 = NULL;
5102 else{
5103 new_mods = NULL;
5104 new_mods64 = allocate(nmodtab * sizeof(struct dylib_module_64));
5107 inew_syms = 0;
5109 * This first loop through the module table sets the index and
5110 * counts of the local symbols for each module.
5112 for(i = 0; i < nmodtab; i++){
5114 * First put the existing local symbols into the new symbol
5115 * table.
5117 if(object->mh != NULL){
5118 new_mods[i].ilocalsym = inew_syms;
5119 new_mods[i].nlocalsym = 0;
5120 ilocalsym = mods[i].ilocalsym;
5121 nlocalsym = mods[i].nlocalsym;
5123 else{
5124 new_mods64[i].ilocalsym = inew_syms;
5125 new_mods64[i].nlocalsym = 0;
5126 ilocalsym = mods64[i].ilocalsym;
5127 nlocalsym = mods64[i].nlocalsym;
5129 for(j = ilocalsym; j < ilocalsym + nlocalsym; j++){
5130 if(object->mh != NULL){
5131 n_strx = symbols[j].n_un.n_strx;
5132 n_type = symbols[j].n_type;
5134 else{
5135 n_strx = symbols64[j].n_un.n_strx;
5136 n_type = symbols64[j].n_type;
5138 if((n_type & N_EXT) == 0){
5139 if(object->mh != NULL)
5140 new_symbols[inew_syms] = symbols[j];
5141 else
5142 new_symbols64[inew_syms] = symbols64[j];
5143 if(n_strx != 0){
5144 strcpy(q, strings + n_strx);
5145 if(object->mh != NULL)
5146 new_symbols[inew_syms].n_un.n_strx =
5147 q - new_strings;
5148 else
5149 new_symbols64[inew_syms].n_un.n_strx =
5150 q - new_strings;
5151 q += strlen(q) + 1;
5153 inew_syms++;
5154 saves[j] = inew_syms;
5155 if(object->mh != NULL)
5156 new_mods[i].nlocalsym++;
5157 else
5158 new_mods64[i].nlocalsym++;
5162 * Next put the global symbols that were changed into
5163 * non-global symbols into the new symbol table and moved their
5164 * counts to the local symbol counts.
5166 if(object->mh != NULL){
5167 iextdefsym = mods[i].iextdefsym;
5168 nextdefsym = mods[i].nextdefsym;
5170 else{
5171 iextdefsym = mods64[i].iextdefsym;
5172 nextdefsym = mods64[i].nextdefsym;
5174 for(j = iextdefsym; j < iextdefsym + nextdefsym; j++){
5175 if(object->mh != NULL){
5176 n_strx = symbols[j].n_un.n_strx;
5177 n_type = symbols[j].n_type;
5179 else{
5180 n_strx = symbols64[j].n_un.n_strx;
5181 n_type = symbols64[j].n_type;
5183 if((n_type & N_EXT) != 0){
5184 if(nmedits[j] == TRUE){
5186 * Change the new symbol to a private extern symbol
5187 * with the extern bit off.
5189 if(object->mh != NULL){
5190 new_symbols[inew_syms] = symbols[j];
5191 new_symbols[inew_syms].n_type |= N_PEXT;
5192 new_symbols[inew_syms].n_type &= ~N_EXT;
5194 else{
5195 new_symbols64[inew_syms] = symbols64[j];
5196 new_symbols64[inew_syms].n_type |= N_PEXT;
5197 new_symbols64[inew_syms].n_type &= ~N_EXT;
5199 if(n_strx != 0){
5200 strcpy(q, strings + n_strx);
5201 if(object->mh != NULL)
5202 new_symbols[inew_syms].n_un.n_strx =
5203 q - new_strings;
5204 else
5205 new_symbols64[inew_syms].n_un.n_strx =
5206 q - new_strings;
5207 q += strlen(q) + 1;
5209 inew_syms++;
5210 saves[j] = inew_syms;
5211 if(object->mh != NULL)
5212 new_mods[i].nlocalsym++;
5213 else
5214 new_mods64[i].nlocalsym++;
5220 * Next put the unchanged defined global symbols into the new
5221 * symbol table.
5223 for(i = 0; i < nmodtab; i++){
5224 if(object->mh != NULL){
5225 new_mods[i].iextdefsym = inew_syms;
5226 new_mods[i].nextdefsym = 0;
5227 iextdefsym = mods[i].iextdefsym;
5228 nextdefsym = mods[i].nextdefsym;
5230 else{
5231 new_mods64[i].iextdefsym = inew_syms;
5232 new_mods64[i].nextdefsym = 0;
5233 iextdefsym = mods64[i].iextdefsym;
5234 nextdefsym = mods64[i].nextdefsym;
5236 for(j = iextdefsym; j < iextdefsym + nextdefsym; j++){
5237 if(object->mh != NULL){
5238 n_strx = symbols[j].n_un.n_strx;
5239 n_type = symbols[j].n_type;
5241 else{
5242 n_strx = symbols64[j].n_un.n_strx;
5243 n_type = symbols64[j].n_type;
5245 if((n_type & N_EXT) != 0){
5246 if(nmedits[j] == FALSE){
5247 if(object->mh != NULL)
5248 new_symbols[inew_syms] = symbols[j];
5249 else
5250 new_symbols64[inew_syms] = symbols64[j];
5251 if(n_strx != 0){
5252 strcpy(p, strings + n_strx);
5253 if(object->mh != NULL)
5254 new_symbols[inew_syms].n_un.n_strx =
5255 p - new_strings;
5256 else
5257 new_symbols64[inew_syms].n_un.n_strx =
5258 p - new_strings;
5259 p += strlen(p) + 1;
5261 inew_syms++;
5262 saves[j] = inew_syms;
5263 if(object->mh != NULL)
5264 new_mods[i].nextdefsym++;
5265 else
5266 new_mods64[i].nextdefsym++;
5272 * Last put the undefined symbols into the new symbol table.
5274 for(i = 0; i < nsyms; i++){
5275 if(object->mh != NULL){
5276 n_strx = symbols[i].n_un.n_strx;
5277 n_type = symbols[i].n_type;
5279 else{
5280 n_strx = symbols64[i].n_un.n_strx;
5281 n_type = symbols64[i].n_type;
5283 if((n_type & N_EXT) != 0 &&
5284 ((n_type & N_TYPE) == N_UNDF ||
5285 (n_type & N_TYPE) == N_PBUD)){
5286 if(object->mh != NULL)
5287 new_symbols[inew_syms] = symbols[i];
5288 else
5289 new_symbols64[inew_syms] = symbols64[i];
5290 if(n_strx != 0){
5291 strcpy(p, strings + n_strx);
5292 if(object->mh != NULL)
5293 new_symbols[inew_syms].n_un.n_strx =
5294 p - new_strings;
5295 else
5296 new_symbols64[inew_syms].n_un.n_strx =
5297 p - new_strings;
5298 p += strlen(p) + 1;
5300 inew_syms++;
5301 saves[i] = inew_syms;
5306 * Place the module table's module names with the external strings
5307 * and set the names in the new module table. And then copy the
5308 * other unchanged fields.
5310 for(i = 0; i < nmodtab; i++){
5311 if(object->mh != NULL){
5312 strcpy(p, strings + mods[i].module_name);
5313 new_mods[i].module_name = p - new_strings;
5314 p += strlen(p) + 1;
5316 new_mods[i].irefsym = mods[i].irefsym;
5317 new_mods[i].nrefsym = mods[i].nrefsym;
5318 new_mods[i].iextrel = mods[i].iextrel;
5319 new_mods[i].nextrel = mods[i].nextrel;
5320 new_mods[i].iinit_iterm = mods[i].iinit_iterm;
5321 new_mods[i].ninit_nterm = mods[i].ninit_nterm;
5322 new_mods[i].objc_module_info_addr =
5323 mods[i].objc_module_info_addr;
5324 new_mods[i].objc_module_info_size =
5325 mods[i].objc_module_info_size;
5327 else{
5328 strcpy(p, strings + mods64[i].module_name);
5329 new_mods64[i].module_name = p - new_strings;
5330 p += strlen(p) + 1;
5332 new_mods64[i].irefsym = mods64[i].irefsym;
5333 new_mods64[i].nrefsym = mods64[i].nrefsym;
5334 new_mods64[i].iextrel = mods64[i].iextrel;
5335 new_mods64[i].nextrel = mods64[i].nextrel;
5336 new_mods64[i].iinit_iterm = mods64[i].iinit_iterm;
5337 new_mods64[i].ninit_nterm = mods64[i].ninit_nterm;
5338 new_mods64[i].objc_module_info_addr =
5339 mods64[i].objc_module_info_addr;
5340 new_mods64[i].objc_module_info_size =
5341 mods64[i].objc_module_info_size;
5346 * Update the reference table with the new symbol indexes for all
5347 * entries and change type of reference (the flags field) for those
5348 * symbols that got changed from globals to non-globals.
5350 new_nextrefsyms = nextrefsyms;
5351 new_refs = allocate(new_nextrefsyms *
5352 sizeof(struct dylib_reference));
5353 j = 0;
5354 for(i = 0; i < nextrefsyms; i++){
5355 if(nmedits[refs[i].isym] == TRUE){
5356 if(refs[i].flags == REFERENCE_FLAG_DEFINED)
5357 new_refs[i].flags =
5358 REFERENCE_FLAG_PRIVATE_DEFINED;
5359 else if(refs[i].flags == REFERENCE_FLAG_UNDEFINED_NON_LAZY)
5360 new_refs[i].flags =
5361 REFERENCE_FLAG_PRIVATE_UNDEFINED_NON_LAZY;
5362 else if(refs[i].flags == REFERENCE_FLAG_UNDEFINED_LAZY)
5363 new_refs[i].flags =
5364 REFERENCE_FLAG_PRIVATE_UNDEFINED_LAZY;
5365 else
5366 new_refs[i].flags = refs[i].flags;
5368 else{
5369 new_refs[i].flags = refs[i].flags;
5371 new_refs[i].isym = saves[refs[i].isym] - 1;
5375 * Create a new dylib table of contents without the global symbols
5376 * that got turned into non-globals.
5378 new_ntoc = ntoc - nchanged_globals;
5379 new_tocs = allocate(new_ntoc *
5380 sizeof(struct dylib_table_of_contents));
5381 k = 0;
5382 for(i = 0; i < ntoc; i++){
5383 if(tocs[i].symbol_index >= nsyms){
5384 error_arch(arch, member, "bad symbol index for table of "
5385 "contents table entry %d in: ", i);
5386 return(FALSE);
5388 if(nmedits[tocs[i].symbol_index] == FALSE){
5389 new_tocs[k].symbol_index = saves[tocs[i].symbol_index] - 1;
5390 new_tocs[k].module_index = tocs[i].module_index;
5391 k++;
5396 * If is not a dynamic library so all global symbols changed into
5397 * statics can be moved to the end of the local symbols. If the pflag
5398 * is set then the changed symbols remain global and just get the
5399 * private extern bit set.
5401 else{
5403 * First put the existing local symbols into the new symbol table.
5405 inew_syms = 0;
5406 for(i = 0; i < nsyms; i++){
5407 if(object->mh != NULL){
5408 n_strx = symbols[i].n_un.n_strx;
5409 n_type = symbols[i].n_type;
5411 else{
5412 n_strx = symbols64[i].n_un.n_strx;
5413 n_type = symbols64[i].n_type;
5415 if((n_type & N_EXT) == 0){
5416 if(object->mh != NULL)
5417 new_symbols[inew_syms] = symbols[i];
5418 else
5419 new_symbols64[inew_syms] = symbols64[i];
5420 if(n_strx != 0){
5421 strcpy(q, strings + n_strx);
5422 if(object->mh != NULL)
5423 new_symbols[inew_syms].n_un.n_strx =
5424 q - new_strings;
5425 else
5426 new_symbols64[inew_syms].n_un.n_strx =
5427 q - new_strings;
5428 q += strlen(q) + 1;
5430 inew_syms++;
5431 saves[i] = inew_syms;
5435 * Next put the global symbols that were changed into statics
5436 * symbols into the new symbol table.
5438 if(pflag == FALSE){
5439 for(i = 0; i < nsyms; i++){
5440 if(object->mh != NULL){
5441 n_strx = symbols[i].n_un.n_strx;
5442 n_type = symbols[i].n_type;
5444 else{
5445 n_strx = symbols64[i].n_un.n_strx;
5446 n_type = symbols64[i].n_type;
5448 if((n_type & N_EXT) != 0){
5449 if(nmedits[i] == TRUE){
5451 * Change the new symbol to not be an extern symbol
5452 * by turning off the extern bit.
5454 if(object->mh != NULL){
5455 new_symbols[inew_syms] = symbols[i];
5456 new_symbols[inew_syms].n_type &= ~N_EXT;
5457 new_symbols[inew_syms].n_desc &= ~N_WEAK_DEF;
5459 else{
5460 new_symbols64[inew_syms] = symbols64[i];
5461 new_symbols64[inew_syms].n_type &= ~N_EXT;
5462 new_symbols64[inew_syms].n_desc &= ~N_WEAK_DEF;
5464 if(n_strx != 0){
5465 strcpy(q, strings + n_strx);
5466 if(object->mh != NULL)
5467 new_symbols[inew_syms].n_un.n_strx =
5468 q - new_strings;
5469 else
5470 new_symbols64[inew_syms].n_un.n_strx =
5471 q - new_strings;
5472 q += strlen(q) + 1;
5474 inew_syms++;
5475 saves[i] = inew_syms;
5481 * Last put the unchanged global symbols into the new symbol table
5482 * and symbols changed into private externs.
5484 for(i = 0; i < nsyms; i++){
5485 if(object->mh != NULL){
5486 n_strx = symbols[i].n_un.n_strx;
5487 n_type = symbols[i].n_type;
5489 else{
5490 n_strx = symbols64[i].n_un.n_strx;
5491 n_type = symbols64[i].n_type;
5493 if((n_type & N_EXT) != 0){
5494 if(nmedits[i] == FALSE || pflag == TRUE){
5495 if(object->mh != NULL)
5496 new_symbols[inew_syms] = symbols[i];
5497 else
5498 new_symbols64[inew_syms] = symbols64[i];
5499 if(nmedits[i] == TRUE && pflag == TRUE){
5501 * Change the new symbol to be a private extern
5502 * symbol by turning on the private extern bit.
5504 if(object->mh != NULL)
5505 new_symbols[inew_syms].n_type |= N_PEXT;
5506 else
5507 new_symbols64[inew_syms].n_type |= N_PEXT;
5509 if(n_strx != 0){
5510 strcpy(p, strings + n_strx);
5511 if(object->mh != NULL)
5512 new_symbols[inew_syms].n_un.n_strx =
5513 p - new_strings;
5514 else
5515 new_symbols64[inew_syms].n_un.n_strx =
5516 p - new_strings;
5517 p += strlen(p) + 1;
5519 inew_syms++;
5520 saves[i] = inew_syms;
5526 if(sections != NULL)
5527 free(sections);
5528 if(sections64 != NULL)
5529 free(sections64);
5531 if(errors == 0)
5532 return(TRUE);
5533 else
5534 return(FALSE);
5538 * Function for qsort for comparing global symbol names.
5540 static
5542 cmp_qsort_global(
5543 const struct nlist **sym1,
5544 const struct nlist **sym2)
5546 return(strcmp(global_strings + (*sym1)->n_un.n_strx,
5547 global_strings + (*sym2)->n_un.n_strx));
5550 static
5552 cmp_qsort_global_64(
5553 const struct nlist_64 **sym1,
5554 const struct nlist_64 **sym2)
5556 return(strcmp(global_strings + (*sym1)->n_un.n_strx,
5557 global_strings + (*sym2)->n_un.n_strx));
5561 * Function for bsearch for finding a global symbol that matches a stab name.
5563 static
5565 cmp_bsearch_global_stab(
5566 const char *name,
5567 const struct nlist **sym)
5570 * The +1 is for the '_' on the global symbol that is not on the
5571 * stab string that is trying to be matched.
5573 return(strcmp(name, global_strings + (*sym)->n_un.n_strx + 1));
5576 static
5578 cmp_bsearch_global_stab_64(
5579 const char *name,
5580 const struct nlist_64 **sym)
5583 * The +1 is for the '_' on the global symbol that is not on the
5584 * stab string that is trying to be matched.
5586 return(strcmp(name, global_strings + (*sym)->n_un.n_strx + 1));
5590 * Function for bsearch for finding a global symbol that matches a stab name
5591 * in the debug map.
5593 static
5595 cmp_bsearch_global(
5596 const char *name,
5597 const struct nlist **sym)
5599 return(strcmp(name, global_strings + (*sym)->n_un.n_strx));
5602 static
5604 cmp_bsearch_global_64(
5605 const char *name,
5606 const struct nlist_64 **sym)
5608 return(strcmp(name, global_strings + (*sym)->n_un.n_strx));
5610 #endif /* defined(NMEDIT) */