Rename README -> README.txt
[striptease.git] / tease.c
blob8ac9bdef1b5d53799582bc7ab3cd78c7e4a23633
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 */
355 main(
356 int argc,
357 char *argv[],
358 char *envp[])
360 int i;
361 uint32_t j, args_left, files_specified;
362 struct arch_flag *arch_flags;
363 uint32_t narch_flags;
364 enum bool all_archs;
365 struct symbol_list *sp;
367 progname = argv[0];
369 arch_flags = NULL;
370 narch_flags = 0;
371 all_archs = FALSE;
373 files_specified = 0;
374 args_left = 1;
375 for (i = 1; i < argc; i++){
376 if(argv[i][0] == '-'){
377 if(argv[i][1] == '\0'){
378 args_left = 0;
379 break;
381 if(strcmp(argv[i], "-o") == 0){
382 if(i + 1 >= argc)
383 fatal("-o requires an argument");
384 if(output_file != NULL)
385 fatal("only one -o option allowed");
386 output_file = argv[i + 1];
387 i++;
389 else if(strcmp(argv[i], "-s") == 0){
390 if(i + 1 >= argc)
391 fatal("-s requires an argument");
392 if(sfile != NULL)
393 fatal("only one -s option allowed");
394 sfile = argv[i + 1];
395 i++;
397 else if(strcmp(argv[i], "-R") == 0){
398 if(i + 1 >= argc)
399 fatal("-R requires an argument");
400 if(Rfile != NULL)
401 fatal("only one -R option allowed");
402 Rfile = argv[i + 1];
403 i++;
405 #ifndef NMEDIT
406 else if(strcmp(argv[i], "-d") == 0){
407 if(i + 1 >= argc)
408 fatal("-d requires an argument");
409 if(dfile != NULL)
410 fatal("only one -d option allowed");
411 dfile = argv[i + 1];
412 i++;
414 else if(strcmp(argv[i], "-no_uuid") == 0){
415 no_uuid = 1;
417 else if(strcmp(argv[i], "-no_code_signature") == 0){
418 no_code_signature = 1;
420 #endif /* !defined(NMEDIT) */
421 else if(strcmp(argv[i], "-arch") == 0){
422 if(i + 1 == argc){
423 error("missing argument(s) to %s option", argv[i]);
424 usage();
426 if(strcmp("all", argv[i+1]) == 0){
427 all_archs = TRUE;
429 else{
430 arch_flags = reallocate(arch_flags,
431 (narch_flags + 1) * sizeof(struct arch_flag));
432 if(get_arch_from_flag(argv[i+1],
433 arch_flags + narch_flags) == 0){
434 error("unknown architecture specification flag: "
435 "%s %s", argv[i], argv[i+1]);
436 arch_usage();
437 usage();
439 for(j = 0; j < narch_flags; j++){
440 if(arch_flags[j].cputype ==
441 arch_flags[narch_flags].cputype &&
442 (arch_flags[j].cpusubtype & ~CPU_SUBTYPE_MASK) ==
443 (arch_flags[narch_flags].cpusubtype &
444 ~CPU_SUBTYPE_MASK) &&
445 strcmp(arch_flags[j].name,
446 arch_flags[narch_flags].name) == 0)
447 break;
449 if(j == narch_flags)
450 narch_flags++;
452 i++;
454 else{
455 for(j = 1; argv[i][j] != '\0'; j++){
456 switch(argv[i][j]){
457 #ifdef NMEDIT
458 case 'p':
459 pflag = 1;
460 break;
461 #else /* !defined(NMEDIT) */
462 case 'S':
463 Sflag = 1;
464 strip_all = 0;
465 break;
466 case 'X':
467 Xflag = 1;
468 strip_all = 0;
469 break;
470 case 'x':
471 xflag = 1;
472 strip_all = 0;
473 break;
474 case 't':
475 tflag = 1;
476 strip_all = 0;
477 break;
478 case 'i':
479 iflag = 1;
480 break;
481 case 'u':
482 uflag = 1;
483 strip_all = 0;
484 break;
485 case 'r':
486 rflag = 1;
487 strip_all = 0;
488 break;
489 case 'n':
490 nflag = 1;
491 strip_all = 0;
492 break;
493 #endif /* !defined(NMEDIT) */
494 case 'A':
495 Aflag = 1;
496 #ifndef NMEDIT
497 strip_all = 0;
498 #endif /* !defined(NMEDIT) */
499 break;
500 #ifndef NMEDIT
501 case 'a':
502 aflag = 1;
503 strip_all = 0;
504 break;
505 case 'c':
506 cflag = 1;
507 strip_all = 0;
508 break;
509 case 'v':
510 vflag = 1;
511 break;
512 case 'l':
513 lflag = 1;
514 break;
515 #endif /* NMEDIT */
516 default:
517 error("unrecognized option: %s", argv[i]);
518 usage();
523 else
524 files_specified++;
526 if(args_left == 0)
527 files_specified += argc - (i + 1);
529 if(files_specified > 1 && output_file != NULL){
530 error("-o <filename> can only be used when one file is specified");
531 usage();
534 if(sfile){
535 setup_symbol_list(sfile, &save_symbols, &nsave_symbols);
537 #ifdef NMEDIT
538 else{
539 if(Rfile == NULL && pflag == 0){
540 error("-s <filename>, -R <filename> or -p argument required");
541 usage();
544 #endif /* NMEDIT */
546 if(Rfile){
547 setup_symbol_list(Rfile, &remove_symbols, &nremove_symbols);
548 if(sfile){
549 for(j = 0; j < nremove_symbols ; j++){
550 sp = bsearch(remove_symbols[j].name,
551 save_symbols, nsave_symbols,
552 sizeof(struct symbol_list),
553 (int (*)(const void *, const void *))
554 symbol_list_bsearch);
555 if(sp != NULL){
556 error("symbol name: %s is listed in both -s %s and -R "
557 "%s files (can't be both saved and removed)",
558 remove_symbols[j].name, sfile, Rfile);
561 if(errors)
562 exit(EXIT_FAILURE);
566 /* the default when no -arch flags is present is to strip all archs */
567 if(narch_flags == 0)
568 all_archs = TRUE;
570 #ifndef NMEDIT
571 if(dfile){
572 setup_debug_filenames(dfile);
574 #endif /* !defined(NMEDIT) */
576 files_specified = 0;
577 args_left = 1;
578 for (i = 1; i < argc; i++) {
579 if(args_left && argv[i][0] == '-'){
580 if(argv[i][1] == '\0')
581 args_left = 0;
582 else if(strcmp(argv[i], "-o") == 0 ||
583 strcmp(argv[i], "-s") == 0 ||
584 strcmp(argv[i], "-R") == 0 ||
585 #ifndef NMEDIT
586 strcmp(argv[i], "-d") == 0 ||
587 #endif /* !defined(NMEDIT) */
588 strcmp(argv[i], "-arch") == 0)
589 i++;
591 else{
592 char resolved_path[PATH_MAX + 1];
594 if(realpath(argv[i], resolved_path) == NULL)
595 strip_file(argv[i], arch_flags, narch_flags, all_archs);
596 else
597 strip_file(resolved_path, arch_flags,narch_flags,all_archs);
598 files_specified++;
601 if(files_specified == 0)
602 fatal("no files specified");
604 if(errors)
605 return(EXIT_FAILURE);
606 else
607 return(EXIT_SUCCESS);
610 static
611 void
612 usage(
613 void)
615 #ifndef NMEDIT
616 fprintf(stderr, "Usage: %s [-AanuStXx] [-no_uuid] [-no_code_signature] "
617 "[-] [-d filename] [-s filename] [-R filename] [-o output] "
618 "file [...]\n", progname);
619 #else /* defined(NMEDIT) */
620 fprintf(stderr, "Usage: %s -s filename [-R filename] [-p] [-A] [-] "
621 "[-o output] file [...] \n",
622 progname);
623 #endif /* NMEDIT */
624 exit(EXIT_FAILURE);
627 static
628 void
629 strip_file(
630 char *input_file,
631 struct arch_flag *arch_flags,
632 uint32_t narch_flags,
633 enum bool all_archs)
635 struct ofile *ofile;
636 struct arch *archs;
637 uint32_t narchs;
638 struct stat stat_buf;
639 uint32_t previous_errors;
640 enum bool unix_standard_mode;
641 int cwd_fd;
642 char *rename_file;
643 #ifndef NMEDIT
644 char *p;
645 #endif
647 archs = NULL;
648 narchs = 0;
649 previous_errors = errors;
650 errors = 0;
652 /* breakout the file for processing */
653 ofile = breakout(input_file, &archs, &narchs, FALSE);
654 if(errors)
655 return;
657 /* checkout the file for symbol table replacement processing */
658 checkout(archs, narchs);
660 /* process the symbols in the input file */
661 strip_arch(archs, narchs, arch_flags, narch_flags, all_archs);
662 if(errors){
663 free_archs(archs, narchs);
664 ofile_unmap(ofile);
665 return;
668 /* create the output file */
669 if(stat(input_file, &stat_buf) == -1)
670 system_error("can't stat input file: %s", input_file);
671 if(output_file != NULL){
672 writeout(archs, narchs, output_file, stat_buf.st_mode & 0777,
673 TRUE, FALSE, FALSE, NULL);
675 else{
676 unix_standard_mode = get_unix_standard_mode();
677 rename_file = NULL;
678 cwd_fd = -1;
679 #ifdef NMEDIT
680 output_file = makestr(input_file, ".nmedit", NULL);
681 #else /* !defined(NMEDIT) */
683 * In UNIX standard conformance mode we are not allowed to replace
684 * a file that is not writeable.
686 if(unix_standard_mode == TRUE &&
687 access(input_file, W_OK) == -1){
688 system_error("file: %s is not writable", input_file);
689 goto strip_file_return;
691 output_file = makestr(input_file, ".strip", NULL);
694 * The UNIX standard conformance test suite expects files of
695 * MAXPATHLEN to work.
697 if(strlen(output_file) >= MAXPATHLEN){
699 * If there is a directory path in the name try to change
700 * the current working directory to that path.
702 if((p = rindex(output_file, '/')) != NULL){
703 if((cwd_fd = open(".", O_RDONLY, 0)) == -1){
704 system_error("can't open current working directory");
705 goto strip_file_return;
707 *p = '\0';
708 if(chdir(output_file) == -1){
709 system_error("can't change current working directory "
710 "to: %s", output_file);
711 goto strip_file_return;
713 p = rindex(input_file, '/');
714 rename_file = makestr(p + 1, NULL);
717 * Create what might be a short enough name.
719 free(output_file);
720 output_file = makestr("strip.XXXXXX", NULL);
721 output_file = mktemp(output_file);
723 #endif /* NMEDIT */
724 writeout(archs, narchs, output_file, stat_buf.st_mode & 0777,
725 TRUE, FALSE, FALSE, NULL);
726 if(rename_file != NULL){
727 if(rename(output_file, rename_file) == -1)
728 system_error("can't move temporary file: %s to file: %s",
729 output_file, rename_file);
730 free(rename_file);
732 else{
733 if(rename(output_file, input_file) == -1)
734 system_error("can't move temporary file: %s to input "
735 "file: %s", output_file, input_file);
737 free(output_file);
738 output_file = NULL;
741 * If we changed the current working directory change back to
742 * the previous working directory.
744 if(cwd_fd != -1){
745 if(fchdir(cwd_fd) == -1)
746 system_error("can't change back to previous working "
747 "directory");
748 if(close(cwd_fd) == -1)
749 system_error("can't close previous working directory");
753 #ifndef NMEDIT
754 strip_file_return:
755 #endif /* !defined(NMEDIT) */
756 /* clean-up data structures */
757 free_archs(archs, narchs);
758 ofile_unmap(ofile);
760 errors += previous_errors;
763 static
764 void
765 strip_arch(
766 struct arch *archs,
767 uint32_t narchs,
768 struct arch_flag *arch_flags,
769 uint32_t narch_flags,
770 enum bool all_archs)
772 uint32_t i, j, k, offset, size, missing_syms;
773 cpu_type_t cputype;
774 cpu_subtype_t cpusubtype;
775 struct arch_flag host_arch_flag;
776 enum bool arch_process, any_processing, *arch_flag_processed, family;
777 const struct arch_flag *family_arch_flag;
780 * Using the specified arch_flags process specified objects for those
781 * architecures.
783 any_processing = FALSE;
784 arch_flag_processed = NULL;
785 if(narch_flags != 0)
786 arch_flag_processed = allocate(narch_flags * sizeof(enum bool));
787 memset(arch_flag_processed, '\0', narch_flags * sizeof(enum bool));
788 for(i = 0; i < narchs; i++){
790 * Determine the architecture (cputype and cpusubtype) of arch[i]
792 cputype = 0;
793 cpusubtype = 0;
794 if(archs[i].type == OFILE_ARCHIVE){
795 for(j = 0; j < archs[i].nmembers; j++){
796 if(archs[i].members[j].type == OFILE_Mach_O){
797 cputype = archs[i].members[j].object->mh_cputype;
798 cpusubtype = archs[i].members[j].object->mh_cpusubtype;
799 break;
803 else if(archs[i].type == OFILE_Mach_O){
804 cputype = archs[i].object->mh_cputype;
805 cpusubtype = archs[i].object->mh_cpusubtype;
807 else if(archs[i].fat_arch != NULL){
808 cputype = archs[i].fat_arch->cputype;
809 cpusubtype = archs[i].fat_arch->cpusubtype;
811 arch_process = FALSE;
812 if(all_archs == TRUE){
813 arch_process = TRUE;
815 else if(narch_flags != 0){
816 family = FALSE;
817 if(narch_flags == 1){
818 family_arch_flag =
819 get_arch_family_from_cputype(arch_flags[0].cputype);
820 if(family_arch_flag != NULL)
821 family = (enum bool)
822 ((family_arch_flag->cpusubtype & ~CPU_SUBTYPE_MASK) ==
823 (arch_flags[0].cpusubtype & ~CPU_SUBTYPE_MASK));
825 for(j = 0; j < narch_flags; j++){
826 if(arch_flags[j].cputype == cputype &&
827 ((arch_flags[j].cpusubtype & ~CPU_SUBTYPE_MASK) ==
828 (cpusubtype & ~CPU_SUBTYPE_MASK) ||
829 family == TRUE)){
830 arch_process = TRUE;
831 arch_flag_processed[j] = TRUE;
832 break;
836 else{
837 (void)get_arch_from_host(&host_arch_flag, NULL);
838 if(host_arch_flag.cputype == cputype &&
839 (host_arch_flag.cpusubtype & ~CPU_SUBTYPE_MASK) ==
840 (cpusubtype & ~CPU_SUBTYPE_MASK))
841 arch_process = TRUE;
843 if(narchs != 1 && arch_process == FALSE)
844 continue;
845 any_processing = TRUE;
848 * Now this arch[i] has been selected to be processed so process it
849 * according to its type.
851 if(archs[i].type == OFILE_ARCHIVE){
852 for(j = 0; j < archs[i].nmembers; j++){
853 if(archs[i].members[j].type == OFILE_Mach_O){
854 strip_object(archs + i, archs[i].members + j,
855 archs[i].members[j].object);
858 missing_syms = 0;
859 if(iflag == 0){
860 for(k = 0; k < nsave_symbols; k++){
861 if(save_symbols[k].seen == FALSE){
862 if(missing_syms == 0){
863 error_arch(archs + i, NULL, "symbols names "
864 "listed in: %s not in: ", sfile);
865 missing_syms = 1;
867 fprintf(stderr, "%s\n", save_symbols[k].name);
871 for(k = 0; k < nsave_symbols; k++){
872 save_symbols[k].seen = FALSE;
874 missing_syms = 0;
875 if(iflag == 0){
876 for(k = 0; k < nremove_symbols; k++){
877 if(remove_symbols[k].seen == FALSE){
878 if(missing_syms == 0){
879 error_arch(archs + i, NULL, "symbols names "
880 "listed in: %s not defined in: ",
881 Rfile);
882 missing_syms = 1;
884 fprintf(stderr, "%s\n", remove_symbols[k].name);
888 for(k = 0; k < nremove_symbols; k++){
889 remove_symbols[k].seen = FALSE;
892 * Reset the library offsets and size.
894 offset = 0;
895 for(j = 0; j < archs[i].nmembers; j++){
896 archs[i].members[j].offset = offset;
897 size = 0;
898 if(archs[i].members[j].member_long_name == TRUE){
899 size = rnd(archs[i].members[j].member_name_size, 8) +
900 (rnd(sizeof(struct ar_hdr), 8) -
901 sizeof(struct ar_hdr));
902 archs[i].toc_long_name = TRUE;
904 if(archs[i].members[j].object != NULL){
905 size +=
906 rnd(archs[i].members[j].object->object_size -
907 archs[i].members[j].object->input_sym_info_size +
908 archs[i].members[j].object->output_sym_info_size,
910 sprintf(archs[i].members[j].ar_hdr->ar_size, "%-*ld",
911 (int)sizeof(archs[i].members[j].ar_hdr->ar_size),
912 (long)(size));
914 * This has to be done by hand because sprintf puts a
915 * null at the end of the buffer.
917 memcpy(archs[i].members[j].ar_hdr->ar_fmag, ARFMAG,
918 (int)sizeof(archs[i].members[j].ar_hdr->ar_fmag));
920 else{
921 size += archs[i].members[j].unknown_size;
923 offset += sizeof(struct ar_hdr) + size;
925 archs[i].library_size = offset;
927 else if(archs[i].type == OFILE_Mach_O){
928 strip_object(archs + i, NULL, archs[i].object);
930 else {
931 warning_arch(archs + i, NULL, "can't process non-object and "
932 "non-archive file: ");
933 return;
936 if(all_archs == FALSE && narch_flags != 0){
937 for(i = 0; i < narch_flags; i++){
938 if(arch_flag_processed[i] == FALSE)
939 error("file: %s does not contain architecture: %s",
940 archs[0].file_name, arch_flags[i].name);
942 free(arch_flag_processed);
944 if(any_processing == FALSE)
945 fatal("no processing done on input file: %s (specify a -arch flag)",
946 archs[0].file_name);
949 static
950 void
951 strip_object(
952 struct arch *arch,
953 struct member *member,
954 struct object *object)
956 enum byte_sex host_byte_sex;
957 uint32_t offset;
958 struct dylib_table_of_contents *tocs;
959 uint32_t ntoc;
960 struct dylib_module *mods;
961 struct dylib_module_64 *mods64;
962 uint32_t nmodtab;
963 struct dylib_reference *refs;
964 uint32_t nextrefsyms;
965 uint32_t i, j;
966 struct load_command *lc;
967 struct segment_command *sg;
968 struct segment_command_64 *sg64;
969 struct section *s;
970 struct section_64 *s64;
971 struct relocation_info *relocs;
972 struct scattered_relocation_info *sreloc;
973 int32_t missing_reloc_symbols;
974 uint32_t stride, section_type, nitems;
975 char *contents;
976 uint32_t dyld_info_start;
977 uint32_t dyld_info_end;
978 #ifndef NMEDIT
979 uint32_t flags;
980 uint32_t k;
981 #endif
982 uint32_t ncmds;
984 host_byte_sex = get_host_byte_sex();
986 /* Don't do anything to stub dylibs which have no load commands. */
987 if(object->mh_filetype == MH_DYLIB_STUB){
988 if((object->mh != NULL && object->mh->ncmds == 0) ||
989 (object->mh64 != NULL && object->mh64->ncmds == 0)){
990 return;
993 if(object->mh_filetype == MH_DSYM)
994 fatal_arch(arch, member, "can't process dSYM companion file: ");
995 if(object->st == NULL || object->st->nsyms == 0){
996 warning_arch(arch, member, "input object file stripped: ");
997 return;
1000 nsyms = object->st->nsyms;
1001 if(object->mh != NULL){
1002 symbols = (struct nlist *)
1003 (object->object_addr + object->st->symoff);
1004 if(object->object_byte_sex != host_byte_sex)
1005 swap_nlist(symbols, nsyms, host_byte_sex);
1006 symbols64 = NULL;
1008 else{
1009 symbols = NULL;
1010 symbols64 = (struct nlist_64 *)
1011 (object->object_addr + object->st->symoff);
1012 if(object->object_byte_sex != host_byte_sex)
1013 swap_nlist_64(symbols64, nsyms, host_byte_sex);
1015 strings = object->object_addr + object->st->stroff;
1016 strsize = object->st->strsize;
1018 #ifndef NMEDIT
1019 if(object->mh != NULL)
1020 flags = object->mh->flags;
1021 else
1022 flags = object->mh64->flags;
1023 if(object->mh_filetype == MH_DYLIB &&
1024 (flags & MH_PREBOUND) != MH_PREBOUND){
1025 arch->dont_update_LC_ID_DYLIB_timestamp = TRUE;
1027 if(object->mh_filetype != MH_DYLIB && cflag)
1028 fatal_arch(arch, member, "-c can't be used on non-dynamic "
1029 "library: ");
1030 #endif /* !(NMEDIT) */
1031 if(object->mh_filetype == MH_DYLIB_STUB)
1032 fatal_arch(arch, member, "dynamic stub library can't be changed "
1033 "once created: ");
1035 if(object->mh_filetype == MH_DYLIB){
1036 tocs = (struct dylib_table_of_contents *)
1037 (object->object_addr + object->dyst->tocoff);
1038 ntoc = object->dyst->ntoc;
1039 nmodtab = object->dyst->nmodtab;
1040 if(object->mh != NULL){
1041 mods = (struct dylib_module *)
1042 (object->object_addr + object->dyst->modtaboff);
1043 if(object->object_byte_sex != host_byte_sex)
1044 swap_dylib_module(mods, nmodtab, host_byte_sex);
1045 mods64 = NULL;
1047 else{
1048 mods = NULL;
1049 mods64 = (struct dylib_module_64 *)
1050 (object->object_addr + object->dyst->modtaboff);
1051 if(object->object_byte_sex != host_byte_sex)
1052 swap_dylib_module_64(mods64, nmodtab, host_byte_sex);
1054 refs = (struct dylib_reference *)
1055 (object->object_addr + object->dyst->extrefsymoff);
1056 nextrefsyms = object->dyst->nextrefsyms;
1057 if(object->object_byte_sex != host_byte_sex){
1058 swap_dylib_table_of_contents(tocs, ntoc, host_byte_sex);
1059 swap_dylib_reference(refs, nextrefsyms, host_byte_sex);
1061 #ifndef NMEDIT
1063 * In the -c flag is specified then strip the section contents of
1064 * this dynamic library and change it into a stub library. When
1065 * creating a stub library the timestamp is not changed.
1067 if(cflag){
1068 arch->dont_update_LC_ID_DYLIB_timestamp = TRUE;
1070 lc = object->load_commands;
1071 if(object->mh != NULL){
1072 ncmds = object->mh->ncmds;
1073 object->mh_filetype = MH_DYLIB_STUB;
1074 object->mh->filetype = MH_DYLIB_STUB;
1076 else{
1077 ncmds = object->mh64->ncmds;
1078 object->mh_filetype = MH_DYLIB_STUB;
1079 object->mh64->filetype = MH_DYLIB_STUB;
1081 for(i = 0; i < ncmds; i++){
1082 if(lc->cmd == LC_SEGMENT){
1083 sg = (struct segment_command *)lc;
1084 if(strcmp(sg->segname, SEG_LINKEDIT) != 0){
1086 * Zero out the section offset, reloff, and size
1087 * fields as the section contents are being removed.
1089 s = (struct section *)
1090 ((char *)sg + sizeof(struct segment_command));
1091 for(j = 0; j < sg->nsects; j++){
1093 * For section types with indirect tables we
1094 * do not zero out the section size in a stub
1095 * library. As the section size is needed to
1096 * know now many indirect table entries the
1097 * section has. This is a bit odd but programs
1098 * dealing with MH_DYLIB_STUB filetypes special
1099 * case this.
1101 section_type = s[j].flags & SECTION_TYPE;
1102 if(section_type != S_SYMBOL_STUBS &&
1103 section_type != S_LAZY_SYMBOL_POINTERS &&
1104 section_type != S_LAZY_DYLIB_SYMBOL_POINTERS &&
1105 section_type != S_NON_LAZY_SYMBOL_POINTERS){
1106 s[j].size = 0;
1108 s[j].addr = 0;
1109 s[j].offset = 0;
1110 s[j].reloff = 0;
1112 /* zero out file offset and size in the segment */
1113 sg->fileoff = 0;
1114 sg->filesize = 0;
1117 else if(lc->cmd == LC_SEGMENT_64){
1118 sg64 = (struct segment_command_64 *)lc;
1119 if(strcmp(sg64->segname, SEG_LINKEDIT) != 0){
1121 * Zero out the section offset, reloff, and size
1122 * fields as the section contents are being removed.
1124 s64 = (struct section_64 *)
1125 ((char *)sg64 +
1126 sizeof(struct segment_command_64));
1127 for(j = 0; j < sg64->nsects; j++){
1129 * For section types with indirect tables we
1130 * do not zero out the section size in a stub
1131 * library. As the section size is needed to
1132 * know now many indirect table entries the
1133 * section has. This is a bit odd but programs
1134 * dealing with MH_DYLIB_STUB filetypes special
1135 * case this.
1137 section_type = s64[j].flags & SECTION_TYPE;
1138 if(section_type != S_SYMBOL_STUBS &&
1139 section_type != S_LAZY_SYMBOL_POINTERS &&
1140 section_type != S_LAZY_DYLIB_SYMBOL_POINTERS &&
1141 section_type != S_NON_LAZY_SYMBOL_POINTERS){
1142 s64[j].size = 0;
1144 s64[j].addr = 0;
1145 s64[j].offset = 0;
1146 s64[j].reloff = 0;
1148 /* zero out file offset and size in the segment */
1149 sg64->fileoff = 0;
1150 sg64->filesize = 0;
1153 lc = (struct load_command *)((char *)lc + lc->cmdsize);
1156 * To get the right amount of the file copied out by writeout()
1157 * for the case when we are stripping out the section contents
1158 * we reduce the object size by the size of the section contents
1159 * including the padding after the load commands. Then this
1160 * size minus the size of the input symbolic information is
1161 * copied out.
1163 if(object->mh != NULL){
1164 object->object_size -= (object->seg_linkedit->fileoff -
1165 (sizeof(struct mach_header) +
1166 object->mh->sizeofcmds));
1168 * Set the file offset to the link edit information to be
1169 * right after the load commands.
1171 object->seg_linkedit->fileoff =
1172 sizeof(struct mach_header) +
1173 object->mh->sizeofcmds;
1175 else{
1176 object->object_size -= (object->seg_linkedit64->fileoff -
1177 (sizeof(struct mach_header_64) +
1178 object->mh64->sizeofcmds));
1180 * Set the file offset to the link edit information to be
1181 * right after the load commands.
1183 object->seg_linkedit64->fileoff =
1184 sizeof(struct mach_header_64) +
1185 object->mh64->sizeofcmds;
1188 #endif /* !(NMEDIT) */
1190 else{
1191 tocs = NULL;
1192 ntoc = 0;
1193 mods = NULL;
1194 mods64 = NULL;
1195 nmodtab = 0;
1196 refs = NULL;
1197 nextrefsyms = 0;
1201 * coalesced symbols can be stripped only if they are not used via an
1202 * symbol pointer. So to know that strip_symtab() needs to be passed
1203 * the indirect symbol table.
1205 if(object->dyst != NULL && object->dyst->nindirectsyms != 0){
1206 nindirectsyms = object->dyst->nindirectsyms;
1207 indirectsyms = (uint32_t *)
1208 (object->object_addr + object->dyst->indirectsymoff);
1209 if(object->object_byte_sex != host_byte_sex)
1210 swap_indirect_symbols(indirectsyms, nindirectsyms,
1211 host_byte_sex);
1213 else{
1214 indirectsyms = NULL;
1215 nindirectsyms = 0;
1218 if(object->mh != NULL)
1219 object->input_sym_info_size =
1220 nsyms * sizeof(struct nlist) +
1221 strsize;
1222 else
1223 object->input_sym_info_size =
1224 nsyms * sizeof(struct nlist_64) +
1225 strsize;
1226 #ifndef NMEDIT
1227 if(object->mh != NULL)
1228 flags = object->mh->flags;
1229 else
1230 flags = object->mh64->flags;
1231 if(strip_all &&
1232 (flags & MH_DYLDLINK) == MH_DYLDLINK &&
1233 object->mh_filetype == MH_EXECUTE)
1234 default_dyld_executable = TRUE;
1235 else
1236 default_dyld_executable = FALSE;
1237 #endif /* !defined(NMEDIT) */
1239 #ifndef NMEDIT
1240 if(sfile != NULL || Rfile != NULL || dfile != NULL || Aflag || aflag ||
1241 uflag || Sflag || xflag || Xflag || tflag || nflag || rflag ||
1242 default_dyld_executable || object->mh_filetype == MH_DYLIB ||
1243 object->mh_filetype == MH_DYLINKER)
1244 #endif /* !defined(NMEDIT) */
1246 #ifdef NMEDIT
1247 if(edit_symtab(arch, member, object, symbols, symbols64, nsyms,
1248 strings, strsize, tocs, ntoc, mods, mods64, nmodtab, refs,
1249 nextrefsyms) == FALSE)
1250 return;
1251 #else /* !defined(NMEDIT) */
1252 if(strip_symtab(arch, member, object, tocs, ntoc, mods, mods64,
1253 nmodtab, refs, nextrefsyms) == FALSE)
1254 return;
1255 if(no_uuid == TRUE)
1256 strip_LC_UUID_commands(arch, member, object);
1257 #endif /* !defined(NMEDIT) */
1258 if(object->mh != NULL)
1259 object->output_sym_info_size =
1260 new_nsyms * sizeof(struct nlist) +
1261 new_strsize;
1262 else
1263 object->output_sym_info_size =
1264 new_nsyms * sizeof(struct nlist_64) +
1265 new_strsize;
1267 object->st->nsyms = new_nsyms;
1268 object->st->strsize = new_strsize;
1270 if(object->mh != NULL)
1271 object->output_symbols = new_symbols;
1272 else
1273 object->output_symbols64 = new_symbols64;
1274 object->output_nsymbols = new_nsyms;
1275 object->output_strings = new_strings;
1276 object->output_strings_size = new_strsize;
1278 if(object->dyld_info != NULL){
1279 /* there are five parts to the dyld info, but
1280 strip does not alter them, so copy as a block */
1281 dyld_info_start = 0;
1282 if (object->dyld_info->rebase_off != 0)
1283 dyld_info_start = object->dyld_info->rebase_off;
1284 else if (object->dyld_info->bind_off != 0)
1285 dyld_info_start = object->dyld_info->bind_off;
1286 else if (object->dyld_info->weak_bind_off != 0)
1287 dyld_info_start = object->dyld_info->weak_bind_off;
1288 else if (object->dyld_info->lazy_bind_off != 0)
1289 dyld_info_start = object->dyld_info->lazy_bind_off;
1290 else if (object->dyld_info->export_off != 0)
1291 dyld_info_start = object->dyld_info->export_off;
1292 dyld_info_end = 0;
1293 if (object->dyld_info->export_size != 0)
1294 dyld_info_end = object->dyld_info->export_off
1295 + object->dyld_info->export_size;
1296 else if (object->dyld_info->lazy_bind_size != 0)
1297 dyld_info_end = object->dyld_info->lazy_bind_off
1298 + object->dyld_info->lazy_bind_size;
1299 else if (object->dyld_info->weak_bind_size != 0)
1300 dyld_info_end = object->dyld_info->weak_bind_off
1301 + object->dyld_info->weak_bind_size;
1302 else if (object->dyld_info->bind_size != 0)
1303 dyld_info_end = object->dyld_info->bind_off
1304 + object->dyld_info->bind_size;
1305 else if (object->dyld_info->rebase_size != 0)
1306 dyld_info_end = object->dyld_info->rebase_off
1307 + object->dyld_info->rebase_size;
1308 object->output_dyld_info = object->object_addr +dyld_info_start;
1309 object->output_dyld_info_size = dyld_info_end - dyld_info_start;
1310 object->output_sym_info_size += object->output_dyld_info_size;
1312 * Warn about strip -s or -R on a final linked image with
1313 * dyld_info.
1315 if(nsave_symbols != 0){
1316 warning_arch(arch, NULL, "removing global symbols from a "
1317 "final linked no longer supported. Use "
1318 "-exported_symbols_list at link time when "
1319 "building: ");
1322 if(object->split_info_cmd != NULL){
1323 object->output_split_info_data = object->object_addr +
1324 object->split_info_cmd->dataoff;
1325 object->output_split_info_data_size =
1326 object->split_info_cmd->datasize;
1328 if(object->func_starts_info_cmd != NULL){
1329 object->output_func_start_info_data = object->object_addr +
1330 object->func_starts_info_cmd->dataoff;
1331 object->output_func_start_info_data_size =
1332 object->func_starts_info_cmd->datasize;
1334 if(object->code_sig_cmd != NULL){
1335 #ifndef NMEDIT
1336 if(!cflag && !no_code_signature)
1337 #endif /* !(NMEDIT) */
1339 object->output_code_sig_data = object->object_addr +
1340 object->code_sig_cmd->dataoff;
1341 object->output_code_sig_data_size =
1342 object->code_sig_cmd->datasize;
1346 if(object->dyst != NULL){
1347 object->dyst->ilocalsym = 0;
1348 object->dyst->nlocalsym = new_nlocalsym;
1349 object->dyst->iextdefsym = new_nlocalsym;
1350 object->dyst->nextdefsym = new_nextdefsym;
1351 object->dyst->iundefsym = new_nlocalsym + new_nextdefsym;
1352 object->dyst->nundefsym = new_nundefsym;
1353 if(object->dyst->nindirectsyms != 0){
1354 object->output_indirect_symtab = indirectsyms;
1355 if(object->object_byte_sex != host_byte_sex)
1356 swap_indirect_symbols(indirectsyms, nindirectsyms,
1357 object->object_byte_sex);
1361 * If the -c option is specified the object's filetype will
1362 * have been changed from MH_DYLIB to MH_DYLIB_STUB above.
1364 if(object->mh_filetype == MH_DYLIB ||
1365 object->mh_filetype == MH_DYLIB_STUB){
1366 object->output_tocs = new_tocs;
1367 object->output_ntoc = new_ntoc;
1368 #ifdef NMEDIT
1369 if(object->mh != NULL)
1370 object->output_mods = new_mods;
1371 else
1372 object->output_mods64 = new_mods64;
1373 object->output_nmodtab = new_nmodtab;
1374 #else
1375 object->output_mods = mods;
1376 object->output_nmodtab = nmodtab;
1377 #endif
1378 object->output_refs = new_refs;
1379 object->output_nextrefsyms = new_nextrefsyms;
1380 if(object->object_byte_sex != host_byte_sex){
1381 swap_dylib_table_of_contents(new_tocs, new_ntoc,
1382 object->object_byte_sex);
1383 #ifdef NMEDIT
1384 if(object->mh != NULL)
1385 swap_dylib_module(new_mods, new_nmodtab,
1386 object->object_byte_sex);
1387 else
1388 swap_dylib_module_64(new_mods64, new_nmodtab,
1389 object->object_byte_sex);
1390 #else
1391 if(object->mh != NULL)
1392 swap_dylib_module(mods, nmodtab,
1393 object->object_byte_sex);
1394 else
1395 swap_dylib_module_64(mods64, nmodtab,
1396 object->object_byte_sex);
1397 #endif
1398 swap_dylib_reference(new_refs, new_nextrefsyms,
1399 object->object_byte_sex);
1402 if(object->dyld_info != NULL){
1403 object->input_sym_info_size += object->dyld_info->rebase_size
1404 + object->dyld_info->bind_size
1405 + object->dyld_info->weak_bind_size
1406 + object->dyld_info->lazy_bind_size
1407 + object->dyld_info->export_size;
1409 object->input_sym_info_size +=
1410 object->dyst->nlocrel * sizeof(struct relocation_info) +
1411 object->dyst->nextrel * sizeof(struct relocation_info) +
1412 object->dyst->ntoc * sizeof(struct dylib_table_of_contents)+
1413 object->dyst->nextrefsyms * sizeof(struct dylib_reference);
1414 if(object->mh != NULL){
1415 object->input_sym_info_size +=
1416 object->dyst->nmodtab * sizeof(struct dylib_module) +
1417 object->dyst->nindirectsyms * sizeof(uint32_t);
1419 else{
1420 object->input_sym_info_size +=
1421 object->dyst->nmodtab * sizeof(struct dylib_module_64) +
1422 object->dyst->nindirectsyms * sizeof(uint32_t) +
1423 object->input_indirectsym_pad;
1425 #ifndef NMEDIT
1427 * When stripping out the section contents to create a
1428 * dynamic library stub the relocation info also gets
1429 * stripped.
1431 if(!cflag)
1432 #endif /* !(NMEDIT) */
1434 object->output_sym_info_size +=
1435 object->dyst->nlocrel * sizeof(struct relocation_info) +
1436 object->dyst->nextrel * sizeof(struct relocation_info);
1438 object->output_sym_info_size +=
1439 new_ntoc * sizeof(struct dylib_table_of_contents)+
1440 new_nextrefsyms * sizeof(struct dylib_reference) +
1441 object->dyst->nindirectsyms * sizeof(uint32_t) +
1442 object->input_indirectsym_pad;
1443 if(object->mh != NULL){
1444 object->output_sym_info_size +=
1445 object->dyst->nmodtab * sizeof(struct dylib_module);
1447 else{
1448 object->output_sym_info_size +=
1449 object->dyst->nmodtab * sizeof(struct dylib_module_64);
1451 if(object->hints_cmd != NULL){
1452 object->input_sym_info_size +=
1453 object->hints_cmd->nhints *
1454 sizeof(struct twolevel_hint);
1455 object->output_sym_info_size +=
1456 object->hints_cmd->nhints *
1457 sizeof(struct twolevel_hint);
1459 if(object->split_info_cmd != NULL){
1460 object->input_sym_info_size +=
1461 object->split_info_cmd->datasize;
1462 object->output_sym_info_size +=
1463 object->split_info_cmd->datasize;
1465 if(object->func_starts_info_cmd != NULL){
1466 object->input_sym_info_size +=
1467 object->func_starts_info_cmd->datasize;
1468 object->output_sym_info_size +=
1469 object->func_starts_info_cmd->datasize;
1471 if(object->code_sig_cmd != NULL){
1472 object->input_sym_info_size =
1473 rnd(object->input_sym_info_size, 16);
1474 object->input_sym_info_size +=
1475 object->code_sig_cmd->datasize;
1476 #ifndef NMEDIT
1477 if(cflag || no_code_signature){
1478 strip_LC_CODE_SIGNATURE_commands(arch, member, object);
1480 else
1481 #endif /* !(NMEDIT) */
1483 object->output_sym_info_size =
1484 rnd(object->output_sym_info_size, 16);
1485 object->output_sym_info_size +=
1486 object->code_sig_cmd->datasize;
1490 object->dyst->ntoc = new_ntoc;
1491 object->dyst->nextrefsyms = new_nextrefsyms;
1493 offset = get_starting_syminfo_offset(object);
1495 if(object->dyld_info != 0){
1496 if (object->dyld_info->rebase_off != 0){
1497 object->dyld_info->rebase_off = offset;
1498 offset += object->dyld_info->rebase_size;
1500 if (object->dyld_info->bind_off != 0){
1501 object->dyld_info->bind_off = offset;
1502 offset += object->dyld_info->bind_size;
1504 if (object->dyld_info->weak_bind_off != 0){
1505 object->dyld_info->weak_bind_off = offset;
1506 offset += object->dyld_info->weak_bind_size;
1508 if (object->dyld_info->lazy_bind_off != 0){
1509 object->dyld_info->lazy_bind_off = offset;
1510 offset += object->dyld_info->lazy_bind_size;
1512 if (object->dyld_info->export_off != 0){
1513 object->dyld_info->export_off = offset;
1514 offset += object->dyld_info->export_size;
1518 if(object->dyst->nlocrel != 0){
1519 object->output_loc_relocs = (struct relocation_info *)
1520 (object->object_addr + object->dyst->locreloff);
1521 #ifndef NMEDIT
1523 * When stripping out the section contents to create a
1524 * dynamic library stub the relocation info also gets
1525 * stripped.
1527 if(cflag){
1528 object->dyst->nlocrel = 0;
1529 object->dyst->locreloff = 0;
1531 else
1532 #endif /* defined(NMEDIT) */
1534 object->dyst->locreloff = offset;
1535 offset += object->dyst->nlocrel *
1536 sizeof(struct relocation_info);
1539 else
1540 object->dyst->locreloff = 0;
1542 if(object->split_info_cmd != NULL){
1543 object->split_info_cmd->dataoff = offset;
1544 offset += object->split_info_cmd->datasize;
1547 if(object->func_starts_info_cmd != NULL){
1548 object->func_starts_info_cmd->dataoff = offset;
1549 offset += object->func_starts_info_cmd->datasize;
1552 if(object->st->nsyms != 0){
1553 object->st->symoff = offset;
1554 if(object->mh != NULL)
1555 offset += object->st->nsyms * sizeof(struct nlist);
1556 else
1557 offset += object->st->nsyms * sizeof(struct nlist_64);
1559 else
1560 object->st->symoff = 0;
1562 if(object->hints_cmd != NULL){
1563 if(object->hints_cmd->nhints != 0){
1564 object->output_hints = (struct twolevel_hint *)
1565 (object->object_addr + object->hints_cmd->offset);
1566 object->hints_cmd->offset = offset;
1567 offset += object->hints_cmd->nhints *
1568 sizeof(struct twolevel_hint);
1570 else
1571 object->hints_cmd->offset = 0;
1574 if(object->dyst->nextrel != 0){
1575 object->output_ext_relocs = (struct relocation_info *)
1576 (object->object_addr + object->dyst->extreloff);
1577 #ifndef NMEDIT
1579 * When stripping out the section contents to create a
1580 * dynamic library stub the relocation info also gets
1581 * stripped.
1583 if(cflag){
1584 object->dyst->nextrel = 0;
1585 object->dyst->extreloff = 0;
1587 else
1588 #endif /* defined(NMEDIT) */
1590 object->dyst->extreloff = offset;
1591 offset += object->dyst->nextrel *
1592 sizeof(struct relocation_info);
1595 else
1596 object->dyst->extreloff = 0;
1598 if(object->dyst->nindirectsyms != 0){
1599 object->dyst->indirectsymoff = offset;
1600 offset += object->dyst->nindirectsyms * sizeof(uint32_t) +
1601 object->input_indirectsym_pad;
1603 else
1604 object->dyst->indirectsymoff = 0;;
1606 if(object->dyst->ntoc != 0){
1607 object->dyst->tocoff = offset;
1608 offset += object->dyst->ntoc *
1609 sizeof(struct dylib_table_of_contents);
1611 else
1612 object->dyst->tocoff = 0;
1614 if(object->dyst->nmodtab != 0){
1615 #ifndef NMEDIT
1617 * When stripping out the section contents to create a
1618 * dynamic library stub zero out the fields in the module
1619 * table for the sections and relocation information and
1620 * clear Objective-C address and size from modules.
1622 if(cflag){
1623 if(object->mh != NULL){
1624 for(k = 0; k < object->dyst->nmodtab; k++){
1625 mods[k].iinit_iterm = 0;
1626 mods[k].ninit_nterm = 0;
1627 mods[k].iextrel = 0;
1628 mods[k].nextrel = 0;
1629 mods[k].objc_module_info_addr = 0;
1630 mods[k].objc_module_info_size = 0;
1633 else{
1634 for(k = 0; k < object->dyst->nmodtab; k++){
1635 mods64[k].iinit_iterm = 0;
1636 mods64[k].ninit_nterm = 0;
1637 mods64[k].iextrel = 0;
1638 mods64[k].nextrel = 0;
1639 mods64[k].objc_module_info_addr = 0;
1640 mods64[k].objc_module_info_size = 0;
1644 #endif /* !(NMEDIT) */
1645 object->dyst->modtaboff = offset;
1646 if(object->mh != NULL)
1647 offset += object->dyst->nmodtab *
1648 sizeof(struct dylib_module);
1649 else
1650 offset += object->dyst->nmodtab *
1651 sizeof(struct dylib_module_64);
1653 else
1654 object->dyst->modtaboff = 0;
1656 if(object->dyst->nextrefsyms != 0){
1657 object->dyst->extrefsymoff = offset;
1658 offset += object->dyst->nextrefsyms *
1659 sizeof(struct dylib_reference);
1661 else
1662 object->dyst->extrefsymoff = 0;
1664 if(object->st->strsize != 0){
1665 object->st->stroff = offset;
1666 offset += object->st->strsize;
1668 else
1669 object->st->stroff = 0;
1671 if(object->code_sig_cmd != NULL){
1672 offset = rnd(offset, 16);
1673 object->code_sig_cmd->dataoff = offset;
1674 offset += object->code_sig_cmd->datasize;
1677 else{
1678 if(new_strsize != 0){
1679 if(object->mh != NULL)
1680 object->st->stroff = object->st->symoff +
1681 new_nsyms * sizeof(struct nlist);
1682 else
1683 object->st->stroff = object->st->symoff +
1684 new_nsyms * sizeof(struct nlist_64);
1686 else
1687 object->st->stroff = 0;
1688 if(new_nsyms == 0)
1689 object->st->symoff = 0;
1692 #ifndef NMEDIT
1693 else{
1695 * Here we are doing a full symbol strip. In some cases it may
1696 * leave the local relocation entries as well as LOCAL indirect
1697 * symbol table entries.
1699 if(saves != NULL)
1700 free(saves);
1701 saves = (int32_t *)allocate(object->st->nsyms * sizeof(int32_t));
1702 bzero(saves, object->st->nsyms * sizeof(int32_t));
1705 * Account for the symbolic info in the input file.
1707 if(object->dyst != NULL){
1708 object->input_sym_info_size +=
1709 object->dyst->nlocrel * sizeof(struct relocation_info) +
1710 object->dyst->nextrel * sizeof(struct relocation_info) +
1711 object->dyst->ntoc * sizeof(struct dylib_table_of_contents)+
1712 object->dyst->nextrefsyms * sizeof(struct dylib_reference);
1713 if(object->mh != NULL){
1714 object->input_sym_info_size +=
1715 object->dyst->nmodtab * sizeof(struct dylib_module) +
1716 object->dyst->nindirectsyms * sizeof(uint32_t);
1718 else{
1719 object->input_sym_info_size +=
1720 object->dyst->nmodtab * sizeof(struct dylib_module_64) +
1721 object->dyst->nindirectsyms * sizeof(uint32_t) +
1722 object->input_indirectsym_pad;
1727 * Determine the offset where the remaining symbolic info will start
1728 * in the output file (if any).
1730 offset = get_starting_syminfo_offset(object);
1733 * For a full symbol strip all these values in the output file are
1734 * set to zero.
1736 object->st->symoff = 0;
1737 object->st->nsyms = 0;
1738 object->st->stroff = 0;
1739 object->st->strsize = 0;
1740 if(object->dyst != NULL){
1741 object->dyst->ilocalsym = 0;
1742 object->dyst->nlocalsym = 0;
1743 object->dyst->iextdefsym = 0;
1744 object->dyst->nextdefsym = 0;
1745 object->dyst->iundefsym = 0;
1746 object->dyst->nundefsym = 0;
1750 * This will accumulate any remaining symbolic info size in the
1751 * output file.
1753 object->output_sym_info_size = 0;
1756 * We set these so that checking can be done below to report the
1757 * symbols that can't be stripped because of relocation entries
1758 * or indirect symbol table entries. Normally if these table have a
1759 * non-zero number of entries it will be an error as we are trying
1760 * to strip everything. But it maybe that there are only LOCAL
1761 * indirect entries which is odd but will be OK.
1763 if(object->dyst != NULL){
1764 if(object->dyst->nextrel != 0){
1765 object->output_ext_relocs = (struct relocation_info *)
1766 (object->object_addr + object->dyst->extreloff);
1769 * Since this file has a dynamic symbol table and if this file
1770 * has local relocation entries on input make sure they are
1771 * there on output. This is a rare case that it will not have
1772 * external relocs or indirect symbols but can happen as is the
1773 * case with the dynamic linker itself.
1775 if(object->dyst->nlocrel != 0){
1776 object->output_loc_relocs = (struct relocation_info *)
1777 (object->object_addr + object->dyst->locreloff);
1778 object->output_sym_info_size +=
1779 object->dyst->nlocrel * sizeof(struct relocation_info);
1781 object->dyst->locreloff = offset;
1782 offset += object->dyst->nlocrel *
1783 sizeof(struct relocation_info);
1786 if(object->dyst->nindirectsyms != 0){
1787 object->output_indirect_symtab = (uint32_t *)
1788 (object->object_addr +
1789 object->dyst->indirectsymoff);
1790 if(object->object_byte_sex != host_byte_sex)
1791 swap_indirect_symbols(
1792 object->output_indirect_symtab,
1793 object->dyst->nindirectsyms,
1794 object->object_byte_sex);
1796 object->output_sym_info_size +=
1797 object->dyst->nindirectsyms * sizeof(uint32_t) +
1798 object->input_indirectsym_pad;
1800 object->dyst->indirectsymoff = offset;
1801 offset += object->dyst->nindirectsyms * sizeof(uint32_t) +
1802 object->input_indirectsym_pad;
1806 #endif /* !defined(NMEDIT) */
1809 * Always clear the prebind checksum if any when creating a new file.
1811 if(object->cs != NULL)
1812 object->cs->cksum = 0;
1814 if(object->seg_linkedit != NULL){
1815 object->seg_linkedit->filesize += object->output_sym_info_size -
1816 object->input_sym_info_size;
1817 object->seg_linkedit->vmsize = object->seg_linkedit->filesize;
1819 else if(object->seg_linkedit64 != NULL){
1820 /* Do this in two steps to avoid 32/64-bit casting problems. */
1821 object->seg_linkedit64->filesize -= object->input_sym_info_size;
1822 object->seg_linkedit64->filesize += object->output_sym_info_size;
1823 object->seg_linkedit64->vmsize = object->seg_linkedit64->filesize;
1827 * Check and update the external relocation entries to make sure
1828 * referenced symbols are not stripped and refer to the new symbol
1829 * table indexes.
1831 * The external relocation entries can be located in one of two places,
1832 * first off of the sections or second off of the dynamic symtab.
1834 missing_reloc_symbols = 0;
1835 lc = object->load_commands;
1836 if(object->mh != NULL)
1837 ncmds = object->mh->ncmds;
1838 else
1839 ncmds = object->mh64->ncmds;
1840 for(i = 0; i < ncmds; i++){
1841 if(lc->cmd == LC_SEGMENT &&
1842 object->seg_linkedit != (struct segment_command *)lc){
1843 sg = (struct segment_command *)lc;
1844 s = (struct section *)((char *)sg +
1845 sizeof(struct segment_command));
1846 for(j = 0; j < sg->nsects; j++){
1847 if(s->nreloc != 0){
1848 if(s->reloff + s->nreloc *
1849 sizeof(struct relocation_info) >
1850 object->object_size){
1851 fatal_arch(arch, member, "truncated or malformed "
1852 "object (relocation entries for section (%.16s,"
1853 "%.16s) extends past the end of the file)",
1854 s->segname, s->sectname);
1856 relocs = (struct relocation_info *)
1857 (object->object_addr + s->reloff);
1858 if(object->object_byte_sex != host_byte_sex)
1859 swap_relocation_info(relocs, s->nreloc,
1860 host_byte_sex);
1861 if(s->offset + s->size > object->object_size){
1862 fatal_arch(arch, member, "truncated or malformed "
1863 "object (contents of section (%.16s,"
1864 "%.16s) extends past the end of the file)",
1865 s->segname, s->sectname);
1867 contents = object->object_addr + s->offset;
1868 check_object_relocs(arch, member, object, s->segname,
1869 s->sectname, s->size, contents, relocs, s->nreloc,
1870 symbols, symbols64, nsyms, strings,
1871 &missing_reloc_symbols, host_byte_sex);
1872 if(object->object_byte_sex != host_byte_sex)
1873 swap_relocation_info(relocs, s->nreloc,
1874 object->object_byte_sex);
1876 s++;
1879 else if(lc->cmd == LC_SEGMENT_64 &&
1880 object->seg_linkedit64 != (struct segment_command_64 *)lc){
1881 sg64 = (struct segment_command_64 *)lc;
1882 s64 = (struct section_64 *)((char *)sg64 +
1883 sizeof(struct segment_command_64));
1884 for(j = 0; j < sg64->nsects; j++){
1885 if(s64->nreloc != 0){
1886 if(s64->reloff + s64->nreloc *
1887 sizeof(struct relocation_info) >
1888 object->object_size){
1889 fatal_arch(arch, member, "truncated or malformed "
1890 "object (relocation entries for section (%.16s,"
1891 "%.16s) extends past the end of the file)",
1892 s64->segname, s64->sectname);
1894 relocs = (struct relocation_info *)
1895 (object->object_addr + s64->reloff);
1896 if(object->object_byte_sex != host_byte_sex)
1897 swap_relocation_info(relocs, s64->nreloc,
1898 host_byte_sex);
1899 if(s64->offset + s64->size > object->object_size){
1900 fatal_arch(arch, member, "truncated or malformed "
1901 "object (contents of section (%.16s,"
1902 "%.16s) extends past the end of the file)",
1903 s64->segname, s64->sectname);
1905 contents = object->object_addr + s64->offset;
1906 check_object_relocs(arch, member, object, s64->segname,
1907 s64->sectname, s64->size, contents, relocs,
1908 s64->nreloc, symbols, symbols64, nsyms, strings,
1909 &missing_reloc_symbols, host_byte_sex);
1910 if(object->object_byte_sex != host_byte_sex)
1911 swap_relocation_info(relocs, s64->nreloc,
1912 object->object_byte_sex);
1914 s64++;
1917 lc = (struct load_command *)((char *)lc + lc->cmdsize);
1919 if(object->dyst != NULL && object->dyst->nextrel != 0){
1920 relocs = object->output_ext_relocs;
1921 if(object->object_byte_sex != host_byte_sex)
1922 swap_relocation_info(relocs, object->dyst->nextrel,
1923 host_byte_sex);
1925 for(i = 0; i < object->dyst->nextrel; i++){
1926 if((relocs[i].r_address & R_SCATTERED) == 0 &&
1927 relocs[i].r_extern == 1){
1928 if(relocs[i].r_symbolnum > nsyms){
1929 fatal_arch(arch, member, "bad r_symbolnum for external "
1930 "relocation entry %d in: ", i);
1932 if(saves[relocs[i].r_symbolnum] == 0){
1933 if(missing_reloc_symbols == 0){
1934 error_arch(arch, member, "symbols referenced by "
1935 "relocation entries that can't be stripped in: ");
1936 missing_reloc_symbols = 1;
1938 if(object->mh != NULL){
1939 fprintf(stderr, "%s\n", strings + symbols
1940 [relocs[i].r_symbolnum].n_un.n_strx);
1942 else {
1943 fprintf(stderr, "%s\n", strings + symbols64
1944 [relocs[i].r_symbolnum].n_un.n_strx);
1946 saves[relocs[i].r_symbolnum] = -1;
1948 if(saves[relocs[i].r_symbolnum] != -1){
1949 relocs[i].r_symbolnum =
1950 saves[relocs[i].r_symbolnum] - 1;
1953 else{
1954 fatal_arch(arch, member, "bad external relocation entry "
1955 "%d (not external) in: ", i);
1957 if((relocs[i].r_address & R_SCATTERED) == 0){
1958 if(reloc_has_pair(object->mh_cputype, relocs[i].r_type))
1959 i++;
1961 else{
1962 sreloc = (struct scattered_relocation_info *)relocs + i;
1963 if(reloc_has_pair(object->mh_cputype, sreloc->r_type))
1964 i++;
1967 if(object->object_byte_sex != host_byte_sex)
1968 swap_relocation_info(relocs, object->dyst->nextrel,
1969 object->object_byte_sex);
1973 * Check and update the indirect symbol table entries to make sure
1974 * referenced symbols are not stripped and refer to the new symbol
1975 * table indexes.
1977 if(object->dyst != NULL && object->dyst->nindirectsyms != 0){
1978 if(object->object_byte_sex != host_byte_sex)
1979 swap_indirect_symbols(object->output_indirect_symtab,
1980 object->dyst->nindirectsyms, host_byte_sex);
1982 lc = object->load_commands;
1983 if(object->mh != NULL)
1984 ncmds = object->mh->ncmds;
1985 else
1986 ncmds = object->mh64->ncmds;
1987 for(i = 0; i < ncmds; i++){
1988 if(lc->cmd == LC_SEGMENT &&
1989 object->seg_linkedit != (struct segment_command *)lc){
1990 sg = (struct segment_command *)lc;
1991 s = (struct section *)((char *)sg +
1992 sizeof(struct segment_command));
1993 for(j = 0; j < sg->nsects; j++){
1994 section_type = s->flags & SECTION_TYPE;
1995 if(section_type == S_LAZY_SYMBOL_POINTERS ||
1996 section_type == S_LAZY_DYLIB_SYMBOL_POINTERS ||
1997 section_type == S_NON_LAZY_SYMBOL_POINTERS)
1998 stride = 4;
1999 else if(section_type == S_SYMBOL_STUBS)
2000 stride = s->reserved2;
2001 else{
2002 s++;
2003 continue;
2005 nitems = s->size / stride;
2006 contents = object->object_addr + s->offset;
2007 check_indirect_symtab(arch, member, object, nitems,
2008 s->reserved1, section_type, contents, symbols,
2009 symbols64, nsyms, strings, &missing_reloc_symbols,
2010 host_byte_sex);
2011 s++;
2014 else if(lc->cmd == LC_SEGMENT_64 &&
2015 object->seg_linkedit64 != (struct segment_command_64 *)lc){
2016 sg64 = (struct segment_command_64 *)lc;
2017 s64 = (struct section_64 *)((char *)sg64 +
2018 sizeof(struct segment_command_64));
2019 for(j = 0; j < sg64->nsects; j++){
2020 section_type = s64->flags & SECTION_TYPE;
2021 if(section_type == S_LAZY_SYMBOL_POINTERS ||
2022 section_type == S_LAZY_DYLIB_SYMBOL_POINTERS ||
2023 section_type == S_NON_LAZY_SYMBOL_POINTERS)
2024 stride = 8;
2025 else if(section_type == S_SYMBOL_STUBS)
2026 stride = s64->reserved2;
2027 else{
2028 s64++;
2029 continue;
2031 nitems = s64->size / stride;
2032 contents = object->object_addr + s64->offset;
2033 check_indirect_symtab(arch, member, object, nitems,
2034 s64->reserved1, section_type, contents, symbols,
2035 symbols64, nsyms, strings, &missing_reloc_symbols,
2036 host_byte_sex);
2037 s64++;
2040 lc = (struct load_command *)((char *)lc + lc->cmdsize);
2043 if(object->object_byte_sex != host_byte_sex)
2044 swap_indirect_symbols(object->output_indirect_symtab,
2045 object->dyst->nindirectsyms, object->object_byte_sex);
2049 * Issue a warning if object file has a code signature that the
2050 * operation will invalidate it.
2052 if(object->code_sig_cmd != NULL)
2053 warning_arch(arch, member, "changes being made to the file will "
2054 "invalidate the code signature in: ");
2058 * get_starting_syminfo_offset() returns the starting offset of the symbolic
2059 * info in the object file.
2061 static
2062 uint32_t
2063 get_starting_syminfo_offset(
2064 struct object *object)
2066 uint32_t offset;
2068 if(object->seg_linkedit != NULL ||
2069 object->seg_linkedit64 != NULL){
2070 if(object->mh != NULL)
2071 offset = object->seg_linkedit->fileoff;
2072 else
2073 offset = object->seg_linkedit64->fileoff;
2075 else{
2076 offset = UINT_MAX;
2077 if(object->dyst != NULL &&
2078 object->dyst->nlocrel != 0 &&
2079 object->dyst->locreloff < offset)
2080 offset = object->dyst->locreloff;
2081 if(object->st->nsyms != 0 &&
2082 object->st->symoff < offset)
2083 offset = object->st->symoff;
2084 if(object->dyst != NULL &&
2085 object->dyst->nextrel != 0 &&
2086 object->dyst->extreloff < offset)
2087 offset = object->dyst->extreloff;
2088 if(object->dyst != NULL &&
2089 object->dyst->nindirectsyms != 0 &&
2090 object->dyst->indirectsymoff < offset)
2091 offset = object->dyst->indirectsymoff;
2092 if(object->dyst != NULL &&
2093 object->dyst->ntoc != 0 &&
2094 object->dyst->tocoff < offset)
2095 offset = object->dyst->tocoff;
2096 if(object->dyst != NULL &&
2097 object->dyst->nmodtab != 0 &&
2098 object->dyst->modtaboff < offset)
2099 offset = object->dyst->modtaboff;
2100 if(object->dyst != NULL &&
2101 object->dyst->nextrefsyms != 0 &&
2102 object->dyst->extrefsymoff < offset)
2103 offset = object->dyst->extrefsymoff;
2104 if(object->st->strsize != 0 &&
2105 object->st->stroff < offset)
2106 offset = object->st->stroff;
2108 return(offset);
2112 * check_object_relocs() is used to check and update the external relocation
2113 * entries from a section in an object file, to make sure referenced symbols
2114 * are not stripped and are changed to refer to the new symbol table indexes.
2116 static
2117 void
2118 check_object_relocs(
2119 struct arch *arch,
2120 struct member *member,
2121 struct object *object,
2122 char *segname,
2123 char *sectname,
2124 uint64_t sectsize,
2125 char *contents,
2126 struct relocation_info *relocs,
2127 uint32_t nreloc,
2128 struct nlist *symbols,
2129 struct nlist_64 *symbols64,
2130 uint32_t nsyms,
2131 char *strings,
2132 int32_t *missing_reloc_symbols,
2133 enum byte_sex host_byte_sex)
2135 uint32_t k, n_strx;
2136 uint64_t n_value;
2137 #ifdef NMEDIT
2138 uint32_t value, n_ext;
2139 uint64_t value64;
2140 #endif
2141 struct scattered_relocation_info *sreloc;
2143 for(k = 0; k < nreloc; k++){
2144 if((relocs[k].r_address & R_SCATTERED) == 0 &&
2145 relocs[k].r_extern == 1){
2146 if(relocs[k].r_symbolnum > nsyms){
2147 fatal_arch(arch, member, "bad r_symbolnum for relocation "
2148 "entry %d in section (%.16s,%.16s) in: ", k, segname,
2149 sectname);
2151 if(object->mh != NULL){
2152 n_strx = symbols[relocs[k].r_symbolnum].n_un.n_strx;
2153 n_value = symbols[relocs[k].r_symbolnum].n_value;
2155 else{
2156 n_strx = symbols64[relocs[k].r_symbolnum].n_un.n_strx;
2157 n_value = symbols64[relocs[k].r_symbolnum].n_value;
2159 #ifndef NMEDIT
2160 if(saves[relocs[k].r_symbolnum] == 0){
2161 if(*missing_reloc_symbols == 0){
2162 error_arch(arch, member, "symbols referenced by "
2163 "relocation entries that can't be stripped in: ");
2164 *missing_reloc_symbols = 1;
2166 fprintf(stderr, "%s\n", strings + n_strx);
2167 saves[relocs[k].r_symbolnum] = -1;
2169 #else /* defined(NMEDIT) */
2171 * We are letting nmedit change global coalesed symbols into
2172 * statics in MH_OBJECT file types only. Relocation entries to
2173 * global coalesced symbols are external relocs.
2175 if(object->mh != NULL)
2176 n_ext = new_symbols[saves[relocs[k].r_symbolnum] - 1].
2177 n_type & N_EXT;
2178 else
2179 n_ext = new_symbols64[saves[relocs[k].r_symbolnum] - 1].
2180 n_type & N_EXT;
2181 if(n_ext != N_EXT &&
2182 object->mh_cputype != CPU_TYPE_X86_64){
2184 * We need to do the relocation for this external relocation
2185 * entry so the item to be relocated is correct for a local
2186 * relocation entry. We don't need to do this for x86-64.
2188 if(relocs[k].r_address + sizeof(int32_t) > sectsize){
2189 fatal_arch(arch, member, "truncated or malformed "
2190 "object (r_address of relocation entry %u of "
2191 "section (%.16s,%.16s) extends past the end "
2192 "of the section)", k, segname, sectname);
2194 if(object->mh != NULL){
2195 value = *(uint32_t *)
2196 (contents + relocs[k].r_address);
2197 if(object->object_byte_sex != host_byte_sex)
2198 value = SWAP_INT(value);
2200 * We handle a very limited form here. Only VANILLA
2201 * (r_type == 0) long (r_length==2) absolute or pcrel
2202 * that won't need a scattered relocation entry.
2204 if(relocs[k].r_type != 0 ||
2205 relocs[k].r_length != 2){
2206 fatal_arch(arch, member, "don't have "
2207 "code to convert external relocation "
2208 "entry %d in section (%.16s,%.16s) "
2209 "for global coalesced symbol: %s "
2210 "in: ", k, segname, sectname,
2211 strings + n_strx);
2213 value += n_value;
2214 if(object->object_byte_sex != host_byte_sex)
2215 value = SWAP_INT(value);
2216 *(uint32_t *)(contents + relocs[k].r_address) =
2217 value;
2219 else{
2220 value64 = *(uint64_t *)(contents + relocs[k].r_address);
2221 if(object->object_byte_sex != host_byte_sex)
2222 value64 = SWAP_LONG_LONG(value64);
2224 * We handle a very limited form here. Only VANILLA
2225 * (r_type == 0) quad (r_length==3) absolute or pcrel
2226 * that won't need a scattered relocation entry.
2228 if(relocs[k].r_type != 0 ||
2229 relocs[k].r_length != 3){
2230 fatal_arch(arch, member, "don't have "
2231 "code to convert external relocation "
2232 "entry %d in section (%.16s,%.16s) "
2233 "for global coalesced symbol: %s "
2234 "in: ", k, segname, sectname,
2235 strings + n_strx);
2237 value64 += n_value;
2238 if(object->object_byte_sex != host_byte_sex)
2239 value64 = SWAP_LONG_LONG(value64);
2240 *(uint64_t *)(contents + relocs[k].r_address) = value64;
2243 * Turn the extern reloc into a local.
2245 if(object->mh != NULL)
2246 relocs[k].r_symbolnum =
2247 new_symbols[saves[relocs[k].r_symbolnum] - 1].n_sect;
2248 else
2249 relocs[k].r_symbolnum =
2250 new_symbols64[saves[relocs[k].r_symbolnum] - 1].n_sect;
2251 relocs[k].r_extern = 0;
2253 #endif /* NMEDIT */
2254 if(relocs[k].r_extern == 1 &&
2255 saves[relocs[k].r_symbolnum] != -1){
2256 relocs[k].r_symbolnum = saves[relocs[k].r_symbolnum] - 1;
2259 if((relocs[k].r_address & R_SCATTERED) == 0){
2260 if(reloc_has_pair(object->mh_cputype, relocs[k].r_type) == TRUE)
2261 k++;
2263 else{
2264 sreloc = (struct scattered_relocation_info *)relocs + k;
2265 if(reloc_has_pair(object->mh_cputype, sreloc->r_type) == TRUE)
2266 k++;
2272 * check_indirect_symtab() checks and updates the indirect symbol table entries
2273 * to make sure referenced symbols are not stripped and refer to the new symbol
2274 * table indexes.
2276 static
2277 void
2278 check_indirect_symtab(
2279 struct arch *arch,
2280 struct member *member,
2281 struct object *object,
2282 uint32_t nitems,
2283 uint32_t reserved1,
2284 uint32_t section_type,
2285 char *contents,
2286 struct nlist *symbols,
2287 struct nlist_64 *symbols64,
2288 uint32_t nsyms,
2289 char *strings,
2290 int32_t *missing_reloc_symbols,
2291 enum byte_sex host_byte_sex)
2293 uint32_t k, index;
2294 uint8_t n_type;
2295 uint32_t n_strx, value;
2296 uint64_t value64;
2297 enum bool made_local;
2299 for(k = 0; k < nitems; k++){
2300 made_local = FALSE;
2301 index = object->output_indirect_symtab[reserved1 + k];
2302 if(index == INDIRECT_SYMBOL_LOCAL ||
2303 index == INDIRECT_SYMBOL_ABS ||
2304 index == (INDIRECT_SYMBOL_LOCAL | INDIRECT_SYMBOL_ABS))
2305 continue;
2306 if(index > nsyms)
2307 fatal_arch(arch, member,"indirect symbol table entry %d (past " "the end of the symbol table) in: ", reserved1 + k);
2308 #ifdef NMEDIT
2309 if(pflag == 0 && nmedits[index] == TRUE && saves[index] != -1)
2310 #else
2311 if(saves[index] == 0)
2312 #endif
2315 * Indirect symbol table entries for defined symbols in a
2316 * non-lazy pointer section that are not saved are changed to
2317 * INDIRECT_SYMBOL_LOCAL which their values just have to be
2318 * slid if the are not absolute symbols.
2320 if(object->mh != NULL){
2321 n_type = symbols[index].n_type;
2322 n_strx = symbols[index].n_un.n_strx;
2324 else{
2325 n_type = symbols64[index].n_type;
2326 n_strx = symbols64[index].n_un.n_strx;
2328 if((n_type && N_TYPE) != N_UNDF &&
2329 (n_type && N_TYPE) != N_PBUD &&
2330 section_type == S_NON_LAZY_SYMBOL_POINTERS){
2331 object->output_indirect_symtab[reserved1 + k] =
2332 INDIRECT_SYMBOL_LOCAL;
2333 if((n_type & N_TYPE) == N_ABS)
2334 object->output_indirect_symtab[reserved1 + k] |=
2335 INDIRECT_SYMBOL_ABS;
2336 made_local = TRUE;
2338 * When creating a stub shared library the section contents
2339 * are not updated since they will be stripped.
2341 if(object->mh_filetype != MH_DYLIB_STUB){
2342 if(object->mh != NULL){
2343 value = symbols[index].n_value;
2344 if (symbols[index].n_desc & N_ARM_THUMB_DEF)
2345 value |= 1;
2346 if(object->object_byte_sex != host_byte_sex)
2347 value = SWAP_INT(value);
2348 *(uint32_t *)(contents + k * 4) = value;
2350 else{
2351 value64 = symbols64[index].n_value;
2352 if(object->object_byte_sex != host_byte_sex)
2353 value64 = SWAP_LONG_LONG(value64);
2354 *(uint64_t *)(contents + k * 8) = value64;
2358 #ifdef NMEDIT
2359 else {
2360 object->output_indirect_symtab[reserved1 + k] =
2361 saves[index] - 1;
2363 #else /* !defined(NMEDIT) */
2364 else{
2365 if(*missing_reloc_symbols == 0){
2366 error_arch(arch, member, "symbols referenced by "
2367 "indirect symbol table entries that can't be "
2368 "stripped in: ");
2369 *missing_reloc_symbols = 1;
2371 fprintf(stderr, "%s\n", strings + n_strx);
2372 saves[index] = -1;
2374 #endif /* !defined(NMEDIT) */
2376 #ifdef NMEDIT
2377 else
2378 #else /* !defined(NMEDIT) */
2379 if(made_local == FALSE && saves[index] != -1)
2380 #endif /* !defined(NMEDIT) */
2382 object->output_indirect_symtab[reserved1+k] = saves[index] - 1;
2387 #ifndef NMEDIT
2389 * This is called if there is a -d option specified. It reads the file with
2390 * the strings in it and places them in the array debug_filenames and sorts
2391 * them by name. The file that contains the file names must have names one
2392 * per line with no white space (except the newlines).
2394 static
2395 void
2396 setup_debug_filenames(
2397 char *dfile)
2399 int fd, i, strings_size;
2400 struct stat stat_buf;
2401 char *strings, *p;
2403 if((fd = open(dfile, O_RDONLY)) < 0){
2404 system_error("can't open: %s", dfile);
2405 return;
2407 if(fstat(fd, &stat_buf) == -1){
2408 system_error("can't stat: %s", dfile);
2409 close(fd);
2410 return;
2412 strings_size = stat_buf.st_size;
2413 strings = (char *)allocate(strings_size + 1);
2414 strings[strings_size] = '\0';
2415 if(read(fd, strings, strings_size) != strings_size){
2416 system_error("can't read: %s", dfile);
2417 close(fd);
2418 return;
2420 p = strings;
2421 for(i = 0; i < strings_size; i++){
2422 if(*p == '\n'){
2423 *p = '\0';
2424 ndebug_filenames++;
2426 p++;
2428 debug_filenames = (char **)allocate(ndebug_filenames * sizeof(char *));
2429 p = strings;
2430 for(i = 0; i < ndebug_filenames; i++){
2431 debug_filenames[i] = p;
2432 p += strlen(p) + 1;
2434 qsort(debug_filenames, ndebug_filenames, sizeof(char *),
2435 (int (*)(const void *, const void *))cmp_qsort_filename);
2437 #ifdef DEBUG
2438 printf("Debug filenames:\n");
2439 for(i = 0; i < ndebug_filenames; i++){
2440 printf("filename = %s\n", debug_filenames[i]);
2442 #endif /* DEBUG */
2446 * Strip the symbol table to the level specified by the command line arguments.
2447 * The new symbol table is built and new_symbols is left pointing to it. The
2448 * number of new symbols is left in new_nsyms, the new string table is built
2449 * and new_stings is left pointing to it and new_strsize is left containing it.
2450 * This routine returns zero if successfull and non-zero otherwise.
2452 static
2453 enum bool
2454 strip_symtab(
2455 struct arch *arch,
2456 struct member *member,
2457 struct object *object,
2458 struct dylib_table_of_contents *tocs,
2459 uint32_t ntoc,
2460 struct dylib_module *mods,
2461 struct dylib_module_64 *mods64,
2462 uint32_t nmodtab,
2463 struct dylib_reference *refs,
2464 uint32_t nextrefsyms)
2466 uint32_t i, j, k, n, inew_syms, save_debug, missing_syms;
2467 uint32_t missing_symbols;
2468 char *p, *q, **pp, *basename;
2469 struct symbol_list *sp;
2470 uint32_t new_ext_strsize, len, *changes, inew_undefsyms;
2471 unsigned char nsects;
2472 struct load_command *lc;
2473 struct segment_command *sg;
2474 struct segment_command_64 *sg64;
2475 struct section *s, **sections;
2476 struct section_64 *s64, **sections64;
2477 uint32_t ncmds, mh_flags, s_flags, n_strx;
2478 struct nlist *sym;
2479 struct undef_map *undef_map;
2480 struct undef_map64 *undef_map64;
2481 uint8_t n_type, n_sect;
2482 uint16_t n_desc;
2483 uint64_t n_value;
2484 uint32_t module_name, iextdefsym, nextdefsym, ilocalsym, nlocalsym;
2485 uint32_t irefsym, nrefsym;
2486 unsigned char text_nsect;
2487 enum bool has_dwarf, hack_5614542;
2489 save_debug = 0;
2490 if(saves != NULL)
2491 free(saves);
2492 changes = NULL;
2493 for(i = 0; i < nsave_symbols; i++)
2494 save_symbols[i].sym = NULL;
2495 for(i = 0; i < nremove_symbols; i++)
2496 remove_symbols[i].sym = NULL;
2497 if(member == NULL){
2498 for(i = 0; i < nsave_symbols; i++)
2499 save_symbols[i].seen = FALSE;
2500 for(i = 0; i < nremove_symbols; i++)
2501 remove_symbols[i].seen = FALSE;
2504 new_nsyms = 0;
2505 if(object->mh != NULL)
2506 new_strsize = sizeof(int32_t);
2507 else
2508 new_strsize = sizeof(int64_t);
2509 new_nlocalsym = 0;
2510 new_nextdefsym = 0;
2511 new_nundefsym = 0;
2512 new_ext_strsize = 0;
2515 * If this an object file that has DWARF debugging sections to strip
2516 * then we have to run ld -r on it.
2518 if(object->mh_filetype == MH_OBJECT && (Sflag || xflag)){
2519 has_dwarf = FALSE;
2520 lc = object->load_commands;
2521 if(object->mh != NULL)
2522 ncmds = object->mh->ncmds;
2523 else
2524 ncmds = object->mh64->ncmds;
2525 for(i = 0; i < ncmds && has_dwarf == FALSE; i++){
2526 if(lc->cmd == LC_SEGMENT){
2527 sg = (struct segment_command *)lc;
2528 s = (struct section *)((char *)sg +
2529 sizeof(struct segment_command));
2530 for(j = 0; j < sg->nsects; j++){
2531 if(s->flags & S_ATTR_DEBUG){
2532 has_dwarf = TRUE;
2533 break;
2535 s++;
2538 else if(lc->cmd == LC_SEGMENT_64){
2539 sg64 = (struct segment_command_64 *)lc;
2540 s64 = (struct section_64 *)((char *)sg64 +
2541 sizeof(struct segment_command_64));
2542 for(j = 0; j < sg64->nsects; j++){
2543 if(s64->flags & S_ATTR_DEBUG){
2544 has_dwarf = TRUE;
2545 break;
2547 s64++;
2550 lc = (struct load_command *)((char *)lc + lc->cmdsize);
2553 * Because of the bugs in ld(1) for:
2554 * radr://5675774 ld64 should preserve JBSR relocations without
2555 * -static
2556 * radr://5658046 cctools-679 creates scattered relocations in
2557 * __TEXT,__const section in kexts, which breaks
2558 * kexts built for older systems
2559 * we can't use ld -r to strip dwarf info in 32-bit objects until
2560 * these are fixed. But if the user as specified the -l flag then
2561 * go ahead and do it and the user will have to be aware of these
2562 * bugs.
2564 if((lflag == TRUE && has_dwarf == TRUE) || object->mh64 != NULL)
2565 make_ld_r_object(arch, member, object);
2568 * Because of the "design" of 64-bit object files and the lack of
2569 * local relocation entries it is not possible for strip(1) to do its
2570 * job without becoming a static link editor. The "design" does not
2571 * actually strip the symbols it simply renames them to things like
2572 * "l1000". And they become static symbols but still have external
2573 * relocation entries. Thus can never actually be stripped. Also some
2574 * symbols, *.eh, symbols are not even changed to these names if there
2575 * corresponding global symbol is not stripped. So strip(1) only
2576 * recourse is to use the unified linker to create an ld -r object then
2577 * save all resulting symbols (both static and global) and hope the user
2578 * does not notice the stripping is not what they asked for.
2580 if(object->mh_filetype == MH_OBJECT &&
2581 (object->mh64 != NULL && object->ld_r_ofile == NULL))
2582 make_ld_r_object(arch, member, object);
2585 * Since make_ld_r_object() may create an object with more symbols
2586 * this has to be done after make_ld_r_object() and nsyms is updated.
2588 saves = (int32_t *)allocate(nsyms * sizeof(int32_t));
2589 bzero(saves, nsyms * sizeof(int32_t));
2592 * Gather an array of section struct pointers so we can later determine
2593 * if we run into a global symbol in a coalesced section and not strip
2594 * those symbols.
2595 * statics.
2597 nsects = 0;
2598 text_nsect = NO_SECT;
2599 lc = object->load_commands;
2600 if(object->mh != NULL)
2601 ncmds = object->mh->ncmds;
2602 else
2603 ncmds = object->mh64->ncmds;
2604 for(i = 0; i < ncmds; i++){
2605 if(lc->cmd == LC_SEGMENT){
2606 sg = (struct segment_command *)lc;
2607 nsects += sg->nsects;
2609 else if(lc->cmd == LC_SEGMENT_64){
2610 sg64 = (struct segment_command_64 *)lc;
2611 nsects += sg64->nsects;
2613 lc = (struct load_command *)((char *)lc + lc->cmdsize);
2615 if(object->mh != NULL){
2616 sections = allocate(nsects * sizeof(struct section *));
2617 sections64 = NULL;
2619 else{
2620 sections = NULL;
2621 sections64 = allocate(nsects * sizeof(struct section_64 *));
2623 nsects = 0;
2624 lc = object->load_commands;
2625 for(i = 0; i < ncmds; i++){
2626 if(lc->cmd == LC_SEGMENT){
2627 sg = (struct segment_command *)lc;
2628 s = (struct section *)((char *)sg +
2629 sizeof(struct segment_command));
2630 for(j = 0; j < sg->nsects; j++){
2631 if(strcmp((s + j)->sectname, SECT_TEXT) == 0 &&
2632 strcmp((s + j)->segname, SEG_TEXT) == 0)
2633 text_nsect = nsects + 1;
2634 sections[nsects++] = s++;
2637 else if(lc->cmd == LC_SEGMENT_64){
2638 sg64 = (struct segment_command_64 *)lc;
2639 s64 = (struct section_64 *)((char *)sg64 +
2640 sizeof(struct segment_command_64));
2641 for(j = 0; j < sg64->nsects; j++){
2642 if(strcmp((s64 + j)->sectname, SECT_TEXT) == 0 &&
2643 strcmp((s64 + j)->segname, SEG_TEXT) == 0)
2644 text_nsect = nsects + 1;
2645 sections64[nsects++] = s64++;
2648 lc = (struct load_command *)((char *)lc + lc->cmdsize);
2651 for(i = 0; i < nsyms; i++){
2652 s_flags = 0;
2653 if(object->mh != NULL){
2654 mh_flags = object->mh->flags;
2655 n_strx = symbols[i].n_un.n_strx;
2656 n_type = symbols[i].n_type;
2657 n_sect = symbols[i].n_sect;
2658 if((n_type & N_TYPE) == N_SECT){
2659 if(n_sect == 0 || n_sect > nsects){
2660 error_arch(arch, member, "bad n_sect for symbol "
2661 "table entry %d in: ", i);
2662 return(FALSE);
2664 s_flags = sections[n_sect - 1]->flags;
2666 n_desc = symbols[i].n_desc;
2667 n_value = symbols[i].n_value;
2669 else{
2670 mh_flags = object->mh64->flags;
2671 n_strx = symbols64[i].n_un.n_strx;
2672 n_type = symbols64[i].n_type;
2673 n_sect = symbols64[i].n_sect;
2674 if((n_type & N_TYPE) == N_SECT){
2675 if(n_sect == 0 || n_sect > nsects){
2676 error_arch(arch, member, "bad n_sect for symbol "
2677 "table entry %d in: ", i);
2678 return(FALSE);
2680 s_flags = sections64[n_sect - 1]->flags;
2682 n_desc = symbols64[i].n_desc;
2683 n_value = symbols64[i].n_value;
2685 if(n_strx != 0){
2686 if(n_strx > strsize){
2687 error_arch(arch, member, "bad string index for symbol "
2688 "table entry %d in: ", i);
2689 return(FALSE);
2692 if((n_type & N_TYPE) == N_INDR){
2693 if(n_value != 0){
2694 if(n_value > strsize){
2695 error_arch(arch, member, "bad string index for "
2696 "indirect symbol table entry %d in: ", i);
2697 return(FALSE);
2701 if((n_type & N_EXT) == 0){ /* local symbol */
2702 if(aflag){
2703 if(n_strx != 0)
2704 new_strsize += strlen(strings + n_strx) + 1;
2705 new_nlocalsym++;
2706 new_nsyms++;
2707 saves[i] = new_nsyms;
2710 * For x86_64 .o files we have run ld -r on them and are stuck
2711 * keeping all resulting symbols.
2713 else if(object->mh == NULL && (
2714 object->mh64->cputype == CPU_TYPE_X86_64) &&
2715 object->mh64->filetype == MH_OBJECT){
2716 if(n_strx != 0)
2717 new_strsize += strlen(strings + n_strx) + 1;
2718 new_nlocalsym++;
2719 new_nsyms++;
2720 saves[i] = new_nsyms;
2723 * The cases a local symbol might be saved are with -X, -S, -t,
2724 * or with -d filename.
2726 else if((!strip_all && (Xflag || tflag || Sflag)) || dfile){
2727 if(n_type & N_STAB){ /* debug symbol */
2728 if(dfile && n_type == N_SO){
2729 if(n_strx != 0){
2730 basename = strrchr(strings + n_strx, '/');
2731 if(basename != NULL)
2732 basename++;
2733 else
2734 basename = strings + n_strx;
2735 pp = bsearch(basename, debug_filenames,
2736 ndebug_filenames, sizeof(char *),
2737 (int (*)(const void *, const void *)
2738 )cmp_bsearch_filename);
2740 * Save the bracketing N_SO. For each N_SO that
2741 * has a filename there is an N_SO that has a
2742 * name of "" which ends the stabs for that file
2744 if(*basename != '\0'){
2745 if(pp != NULL)
2746 save_debug = 1;
2747 else
2748 save_debug = 0;
2750 else{
2752 * This is a bracketing SO so if we are
2753 * currently saving debug symbols save this
2754 * last one and turn off saving debug syms.
2756 if(save_debug){
2757 if(n_strx != 0)
2758 new_strsize += strlen(strings +
2759 n_strx) + 1;
2760 new_nlocalsym++;
2761 new_nsyms++;
2762 saves[i] = new_nsyms;
2764 save_debug = 0;
2767 else{
2768 save_debug = 0;
2771 if(saves[i] == 0 && (!Sflag || save_debug)){
2772 if(n_strx != 0)
2773 new_strsize += strlen(strings + n_strx) + 1;
2774 new_nlocalsym++;
2775 new_nsyms++;
2776 saves[i] = new_nsyms;
2779 else{ /* non-debug local symbol */
2780 if(xflag == 0 && (Sflag || Xflag || tflag)){
2782 * No -x (strip all local), and one of -S (strip
2783 * debug), -X (strip 'L' local), or -t (strip
2784 * local except non-'L' text) was given.
2786 if((Xflag && n_strx != 0 &&
2787 strings[n_strx] != 'L') ||
2788 (tflag && (n_type & N_TYPE) == N_SECT &&
2789 n_sect == text_nsect && n_strx != 0 &&
2790 strings[n_strx] != 'L') ||
2791 (Sflag && !Xflag && !tflag)) {
2793 * If this file is a for the dynamic linker and
2794 * this symbol is in a section marked so that
2795 * static symbols are stripped then don't
2796 * keep this symbol.
2798 if((mh_flags & MH_DYLDLINK) != MH_DYLDLINK ||
2799 (n_type & N_TYPE) != N_SECT ||
2800 (s_flags & S_ATTR_STRIP_STATIC_SYMS) !=
2801 S_ATTR_STRIP_STATIC_SYMS){
2802 new_strsize += strlen(strings + n_strx) + 1;
2803 new_nlocalsym++;
2804 new_nsyms++;
2805 saves[i] = new_nsyms;
2810 * Treat a local symbol that was a private extern as if
2811 * were global if it is referenced by a module and save
2812 * it.
2814 if((n_type & N_PEXT) == N_PEXT){
2815 if(saves[i] == 0 &&
2816 private_extern_reference_by_module(
2817 i, refs ,nextrefsyms) == TRUE){
2818 if(n_strx != 0)
2819 new_strsize += strlen(strings + n_strx) + 1;
2820 new_nlocalsym++;
2821 new_nsyms++;
2822 saves[i] = new_nsyms;
2825 * We need to save symbols that were private externs
2826 * that are used with indirect symbols.
2828 if(saves[i] == 0 &&
2829 symbol_pointer_used(i, indirectsyms,
2830 nindirectsyms) == TRUE){
2831 if(n_strx != 0){
2832 len = strlen(strings + n_strx) + 1;
2833 new_strsize += len;
2835 new_nlocalsym++;
2836 new_nsyms++;
2837 saves[i] = new_nsyms;
2843 * Treat a local symbol that was a private extern as if were
2844 * global if it is not referenced by a module.
2846 else if((n_type & N_PEXT) == N_PEXT){
2847 if(saves[i] == 0 && sfile){
2848 sp = bsearch(strings + n_strx,
2849 save_symbols, nsave_symbols,
2850 sizeof(struct symbol_list),
2851 (int (*)(const void *, const void *))
2852 symbol_list_bsearch);
2853 if(sp != NULL){
2854 if(sp->sym == NULL){
2855 if(object->mh != NULL)
2856 sp->sym = &(symbols[i]);
2857 else
2858 sp->sym = &(symbols64[i]);
2859 sp->seen = TRUE;
2861 if(n_strx != 0)
2862 new_strsize += strlen(strings + n_strx) + 1;
2863 new_nlocalsym++;
2864 new_nsyms++;
2865 saves[i] = new_nsyms;
2868 if(saves[i] == 0 &&
2869 private_extern_reference_by_module(
2870 i, refs ,nextrefsyms) == TRUE){
2871 if(n_strx != 0)
2872 new_strsize += strlen(strings + n_strx) + 1;
2873 new_nlocalsym++;
2874 new_nsyms++;
2875 saves[i] = new_nsyms;
2878 * We need to save symbols that were private externs that
2879 * are used with indirect symbols.
2881 if(saves[i] == 0 &&
2882 symbol_pointer_used(i, indirectsyms, nindirectsyms) ==
2883 TRUE){
2884 if(n_strx != 0){
2885 len = strlen(strings + n_strx) + 1;
2886 new_strsize += len;
2888 new_nlocalsym++;
2889 new_nsyms++;
2890 saves[i] = new_nsyms;
2894 else{ /* global symbol */
2896 * strip -R on an x86_64 .o file should do nothing.
2898 if(Rfile &&
2899 (object->mh != NULL ||
2900 object->mh64->cputype != CPU_TYPE_X86_64 ||
2901 object->mh64->filetype != MH_OBJECT)){
2902 sp = bsearch(strings + n_strx,
2903 remove_symbols, nremove_symbols,
2904 sizeof(struct symbol_list),
2905 (int (*)(const void *, const void *))
2906 symbol_list_bsearch);
2907 if(sp != NULL){
2908 if((n_type & N_TYPE) == N_UNDF ||
2909 (n_type & N_TYPE) == N_PBUD){
2910 error_arch(arch, member, "symbol: %s undefined"
2911 " and can't be stripped from: ",
2912 sp->name);
2914 else if(sp->sym != NULL){
2915 sym = (struct nlist *)sp->sym;
2916 if((sym->n_type & N_PEXT) != N_PEXT)
2917 error_arch(arch, member, "more than one symbol "
2918 "for: %s found in: ", sp->name);
2920 else{
2921 if(object->mh != NULL)
2922 sp->sym = &(symbols[i]);
2923 else
2924 sp->sym = &(symbols64[i]);
2925 sp->seen = TRUE;
2927 if(n_desc & REFERENCED_DYNAMICALLY){
2928 error_arch(arch, member, "symbol: %s is dynamically"
2929 " referenced and can't be stripped "
2930 "from: ", sp->name);
2932 if((n_type & N_TYPE) == N_SECT &&
2933 (s_flags & SECTION_TYPE) == S_COALESCED){
2934 error_arch(arch, member, "symbol: %s is a global "
2935 "coalesced symbol and can't be "
2936 "stripped from: ", sp->name);
2938 /* don't save this symbol */
2939 continue;
2942 if(Aflag && (n_type & N_TYPE) == N_ABS &&
2943 (n_value != 0 ||
2944 (n_strx != 0 &&
2945 strncmp(strings + n_strx,
2946 ".objc_class_name_",
2947 sizeof(".objc_class_name_") - 1) == 0))){
2948 len = strlen(strings + n_strx) + 1;
2949 new_strsize += len;
2950 new_ext_strsize += len;
2951 new_nextdefsym++;
2952 new_nsyms++;
2953 saves[i] = new_nsyms;
2955 if(saves[i] == 0 && (uflag || default_dyld_executable) &&
2956 ((((n_type & N_TYPE) == N_UNDF) &&
2957 n_value == 0) ||
2958 (n_type & N_TYPE) == N_PBUD)){
2959 if(n_strx != 0){
2960 len = strlen(strings + n_strx) + 1;
2961 new_strsize += len;
2962 new_ext_strsize += len;
2964 new_nundefsym++;
2965 new_nsyms++;
2966 saves[i] = new_nsyms;
2968 if(saves[i] == 0 && nflag &&
2969 (n_type & N_TYPE) == N_SECT){
2970 if(n_strx != 0){
2971 len = strlen(strings + n_strx) + 1;
2972 new_strsize += len;
2973 new_ext_strsize += len;
2975 new_nextdefsym++;
2976 new_nsyms++;
2977 saves[i] = new_nsyms;
2979 if(saves[i] == 0 && sfile){
2980 sp = bsearch(strings + n_strx,
2981 save_symbols, nsave_symbols,
2982 sizeof(struct symbol_list),
2983 (int (*)(const void *, const void *))
2984 symbol_list_bsearch);
2985 if(sp != NULL){
2986 if(sp->sym != NULL){
2987 sym = (struct nlist *)sp->sym;
2988 if((sym->n_type & N_PEXT) != N_PEXT)
2989 error_arch(arch, member, "more than one symbol "
2990 "for: %s found in: ", sp->name);
2992 else{
2993 if(object->mh != NULL)
2994 sp->sym = &(symbols[i]);
2995 else
2996 sp->sym = &(symbols64[i]);
2997 sp->seen = TRUE;
2998 len = strlen(strings + n_strx) + 1;
2999 new_strsize += len;
3000 new_ext_strsize += len;
3001 if((n_type & N_TYPE) == N_UNDF ||
3002 (n_type & N_TYPE) == N_PBUD)
3003 new_nundefsym++;
3004 else
3005 new_nextdefsym++;
3006 new_nsyms++;
3007 saves[i] = new_nsyms;
3012 * We only need to save coalesced symbols that are used as
3013 * indirect symbols in 32-bit applications.
3015 * In 64-bit applications, we only need to save coalesced
3016 * symbols that are used as weak definitions.
3018 if(object->mh != NULL &&
3019 saves[i] == 0 &&
3020 (n_type & N_TYPE) == N_SECT &&
3021 (s_flags & SECTION_TYPE) == S_COALESCED &&
3022 symbol_pointer_used(i, indirectsyms, nindirectsyms) == TRUE){
3023 if(n_strx != 0){
3024 len = strlen(strings + n_strx) + 1;
3025 new_strsize += len;
3026 new_ext_strsize += len;
3028 new_nextdefsym++;
3029 new_nsyms++;
3030 saves[i] = new_nsyms;
3032 if(saves[i] == 0 &&
3033 (n_type & N_TYPE) == N_SECT &&
3034 (n_desc & N_WEAK_DEF) != 0){
3035 if(n_strx != 0){
3036 len = strlen(strings + n_strx) + 1;
3037 new_strsize += len;
3038 new_ext_strsize += len;
3040 new_nextdefsym++;
3041 new_nsyms++;
3042 saves[i] = new_nsyms;
3044 if(saves[i] == 0 &&
3045 ((Xflag || Sflag || xflag || tflag || aflag) ||
3046 ((rflag || default_dyld_executable) &&
3047 n_desc & REFERENCED_DYNAMICALLY))){
3048 len = strlen(strings + n_strx) + 1;
3049 new_strsize += len;
3050 new_ext_strsize += len;
3051 if((n_type & N_TYPE) == N_INDR){
3052 len = strlen(strings + n_value) + 1;
3053 new_strsize += len;
3054 new_ext_strsize += len;
3056 if((n_type & N_TYPE) == N_UNDF ||
3057 (n_type & N_TYPE) == N_PBUD)
3058 new_nundefsym++;
3059 else
3060 new_nextdefsym++;
3061 new_nsyms++;
3062 saves[i] = new_nsyms;
3065 * For x86_64 .o files we have run ld -r on them and are stuck
3066 * keeping all resulting symbols.
3068 if(saves[i] == 0 &&
3069 object->mh == NULL &&
3070 object->mh64->cputype == CPU_TYPE_X86_64 &&
3071 object->mh64->filetype == MH_OBJECT){
3072 len = strlen(strings + n_strx) + 1;
3073 new_strsize += len;
3074 new_ext_strsize += len;
3075 if((n_type & N_TYPE) == N_INDR){
3076 len = strlen(strings + n_value) + 1;
3077 new_strsize += len;
3078 new_ext_strsize += len;
3080 if((n_type & N_TYPE) == N_UNDF ||
3081 (n_type & N_TYPE) == N_PBUD)
3082 new_nundefsym++;
3083 else
3084 new_nextdefsym++;
3085 new_nsyms++;
3086 saves[i] = new_nsyms;
3091 * The module table's module names are placed with the external strings.
3092 * So size them and add this to the external string size.
3094 for(i = 0; i < nmodtab; i++){
3095 if(object->mh != NULL)
3096 module_name = mods[i].module_name;
3097 else
3098 module_name = mods64[i].module_name;
3099 if(module_name == 0 || module_name > strsize){
3100 error_arch(arch, member, "bad string index for module_name "
3101 "of module table entry %d in: ", i);
3102 return(FALSE);
3104 len = strlen(strings + module_name) + 1;
3105 new_strsize += len;
3106 new_ext_strsize += len;
3110 * Updating the reference table may require a symbol not yet listed as
3111 * as saved to be present in the output file. If a defined external
3112 * symbol is removed and there is a undefined reference to it in the
3113 * reference table an undefined symbol needs to be created for it in
3114 * the output file. If this happens the number of new symbols and size
3115 * of the new strings are adjusted. And the array changes[] is set to
3116 * map the old symbol index to the new symbol index for the symbol that
3117 * is changed to an undefined symbol.
3119 missing_symbols = 0;
3120 if(ref_saves != NULL)
3121 free(ref_saves);
3122 ref_saves = (int32_t *)allocate(nextrefsyms * sizeof(int32_t));
3123 bzero(ref_saves, nextrefsyms * sizeof(int32_t));
3124 changes = (uint32_t *)allocate(nsyms * sizeof(int32_t));
3125 bzero(changes, nsyms * sizeof(int32_t));
3126 new_nextrefsyms = 0;
3127 for(i = 0; i < nextrefsyms; i++){
3128 if(refs[i].isym > nsyms){
3129 error_arch(arch, member, "bad symbol table index for "
3130 "reference table entry %d in: ", i);
3131 return(FALSE);
3133 if(saves[refs[i].isym]){
3134 new_nextrefsyms++;
3135 ref_saves[i] = new_nextrefsyms;
3137 else{
3138 if(refs[i].flags == REFERENCE_FLAG_UNDEFINED_NON_LAZY ||
3139 refs[i].flags == REFERENCE_FLAG_UNDEFINED_LAZY){
3140 if(changes[refs[i].isym] == 0){
3141 if(object->mh != NULL)
3142 n_strx = symbols[refs[i].isym].n_un.n_strx;
3143 else
3144 n_strx = symbols64[refs[i].isym].n_un.n_strx;
3145 len = strlen(strings + n_strx) + 1;
3146 new_strsize += len;
3147 new_ext_strsize += len;
3148 new_nundefsym++;
3149 new_nsyms++;
3150 changes[refs[i].isym] = new_nsyms;
3151 new_nextrefsyms++;
3152 ref_saves[i] = new_nextrefsyms;
3155 else{
3156 if(refs[i].flags ==
3157 REFERENCE_FLAG_PRIVATE_UNDEFINED_NON_LAZY ||
3158 refs[i].flags == REFERENCE_FLAG_PRIVATE_UNDEFINED_LAZY){
3159 if(missing_symbols == 0){
3160 error_arch(arch, member, "private extern symbols "
3161 "referenced by modules can't be stripped in: ");
3162 missing_symbols = 1;
3164 if(object->mh != NULL)
3165 n_strx = symbols[refs[i].isym].n_un.n_strx;
3166 else
3167 n_strx = symbols64[refs[i].isym].n_un.n_strx;
3168 fprintf(stderr, "%s\n", strings + n_strx);
3169 saves[refs[i].isym] = -1;
3174 if(missing_symbols == 1)
3175 return(FALSE);
3177 if(member == NULL){
3178 missing_syms = 0;
3179 if(iflag == 0){
3180 for(i = 0; i < nsave_symbols; i++){
3181 if(save_symbols[i].sym == NULL){
3182 if(missing_syms == 0){
3183 error_arch(arch, member, "symbols names listed "
3184 "in: %s not in: ", sfile);
3185 missing_syms = 1;
3187 fprintf(stderr, "%s\n", save_symbols[i].name);
3191 missing_syms = 0;
3193 * strip -R on an x86_64 .o file should do nothing.
3195 if(iflag == 0 &&
3196 (object->mh != NULL ||
3197 object->mh64->cputype != CPU_TYPE_X86_64 ||
3198 object->mh64->filetype != MH_OBJECT)){
3199 for(i = 0; i < nremove_symbols; i++){
3200 if(remove_symbols[i].sym == NULL){
3201 if(missing_syms == 0){
3202 error_arch(arch, member, "symbols names listed "
3203 "in: %s not in: ", Rfile);
3204 missing_syms = 1;
3206 fprintf(stderr, "%s\n", remove_symbols[i].name);
3213 * If there is a chance that we could end up with an indirect symbol
3214 * with an index of zero we need to avoid that due to a work around
3215 * in the dynamic linker for a bug it is working around that was in
3216 * the old classic static linker. See radar bug 5614542 and the
3217 * related bugs 3685312 and 3534709.
3219 * A reasonable way to do this to know that local symbols are first in
3220 * the symbol table. So if we have any local symbols this won't happen
3221 * and if there are no indirect symbols it will also not happen. Past
3222 * that we'll just add a local symbol so it will end up at symbol index
3223 * zero and avoid any indirect symbol having that index.
3225 * If one really wanted they could build up the new symbol table then
3226 * look at all the indirect symbol table entries to see if any of them
3227 * have an index of zero then in that case throw that new symbol table
3228 * away and rebuild the symbol and string table once again after adding
3229 * a local symbol. This seems not all that resonable to save one symbol
3230 * table entry and a few bytes in the string table for the complexity it
3231 * would add and what it would save.
3233 if(new_nlocalsym == 0 && nindirectsyms != 0){
3234 len = strlen("radr://5614542") + 1;
3235 new_strsize += len;
3236 new_nlocalsym++;
3237 new_nsyms++;
3238 hack_5614542 = TRUE;
3240 else{
3241 hack_5614542 = FALSE;
3244 if(object->mh != NULL){
3245 new_symbols = (struct nlist *)
3246 allocate(new_nsyms * sizeof(struct nlist));
3247 new_symbols64 = NULL;
3249 else{
3250 new_symbols = NULL;
3251 new_symbols64 = (struct nlist_64 *)
3252 allocate(new_nsyms * sizeof(struct nlist_64));
3254 if(object->mh != NULL)
3255 new_strsize = rnd(new_strsize, sizeof(int32_t));
3256 else
3257 new_strsize = rnd(new_strsize, sizeof(int64_t));
3258 new_strings = (char *)allocate(new_strsize);
3259 if(object->mh != NULL){
3260 new_strings[new_strsize - 3] = '\0';
3261 new_strings[new_strsize - 2] = '\0';
3262 new_strings[new_strsize - 1] = '\0';
3264 else{
3265 new_strings[new_strsize - 7] = '\0';
3266 new_strings[new_strsize - 6] = '\0';
3267 new_strings[new_strsize - 5] = '\0';
3268 new_strings[new_strsize - 4] = '\0';
3269 new_strings[new_strsize - 3] = '\0';
3270 new_strings[new_strsize - 2] = '\0';
3271 new_strings[new_strsize - 1] = '\0';
3274 memset(new_strings, '\0', sizeof(int32_t));
3275 p = new_strings + sizeof(int32_t);
3276 q = p + new_ext_strsize;
3279 * If all strings were stripped set the size to zero but only for 32-bit
3280 * because the unified linker seems to set the filesize of empty .o
3281 * files to include the string table.
3283 if(object->mh != NULL && new_strsize == sizeof(int32_t))
3284 new_strsize = 0;
3287 * Now create a symbol table and string table in this order
3288 * symbol table
3289 * local symbols
3290 * external defined symbols
3291 * undefined symbols
3292 * string table
3293 * external strings
3294 * local strings
3296 inew_syms = 0;
3299 * If we are doing the hack for radar bug 5614542 (see above) add the
3300 * one local symbol and string.
3302 * We use an N_OPT stab which should be safe to use and not mess any
3303 * thing up. In Mac OS X, gcc(1) writes one N_OPT stab saying the file
3304 * is compiled with gcc(1). Then gdb(1) looks for that stab, but it
3305 * also looks at the name. If the name string is "gcc_compiled" or
3306 * "gcc2_compiled" gdb(1) sets its "compiled by gcc flag. If the N_OPT
3307 * is emitted INSIDE an N_SO section, then gdb(1) thinks that object
3308 * module was compiled by Sun's compiler, which apparently sticks one
3309 * outermost N_LBRAC/N_RBRAC pair, which gdb(1) strips off. But if the
3310 * N_OPT comes before any N_SO stabs, then gdb(1) will just ignore it.
3311 * Since this N_OPT is the first local symbol, it will always come
3312 * before any N_SO stabs that might be around and should be fine.
3314 if(hack_5614542 == TRUE){
3315 if(object->mh != NULL){
3316 new_symbols[inew_syms].n_type = N_OPT;
3317 new_symbols[inew_syms].n_sect = NO_SECT;
3318 new_symbols[inew_syms].n_desc = 0;
3319 new_symbols[inew_syms].n_value = 0x05614542;
3321 else{
3322 new_symbols64[inew_syms].n_type = N_OPT;
3323 new_symbols64[inew_syms].n_sect = NO_SECT;
3324 new_symbols64[inew_syms].n_desc = 0;
3325 new_symbols64[inew_syms].n_value = 0x05614542;
3327 strcpy(q, "radr://5614542");
3328 if(object->mh != NULL)
3329 new_symbols[inew_syms].n_un.n_strx =
3330 q - new_strings;
3331 else
3332 new_symbols64[inew_syms].n_un.n_strx =
3333 q - new_strings;
3334 q += strlen(q) + 1;
3335 inew_syms++;
3338 for(i = 0; i < nsyms; i++){
3339 if(saves[i]){
3340 if(object->mh != NULL){
3341 n_strx = symbols[i].n_un.n_strx;
3342 n_type = symbols[i].n_type;
3344 else{
3345 n_strx = symbols64[i].n_un.n_strx;
3346 n_type = symbols64[i].n_type;
3348 if((n_type & N_EXT) == 0){
3349 if(object->mh != NULL)
3350 new_symbols[inew_syms] = symbols[i];
3351 else
3352 new_symbols64[inew_syms] = symbols64[i];
3353 if(n_strx != 0){
3354 strcpy(q, strings + n_strx);
3355 if(object->mh != NULL)
3356 new_symbols[inew_syms].n_un.n_strx =
3357 q - new_strings;
3358 else
3359 new_symbols64[inew_syms].n_un.n_strx =
3360 q - new_strings;
3361 q += strlen(q) + 1;
3363 inew_syms++;
3364 saves[i] = inew_syms;
3368 #ifdef TRIE_SUPPORT
3369 inew_nextdefsym = inew_syms;
3370 #endif /* TRIE_SUPPORT */
3371 for(i = 0; i < nsyms; i++){
3372 if(saves[i]){
3373 if(object->mh != NULL){
3374 n_strx = symbols[i].n_un.n_strx;
3375 n_type = symbols[i].n_type;
3376 n_value = symbols[i].n_value;
3378 else{
3379 n_strx = symbols64[i].n_un.n_strx;
3380 n_type = symbols64[i].n_type;
3381 n_value = symbols64[i].n_value;
3383 if((n_type & N_EXT) == N_EXT &&
3384 ((n_type & N_TYPE) != N_UNDF &&
3385 (n_type & N_TYPE) != N_PBUD)){
3386 if(object->mh != NULL)
3387 new_symbols[inew_syms] = symbols[i];
3388 else
3389 new_symbols64[inew_syms] = symbols64[i];
3390 if(n_strx != 0){
3391 strcpy(p, strings + n_strx);
3392 if(object->mh != NULL)
3393 new_symbols[inew_syms].n_un.n_strx =
3394 p - new_strings;
3395 else
3396 new_symbols64[inew_syms].n_un.n_strx =
3397 p - new_strings;
3398 p += strlen(p) + 1;
3400 if((n_type & N_TYPE) == N_INDR){
3401 if(n_value != 0){
3402 strcpy(p, strings + n_value);
3403 if(object->mh != NULL)
3404 new_symbols[inew_syms].n_value =
3405 p - new_strings;
3406 else
3407 new_symbols64[inew_syms].n_value =
3408 p - new_strings;
3409 p += strlen(p) + 1;
3412 inew_syms++;
3413 saves[i] = inew_syms;
3418 * Build the new undefined symbols into a map and sort it.
3420 inew_undefsyms = 0;
3421 if(object->mh != NULL){
3422 undef_map = (struct undef_map *)allocate(new_nundefsym *
3423 sizeof(struct undef_map));
3424 undef_map64 = NULL;
3426 else{
3427 undef_map = NULL;
3428 undef_map64 = (struct undef_map64 *)allocate(new_nundefsym *
3429 sizeof(struct undef_map64));
3431 for(i = 0; i < nsyms; i++){
3432 if(saves[i]){
3433 if(object->mh != NULL){
3434 n_strx = symbols[i].n_un.n_strx;
3435 n_type = symbols[i].n_type;
3437 else{
3438 n_strx = symbols64[i].n_un.n_strx;
3439 n_type = symbols64[i].n_type;
3441 if((n_type & N_EXT) == N_EXT &&
3442 ((n_type & N_TYPE) == N_UNDF ||
3443 (n_type & N_TYPE) == N_PBUD)){
3444 if(object->mh != NULL)
3445 undef_map[inew_undefsyms].symbol = symbols[i];
3446 else
3447 undef_map64[inew_undefsyms].symbol64 = symbols64[i];
3448 if(n_strx != 0){
3449 strcpy(p, strings + n_strx);
3450 if(object->mh != NULL)
3451 undef_map[inew_undefsyms].symbol.n_un.n_strx =
3452 p - new_strings;
3453 else
3454 undef_map64[inew_undefsyms].symbol64.n_un.n_strx =
3455 p - new_strings;
3456 p += strlen(p) + 1;
3458 if(object->mh != NULL)
3459 undef_map[inew_undefsyms].index = i;
3460 else
3461 undef_map64[inew_undefsyms].index = i;
3462 inew_undefsyms++;
3466 for(i = 0; i < nsyms; i++){
3467 if(changes[i]){
3468 if(object->mh != NULL)
3469 n_strx = symbols[i].n_un.n_strx;
3470 else
3471 n_strx = symbols64[i].n_un.n_strx;
3472 if(n_strx != 0){
3473 strcpy(p, strings + n_strx);
3474 if(object->mh != NULL)
3475 undef_map[inew_undefsyms].symbol.n_un.n_strx =
3476 p - new_strings;
3477 else
3478 undef_map64[inew_undefsyms].symbol64.n_un.n_strx =
3479 p - new_strings;
3480 p += strlen(p) + 1;
3482 if(object->mh != NULL){
3483 undef_map[inew_undefsyms].symbol.n_type = N_UNDF | N_EXT;
3484 undef_map[inew_undefsyms].symbol.n_sect = NO_SECT;
3485 undef_map[inew_undefsyms].symbol.n_desc = 0;
3486 undef_map[inew_undefsyms].symbol.n_value = 0;
3487 undef_map[inew_undefsyms].index = i;
3489 else{
3490 undef_map64[inew_undefsyms].symbol64.n_type = N_UNDF |N_EXT;
3491 undef_map64[inew_undefsyms].symbol64.n_sect = NO_SECT;
3492 undef_map64[inew_undefsyms].symbol64.n_desc = 0;
3493 undef_map64[inew_undefsyms].symbol64.n_value = 0;
3494 undef_map64[inew_undefsyms].index = i;
3496 inew_undefsyms++;
3499 /* Sort the undefined symbols by name */
3500 qsort_strings = new_strings;
3501 if(object->mh != NULL)
3502 qsort(undef_map, new_nundefsym, sizeof(struct undef_map),
3503 (int (*)(const void *, const void *))cmp_qsort_undef_map);
3504 else
3505 qsort(undef_map64, new_nundefsym, sizeof(struct undef_map64),
3506 (int (*)(const void *, const void *))cmp_qsort_undef_map_64);
3507 /* Copy the symbols now in sorted order into new_symbols */
3508 for(i = 0; i < new_nundefsym; i++){
3509 if(object->mh != NULL){
3510 new_symbols[inew_syms] = undef_map[i].symbol;
3511 inew_syms++;
3512 saves[undef_map[i].index] = inew_syms;
3514 else{
3515 new_symbols64[inew_syms] = undef_map64[i].symbol64;
3516 inew_syms++;
3517 saves[undef_map64[i].index] = inew_syms;
3522 * Fixup the module table's module name strings adding them to the
3523 * string table. Also fix the indexes into the symbol table for
3524 * external and local symbols. And fix up the indexes into the
3525 * reference table.
3527 for(i = 0; i < nmodtab; i++){
3528 if(object->mh != NULL){
3529 strcpy(p, strings + mods[i].module_name);
3530 mods[i].module_name = p - new_strings;
3531 iextdefsym = mods[i].iextdefsym;
3532 nextdefsym = mods[i].nextdefsym;
3533 ilocalsym = mods[i].ilocalsym;
3534 nlocalsym = mods[i].nlocalsym;
3535 irefsym = mods[i].irefsym;
3536 nrefsym = mods[i].nrefsym;
3538 else{
3539 strcpy(p, strings + mods64[i].module_name);
3540 mods64[i].module_name = p - new_strings;
3541 iextdefsym = mods64[i].iextdefsym;
3542 nextdefsym = mods64[i].nextdefsym;
3543 ilocalsym = mods64[i].ilocalsym;
3544 nlocalsym = mods64[i].nlocalsym;
3545 irefsym = mods64[i].irefsym;
3546 nrefsym = mods64[i].nrefsym;
3548 p += strlen(p) + 1;
3550 if(iextdefsym > nsyms){
3551 error_arch(arch, member, "bad index into externally defined "
3552 "symbols of module table entry %d in: ", i);
3553 return(FALSE);
3555 if(iextdefsym + nextdefsym > nsyms){
3556 error_arch(arch, member, "bad number of externally defined "
3557 "symbols of module table entry %d in: ", i);
3558 return(FALSE);
3560 for(j = iextdefsym; j < iextdefsym + nextdefsym; j++){
3561 if(saves[j] != 0 && changes[j] == 0)
3562 break;
3564 n = 0;
3565 for(k = j; k < iextdefsym + nextdefsym; k++){
3566 if(saves[k] != 0 && changes[k] == 0)
3567 n++;
3569 if(n == 0){
3570 if(object->mh != NULL){
3571 mods[i].iextdefsym = 0;
3572 mods[i].nextdefsym = 0;
3574 else{
3575 mods64[i].iextdefsym = 0;
3576 mods64[i].nextdefsym = 0;
3579 else{
3580 if(object->mh != NULL){
3581 mods[i].iextdefsym = saves[j] - 1;
3582 mods[i].nextdefsym = n;
3584 else{
3585 mods64[i].iextdefsym = saves[j] - 1;
3586 mods64[i].nextdefsym = n;
3590 if(ilocalsym > nsyms){
3591 error_arch(arch, member, "bad index into symbols for local "
3592 "symbols of module table entry %d in: ", i);
3593 return(FALSE);
3595 if(ilocalsym + nlocalsym > nsyms){
3596 error_arch(arch, member, "bad number of local "
3597 "symbols of module table entry %d in: ", i);
3598 return(FALSE);
3600 for(j = ilocalsym; j < ilocalsym + nlocalsym; j++){
3601 if(saves[j] != 0)
3602 break;
3604 n = 0;
3605 for(k = j; k < ilocalsym + nlocalsym; k++){
3606 if(saves[k] != 0)
3607 n++;
3609 if(n == 0){
3610 if(object->mh != NULL){
3611 mods[i].ilocalsym = 0;
3612 mods[i].nlocalsym = 0;
3614 else{
3615 mods64[i].ilocalsym = 0;
3616 mods64[i].nlocalsym = 0;
3619 else{
3620 if(object->mh != NULL){
3621 mods[i].ilocalsym = saves[j] - 1;
3622 mods[i].nlocalsym = n;
3624 else{
3625 mods64[i].ilocalsym = saves[j] - 1;
3626 mods64[i].nlocalsym = n;
3630 if(irefsym > nextrefsyms){
3631 error_arch(arch, member, "bad index into reference table "
3632 "of module table entry %d in: ", i);
3633 return(FALSE);
3635 if(irefsym + nrefsym > nextrefsyms){
3636 error_arch(arch, member, "bad number of reference table "
3637 "entries of module table entry %d in: ", i);
3638 return(FALSE);
3640 for(j = irefsym; j < irefsym + nrefsym; j++){
3641 if(ref_saves[j] != 0)
3642 break;
3644 n = 0;
3645 for(k = j; k < irefsym + nrefsym; k++){
3646 if(ref_saves[k] != 0)
3647 n++;
3649 if(n == 0){
3650 if(object->mh != NULL){
3651 mods[i].irefsym = 0;
3652 mods[i].nrefsym = 0;
3654 else{
3655 mods64[i].irefsym = 0;
3656 mods64[i].nrefsym = 0;
3659 else{
3660 if(object->mh != NULL){
3661 mods[i].irefsym = ref_saves[j] - 1;
3662 mods[i].nrefsym = n;
3664 else{
3665 mods64[i].irefsym = ref_saves[j] - 1;
3666 mods64[i].nrefsym = n;
3672 * Create a new reference table.
3674 new_refs = allocate(new_nextrefsyms * sizeof(struct dylib_reference));
3675 j = 0;
3676 for(i = 0; i < nextrefsyms; i++){
3677 if(ref_saves[i]){
3678 if(saves[refs[i].isym]){
3679 new_refs[j].isym = saves[refs[i].isym] - 1;
3680 new_refs[j].flags = refs[i].flags;
3682 else{
3683 if(refs[i].flags == REFERENCE_FLAG_UNDEFINED_NON_LAZY ||
3684 refs[i].flags == REFERENCE_FLAG_UNDEFINED_LAZY){
3685 new_refs[j].isym = changes[refs[i].isym] - 1;
3686 new_refs[j].flags = refs[i].flags;
3689 j++;
3694 * Create a new dylib table of contents.
3696 new_ntoc = 0;
3697 for(i = 0; i < ntoc; i++){
3698 if(tocs[i].symbol_index >= nsyms){
3699 error_arch(arch, member, "bad symbol index for table of "
3700 "contents table entry %d in: ", i);
3701 return(FALSE);
3703 if(saves[tocs[i].symbol_index] != 0 &&
3704 changes[tocs[i].symbol_index] == 0)
3705 new_ntoc++;
3707 new_tocs = allocate(new_ntoc * sizeof(struct dylib_table_of_contents));
3708 j = 0;
3709 for(i = 0; i < ntoc; i++){
3710 if(saves[tocs[i].symbol_index] != 0 &&
3711 changes[tocs[i].symbol_index] == 0){
3712 new_tocs[j].symbol_index = saves[tocs[i].symbol_index] - 1;
3713 new_tocs[j].module_index = tocs[i].module_index;
3714 j++;
3717 #ifdef TRIE_SUPPORT
3719 * Update the export trie if it has one but only call the the
3720 * prune_trie() routine when we are removing global symbols as is
3721 * done with default stripping of a dyld executable or with the -s
3722 * or -R options.
3724 if(object->dyld_info != NULL &&
3725 object->dyld_info->export_size != 0 &&
3726 (default_dyld_executable || sfile != NULL || Rfile != NULL)){
3727 const char *error_string;
3728 uint32_t trie_new_size;
3730 error_string = prune_trie((uint8_t *)(object->object_addr +
3731 object->dyld_info->export_off),
3732 object->dyld_info->export_size,
3733 prune,
3734 &trie_new_size);
3735 if(error_string != NULL){
3736 error_arch(arch, member, "%s", error_string);
3737 return(FALSE);
3740 #endif /* TRIE_SUPPORT */
3742 if(undef_map != NULL)
3743 free(undef_map);
3744 if(undef_map64 != NULL)
3745 free(undef_map64);
3746 if(changes != NULL)
3747 free(changes);
3748 if(sections != NULL)
3749 free(sections);
3750 if(sections64 != NULL)
3751 free(sections64);
3753 if(errors == 0)
3754 return(TRUE);
3755 else
3756 return(FALSE);
3759 #ifdef TRIE_SUPPORT
3761 * prune() is called by prune_trie() and passed a name of an external symbol
3762 * in the trie. It returns 1 if the symbols is to be pruned out and 0 if the
3763 * symbol is to be kept.
3765 * Note that it may seem like a linear search of the new symbols would not be
3766 * the best approach but in 10.6 the only defined global symbol left in a
3767 * stripped executable is __mh_execute_header and new_nextdefsym is usually 1
3768 * so this never actually loops in practice.
3770 static
3772 prune(
3773 const char *name)
3775 uint32_t i;
3777 for(i = 0; i < new_nextdefsym; i++){
3778 if(new_symbols != NULL){
3779 if(strcmp(name, new_strings + new_symbols[inew_nextdefsym + i]
3780 .n_un.n_strx) == 0)
3781 return(0);
3783 else{
3784 if(strcmp(name, new_strings + new_symbols64[inew_nextdefsym + i]
3785 .n_un.n_strx) == 0)
3786 return(0);
3789 return(1);
3791 #endif /* TRIE_SUPPORT */
3794 * make_ld_r_object() takes the object file contents referenced by the passed
3795 * data structures, writes that to a temporary file, runs "ld -r" plus the
3796 * specified stripping option creating a second temporary file, reads that file
3797 * in and replaces the object file contents with that and resets the variables
3798 * pointing to the symbol, string and indirect tables.
3800 static
3801 void
3802 make_ld_r_object(
3803 struct arch *arch,
3804 struct member *member,
3805 struct object *object)
3807 enum byte_sex host_byte_sex;
3808 char *input_file, *output_file;
3809 int fd;
3810 struct ofile *ld_r_ofile;
3811 struct arch *ld_r_archs;
3812 uint32_t ld_r_narchs, save_errors;
3814 host_byte_sex = get_host_byte_sex();
3817 * Swap the object file back into its bytesex before writing it to the
3818 * temporary file if needed.
3820 if(object->object_byte_sex != host_byte_sex){
3821 if(object->mh != NULL){
3822 if(swap_object_headers(object->mh, object->load_commands) ==
3823 FALSE)
3824 fatal("internal error: swap_object_headers() failed");
3825 swap_nlist(symbols, nsyms, object->object_byte_sex);
3827 else{
3828 if(swap_object_headers(object->mh64, object->load_commands) ==
3829 FALSE)
3830 fatal("internal error: swap_object_headers() failed");
3831 swap_nlist_64(symbols64, nsyms, object->object_byte_sex);
3833 swap_indirect_symbols(indirectsyms, nindirectsyms,
3834 object->object_byte_sex);
3838 * Create an input object file for the ld -r command from the bytes
3839 * of this arch's object file.
3841 input_file = makestr("/tmp/strip.XXXXXX", NULL);
3842 input_file = mktemp(input_file);
3844 if((fd = open(input_file, O_WRONLY|O_CREAT, 0600)) < 0)
3845 system_fatal("can't open temporary file: %s", input_file);
3847 if(write(fd, object->object_addr, object->object_size) !=
3848 object->object_size)
3849 system_fatal("can't write temporary file: %s", input_file);
3851 if(close(fd) == -1)
3852 system_fatal("can't close temporary file: %s", input_file);
3855 * Create a temporary name for the output file of the ld -r
3857 output_file = makestr("/tmp/strip.XXXXXX", NULL);
3858 output_file = mktemp(output_file);
3861 * Create the ld -r command line and execute it.
3863 reset_execute_list();
3864 add_execute_list_with_prefix("ld");
3865 add_execute_list("-keep_private_externs");
3866 add_execute_list("-r");
3867 if(Sflag)
3868 add_execute_list("-S");
3869 if(xflag)
3870 add_execute_list("-x");
3871 add_execute_list(input_file);
3872 add_execute_list("-o");
3873 add_execute_list(output_file);
3874 if(sfile != NULL){
3875 add_execute_list("-x");
3876 add_execute_list("-exported_symbols_list");
3877 add_execute_list(sfile);
3879 if(Rfile != NULL){
3880 add_execute_list("-unexported_symbols_list");
3881 add_execute_list(Rfile);
3883 if(execute_list(vflag) == 0)
3884 fatal("internal link edit command failed");
3886 save_errors = errors;
3887 errors = 0;
3888 /* breakout the output file of the ld -f for processing */
3889 ld_r_ofile = breakout(output_file, &ld_r_archs, &ld_r_narchs, FALSE);
3890 if(errors)
3891 goto make_ld_r_object_cleanup;
3893 /* checkout the file for symbol table replacement processing */
3894 checkout(ld_r_archs, ld_r_narchs);
3897 * Make sure the output of the ld -r is an object file with one arch.
3899 if(ld_r_narchs != 1 ||
3900 ld_r_archs->type != OFILE_Mach_O ||
3901 ld_r_archs->object == NULL ||
3902 ld_r_archs->object->mh_filetype != MH_OBJECT)
3903 fatal("internal link edit command failed to produce a thin Mach-O "
3904 "object file");
3907 * Now reset all the data of the input object with the ld -r output
3908 * object file.
3910 nsyms = ld_r_archs->object->st->nsyms;
3911 if(ld_r_archs->object->mh != NULL){
3912 symbols = (struct nlist *)
3913 (ld_r_archs->object->object_addr +
3914 ld_r_archs->object->st->symoff);
3915 if(ld_r_archs->object->object_byte_sex != host_byte_sex)
3916 swap_nlist(symbols, nsyms, host_byte_sex);
3917 symbols64 = NULL;
3919 else{
3920 symbols = NULL;
3921 symbols64 = (struct nlist_64 *)
3922 (ld_r_archs->object->object_addr +
3923 ld_r_archs->object->st->symoff);
3924 if(ld_r_archs->object->object_byte_sex != host_byte_sex)
3925 swap_nlist_64(symbols64, nsyms, host_byte_sex);
3927 strings = ld_r_archs->object->object_addr +
3928 ld_r_archs->object->st->stroff;
3929 strsize = ld_r_archs->object->st->strsize;
3931 if(ld_r_archs->object->dyst != NULL &&
3932 ld_r_archs->object->dyst->nindirectsyms != 0){
3933 nindirectsyms = ld_r_archs->object->dyst->nindirectsyms;
3934 indirectsyms = (uint32_t *)
3935 (ld_r_archs->object->object_addr +
3936 ld_r_archs->object->dyst->indirectsymoff);
3937 if(ld_r_archs->object->object_byte_sex != host_byte_sex)
3938 swap_indirect_symbols(indirectsyms, nindirectsyms,
3939 host_byte_sex);
3941 else{
3942 indirectsyms = NULL;
3943 nindirectsyms = 0;
3946 if(ld_r_archs->object->mh != NULL)
3947 ld_r_archs->object->input_sym_info_size =
3948 nsyms * sizeof(struct nlist) +
3949 strsize;
3950 else
3951 ld_r_archs->object->input_sym_info_size =
3952 nsyms * sizeof(struct nlist_64) +
3953 strsize;
3956 * Copy over the object struct from the ld -r object file onto the
3957 * input object file.
3959 *object = *ld_r_archs->object;
3962 * Save the ofile struct for the ld -r output so it can be umapped when
3963 * we are done. And free up the ld_r_archs now that we are done with
3964 * them.
3966 object->ld_r_ofile = ld_r_ofile;
3967 free_archs(ld_r_archs, ld_r_narchs);
3969 make_ld_r_object_cleanup:
3970 errors += save_errors;
3972 * Remove the input and output files and clean up.
3974 if(unlink(input_file) == -1)
3975 system_fatal("can't remove temporary file: %s", input_file);
3976 if(unlink(output_file) == -1)
3977 system_fatal("can't remove temporary file: %s", output_file);
3978 free(input_file);
3979 free(output_file);
3983 * strip_LC_UUID_commands() is called when -no_uuid is specified to remove any
3984 * LC_UUID load commands from the object's load commands.
3986 static
3987 void
3988 strip_LC_UUID_commands(
3989 struct arch *arch,
3990 struct member *member,
3991 struct object *object)
3993 uint32_t i, ncmds, nuuids, mh_sizeofcmds, sizeofcmds;
3994 struct load_command *lc1, *lc2, *new_load_commands;
3995 struct segment_command *sg;
3998 * See if there are any LC_UUID load commands.
4000 nuuids = 0;
4001 lc1 = arch->object->load_commands;
4002 if(arch->object->mh != NULL){
4003 ncmds = arch->object->mh->ncmds;
4004 mh_sizeofcmds = arch->object->mh->sizeofcmds;
4006 else{
4007 ncmds = arch->object->mh64->ncmds;
4008 mh_sizeofcmds = arch->object->mh64->sizeofcmds;
4010 for(i = 0; i < ncmds; i++){
4011 if(lc1->cmd == LC_UUID){
4012 nuuids++;
4014 lc1 = (struct load_command *)((char *)lc1 + lc1->cmdsize);
4016 /* if no LC_UUID load commands just return */
4017 if(nuuids == 0)
4018 return;
4021 * Allocate space for the new load commands as zero it out so any holes
4022 * will be zero bytes.
4024 new_load_commands = allocate(mh_sizeofcmds);
4025 memset(new_load_commands, '\0', mh_sizeofcmds);
4028 * Copy all the load commands except the LC_UUID load commands into the
4029 * allocated space for the new load commands.
4031 lc1 = arch->object->load_commands;
4032 lc2 = new_load_commands;
4033 sizeofcmds = 0;
4034 for(i = 0; i < ncmds; i++){
4035 if(lc1->cmd != LC_UUID){
4036 memcpy(lc2, lc1, lc1->cmdsize);
4037 sizeofcmds += lc2->cmdsize;
4038 lc2 = (struct load_command *)((char *)lc2 + lc2->cmdsize);
4040 lc1 = (struct load_command *)((char *)lc1 + lc1->cmdsize);
4044 * Finally copy the updated load commands over the existing load
4045 * commands.
4047 memcpy(arch->object->load_commands, new_load_commands, sizeofcmds);
4048 if(mh_sizeofcmds > sizeofcmds){
4049 memset((char *)arch->object->load_commands + sizeofcmds, '\0',
4050 (mh_sizeofcmds - sizeofcmds));
4052 ncmds -= nuuids;
4053 if(arch->object->mh != NULL) {
4054 arch->object->mh->sizeofcmds = sizeofcmds;
4055 arch->object->mh->ncmds = ncmds;
4056 } else {
4057 arch->object->mh64->sizeofcmds = sizeofcmds;
4058 arch->object->mh64->ncmds = ncmds;
4060 free(new_load_commands);
4062 /* reset the pointers into the load commands */
4063 lc1 = arch->object->load_commands;
4064 for(i = 0; i < ncmds; i++){
4065 switch(lc1->cmd){
4066 case LC_SYMTAB:
4067 arch->object->st = (struct symtab_command *)lc1;
4068 break;
4069 case LC_DYSYMTAB:
4070 arch->object->dyst = (struct dysymtab_command *)lc1;
4071 break;
4072 case LC_TWOLEVEL_HINTS:
4073 arch->object->hints_cmd = (struct twolevel_hints_command *)lc1;
4074 break;
4075 case LC_PREBIND_CKSUM:
4076 arch->object->cs = (struct prebind_cksum_command *)lc1;
4077 break;
4078 case LC_SEGMENT:
4079 sg = (struct segment_command *)lc1;
4080 if(strcmp(sg->segname, SEG_LINKEDIT) == 0)
4081 arch->object->seg_linkedit = sg;
4082 break;
4083 case LC_SEGMENT_SPLIT_INFO:
4084 object->split_info_cmd = (struct linkedit_data_command *)lc1;
4085 break;
4086 case LC_FUNCTION_STARTS:
4087 object->func_starts_info_cmd =
4088 (struct linkedit_data_command *)lc1;
4089 break;
4090 case LC_CODE_SIGNATURE:
4091 object->code_sig_cmd = (struct linkedit_data_command *)lc1;
4092 break;
4093 case LC_DYLD_INFO_ONLY:
4094 case LC_DYLD_INFO:
4095 object->dyld_info = (struct dyld_info_command *)lc1;
4097 lc1 = (struct load_command *)((char *)lc1 + lc1->cmdsize);
4101 #ifndef NMEDIT
4103 * strip_LC_CODE_SIGNATURE_commands() is called when -c is specified to remove
4104 * any LC_CODE_SIGNATURE load commands from the object's load commands.
4106 static
4107 void
4108 strip_LC_CODE_SIGNATURE_commands(
4109 struct arch *arch,
4110 struct member *member,
4111 struct object *object)
4113 uint32_t i, ncmds, mh_sizeofcmds, sizeofcmds;
4114 struct load_command *lc1, *lc2, *new_load_commands;
4115 struct segment_command *sg;
4118 * See if there is an LC_CODE_SIGNATURE load command and if no command
4119 * just return.
4121 if(object->code_sig_cmd == NULL)
4122 return;
4125 * Allocate space for the new load commands and zero it out so any holes
4126 * will be zero bytes.
4128 if(arch->object->mh != NULL){
4129 ncmds = arch->object->mh->ncmds;
4130 mh_sizeofcmds = arch->object->mh->sizeofcmds;
4132 else{
4133 ncmds = arch->object->mh64->ncmds;
4134 mh_sizeofcmds = arch->object->mh64->sizeofcmds;
4136 new_load_commands = allocate(mh_sizeofcmds);
4137 memset(new_load_commands, '\0', mh_sizeofcmds);
4140 * Copy all the load commands except the LC_CODE_SIGNATURE load commands
4141 * into the allocated space for the new load commands.
4143 lc1 = arch->object->load_commands;
4144 lc2 = new_load_commands;
4145 sizeofcmds = 0;
4146 for(i = 0; i < ncmds; i++){
4147 if(lc1->cmd != LC_CODE_SIGNATURE){
4148 memcpy(lc2, lc1, lc1->cmdsize);
4149 sizeofcmds += lc2->cmdsize;
4150 lc2 = (struct load_command *)((char *)lc2 + lc2->cmdsize);
4152 lc1 = (struct load_command *)((char *)lc1 + lc1->cmdsize);
4156 * Finally copy the updated load commands over the existing load
4157 * commands.
4159 memcpy(arch->object->load_commands, new_load_commands, sizeofcmds);
4160 if(mh_sizeofcmds > sizeofcmds){
4161 memset((char *)arch->object->load_commands + sizeofcmds, '\0',
4162 (mh_sizeofcmds - sizeofcmds));
4164 ncmds -= 1;
4165 if(arch->object->mh != NULL) {
4166 arch->object->mh->sizeofcmds = sizeofcmds;
4167 arch->object->mh->ncmds = ncmds;
4168 } else {
4169 arch->object->mh64->sizeofcmds = sizeofcmds;
4170 arch->object->mh64->ncmds = ncmds;
4172 free(new_load_commands);
4174 /* reset the pointers into the load commands */
4175 object->code_sig_cmd = NULL;
4176 lc1 = arch->object->load_commands;
4177 for(i = 0; i < ncmds; i++){
4178 switch(lc1->cmd){
4179 case LC_SYMTAB:
4180 arch->object->st = (struct symtab_command *)lc1;
4181 break;
4182 case LC_DYSYMTAB:
4183 arch->object->dyst = (struct dysymtab_command *)lc1;
4184 break;
4185 case LC_TWOLEVEL_HINTS:
4186 arch->object->hints_cmd = (struct twolevel_hints_command *)lc1;
4187 break;
4188 case LC_PREBIND_CKSUM:
4189 arch->object->cs = (struct prebind_cksum_command *)lc1;
4190 break;
4191 case LC_SEGMENT:
4192 sg = (struct segment_command *)lc1;
4193 if(strcmp(sg->segname, SEG_LINKEDIT) == 0)
4194 arch->object->seg_linkedit = sg;
4195 break;
4196 case LC_SEGMENT_SPLIT_INFO:
4197 object->split_info_cmd = (struct linkedit_data_command *)lc1;
4198 break;
4199 case LC_FUNCTION_STARTS:
4200 object->func_starts_info_cmd =
4201 (struct linkedit_data_command *)lc1;
4202 break;
4204 lc1 = (struct load_command *)((char *)lc1 + lc1->cmdsize);
4207 if(cflag){
4209 * To get the right amount of the file copied out by writeout() for
4210 * the case when we are stripping out the section contents we
4211 * already reduce the object size by the size of the section
4212 * contents including the padding after the load commands. So here
4213 * we need to further reduce it by the load command for the
4214 * LC_CODE_SIGNATURE (a struct linkedit_data_command) we are
4215 * removing.
4217 object->object_size -= sizeof(struct linkedit_data_command);
4219 * Then this size minus the size of the input symbolic information
4220 * is what is copied out from the file by writeout(). Which in this
4221 * case is just the new headers.
4225 * Finally for -c the file offset to the link edit information is to
4226 * be right after the load commands. So reset this for the updated
4227 * size of the load commands without the LC_CODE_SIGNATURE.
4229 if(object->mh != NULL)
4230 object->seg_linkedit->fileoff = sizeof(struct mach_header) +
4231 sizeofcmds;
4232 else
4233 object->seg_linkedit64->fileoff =
4234 sizeof(struct mach_header_64) + sizeofcmds;
4237 #endif /* !(NMEDIT) */
4240 * private_extern_reference_by_module() is passed a symbol_index of a private
4241 * extern symbol and the module table. If the symbol_index appears in the
4242 * module symbol table this returns TRUE else it returns FALSE.
4244 static
4245 enum bool
4246 private_extern_reference_by_module(
4247 uint32_t symbol_index,
4248 struct dylib_reference *refs,
4249 uint32_t nextrefsyms)
4251 uint32_t i;
4253 for(i = 0; i < nextrefsyms; i++){
4254 if(refs[i].isym == symbol_index){
4255 if(refs[i].flags == REFERENCE_FLAG_PRIVATE_UNDEFINED_NON_LAZY ||
4256 refs[i].flags == REFERENCE_FLAG_PRIVATE_UNDEFINED_LAZY){
4257 return(TRUE);
4261 return(FALSE);
4265 * symbol_pointer_used() is passed a symbol_index and the indirect table. If
4266 * the symbol_index appears in the indirect symbol table this returns TRUE else
4267 * it returns FALSE.
4269 static
4270 enum bool
4271 symbol_pointer_used(
4272 uint32_t symbol_index,
4273 uint32_t *indirectsyms,
4274 uint32_t nindirectsyms)
4276 uint32_t i;
4278 for(i = 0; i < nindirectsyms; i++){
4279 if(indirectsyms[i] == symbol_index)
4280 return(TRUE);
4282 return(FALSE);
4286 * Function for qsort for comparing undefined map entries.
4288 static
4290 cmp_qsort_undef_map(
4291 const struct undef_map *sym1,
4292 const struct undef_map *sym2)
4294 return(strcmp(qsort_strings + sym1->symbol.n_un.n_strx,
4295 qsort_strings + sym2->symbol.n_un.n_strx));
4298 static
4300 cmp_qsort_undef_map_64(
4301 const struct undef_map64 *sym1,
4302 const struct undef_map64 *sym2)
4304 return(strcmp(qsort_strings + sym1->symbol64.n_un.n_strx,
4305 qsort_strings + sym2->symbol64.n_un.n_strx));
4307 #endif /* !defined(NMEDIT) */
4309 #ifndef NMEDIT
4311 * Function for qsort for comparing object names.
4313 static
4315 cmp_qsort_filename(
4316 const char **name1,
4317 const char **name2)
4319 return(strcmp(*name1, *name2));
4323 * Function for bsearch for finding a object name.
4325 static
4327 cmp_bsearch_filename(
4328 const char *name1,
4329 const char **name2)
4331 return(strcmp(name1, *name2));
4333 #endif /* !defined(NMEDIT) */
4335 #ifdef NMEDIT
4336 static
4337 enum bool
4338 edit_symtab(
4339 struct arch *arch,
4340 struct member *member,
4341 struct object *object,
4342 struct nlist *symbols,
4343 struct nlist_64 *symbols64,
4344 uint32_t nsyms,
4345 char *strings,
4346 uint32_t strsize,
4347 struct dylib_table_of_contents *tocs,
4348 uint32_t ntoc,
4349 struct dylib_module *mods,
4350 struct dylib_module_64 *mods64,
4351 uint32_t nmodtab,
4352 struct dylib_reference *refs,
4353 uint32_t nextrefsyms)
4355 uint32_t i, j, k;
4356 unsigned char data_n_sect, nsects;
4357 struct load_command *lc;
4358 struct segment_command *sg;
4359 struct segment_command_64 *sg64;
4360 struct section *s, **sections;
4361 struct section_64 *s64, **sections64;
4363 uint32_t missing_syms;
4364 struct symbol_list *sp;
4365 struct nlist **global_symbol;
4366 struct nlist_64 **global_symbol64;
4367 enum bool global_symbol_found;
4368 char *global_name, save_char;
4369 enum bool dwarf_debug_map;
4370 enum byte_sex host_byte_sex;
4371 int32_t missing_reloc_symbols;
4372 enum bool edit_symtab_return;
4374 char *p, *q;
4375 uint32_t new_ext_strsize, len, inew_syms;
4377 struct nlist **changed_globals;
4378 struct nlist_64 **changed_globals64;
4379 uint32_t nchanged_globals;
4380 uint32_t ncmds, s_flags, n_strx, module_name, ilocalsym, nlocalsym;
4381 uint32_t iextdefsym, nextdefsym;
4382 uint8_t n_type, n_sect, global_symbol_n_sect;
4383 uint64_t n_value;
4384 enum bool warned_about_global_coalesced_symbols;
4386 edit_symtab_return = TRUE;
4387 host_byte_sex = get_host_byte_sex();
4388 missing_reloc_symbols = 0;
4389 warned_about_global_coalesced_symbols = FALSE;
4391 if(nmedits != NULL)
4392 free(nmedits);
4393 nmedits = allocate(nsyms * sizeof(enum bool));
4394 for(i = 0; i < nsyms; i++)
4395 nmedits[i] = FALSE;
4398 * If nmedit is operating on a dynamic library then symbols are turned
4399 * into private externs with the extern bit off not into static symbols.
4401 if(object->mh_filetype == MH_DYLIB && pflag == TRUE){
4402 error_arch(arch, member, "can't use -p with dynamic libraries");
4403 return(FALSE);
4407 * As part of the MAJOR guess for the second pass to fix stabs for the
4408 * globals symbols that get turned into non-global symbols. We need to
4409 * change the stabs. To do this we to know if a N_GSYM is for a data
4410 * symbol or not to know to turn it into an N_STSYM or a N_FUN.
4411 * This logic as determined by compiling test cases with and without
4412 * the key word 'static' and looking at the difference between the STABS
4413 * the compiler generates and trying to match that here.
4415 * We also use this loop and the next to gather an array of section
4416 * struct pointers so we can later determine if we run into a global
4417 * symbol in a coalesced section and not turn those symbols into
4418 * statics.
4420 j = 0;
4421 nsects = 0;
4422 n_sect = 1;
4423 data_n_sect = NO_SECT;
4424 lc = object->load_commands;
4425 if(object->mh != NULL)
4426 ncmds = object->mh->ncmds;
4427 else
4428 ncmds = object->mh64->ncmds;
4429 for(i = 0; i < ncmds; i++){
4430 if(lc->cmd == LC_SEGMENT){
4431 sg = (struct segment_command *)lc;
4432 s = (struct section *)((char *)sg +
4433 sizeof(struct segment_command));
4434 nsects += sg->nsects;
4435 for(j = 0; j < sg->nsects; j++){
4436 if(strcmp(s->segname, SEG_DATA) == 0 &&
4437 strcmp(s->sectname, SECT_DATA) == 0 &&
4438 data_n_sect == NO_SECT){
4439 data_n_sect = n_sect;
4440 break;
4442 n_sect++;
4443 s++;
4446 else if(lc->cmd == LC_SEGMENT_64){
4447 sg64 = (struct segment_command_64 *)lc;
4448 s64 = (struct section_64 *)((char *)sg64 +
4449 sizeof(struct segment_command_64));
4450 nsects += sg64->nsects;
4451 for(j = 0; j < sg64->nsects; j++){
4452 if(strcmp(s64->segname, SEG_DATA) == 0 &&
4453 strcmp(s64->sectname, SECT_DATA) == 0 &&
4454 data_n_sect == NO_SECT){
4455 data_n_sect = n_sect;
4456 break;
4458 n_sect++;
4459 s64++;
4462 lc = (struct load_command *)((char *)lc + lc->cmdsize);
4464 if(object->mh != NULL){
4465 sections = allocate(nsects * sizeof(struct section *));
4466 sections64 = NULL;
4468 else{
4469 sections = NULL;
4470 sections64 = allocate(nsects * sizeof(struct section_64 *));
4472 nsects = 0;
4473 lc = object->load_commands;
4474 for(i = 0; i < ncmds; i++){
4475 if(lc->cmd == LC_SEGMENT){
4476 sg = (struct segment_command *)lc;
4477 s = (struct section *)((char *)sg +
4478 sizeof(struct segment_command));
4479 for(j = 0; j < sg->nsects; j++){
4480 sections[nsects++] = s++;
4483 else if(lc->cmd == LC_SEGMENT_64){
4484 sg64 = (struct segment_command_64 *)lc;
4485 s64 = (struct section_64 *)((char *)sg64 +
4486 sizeof(struct segment_command_64));
4487 for(j = 0; j < sg64->nsects; j++){
4488 sections64[nsects++] = s64++;
4491 lc = (struct load_command *)((char *)lc + lc->cmdsize);
4495 * Zero out the saved symbols so they can be recorded for this file.
4497 for(i = 0; i < nsave_symbols; i++)
4498 save_symbols[i].sym = NULL;
4499 for(i = 0; i < nremove_symbols; i++)
4500 remove_symbols[i].sym = NULL;
4501 if(member == NULL){
4502 for(i = 0; i < nsave_symbols; i++)
4503 save_symbols[i].seen = FALSE;
4504 for(i = 0; i < nremove_symbols; i++)
4505 remove_symbols[i].seen = FALSE;
4508 nchanged_globals = 0;
4509 if(object->mh != NULL){
4510 changed_globals = allocate(nsyms * sizeof(struct nlist *));
4511 changed_globals64 = NULL;
4512 for(i = 0; i < nsyms; i++)
4513 changed_globals[i] = NULL;
4515 else{
4516 changed_globals = NULL;
4517 changed_globals64 = allocate(nsyms * sizeof(struct nlist_64 *));
4518 for(i = 0; i < nsyms; i++)
4519 changed_globals64[i] = NULL;
4523 * These are the variables for the new symbol table and new string
4524 * table. Since this routine only turns globals into non-globals the
4525 * number of symbols does not change. But the count of local, defined
4526 * external symbols does change.
4528 new_nsyms = nsyms;
4529 new_nlocalsym = 0;
4530 new_nextdefsym = 0;
4531 new_nundefsym = 0;
4533 new_strsize = sizeof(int32_t);
4534 new_ext_strsize = 0;
4537 * First pass: turn the globals symbols into non-global symbols.
4539 for(i = 0; i < nsyms; i++){
4540 len = 0;
4541 s_flags = 0;
4542 if(object->mh != NULL){
4543 n_strx = symbols[i].n_un.n_strx;
4544 n_type = symbols[i].n_type;
4545 n_sect = symbols[i].n_sect;
4546 if((n_type & N_TYPE) == N_SECT)
4547 s_flags = sections[n_sect - 1]->flags;
4548 n_value = symbols[i].n_value;
4550 else{
4551 n_strx = symbols64[i].n_un.n_strx;
4552 n_type = symbols64[i].n_type;
4553 n_sect = symbols64[i].n_sect;
4554 if((n_type & N_TYPE) == N_SECT)
4555 s_flags = sections64[n_sect - 1]->flags;
4556 n_value = symbols64[i].n_value;
4558 if(n_strx != 0){
4559 if(n_strx > strsize){
4560 error_arch(arch, member, "bad string index for symbol "
4561 "table entry %u in: ", i);
4562 return(FALSE);
4564 len = strlen(strings + n_strx) + 1;
4566 if(n_type & N_EXT){
4567 if((n_type & N_TYPE) != N_UNDF &&
4568 (n_type & N_TYPE) != N_PBUD){
4569 if((n_type & N_TYPE) == N_SECT){
4570 if(n_sect > nsects){
4571 error_arch(arch, member, "bad n_sect for symbol "
4572 "table entry %u in: ", i);
4573 return(FALSE);
4575 if(((s_flags & SECTION_TYPE) == S_COALESCED) &&
4576 pflag == FALSE &&
4577 object->mh_filetype != MH_OBJECT){
4578 /* this remains a global defined symbol */
4579 if(warned_about_global_coalesced_symbols == FALSE){
4580 warning_arch(arch, member, "can't make global "
4581 "coalesced symbols (like %s) into static "
4582 "symbols (use ld(1)'s "
4583 "-exported_symbols_list option) in a final "
4584 "linked image: ", strings + n_strx);
4585 warned_about_global_coalesced_symbols = TRUE;
4587 new_nextdefsym++;
4588 new_ext_strsize += len;
4589 new_strsize += len;
4590 sp = bsearch(strings + n_strx,
4591 remove_symbols, nremove_symbols,
4592 sizeof(struct symbol_list),
4593 (int (*)(const void *, const void *))
4594 symbol_list_bsearch);
4595 if(sp != NULL){
4596 if(sp->sym != NULL){
4597 error_arch(arch, member, "more than one "
4598 "symbol for: %s found in: ", sp->name);
4599 return(FALSE);
4601 else{
4602 if(object->mh != NULL)
4603 sp->sym = &(symbols[i]);
4604 else
4605 sp->sym = &(symbols64[i]);
4606 sp->seen = TRUE;
4607 warning_arch(arch, member, "can't make "
4608 "global coalesced symbol: %s into a "
4609 "static symbol in: ", sp->name);
4613 * In case the user has listed this coalesced
4614 * symbol in the save list look for it and mark it
4615 * as seen so we don't complain about not seeing it.
4617 sp = bsearch(strings + n_strx,
4618 save_symbols, nsave_symbols,
4619 sizeof(struct symbol_list),
4620 (int (*)(const void *, const void *))
4621 symbol_list_bsearch);
4622 if(sp != NULL){
4623 if(sp->sym != NULL){
4624 error_arch(arch, member, "more than one "
4625 "symbol for: %s found in: ", sp->name);
4626 return(FALSE);
4628 else{
4629 if(object->mh != NULL)
4630 sp->sym = &(symbols[i]);
4631 else
4632 sp->sym = &(symbols64[i]);
4633 sp->seen = TRUE;
4636 continue; /* leave this symbol unchanged */
4639 sp = bsearch(strings + n_strx,
4640 remove_symbols, nremove_symbols,
4641 sizeof(struct symbol_list),
4642 (int (*)(const void *, const void *))
4643 symbol_list_bsearch);
4644 if(sp != NULL){
4645 if(sp->sym != NULL){
4646 error_arch(arch, member, "more than one symbol "
4647 "for: %s found in: ", sp->name);
4648 return(FALSE);
4650 else{
4651 if(object->mh != NULL)
4652 sp->sym = &(symbols[i]);
4653 else
4654 sp->sym = &(symbols64[i]);
4655 sp->seen = TRUE;
4656 goto change_symbol;
4659 else{
4661 * If there is no list of saved symbols, then all
4662 * symbols will be saved unless listed in the remove
4663 * list.
4665 if(sfile == NULL){
4667 * There is no save list, so if there is also no
4668 * remove list but the -p flag is specified or it is
4669 * a dynamic library then change all symbols.
4671 if((pflag || object->mh_filetype == MH_DYLIB)
4672 && nremove_symbols == 0)
4673 goto change_symbol;
4674 /* this remains a global defined symbol */
4675 new_nextdefsym++;
4676 new_ext_strsize += len;
4677 new_strsize += len;
4678 continue; /* leave this symbol unchanged */
4681 sp = bsearch(strings + n_strx,
4682 save_symbols, nsave_symbols,
4683 sizeof(struct symbol_list),
4684 (int (*)(const void *, const void *))
4685 symbol_list_bsearch);
4686 if(sp != NULL){
4687 if(sp->sym != NULL){
4688 error_arch(arch, member, "more than one symbol "
4689 "for: %s found in: ", sp->name);
4690 return(FALSE);
4692 else{
4693 if(object->mh != NULL)
4694 sp->sym = &(symbols[i]);
4695 else
4696 sp->sym = &(symbols64[i]);
4697 sp->seen = TRUE;
4698 /* this remains a global defined symbol */
4699 new_nextdefsym++;
4700 new_ext_strsize += len;
4701 new_strsize += len;
4704 else{
4705 if(Aflag && n_type == (N_EXT | N_ABS) &&
4706 (n_value != 0 ||
4707 (n_strx != 0 &&
4708 strncmp(strings + n_strx,
4709 ".objc_class_name_",
4710 sizeof(".objc_class_name_") - 1) == 0))){
4711 /* this remains a global defined symbol */
4712 new_nextdefsym++;
4713 new_ext_strsize += len;
4714 new_strsize += len;
4716 else{
4717 change_symbol:
4718 if((n_type & N_TYPE) != N_INDR){
4719 nmedits[i] = TRUE;
4720 if(object->mh != NULL)
4721 changed_globals[nchanged_globals++] =
4722 symbols + i;
4723 else
4724 changed_globals64[nchanged_globals++] =
4725 symbols64 + i;
4726 if(pflag){
4727 /* this remains a global defined symbol */
4728 new_nextdefsym++;
4729 new_ext_strsize += len;
4730 new_strsize += len;
4732 else{
4733 /* this will become a non-global symbol */
4734 new_nlocalsym++;
4735 new_strsize += len;
4738 else{
4739 /* this remains a global defined symbol */
4740 new_nextdefsym++;
4741 new_ext_strsize += len;
4742 new_strsize += len;
4747 else{
4748 /* this is an undefined symbol */
4749 new_nundefsym++;
4750 new_ext_strsize += len;
4751 new_strsize += len;
4754 else{
4755 /* this is a local symbol */
4756 new_nlocalsym++;
4757 new_strsize += len;
4762 * The module table's module names are placed with the external
4763 * strings. So size them and add this to the external string size.
4765 for(i = 0; i < nmodtab; i++){
4766 if(object->mh != NULL)
4767 module_name = mods[i].module_name;
4768 else
4769 module_name = mods64[i].module_name;
4770 if(module_name == 0 || module_name > strsize){
4771 error_arch(arch, member, "bad string index for module_name "
4772 "of module table entry %d in: ", i);
4773 return(FALSE);
4775 len = strlen(strings + module_name) + 1;
4776 new_strsize += len;
4777 new_ext_strsize += len;
4781 * Warn about symbols to be saved that were missing.
4783 if(member == NULL){
4784 missing_syms = 0;
4785 if(iflag == 0){
4786 for(i = 0; i < nsave_symbols; i++){
4787 if(save_symbols[i].sym == NULL){
4788 if(missing_syms == 0){
4789 error_arch(arch, member, "symbols names listed "
4790 "in: %s not in: ", sfile);
4791 missing_syms = 1;
4793 fprintf(stderr, "%s\n", save_symbols[i].name);
4796 for(i = 0; i < nremove_symbols; i++){
4797 if(remove_symbols[i].sym == NULL){
4798 if(missing_syms == 0){
4799 error_arch(arch, member, "symbols names listed "
4800 "in: %s not in: ", Rfile);
4801 missing_syms = 1;
4803 fprintf(stderr, "%s\n", remove_symbols[i].name);
4810 * Second pass: fix stabs for the globals symbols that got turned into
4811 * non-global symbols. This is a MAJOR guess. The specific changes
4812 * to do here were determined by compiling test cases with and without
4813 * the key word 'static' and looking at the difference between the STABS
4814 * the compiler generates and trying to match that here.
4816 global_strings = strings;
4817 if(object->mh != NULL)
4818 qsort(changed_globals, nchanged_globals, sizeof(struct nlist *),
4819 (int (*)(const void *, const void *))cmp_qsort_global);
4820 else
4821 qsort(changed_globals64, nchanged_globals,sizeof(struct nlist_64 *),
4822 (int (*)(const void *, const void *))cmp_qsort_global_64);
4823 dwarf_debug_map = FALSE;
4824 for(i = 0; i < nsyms; i++){
4825 uint16_t n_desc;
4826 if(object->mh != NULL){
4827 n_strx = symbols[i].n_un.n_strx;
4828 n_type = symbols[i].n_type;
4829 n_desc = symbols[i].n_desc;
4831 else{
4832 n_strx = symbols64[i].n_un.n_strx;
4833 n_type = symbols64[i].n_type;
4834 n_desc = symbols64[i].n_desc;
4836 if(n_type == N_SO)
4837 dwarf_debug_map = FALSE;
4838 else if (n_type == N_OSO)
4839 dwarf_debug_map = n_desc != 0;
4840 else if (dwarf_debug_map && n_type == N_GSYM){
4841 global_name = strings + n_strx;
4842 if(object->mh != NULL){
4843 global_symbol = bsearch(global_name, changed_globals,
4844 nchanged_globals,sizeof(struct nlist *),
4845 (int (*)(const void *, const void *))
4846 cmp_bsearch_global);
4847 if(global_symbol != NULL){
4848 symbols[i].n_type = N_STSYM;
4849 symbols[i].n_sect = (*global_symbol)->n_sect;
4850 symbols[i].n_value = (*global_symbol)->n_value;
4853 else{
4854 global_symbol64 = bsearch(global_name, changed_globals64,
4855 nchanged_globals,
4856 sizeof(struct nlist_64 *),
4857 (int (*)(const void *, const void *))
4858 cmp_bsearch_global_64);
4859 if(global_symbol64 != NULL){
4860 symbols64[i].n_type = N_STSYM;
4861 symbols64[i].n_sect = (*global_symbol64)->n_sect;
4862 symbols64[i].n_value = (*global_symbol64)->n_value;
4866 else if(! dwarf_debug_map &&
4867 (n_type == N_GSYM || n_type == N_FUN) &&
4868 (n_strx != 0 && strings[n_strx] != '\0')){
4869 global_name = strings + n_strx;
4870 if((global_name[0] == '+' || global_name[0] == '-') &&
4871 global_name[1] == '['){
4872 j = 2;
4873 while(j + n_strx < strsize && global_name[j] != ']')
4874 j++;
4875 if(j + n_strx < strsize && global_name[j] == ']')
4876 j++;
4878 else
4879 j = 0;
4880 while(j + n_strx < strsize && global_name[j] != ':')
4881 j++;
4882 if(j + n_strx >= strsize){
4883 error_arch(arch, member, "bad N_STAB symbol name for entry "
4884 "%u (does not contain ':' separating name from type) "
4885 "in: ", i);
4886 return(FALSE);
4888 save_char = global_name[j];
4889 global_name[j] = '\0';
4891 global_symbol_found = FALSE;
4892 global_symbol_n_sect = 0;
4893 if(object->mh != NULL){
4894 global_symbol = bsearch(global_name, changed_globals,
4895 nchanged_globals,sizeof(struct nlist *),
4896 (int (*)(const void *, const void *))
4897 cmp_bsearch_global_stab);
4898 global_symbol64 = NULL;
4899 if(global_symbol != NULL){
4900 global_symbol_found = TRUE;
4901 global_symbol_n_sect = (*global_symbol)->n_sect;
4904 else{
4905 global_symbol64 = bsearch(global_name, changed_globals64,
4906 nchanged_globals,
4907 sizeof(struct nlist_64 *),
4908 (int (*)(const void *, const void *))
4909 cmp_bsearch_global_stab_64);
4910 global_symbol = NULL;
4911 if(global_symbol64 != NULL){
4912 global_symbol_found = TRUE;
4913 global_symbol_n_sect = (*global_symbol64)->n_sect;
4916 global_name[j] = save_char;
4917 if(global_symbol_found == TRUE){
4918 if(n_type == N_GSYM){
4919 if(global_symbol_n_sect == data_n_sect){
4920 if(object->mh != NULL)
4921 symbols[i].n_type = N_STSYM;
4922 else
4923 symbols64[i].n_type = N_STSYM;
4925 else{
4926 if(object->mh != NULL)
4927 symbols[i].n_type = N_FUN;
4928 else
4929 symbols64[i].n_type = N_FUN;
4931 if(object->mh != NULL){
4932 symbols[i].n_sect = (*global_symbol)->n_sect;
4933 symbols[i].n_value = (*global_symbol)->n_value;
4934 symbols[i].n_desc = (*global_symbol)->n_desc;
4936 else{
4937 symbols64[i].n_sect = (*global_symbol64)->n_sect;
4938 symbols64[i].n_value = (*global_symbol64)->n_value;
4939 symbols64[i].n_desc = (*global_symbol64)->n_desc;
4941 if(j + 1 + n_strx >= strsize ||
4942 global_name[j+1] != 'G'){
4943 error_arch(arch, member, "bad N_GSYM symbol name "
4944 "for entry %u (does not have type 'G' after "
4945 "':' in name) in: ", i);
4946 return(FALSE);
4948 global_name[j+1] = 'S';
4950 else{ /* n_type == N_FUN */
4951 if(j + 1 + n_strx >= strsize ||
4952 global_name[j+1] == 'F'){
4953 global_name[j+1] = 'f';
4959 global_strings = NULL;
4962 * Now what needs to be done is to create the new symbol table moving
4963 * those global symbols being changed into non-globals into the areas
4964 * in the symbol table for local symbols. The symbol table and string
4965 * table must be in this order:
4967 * symbol table
4968 * local symbols
4969 * external defined symbols
4970 * undefined symbols
4971 * string table
4972 * external strings
4973 * local strings
4975 if(saves != NULL)
4976 free(saves);
4977 saves = (int32_t *)allocate(nsyms * sizeof(int32_t));
4978 bzero(saves, nsyms * sizeof(int32_t));
4980 if(object->mh != NULL){
4981 new_symbols = (struct nlist *)
4982 allocate(new_nsyms * sizeof(struct nlist));
4983 new_symbols64 = NULL;
4985 else{
4986 new_symbols = NULL;
4987 new_symbols64 = (struct nlist_64 *)
4988 allocate(new_nsyms * sizeof(struct nlist_64));
4990 new_strsize = rnd(new_strsize, sizeof(int32_t));
4991 new_strings = (char *)allocate(new_strsize);
4992 new_strings[new_strsize - 3] = '\0';
4993 new_strings[new_strsize - 2] = '\0';
4994 new_strings[new_strsize - 1] = '\0';
4996 memset(new_strings, '\0', sizeof(int32_t));
4997 p = new_strings + sizeof(int32_t);
4998 q = p + new_ext_strsize;
5001 * If this is a dynamic library the movement of the symbols has to be
5002 * done with respect to the modules. As the local symbols, and external
5003 * defined symbols are grouped together for each module. Then a new
5004 * module table needs to be created with the new indexes into the symbol
5005 * table for each module.
5007 new_nmodtab = nmodtab;
5008 new_ntoc = ntoc;
5009 new_nextrefsyms = nextrefsyms;
5010 if(object->mh_filetype == MH_DYLIB && nmodtab != 0){
5011 if(object->mh != NULL){
5012 new_mods = allocate(nmodtab * sizeof(struct dylib_module));
5013 new_mods64 = NULL;
5015 else{
5016 new_mods = NULL;
5017 new_mods64 = allocate(nmodtab * sizeof(struct dylib_module_64));
5020 inew_syms = 0;
5022 * This first loop through the module table sets the index and
5023 * counts of the local symbols for each module.
5025 for(i = 0; i < nmodtab; i++){
5027 * First put the existing local symbols into the new symbol
5028 * table.
5030 if(object->mh != NULL){
5031 new_mods[i].ilocalsym = inew_syms;
5032 new_mods[i].nlocalsym = 0;
5033 ilocalsym = mods[i].ilocalsym;
5034 nlocalsym = mods[i].nlocalsym;
5036 else{
5037 new_mods64[i].ilocalsym = inew_syms;
5038 new_mods64[i].nlocalsym = 0;
5039 ilocalsym = mods64[i].ilocalsym;
5040 nlocalsym = mods64[i].nlocalsym;
5042 for(j = ilocalsym; j < ilocalsym + nlocalsym; j++){
5043 if(object->mh != NULL){
5044 n_strx = symbols[j].n_un.n_strx;
5045 n_type = symbols[j].n_type;
5047 else{
5048 n_strx = symbols64[j].n_un.n_strx;
5049 n_type = symbols64[j].n_type;
5051 if((n_type & N_EXT) == 0){
5052 if(object->mh != NULL)
5053 new_symbols[inew_syms] = symbols[j];
5054 else
5055 new_symbols64[inew_syms] = symbols64[j];
5056 if(n_strx != 0){
5057 strcpy(q, strings + n_strx);
5058 if(object->mh != NULL)
5059 new_symbols[inew_syms].n_un.n_strx =
5060 q - new_strings;
5061 else
5062 new_symbols64[inew_syms].n_un.n_strx =
5063 q - new_strings;
5064 q += strlen(q) + 1;
5066 inew_syms++;
5067 saves[j] = inew_syms;
5068 if(object->mh != NULL)
5069 new_mods[i].nlocalsym++;
5070 else
5071 new_mods64[i].nlocalsym++;
5075 * Next put the global symbols that were changed into
5076 * non-global symbols into the new symbol table and moved their
5077 * counts to the local symbol counts.
5079 if(object->mh != NULL){
5080 iextdefsym = mods[i].iextdefsym;
5081 nextdefsym = mods[i].nextdefsym;
5083 else{
5084 iextdefsym = mods64[i].iextdefsym;
5085 nextdefsym = mods64[i].nextdefsym;
5087 for(j = iextdefsym; j < iextdefsym + nextdefsym; j++){
5088 if(object->mh != NULL){
5089 n_strx = symbols[j].n_un.n_strx;
5090 n_type = symbols[j].n_type;
5092 else{
5093 n_strx = symbols64[j].n_un.n_strx;
5094 n_type = symbols64[j].n_type;
5096 if((n_type & N_EXT) != 0){
5097 if(nmedits[j] == TRUE){
5099 * Change the new symbol to a private extern symbol
5100 * with the extern bit off.
5102 if(object->mh != NULL){
5103 new_symbols[inew_syms] = symbols[j];
5104 new_symbols[inew_syms].n_type |= N_PEXT;
5105 new_symbols[inew_syms].n_type &= ~N_EXT;
5107 else{
5108 new_symbols64[inew_syms] = symbols64[j];
5109 new_symbols64[inew_syms].n_type |= N_PEXT;
5110 new_symbols64[inew_syms].n_type &= ~N_EXT;
5112 if(n_strx != 0){
5113 strcpy(q, strings + n_strx);
5114 if(object->mh != NULL)
5115 new_symbols[inew_syms].n_un.n_strx =
5116 q - new_strings;
5117 else
5118 new_symbols64[inew_syms].n_un.n_strx =
5119 q - new_strings;
5120 q += strlen(q) + 1;
5122 inew_syms++;
5123 saves[j] = inew_syms;
5124 if(object->mh != NULL)
5125 new_mods[i].nlocalsym++;
5126 else
5127 new_mods64[i].nlocalsym++;
5133 * Next put the unchanged defined global symbols into the new
5134 * symbol table.
5136 for(i = 0; i < nmodtab; i++){
5137 if(object->mh != NULL){
5138 new_mods[i].iextdefsym = inew_syms;
5139 new_mods[i].nextdefsym = 0;
5140 iextdefsym = mods[i].iextdefsym;
5141 nextdefsym = mods[i].nextdefsym;
5143 else{
5144 new_mods64[i].iextdefsym = inew_syms;
5145 new_mods64[i].nextdefsym = 0;
5146 iextdefsym = mods64[i].iextdefsym;
5147 nextdefsym = mods64[i].nextdefsym;
5149 for(j = iextdefsym; j < iextdefsym + nextdefsym; j++){
5150 if(object->mh != NULL){
5151 n_strx = symbols[j].n_un.n_strx;
5152 n_type = symbols[j].n_type;
5154 else{
5155 n_strx = symbols64[j].n_un.n_strx;
5156 n_type = symbols64[j].n_type;
5158 if((n_type & N_EXT) != 0){
5159 if(nmedits[j] == FALSE){
5160 if(object->mh != NULL)
5161 new_symbols[inew_syms] = symbols[j];
5162 else
5163 new_symbols64[inew_syms] = symbols64[j];
5164 if(n_strx != 0){
5165 strcpy(p, strings + n_strx);
5166 if(object->mh != NULL)
5167 new_symbols[inew_syms].n_un.n_strx =
5168 p - new_strings;
5169 else
5170 new_symbols64[inew_syms].n_un.n_strx =
5171 p - new_strings;
5172 p += strlen(p) + 1;
5174 inew_syms++;
5175 saves[j] = inew_syms;
5176 if(object->mh != NULL)
5177 new_mods[i].nextdefsym++;
5178 else
5179 new_mods64[i].nextdefsym++;
5185 * Last put the undefined symbols into the new symbol table.
5187 for(i = 0; i < nsyms; i++){
5188 if(object->mh != NULL){
5189 n_strx = symbols[i].n_un.n_strx;
5190 n_type = symbols[i].n_type;
5192 else{
5193 n_strx = symbols64[i].n_un.n_strx;
5194 n_type = symbols64[i].n_type;
5196 if((n_type & N_EXT) != 0 &&
5197 ((n_type & N_TYPE) == N_UNDF ||
5198 (n_type & N_TYPE) == N_PBUD)){
5199 if(object->mh != NULL)
5200 new_symbols[inew_syms] = symbols[i];
5201 else
5202 new_symbols64[inew_syms] = symbols64[i];
5203 if(n_strx != 0){
5204 strcpy(p, strings + n_strx);
5205 if(object->mh != NULL)
5206 new_symbols[inew_syms].n_un.n_strx =
5207 p - new_strings;
5208 else
5209 new_symbols64[inew_syms].n_un.n_strx =
5210 p - new_strings;
5211 p += strlen(p) + 1;
5213 inew_syms++;
5214 saves[i] = inew_syms;
5219 * Place the module table's module names with the external strings
5220 * and set the names in the new module table. And then copy the
5221 * other unchanged fields.
5223 for(i = 0; i < nmodtab; i++){
5224 if(object->mh != NULL){
5225 strcpy(p, strings + mods[i].module_name);
5226 new_mods[i].module_name = p - new_strings;
5227 p += strlen(p) + 1;
5229 new_mods[i].irefsym = mods[i].irefsym;
5230 new_mods[i].nrefsym = mods[i].nrefsym;
5231 new_mods[i].iextrel = mods[i].iextrel;
5232 new_mods[i].nextrel = mods[i].nextrel;
5233 new_mods[i].iinit_iterm = mods[i].iinit_iterm;
5234 new_mods[i].ninit_nterm = mods[i].ninit_nterm;
5235 new_mods[i].objc_module_info_addr =
5236 mods[i].objc_module_info_addr;
5237 new_mods[i].objc_module_info_size =
5238 mods[i].objc_module_info_size;
5240 else{
5241 strcpy(p, strings + mods64[i].module_name);
5242 new_mods64[i].module_name = p - new_strings;
5243 p += strlen(p) + 1;
5245 new_mods64[i].irefsym = mods64[i].irefsym;
5246 new_mods64[i].nrefsym = mods64[i].nrefsym;
5247 new_mods64[i].iextrel = mods64[i].iextrel;
5248 new_mods64[i].nextrel = mods64[i].nextrel;
5249 new_mods64[i].iinit_iterm = mods64[i].iinit_iterm;
5250 new_mods64[i].ninit_nterm = mods64[i].ninit_nterm;
5251 new_mods64[i].objc_module_info_addr =
5252 mods64[i].objc_module_info_addr;
5253 new_mods64[i].objc_module_info_size =
5254 mods64[i].objc_module_info_size;
5259 * Update the reference table with the new symbol indexes for all
5260 * entries and change type of reference (the flags field) for those
5261 * symbols that got changed from globals to non-globals.
5263 new_nextrefsyms = nextrefsyms;
5264 new_refs = allocate(new_nextrefsyms *
5265 sizeof(struct dylib_reference));
5266 j = 0;
5267 for(i = 0; i < nextrefsyms; i++){
5268 if(nmedits[refs[i].isym] == TRUE){
5269 if(refs[i].flags == REFERENCE_FLAG_DEFINED)
5270 new_refs[i].flags =
5271 REFERENCE_FLAG_PRIVATE_DEFINED;
5272 else if(refs[i].flags == REFERENCE_FLAG_UNDEFINED_NON_LAZY)
5273 new_refs[i].flags =
5274 REFERENCE_FLAG_PRIVATE_UNDEFINED_NON_LAZY;
5275 else if(refs[i].flags == REFERENCE_FLAG_UNDEFINED_LAZY)
5276 new_refs[i].flags =
5277 REFERENCE_FLAG_PRIVATE_UNDEFINED_LAZY;
5278 else
5279 new_refs[i].flags = refs[i].flags;
5281 else{
5282 new_refs[i].flags = refs[i].flags;
5284 new_refs[i].isym = saves[refs[i].isym] - 1;
5288 * Create a new dylib table of contents without the global symbols
5289 * that got turned into non-globals.
5291 new_ntoc = ntoc - nchanged_globals;
5292 new_tocs = allocate(new_ntoc *
5293 sizeof(struct dylib_table_of_contents));
5294 k = 0;
5295 for(i = 0; i < ntoc; i++){
5296 if(tocs[i].symbol_index >= nsyms){
5297 error_arch(arch, member, "bad symbol index for table of "
5298 "contents table entry %d in: ", i);
5299 return(FALSE);
5301 if(nmedits[tocs[i].symbol_index] == FALSE){
5302 new_tocs[k].symbol_index = saves[tocs[i].symbol_index] - 1;
5303 new_tocs[k].module_index = tocs[i].module_index;
5304 k++;
5309 * If is not a dynamic library so all global symbols changed into
5310 * statics can be moved to the end of the local symbols. If the pflag
5311 * is set then the changed symbols remain global and just get the
5312 * private extern bit set.
5314 else{
5316 * First put the existing local symbols into the new symbol table.
5318 inew_syms = 0;
5319 for(i = 0; i < nsyms; i++){
5320 if(object->mh != NULL){
5321 n_strx = symbols[i].n_un.n_strx;
5322 n_type = symbols[i].n_type;
5324 else{
5325 n_strx = symbols64[i].n_un.n_strx;
5326 n_type = symbols64[i].n_type;
5328 if((n_type & N_EXT) == 0){
5329 if(object->mh != NULL)
5330 new_symbols[inew_syms] = symbols[i];
5331 else
5332 new_symbols64[inew_syms] = symbols64[i];
5333 if(n_strx != 0){
5334 strcpy(q, strings + n_strx);
5335 if(object->mh != NULL)
5336 new_symbols[inew_syms].n_un.n_strx =
5337 q - new_strings;
5338 else
5339 new_symbols64[inew_syms].n_un.n_strx =
5340 q - new_strings;
5341 q += strlen(q) + 1;
5343 inew_syms++;
5344 saves[i] = inew_syms;
5348 * Next put the global symbols that were changed into statics
5349 * symbols into the new symbol table.
5351 if(pflag == FALSE){
5352 for(i = 0; i < nsyms; i++){
5353 if(object->mh != NULL){
5354 n_strx = symbols[i].n_un.n_strx;
5355 n_type = symbols[i].n_type;
5357 else{
5358 n_strx = symbols64[i].n_un.n_strx;
5359 n_type = symbols64[i].n_type;
5361 if((n_type & N_EXT) != 0){
5362 if(nmedits[i] == TRUE){
5364 * Change the new symbol to not be an extern symbol
5365 * by turning off the extern bit.
5367 if(object->mh != NULL){
5368 new_symbols[inew_syms] = symbols[i];
5369 new_symbols[inew_syms].n_type &= ~N_EXT;
5370 new_symbols[inew_syms].n_desc &= ~N_WEAK_DEF;
5372 else{
5373 new_symbols64[inew_syms] = symbols64[i];
5374 new_symbols64[inew_syms].n_type &= ~N_EXT;
5375 new_symbols64[inew_syms].n_desc &= ~N_WEAK_DEF;
5377 if(n_strx != 0){
5378 strcpy(q, strings + n_strx);
5379 if(object->mh != NULL)
5380 new_symbols[inew_syms].n_un.n_strx =
5381 q - new_strings;
5382 else
5383 new_symbols64[inew_syms].n_un.n_strx =
5384 q - new_strings;
5385 q += strlen(q) + 1;
5387 inew_syms++;
5388 saves[i] = inew_syms;
5394 * Last put the unchanged global symbols into the new symbol table
5395 * and symbols changed into private externs.
5397 for(i = 0; i < nsyms; i++){
5398 if(object->mh != NULL){
5399 n_strx = symbols[i].n_un.n_strx;
5400 n_type = symbols[i].n_type;
5402 else{
5403 n_strx = symbols64[i].n_un.n_strx;
5404 n_type = symbols64[i].n_type;
5406 if((n_type & N_EXT) != 0){
5407 if(nmedits[i] == FALSE || pflag == TRUE){
5408 if(object->mh != NULL)
5409 new_symbols[inew_syms] = symbols[i];
5410 else
5411 new_symbols64[inew_syms] = symbols64[i];
5412 if(nmedits[i] == TRUE && pflag == TRUE){
5414 * Change the new symbol to be a private extern
5415 * symbol by turning on the private extern bit.
5417 if(object->mh != NULL)
5418 new_symbols[inew_syms].n_type |= N_PEXT;
5419 else
5420 new_symbols64[inew_syms].n_type |= N_PEXT;
5422 if(n_strx != 0){
5423 strcpy(p, strings + n_strx);
5424 if(object->mh != NULL)
5425 new_symbols[inew_syms].n_un.n_strx =
5426 p - new_strings;
5427 else
5428 new_symbols64[inew_syms].n_un.n_strx =
5429 p - new_strings;
5430 p += strlen(p) + 1;
5432 inew_syms++;
5433 saves[i] = inew_syms;
5439 if(sections != NULL)
5440 free(sections);
5441 if(sections64 != NULL)
5442 free(sections64);
5444 if(errors == 0)
5445 return(TRUE);
5446 else
5447 return(FALSE);
5451 * Function for qsort for comparing global symbol names.
5453 static
5455 cmp_qsort_global(
5456 const struct nlist **sym1,
5457 const struct nlist **sym2)
5459 return(strcmp(global_strings + (*sym1)->n_un.n_strx,
5460 global_strings + (*sym2)->n_un.n_strx));
5463 static
5465 cmp_qsort_global_64(
5466 const struct nlist_64 **sym1,
5467 const struct nlist_64 **sym2)
5469 return(strcmp(global_strings + (*sym1)->n_un.n_strx,
5470 global_strings + (*sym2)->n_un.n_strx));
5474 * Function for bsearch for finding a global symbol that matches a stab name.
5476 static
5478 cmp_bsearch_global_stab(
5479 const char *name,
5480 const struct nlist **sym)
5483 * The +1 is for the '_' on the global symbol that is not on the
5484 * stab string that is trying to be matched.
5486 return(strcmp(name, global_strings + (*sym)->n_un.n_strx + 1));
5489 static
5491 cmp_bsearch_global_stab_64(
5492 const char *name,
5493 const struct nlist_64 **sym)
5496 * The +1 is for the '_' on the global symbol that is not on the
5497 * stab string that is trying to be matched.
5499 return(strcmp(name, global_strings + (*sym)->n_un.n_strx + 1));
5503 * Function for bsearch for finding a global symbol that matches a stab name
5504 * in the debug map.
5506 static
5508 cmp_bsearch_global(
5509 const char *name,
5510 const struct nlist **sym)
5512 return(strcmp(name, global_strings + (*sym)->n_un.n_strx));
5515 static
5517 cmp_bsearch_global_64(
5518 const char *name,
5519 const struct nlist_64 **sym)
5521 return(strcmp(name, global_strings + (*sym)->n_un.n_strx));
5523 #endif /* defined(NMEDIT) */