Integrate cctools-751 changes
[striptease.git] / tease.c
blobd384827c22354be03f0bd6bcabf6f13763ad0ee1
1 /*
2 * Copyright (c) 1999 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
11 * file.
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
21 * @APPLE_LICENSE_HEADER_END@
24 * The strip(1) and nmedit(l) program. This understands only Mach-O format
25 * files (with the restriction the symbol table is at the end of the file) and
26 * fat files with Mach-O files in them.
28 #include <stdio.h>
29 #include <stdlib.h>
30 #include <string.h>
31 #include <limits.h>
32 #include <ctype.h>
33 #include <libc.h>
34 #include <sys/types.h>
35 #include <sys/stat.h>
36 #include <mach-o/loader.h>
37 #include <mach-o/reloc.h>
38 #include <mach-o/nlist.h>
39 #include <mach-o/stab.h>
40 #include "stuff/breakout.h"
41 #include "stuff/allocate.h"
42 #include "stuff/errors.h"
43 #include "stuff/round.h"
44 #include "stuff/reloc.h"
45 #include "stuff/reloc.h"
46 #include "stuff/symbol_list.h"
47 #include "stuff/unix_standard_mode.h"
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;
142 * The index into the new symbols where the defined external start.
144 static uint32_t inew_nextdefsym = 0;
147 * These hold the new table of contents, reference table and module table for
148 * dylibs.
150 static struct dylib_table_of_contents *new_tocs = NULL;
151 static uint32_t new_ntoc = 0;
152 static struct dylib_reference *new_refs = NULL;
153 static uint32_t new_nextrefsyms = 0;
154 #ifdef NMEDIT
155 static struct dylib_module *new_mods = NULL;
156 static struct dylib_module_64 *new_mods64 = NULL;
157 static uint32_t new_nmodtab = 0;
158 #endif
160 #ifndef NMEDIT
162 * The list of file names to save debugging symbols from.
164 static char **debug_filenames = NULL;
165 static uint32_t ndebug_filenames = 0;
166 struct undef_map {
167 uint32_t index;
168 struct nlist symbol;
170 struct undef_map64 {
171 uint32_t index;
172 struct nlist_64 symbol64;
174 static char *qsort_strings = NULL;
175 #endif /* !defined(NMEDIT) */
178 /* Internal routines */
179 static void usage(
180 void);
182 static void strip_file(
183 char *input_file,
184 struct arch_flag *arch_flags,
185 uint32_t narch_flags,
186 enum bool all_archs);
188 static void strip_arch(
189 struct arch *archs,
190 uint32_t narchs,
191 struct arch_flag *arch_flags,
192 uint32_t narch_flags,
193 enum bool all_archs);
195 static void strip_object(
196 struct arch *arch,
197 struct member *member,
198 struct object *object);
200 static uint32_t get_starting_syminfo_offset(
201 struct object *object);
203 static void check_object_relocs(
204 struct arch *arch,
205 struct member *member,
206 struct object *object,
207 char *segname,
208 char *sectname,
209 uint64_t sectsize,
210 char *contents,
211 struct relocation_info *relocs,
212 uint32_t nreloc,
213 struct nlist *symbols,
214 struct nlist_64 *symbols64,
215 uint32_t nsyms,
216 char *strings,
217 int32_t *missing_reloc_symbols,
218 enum byte_sex host_byte_sex);
220 static void check_indirect_symtab(
221 struct arch *arch,
222 struct member *member,
223 struct object *object,
224 uint32_t nitems,
225 uint32_t reserved1,
226 uint32_t section_type,
227 char *contents,
228 struct nlist *symbols,
229 struct nlist_64 *symbols64,
230 uint32_t nsyms,
231 char *strings,
232 int32_t *missing_reloc_symbols,
233 enum byte_sex host_byte_sex);
235 #ifndef NMEDIT
236 static enum bool strip_symtab(
237 struct arch *arch,
238 struct member *member,
239 struct object *object,
240 struct dylib_table_of_contents *tocs,
241 uint32_t ntoc,
242 struct dylib_module *mods,
243 struct dylib_module_64 *mods64,
244 uint32_t nmodtab,
245 struct dylib_reference *refs,
246 uint32_t nextrefsyms);
248 #ifdef TRIE_SUPPORT
249 static int prune(
250 const char *name);
251 #endif /* TRIE_SUPPORT */
253 static void make_ld_r_object(
254 struct arch *arch,
255 struct member *member,
256 struct object *object);
258 static void strip_LC_UUID_commands(
259 struct arch *arch,
260 struct member *member,
261 struct object *object);
263 #ifndef NMEDIT
264 static void strip_LC_CODE_SIGNATURE_commands(
265 struct arch *arch,
266 struct member *member,
267 struct object *object);
268 #endif /* !(NMEDIT) */
270 static enum bool private_extern_reference_by_module(
271 uint32_t symbol_index,
272 struct dylib_reference *refs,
273 uint32_t nextrefsyms);
275 static enum bool symbol_pointer_used(
276 uint32_t symbol_index,
277 uint32_t *indirectsyms,
278 uint32_t nindirectsyms);
280 static int cmp_qsort_undef_map(
281 const struct undef_map *sym1,
282 const struct undef_map *sym2);
284 static int cmp_qsort_undef_map_64(
285 const struct undef_map64 *sym1,
286 const struct undef_map64 *sym2);
287 #endif /* !defined(NMEDIT) */
289 #ifdef NMEDIT
290 static enum bool edit_symtab(
291 struct arch *arch,
292 struct member *member,
293 struct object *object,
294 struct nlist *symbols,
295 struct nlist_64 *symbols64,
296 uint32_t nsyms,
297 char *strings,
298 uint32_t strsize,
299 struct dylib_table_of_contents *tocs,
300 uint32_t ntoc,
301 struct dylib_module *mods,
302 struct dylib_module_64 *mods64,
303 uint32_t nmodtab,
304 struct dylib_reference *refs,
305 uint32_t nextrefsyms);
306 #endif /* NMEDIT */
308 #ifndef NMEDIT
309 static void setup_debug_filenames(
310 char *dfile);
312 static int cmp_qsort_filename(
313 const char **name1,
314 const char **name2);
316 static int cmp_bsearch_filename(
317 const char *name1,
318 const char **name2);
319 #endif /* NMEDIT */
321 #ifdef NMEDIT
323 * This variable and routines are used for nmedit(1) only.
325 static char *global_strings = NULL;
327 static int cmp_qsort_global(
328 const struct nlist **sym1,
329 const struct nlist **sym2);
331 static int cmp_qsort_global_64(
332 const struct nlist_64 **sym1,
333 const struct nlist_64 **sym2);
335 static int cmp_bsearch_global_stab(
336 const char *name,
337 const struct nlist **sym);
339 static int cmp_bsearch_global_stab_64(
340 const char *name,
341 const struct nlist_64 **sym);
343 static int cmp_bsearch_global(
344 const char *name,
345 const struct nlist **sym);
347 static int cmp_bsearch_global_64(
348 const char *name,
349 const struct nlist_64 **sym);
350 #endif /* NMEDIT */
353 main(
354 int argc,
355 char *argv[],
356 char *envp[])
358 int i;
359 uint32_t j, args_left, files_specified;
360 struct arch_flag *arch_flags;
361 uint32_t narch_flags;
362 enum bool all_archs;
363 struct symbol_list *sp;
365 progname = argv[0];
367 arch_flags = NULL;
368 narch_flags = 0;
369 all_archs = FALSE;
371 files_specified = 0;
372 args_left = 1;
373 for (i = 1; i < argc; i++){
374 if(argv[i][0] == '-'){
375 if(argv[i][1] == '\0'){
376 args_left = 0;
377 break;
379 if(strcmp(argv[i], "-o") == 0){
380 if(i + 1 >= argc)
381 fatal("-o requires an argument");
382 if(output_file != NULL)
383 fatal("only one -o option allowed");
384 output_file = argv[i + 1];
385 i++;
387 else if(strcmp(argv[i], "-s") == 0){
388 if(i + 1 >= argc)
389 fatal("-s requires an argument");
390 if(sfile != NULL)
391 fatal("only one -s option allowed");
392 sfile = argv[i + 1];
393 i++;
395 else if(strcmp(argv[i], "-R") == 0){
396 if(i + 1 >= argc)
397 fatal("-R requires an argument");
398 if(Rfile != NULL)
399 fatal("only one -R option allowed");
400 Rfile = argv[i + 1];
401 i++;
403 #ifndef NMEDIT
404 else if(strcmp(argv[i], "-d") == 0){
405 if(i + 1 >= argc)
406 fatal("-d requires an argument");
407 if(dfile != NULL)
408 fatal("only one -d option allowed");
409 dfile = argv[i + 1];
410 i++;
412 else if(strcmp(argv[i], "-no_uuid") == 0){
413 no_uuid = 1;
415 else if(strcmp(argv[i], "-no_code_signature") == 0){
416 no_code_signature = 1;
418 #endif /* !defined(NMEDIT) */
419 else if(strcmp(argv[i], "-arch") == 0){
420 if(i + 1 == argc){
421 error("missing argument(s) to %s option", argv[i]);
422 usage();
424 if(strcmp("all", argv[i+1]) == 0){
425 all_archs = TRUE;
427 else{
428 arch_flags = reallocate(arch_flags,
429 (narch_flags + 1) * sizeof(struct arch_flag));
430 if(get_arch_from_flag(argv[i+1],
431 arch_flags + narch_flags) == 0){
432 error("unknown architecture specification flag: "
433 "%s %s", argv[i], argv[i+1]);
434 arch_usage();
435 usage();
437 for(j = 0; j < narch_flags; j++){
438 if(arch_flags[j].cputype ==
439 arch_flags[narch_flags].cputype &&
440 (arch_flags[j].cpusubtype & ~CPU_SUBTYPE_MASK) ==
441 (arch_flags[narch_flags].cpusubtype &
442 ~CPU_SUBTYPE_MASK) &&
443 strcmp(arch_flags[j].name,
444 arch_flags[narch_flags].name) == 0)
445 break;
447 if(j == narch_flags)
448 narch_flags++;
450 i++;
452 else{
453 for(j = 1; argv[i][j] != '\0'; j++){
454 switch(argv[i][j]){
455 #ifdef NMEDIT
456 case 'p':
457 pflag = 1;
458 break;
459 #else /* !defined(NMEDIT) */
460 case 'S':
461 Sflag = 1;
462 strip_all = 0;
463 break;
464 case 'X':
465 Xflag = 1;
466 strip_all = 0;
467 break;
468 case 'x':
469 xflag = 1;
470 strip_all = 0;
471 break;
472 case 't':
473 tflag = 1;
474 strip_all = 0;
475 break;
476 case 'i':
477 iflag = 1;
478 break;
479 case 'u':
480 uflag = 1;
481 strip_all = 0;
482 break;
483 case 'r':
484 rflag = 1;
485 strip_all = 0;
486 break;
487 case 'n':
488 nflag = 1;
489 strip_all = 0;
490 break;
491 #endif /* !defined(NMEDIT) */
492 case 'A':
493 Aflag = 1;
494 #ifndef NMEDIT
495 strip_all = 0;
496 #endif /* !defined(NMEDIT) */
497 break;
498 #ifndef NMEDIT
499 case 'a':
500 aflag = 1;
501 strip_all = 0;
502 break;
503 case 'c':
504 cflag = 1;
505 strip_all = 0;
506 break;
507 case 'v':
508 vflag = 1;
509 break;
510 case 'l':
511 lflag = 1;
512 break;
513 #endif /* NMEDIT */
514 default:
515 error("unrecognized option: %s", argv[i]);
516 usage();
521 else
522 files_specified++;
524 if(args_left == 0)
525 files_specified += argc - (i + 1);
527 if(files_specified > 1 && output_file != NULL){
528 error("-o <filename> can only be used when one file is specified");
529 usage();
532 if(sfile){
533 setup_symbol_list(sfile, &save_symbols, &nsave_symbols);
535 #ifdef NMEDIT
536 else{
537 if(Rfile == NULL && pflag == 0){
538 error("-s <filename>, -R <filename> or -p argument required");
539 usage();
542 #endif /* NMEDIT */
544 if(Rfile){
545 setup_symbol_list(Rfile, &remove_symbols, &nremove_symbols);
546 if(sfile){
547 for(j = 0; j < nremove_symbols ; j++){
548 sp = bsearch(remove_symbols[j].name,
549 save_symbols, nsave_symbols,
550 sizeof(struct symbol_list),
551 (int (*)(const void *, const void *))
552 symbol_list_bsearch);
553 if(sp != NULL){
554 error("symbol name: %s is listed in both -s %s and -R "
555 "%s files (can't be both saved and removed)",
556 remove_symbols[j].name, sfile, Rfile);
559 if(errors)
560 exit(EXIT_FAILURE);
564 /* the default when no -arch flags is present is to strip all archs */
565 if(narch_flags == 0)
566 all_archs = TRUE;
568 #ifndef NMEDIT
569 if(dfile){
570 setup_debug_filenames(dfile);
572 #endif /* !defined(NMEDIT) */
574 files_specified = 0;
575 args_left = 1;
576 for (i = 1; i < argc; i++) {
577 if(args_left && argv[i][0] == '-'){
578 if(argv[i][1] == '\0')
579 args_left = 0;
580 else if(strcmp(argv[i], "-o") == 0 ||
581 strcmp(argv[i], "-s") == 0 ||
582 strcmp(argv[i], "-R") == 0 ||
583 #ifndef NMEDIT
584 strcmp(argv[i], "-d") == 0 ||
585 #endif /* !defined(NMEDIT) */
586 strcmp(argv[i], "-arch") == 0)
587 i++;
589 else{
590 char resolved_path[PATH_MAX + 1];
592 if(realpath(argv[i], resolved_path) == NULL)
593 strip_file(argv[i], arch_flags, narch_flags, all_archs);
594 else
595 strip_file(resolved_path, arch_flags,narch_flags,all_archs);
596 files_specified++;
599 if(files_specified == 0)
600 fatal("no files specified");
602 if(errors)
603 return(EXIT_FAILURE);
604 else
605 return(EXIT_SUCCESS);
608 static
609 void
610 usage(
611 void)
613 #ifndef NMEDIT
614 fprintf(stderr, "Usage: %s [-AanuStXx] [-no_uuid] [-no_code_signature] "
615 "[-] [-d filename] [-s filename] [-R filename] [-o output] "
616 "file [...]\n", progname);
617 #else /* defined(NMEDIT) */
618 fprintf(stderr, "Usage: %s -s filename [-R filename] [-p] [-A] [-] "
619 "[-o output] file [...] \n",
620 progname);
621 #endif /* NMEDIT */
622 exit(EXIT_FAILURE);
625 static
626 void
627 strip_file(
628 char *input_file,
629 struct arch_flag *arch_flags,
630 uint32_t narch_flags,
631 enum bool all_archs)
633 struct ofile *ofile;
634 struct arch *archs;
635 uint32_t narchs;
636 struct stat stat_buf;
637 uint32_t previous_errors;
638 enum bool unix_standard_mode;
639 int cwd_fd;
640 char *rename_file;
641 #ifndef NMEDIT
642 char *p;
643 #endif
645 archs = NULL;
646 narchs = 0;
647 previous_errors = errors;
648 errors = 0;
650 /* breakout the file for processing */
651 ofile = breakout(input_file, &archs, &narchs, FALSE);
652 if(errors)
653 return;
655 /* checkout the file for symbol table replacement processing */
656 checkout(archs, narchs);
658 /* process the symbols in the input file */
659 strip_arch(archs, narchs, arch_flags, narch_flags, all_archs);
660 if(errors){
661 free_archs(archs, narchs);
662 ofile_unmap(ofile);
663 return;
666 /* create the output file */
667 if(stat(input_file, &stat_buf) == -1)
668 system_error("can't stat input file: %s", input_file);
669 if(output_file != NULL){
670 writeout(archs, narchs, output_file, stat_buf.st_mode & 0777,
671 TRUE, FALSE, FALSE, NULL);
673 else{
674 unix_standard_mode = get_unix_standard_mode();
675 rename_file = NULL;
676 cwd_fd = -1;
677 #ifdef NMEDIT
678 output_file = makestr(input_file, ".nmedit", NULL);
679 #else /* !defined(NMEDIT) */
681 * In UNIX standard conformance mode we are not allowed to replace
682 * a file that is not writeable.
684 if(unix_standard_mode == TRUE &&
685 access(input_file, W_OK) == -1){
686 system_error("file: %s is not writable", input_file);
687 goto strip_file_return;
689 output_file = makestr(input_file, ".strip", NULL);
692 * The UNIX standard conformance test suite expects files of
693 * MAXPATHLEN to work.
695 if(strlen(output_file) >= MAXPATHLEN){
697 * If there is a directory path in the name try to change
698 * the current working directory to that path.
700 if((p = rindex(output_file, '/')) != NULL){
701 if((cwd_fd = open(".", O_RDONLY, 0)) == -1){
702 system_error("can't open current working directory");
703 goto strip_file_return;
705 *p = '\0';
706 if(chdir(output_file) == -1){
707 system_error("can't change current working directory "
708 "to: %s", output_file);
709 goto strip_file_return;
711 p = rindex(input_file, '/');
712 rename_file = makestr(p + 1, NULL);
715 * Create what might be a short enough name.
717 free(output_file);
718 output_file = makestr("strip.XXXXXX", NULL);
719 output_file = mktemp(output_file);
721 #endif /* NMEDIT */
722 writeout(archs, narchs, output_file, stat_buf.st_mode & 0777,
723 TRUE, FALSE, FALSE, NULL);
724 if(rename_file != NULL){
725 if(rename(output_file, rename_file) == -1)
726 system_error("can't move temporary file: %s to file: %s",
727 output_file, rename_file);
728 free(rename_file);
730 else{
731 if(rename(output_file, input_file) == -1)
732 system_error("can't move temporary file: %s to input "
733 "file: %s", output_file, input_file);
735 free(output_file);
736 output_file = NULL;
739 * If we changed the current working directory change back to
740 * the previous working directory.
742 if(cwd_fd != -1){
743 if(fchdir(cwd_fd) == -1)
744 system_error("can't change back to previous working "
745 "directory");
746 if(close(cwd_fd) == -1)
747 system_error("can't close previous working directory");
751 #ifndef NMEDIT
752 strip_file_return:
753 #endif /* !defined(NMEDIT) */
754 /* clean-up data structures */
755 free_archs(archs, narchs);
756 ofile_unmap(ofile);
758 errors += previous_errors;
761 static
762 void
763 strip_arch(
764 struct arch *archs,
765 uint32_t narchs,
766 struct arch_flag *arch_flags,
767 uint32_t narch_flags,
768 enum bool all_archs)
770 uint32_t i, j, k, offset, size, missing_syms;
771 cpu_type_t cputype;
772 cpu_subtype_t cpusubtype;
773 struct arch_flag host_arch_flag;
774 enum bool arch_process, any_processing, *arch_flag_processed, family;
775 const struct arch_flag *family_arch_flag;
778 * Using the specified arch_flags process specified objects for those
779 * architecures.
781 any_processing = FALSE;
782 arch_flag_processed = NULL;
783 if(narch_flags != 0)
784 arch_flag_processed = allocate(narch_flags * sizeof(enum bool));
785 memset(arch_flag_processed, '\0', narch_flags * sizeof(enum bool));
786 for(i = 0; i < narchs; i++){
788 * Determine the architecture (cputype and cpusubtype) of arch[i]
790 cputype = 0;
791 cpusubtype = 0;
792 if(archs[i].type == OFILE_ARCHIVE){
793 for(j = 0; j < archs[i].nmembers; j++){
794 if(archs[i].members[j].type == OFILE_Mach_O){
795 cputype = archs[i].members[j].object->mh_cputype;
796 cpusubtype = archs[i].members[j].object->mh_cpusubtype;
797 break;
801 else if(archs[i].type == OFILE_Mach_O){
802 cputype = archs[i].object->mh_cputype;
803 cpusubtype = archs[i].object->mh_cpusubtype;
805 else if(archs[i].fat_arch != NULL){
806 cputype = archs[i].fat_arch->cputype;
807 cpusubtype = archs[i].fat_arch->cpusubtype;
809 arch_process = FALSE;
810 if(all_archs == TRUE){
811 arch_process = TRUE;
813 else if(narch_flags != 0){
814 family = FALSE;
815 if(narch_flags == 1){
816 family_arch_flag =
817 get_arch_family_from_cputype(arch_flags[0].cputype);
818 if(family_arch_flag != NULL)
819 family = (enum bool)
820 ((family_arch_flag->cpusubtype & ~CPU_SUBTYPE_MASK) ==
821 (arch_flags[0].cpusubtype & ~CPU_SUBTYPE_MASK));
823 for(j = 0; j < narch_flags; j++){
824 if(arch_flags[j].cputype == cputype &&
825 ((arch_flags[j].cpusubtype & ~CPU_SUBTYPE_MASK) ==
826 (cpusubtype & ~CPU_SUBTYPE_MASK) ||
827 family == TRUE)){
828 arch_process = TRUE;
829 arch_flag_processed[j] = TRUE;
830 break;
834 else{
835 (void)get_arch_from_host(&host_arch_flag, NULL);
836 if(host_arch_flag.cputype == cputype &&
837 (host_arch_flag.cpusubtype & ~CPU_SUBTYPE_MASK) ==
838 (cpusubtype & ~CPU_SUBTYPE_MASK))
839 arch_process = TRUE;
841 if(narchs != 1 && arch_process == FALSE)
842 continue;
843 any_processing = TRUE;
846 * Now this arch[i] has been selected to be processed so process it
847 * according to its type.
849 if(archs[i].type == OFILE_ARCHIVE){
850 for(j = 0; j < archs[i].nmembers; j++){
851 if(archs[i].members[j].type == OFILE_Mach_O){
852 strip_object(archs + i, archs[i].members + j,
853 archs[i].members[j].object);
856 missing_syms = 0;
857 if(iflag == 0){
858 for(k = 0; k < nsave_symbols; k++){
859 if(save_symbols[k].seen == FALSE){
860 if(missing_syms == 0){
861 error_arch(archs + i, NULL, "symbols names "
862 "listed in: %s not in: ", sfile);
863 missing_syms = 1;
865 fprintf(stderr, "%s\n", save_symbols[k].name);
869 for(k = 0; k < nsave_symbols; k++){
870 save_symbols[k].seen = FALSE;
872 missing_syms = 0;
873 if(iflag == 0){
874 for(k = 0; k < nremove_symbols; k++){
875 if(remove_symbols[k].seen == FALSE){
876 if(missing_syms == 0){
877 error_arch(archs + i, NULL, "symbols names "
878 "listed in: %s not defined in: ",
879 Rfile);
880 missing_syms = 1;
882 fprintf(stderr, "%s\n", remove_symbols[k].name);
886 for(k = 0; k < nremove_symbols; k++){
887 remove_symbols[k].seen = FALSE;
890 * Reset the library offsets and size.
892 offset = 0;
893 for(j = 0; j < archs[i].nmembers; j++){
894 archs[i].members[j].offset = offset;
895 size = 0;
896 if(archs[i].members[j].member_long_name == TRUE){
897 size = round(archs[i].members[j].member_name_size, 8) +
898 (round(sizeof(struct ar_hdr), 8) -
899 sizeof(struct ar_hdr));
900 archs[i].toc_long_name = TRUE;
902 if(archs[i].members[j].object != NULL){
903 size +=
904 round(archs[i].members[j].object->object_size -
905 archs[i].members[j].object->input_sym_info_size +
906 archs[i].members[j].object->output_sym_info_size,
908 sprintf(archs[i].members[j].ar_hdr->ar_size, "%-*ld",
909 (int)sizeof(archs[i].members[j].ar_hdr->ar_size),
910 (long)(size));
912 * This has to be done by hand because sprintf puts a
913 * null at the end of the buffer.
915 memcpy(archs[i].members[j].ar_hdr->ar_fmag, ARFMAG,
916 (int)sizeof(archs[i].members[j].ar_hdr->ar_fmag));
918 else{
919 size += archs[i].members[j].unknown_size;
921 offset += sizeof(struct ar_hdr) + size;
923 archs[i].library_size = offset;
925 else if(archs[i].type == OFILE_Mach_O){
926 strip_object(archs + i, NULL, archs[i].object);
928 else {
929 warning_arch(archs + i, NULL, "can't process non-object and "
930 "non-archive file: ");
931 return;
934 if(all_archs == FALSE && narch_flags != 0){
935 for(i = 0; i < narch_flags; i++){
936 if(arch_flag_processed[i] == FALSE)
937 error("file: %s does not contain architecture: %s",
938 archs[0].file_name, arch_flags[i].name);
940 free(arch_flag_processed);
942 if(any_processing == FALSE)
943 fatal("no processing done on input file: %s (specify a -arch flag)",
944 archs[0].file_name);
947 static
948 void
949 strip_object(
950 struct arch *arch,
951 struct member *member,
952 struct object *object)
954 enum byte_sex host_byte_sex;
955 uint32_t offset;
956 struct dylib_table_of_contents *tocs;
957 uint32_t ntoc;
958 struct dylib_module *mods;
959 struct dylib_module_64 *mods64;
960 uint32_t nmodtab;
961 struct dylib_reference *refs;
962 uint32_t nextrefsyms;
963 uint32_t i, j;
964 struct load_command *lc;
965 struct segment_command *sg;
966 struct segment_command_64 *sg64;
967 struct section *s;
968 struct section_64 *s64;
969 struct relocation_info *relocs;
970 struct scattered_relocation_info *sreloc;
971 int32_t missing_reloc_symbols;
972 uint32_t stride, section_type, nitems;
973 char *contents;
974 uint32_t dyld_info_start;
975 uint32_t dyld_info_end;
976 #ifndef NMEDIT
977 uint32_t flags;
978 uint32_t k;
979 #endif
980 uint32_t ncmds;
982 host_byte_sex = get_host_byte_sex();
984 /* Don't do anything to stub dylibs which have no load commands. */
985 if(object->mh_filetype == MH_DYLIB_STUB){
986 if((object->mh != NULL && object->mh->ncmds == 0) ||
987 (object->mh64 != NULL && object->mh64->ncmds == 0)){
988 return;
991 if(object->mh_filetype == MH_DSYM)
992 fatal_arch(arch, member, "can't process dSYM companion file: ");
993 if(object->st == NULL || object->st->nsyms == 0){
994 warning_arch(arch, member, "input object file stripped: ");
995 return;
998 nsyms = object->st->nsyms;
999 if(object->mh != NULL){
1000 symbols = (struct nlist *)
1001 (object->object_addr + object->st->symoff);
1002 if(object->object_byte_sex != host_byte_sex)
1003 swap_nlist(symbols, nsyms, host_byte_sex);
1004 symbols64 = NULL;
1006 else{
1007 symbols = NULL;
1008 symbols64 = (struct nlist_64 *)
1009 (object->object_addr + object->st->symoff);
1010 if(object->object_byte_sex != host_byte_sex)
1011 swap_nlist_64(symbols64, nsyms, host_byte_sex);
1013 strings = object->object_addr + object->st->stroff;
1014 strsize = object->st->strsize;
1016 #ifndef NMEDIT
1017 if(object->mh != NULL)
1018 flags = object->mh->flags;
1019 else
1020 flags = object->mh64->flags;
1021 if(object->mh_filetype == MH_DYLIB &&
1022 (flags & MH_PREBOUND) != MH_PREBOUND){
1023 arch->dont_update_LC_ID_DYLIB_timestamp = TRUE;
1025 if(object->mh_filetype != MH_DYLIB && cflag)
1026 fatal_arch(arch, member, "-c can't be used on non-dynamic "
1027 "library: ");
1028 #endif /* !(NMEDIT) */
1029 if(object->mh_filetype == MH_DYLIB_STUB)
1030 fatal_arch(arch, member, "dynamic stub library can't be changed "
1031 "once created: ");
1033 if(object->mh_filetype == MH_DYLIB){
1034 tocs = (struct dylib_table_of_contents *)
1035 (object->object_addr + object->dyst->tocoff);
1036 ntoc = object->dyst->ntoc;
1037 nmodtab = object->dyst->nmodtab;
1038 if(object->mh != NULL){
1039 mods = (struct dylib_module *)
1040 (object->object_addr + object->dyst->modtaboff);
1041 if(object->object_byte_sex != host_byte_sex)
1042 swap_dylib_module(mods, nmodtab, host_byte_sex);
1043 mods64 = NULL;
1045 else{
1046 mods = NULL;
1047 mods64 = (struct dylib_module_64 *)
1048 (object->object_addr + object->dyst->modtaboff);
1049 if(object->object_byte_sex != host_byte_sex)
1050 swap_dylib_module_64(mods64, nmodtab, host_byte_sex);
1052 refs = (struct dylib_reference *)
1053 (object->object_addr + object->dyst->extrefsymoff);
1054 nextrefsyms = object->dyst->nextrefsyms;
1055 if(object->object_byte_sex != host_byte_sex){
1056 swap_dylib_table_of_contents(tocs, ntoc, host_byte_sex);
1057 swap_dylib_reference(refs, nextrefsyms, host_byte_sex);
1059 #ifndef NMEDIT
1061 * In the -c flag is specified then strip the section contents of
1062 * this dynamic library and change it into a stub library. When
1063 * creating a stub library the timestamp is not changed.
1065 if(cflag){
1066 arch->dont_update_LC_ID_DYLIB_timestamp = TRUE;
1068 lc = object->load_commands;
1069 if(object->mh != NULL){
1070 ncmds = object->mh->ncmds;
1071 object->mh_filetype = MH_DYLIB_STUB;
1072 object->mh->filetype = MH_DYLIB_STUB;
1074 else{
1075 ncmds = object->mh64->ncmds;
1076 object->mh_filetype = MH_DYLIB_STUB;
1077 object->mh64->filetype = MH_DYLIB_STUB;
1079 for(i = 0; i < ncmds; i++){
1080 if(lc->cmd == LC_SEGMENT){
1081 sg = (struct segment_command *)lc;
1082 if(strcmp(sg->segname, SEG_LINKEDIT) != 0){
1084 * Zero out the section offset, reloff, and size
1085 * fields as the section contents are being removed.
1087 s = (struct section *)
1088 ((char *)sg + sizeof(struct segment_command));
1089 for(j = 0; j < sg->nsects; j++){
1091 * For section types with indirect tables we
1092 * do not zero out the section size in a stub
1093 * library. As the section size is needed to
1094 * know now many indirect table entries the
1095 * section has. This is a bit odd but programs
1096 * dealing with MH_DYLIB_STUB filetypes special
1097 * case this.
1099 section_type = s[j].flags & SECTION_TYPE;
1100 if(section_type != S_SYMBOL_STUBS &&
1101 section_type != S_LAZY_SYMBOL_POINTERS &&
1102 section_type != S_LAZY_DYLIB_SYMBOL_POINTERS &&
1103 section_type != S_NON_LAZY_SYMBOL_POINTERS){
1104 s[j].size = 0;
1106 s[j].addr = 0;
1107 s[j].offset = 0;
1108 s[j].reloff = 0;
1110 /* zero out file offset and size in the segment */
1111 sg->fileoff = 0;
1112 sg->filesize = 0;
1115 else if(lc->cmd == LC_SEGMENT_64){
1116 sg64 = (struct segment_command_64 *)lc;
1117 if(strcmp(sg64->segname, SEG_LINKEDIT) != 0){
1119 * Zero out the section offset, reloff, and size
1120 * fields as the section contents are being removed.
1122 s64 = (struct section_64 *)
1123 ((char *)sg64 +
1124 sizeof(struct segment_command_64));
1125 for(j = 0; j < sg64->nsects; j++){
1127 * For section types with indirect tables we
1128 * do not zero out the section size in a stub
1129 * library. As the section size is needed to
1130 * know now many indirect table entries the
1131 * section has. This is a bit odd but programs
1132 * dealing with MH_DYLIB_STUB filetypes special
1133 * case this.
1135 section_type = s64[j].flags & SECTION_TYPE;
1136 if(section_type != S_SYMBOL_STUBS &&
1137 section_type != S_LAZY_SYMBOL_POINTERS &&
1138 section_type != S_LAZY_DYLIB_SYMBOL_POINTERS &&
1139 section_type != S_NON_LAZY_SYMBOL_POINTERS){
1140 s64[j].size = 0;
1142 s64[j].addr = 0;
1143 s64[j].offset = 0;
1144 s64[j].reloff = 0;
1146 /* zero out file offset and size in the segment */
1147 sg64->fileoff = 0;
1148 sg64->filesize = 0;
1151 lc = (struct load_command *)((char *)lc + lc->cmdsize);
1154 * To get the right amount of the file copied out by writeout()
1155 * for the case when we are stripping out the section contents
1156 * we reduce the object size by the size of the section contents
1157 * including the padding after the load commands. Then this
1158 * size minus the size of the input symbolic information is
1159 * copied out.
1161 if(object->mh != NULL){
1162 object->object_size -= (object->seg_linkedit->fileoff -
1163 (sizeof(struct mach_header) +
1164 object->mh->sizeofcmds));
1166 * Set the file offset to the link edit information to be
1167 * right after the load commands.
1169 object->seg_linkedit->fileoff =
1170 sizeof(struct mach_header) +
1171 object->mh->sizeofcmds;
1173 else{
1174 object->object_size -= (object->seg_linkedit64->fileoff -
1175 (sizeof(struct mach_header_64) +
1176 object->mh64->sizeofcmds));
1178 * Set the file offset to the link edit information to be
1179 * right after the load commands.
1181 object->seg_linkedit64->fileoff =
1182 sizeof(struct mach_header_64) +
1183 object->mh64->sizeofcmds;
1186 #endif /* !(NMEDIT) */
1188 else{
1189 tocs = NULL;
1190 ntoc = 0;
1191 mods = NULL;
1192 mods64 = NULL;
1193 nmodtab = 0;
1194 refs = NULL;
1195 nextrefsyms = 0;
1199 * coalesced symbols can be stripped only if they are not used via an
1200 * symbol pointer. So to know that strip_symtab() needs to be passed
1201 * the indirect symbol table.
1203 if(object->dyst != NULL && object->dyst->nindirectsyms != 0){
1204 nindirectsyms = object->dyst->nindirectsyms;
1205 indirectsyms = (uint32_t *)
1206 (object->object_addr + object->dyst->indirectsymoff);
1207 if(object->object_byte_sex != host_byte_sex)
1208 swap_indirect_symbols(indirectsyms, nindirectsyms,
1209 host_byte_sex);
1211 else{
1212 indirectsyms = NULL;
1213 nindirectsyms = 0;
1216 if(object->mh != NULL)
1217 object->input_sym_info_size =
1218 nsyms * sizeof(struct nlist) +
1219 strsize;
1220 else
1221 object->input_sym_info_size =
1222 nsyms * sizeof(struct nlist_64) +
1223 strsize;
1224 #ifndef NMEDIT
1225 if(object->mh != NULL)
1226 flags = object->mh->flags;
1227 else
1228 flags = object->mh64->flags;
1229 if(strip_all &&
1230 (flags & MH_DYLDLINK) == MH_DYLDLINK &&
1231 object->mh_filetype == MH_EXECUTE)
1232 default_dyld_executable = TRUE;
1233 else
1234 default_dyld_executable = FALSE;
1235 #endif /* !defined(NMEDIT) */
1237 #ifndef NMEDIT
1238 if(sfile != NULL || Rfile != NULL || dfile != NULL || Aflag || aflag ||
1239 uflag || Sflag || xflag || Xflag || tflag || nflag || rflag ||
1240 default_dyld_executable || object->mh_filetype == MH_DYLIB ||
1241 object->mh_filetype == MH_DYLINKER)
1242 #endif /* !defined(NMEDIT) */
1244 #ifdef NMEDIT
1245 if(edit_symtab(arch, member, object, symbols, symbols64, nsyms,
1246 strings, strsize, tocs, ntoc, mods, mods64, nmodtab, refs,
1247 nextrefsyms) == FALSE)
1248 return;
1249 #else /* !defined(NMEDIT) */
1250 if(strip_symtab(arch, member, object, tocs, ntoc, mods, mods64,
1251 nmodtab, refs, nextrefsyms) == FALSE)
1252 return;
1253 if(no_uuid == TRUE)
1254 strip_LC_UUID_commands(arch, member, object);
1255 #endif /* !defined(NMEDIT) */
1256 if(object->mh != NULL)
1257 object->output_sym_info_size =
1258 new_nsyms * sizeof(struct nlist) +
1259 new_strsize;
1260 else
1261 object->output_sym_info_size =
1262 new_nsyms * sizeof(struct nlist_64) +
1263 new_strsize;
1265 object->st->nsyms = new_nsyms;
1266 object->st->strsize = new_strsize;
1268 if(object->mh != NULL)
1269 object->output_symbols = new_symbols;
1270 else
1271 object->output_symbols64 = new_symbols64;
1272 object->output_nsymbols = new_nsyms;
1273 object->output_strings = new_strings;
1274 object->output_strings_size = new_strsize;
1276 if(object->dyld_info != NULL){
1277 /* there are five parts to the dyld info, but
1278 strip does not alter them, so copy as a block */
1279 dyld_info_start = 0;
1280 if (object->dyld_info->rebase_off != 0)
1281 dyld_info_start = object->dyld_info->rebase_off;
1282 else if (object->dyld_info->bind_off != 0)
1283 dyld_info_start = object->dyld_info->bind_off;
1284 else if (object->dyld_info->weak_bind_off != 0)
1285 dyld_info_start = object->dyld_info->weak_bind_off;
1286 else if (object->dyld_info->lazy_bind_off != 0)
1287 dyld_info_start = object->dyld_info->lazy_bind_off;
1288 else if (object->dyld_info->export_off != 0)
1289 dyld_info_start = object->dyld_info->export_off;
1290 dyld_info_end = 0;
1291 if (object->dyld_info->export_size != 0)
1292 dyld_info_end = object->dyld_info->export_off
1293 + object->dyld_info->export_size;
1294 else if (object->dyld_info->lazy_bind_size != 0)
1295 dyld_info_end = object->dyld_info->lazy_bind_off
1296 + object->dyld_info->lazy_bind_size;
1297 else if (object->dyld_info->weak_bind_size != 0)
1298 dyld_info_end = object->dyld_info->weak_bind_off
1299 + object->dyld_info->weak_bind_size;
1300 else if (object->dyld_info->bind_size != 0)
1301 dyld_info_end = object->dyld_info->bind_off
1302 + object->dyld_info->bind_size;
1303 else if (object->dyld_info->rebase_size != 0)
1304 dyld_info_end = object->dyld_info->rebase_off
1305 + object->dyld_info->rebase_size;
1306 object->output_dyld_info = object->object_addr + dyld_info_start;
1307 object->output_dyld_info_size = dyld_info_end - dyld_info_start;
1308 object->output_sym_info_size += object->output_dyld_info_size;
1309 /* warn about strip -s or -R on a final linked image with dyld_info */
1310 if(nsave_symbols != 0){
1311 warning_arch(arch, NULL, "removing global symbols from a final linked"
1312 " no longer supported. Use -exported_symbols_list at link time when building: ");
1315 if(object->split_info_cmd != NULL){
1316 object->output_split_info_data = object->object_addr +
1317 object->split_info_cmd->dataoff;
1318 object->output_split_info_data_size =
1319 object->split_info_cmd->datasize;
1321 if(object->code_sig_cmd != NULL){
1322 #ifndef NMEDIT
1323 if(!cflag && !no_code_signature)
1324 #endif /* !(NMEDIT) */
1326 object->output_code_sig_data = object->object_addr +
1327 object->code_sig_cmd->dataoff;
1328 object->output_code_sig_data_size =
1329 object->code_sig_cmd->datasize;
1333 if(object->dyst != NULL){
1334 object->dyst->ilocalsym = 0;
1335 object->dyst->nlocalsym = new_nlocalsym;
1336 object->dyst->iextdefsym = new_nlocalsym;
1337 object->dyst->nextdefsym = new_nextdefsym;
1338 object->dyst->iundefsym = new_nlocalsym + new_nextdefsym;
1339 object->dyst->nundefsym = new_nundefsym;
1340 if(object->dyst->nindirectsyms != 0){
1341 object->output_indirect_symtab = indirectsyms;
1342 if(object->object_byte_sex != host_byte_sex)
1343 swap_indirect_symbols(indirectsyms, nindirectsyms,
1344 object->object_byte_sex);
1348 * If the -c option is specified the object's filetype will
1349 * have been changed from MH_DYLIB to MH_DYLIB_STUB above.
1351 if(object->mh_filetype == MH_DYLIB ||
1352 object->mh_filetype == MH_DYLIB_STUB){
1353 object->output_tocs = new_tocs;
1354 object->output_ntoc = new_ntoc;
1355 #ifdef NMEDIT
1356 if(object->mh != NULL)
1357 object->output_mods = new_mods;
1358 else
1359 object->output_mods64 = new_mods64;
1360 object->output_nmodtab = new_nmodtab;
1361 #else
1362 object->output_mods = mods;
1363 object->output_nmodtab = nmodtab;
1364 #endif
1365 object->output_refs = new_refs;
1366 object->output_nextrefsyms = new_nextrefsyms;
1367 if(object->object_byte_sex != host_byte_sex){
1368 swap_dylib_table_of_contents(new_tocs, new_ntoc,
1369 object->object_byte_sex);
1370 #ifdef NMEDIT
1371 if(object->mh != NULL)
1372 swap_dylib_module(new_mods, new_nmodtab,
1373 object->object_byte_sex);
1374 else
1375 swap_dylib_module_64(new_mods64, new_nmodtab,
1376 object->object_byte_sex);
1377 #else
1378 if(object->mh != NULL)
1379 swap_dylib_module(mods, nmodtab,
1380 object->object_byte_sex);
1381 else
1382 swap_dylib_module_64(mods64, nmodtab,
1383 object->object_byte_sex);
1384 #endif
1385 swap_dylib_reference(new_refs, new_nextrefsyms,
1386 object->object_byte_sex);
1389 if(object->dyld_info != NULL){
1390 object->input_sym_info_size += object->dyld_info->rebase_size
1391 + object->dyld_info->bind_size
1392 + object->dyld_info->weak_bind_size
1393 + object->dyld_info->lazy_bind_size
1394 + object->dyld_info->export_size;
1396 object->input_sym_info_size +=
1397 object->dyst->nlocrel * sizeof(struct relocation_info) +
1398 object->dyst->nextrel * sizeof(struct relocation_info) +
1399 object->dyst->ntoc * sizeof(struct dylib_table_of_contents)+
1400 object->dyst->nextrefsyms * sizeof(struct dylib_reference);
1401 if(object->mh != NULL){
1402 object->input_sym_info_size +=
1403 object->dyst->nmodtab * sizeof(struct dylib_module) +
1404 object->dyst->nindirectsyms * sizeof(uint32_t);
1406 else{
1407 object->input_sym_info_size +=
1408 object->dyst->nmodtab * sizeof(struct dylib_module_64) +
1409 object->dyst->nindirectsyms * sizeof(uint32_t) +
1410 object->input_indirectsym_pad;
1412 #ifndef NMEDIT
1414 * When stripping out the section contents to create a
1415 * dynamic library stub the relocation info also gets
1416 * stripped.
1418 if(!cflag)
1419 #endif /* !(NMEDIT) */
1421 object->output_sym_info_size +=
1422 object->dyst->nlocrel * sizeof(struct relocation_info) +
1423 object->dyst->nextrel * sizeof(struct relocation_info);
1425 object->output_sym_info_size +=
1426 new_ntoc * sizeof(struct dylib_table_of_contents)+
1427 new_nextrefsyms * sizeof(struct dylib_reference) +
1428 object->dyst->nindirectsyms * sizeof(uint32_t) +
1429 object->input_indirectsym_pad;
1430 if(object->mh != NULL){
1431 object->output_sym_info_size +=
1432 object->dyst->nmodtab * sizeof(struct dylib_module);
1434 else{
1435 object->output_sym_info_size +=
1436 object->dyst->nmodtab * sizeof(struct dylib_module_64);
1438 if(object->hints_cmd != NULL){
1439 object->input_sym_info_size +=
1440 object->hints_cmd->nhints *
1441 sizeof(struct twolevel_hint);
1442 object->output_sym_info_size +=
1443 object->hints_cmd->nhints *
1444 sizeof(struct twolevel_hint);
1446 if(object->split_info_cmd != NULL){
1447 object->input_sym_info_size +=
1448 object->split_info_cmd->datasize;
1449 object->output_sym_info_size +=
1450 object->split_info_cmd->datasize;
1452 if(object->code_sig_cmd != NULL){
1453 object->input_sym_info_size =
1454 round(object->input_sym_info_size, 16);
1455 object->input_sym_info_size +=
1456 object->code_sig_cmd->datasize;
1457 #ifndef NMEDIT
1458 if(cflag || no_code_signature){
1459 strip_LC_CODE_SIGNATURE_commands(arch, member, object);
1461 else
1462 #endif /* !(NMEDIT) */
1464 object->output_sym_info_size =
1465 round(object->output_sym_info_size, 16);
1466 object->output_sym_info_size +=
1467 object->code_sig_cmd->datasize;
1471 object->dyst->ntoc = new_ntoc;
1472 object->dyst->nextrefsyms = new_nextrefsyms;
1474 offset = get_starting_syminfo_offset(object);
1476 if(object->dyld_info != 0){
1477 if (object->dyld_info->rebase_off != 0){
1478 object->dyld_info->rebase_off = offset;
1479 offset += object->dyld_info->rebase_size;
1481 if (object->dyld_info->bind_off != 0){
1482 object->dyld_info->bind_off = offset;
1483 offset += object->dyld_info->bind_size;
1485 if (object->dyld_info->weak_bind_off != 0){
1486 object->dyld_info->weak_bind_off = offset;
1487 offset += object->dyld_info->weak_bind_size;
1489 if (object->dyld_info->lazy_bind_off != 0){
1490 object->dyld_info->lazy_bind_off = offset;
1491 offset += object->dyld_info->lazy_bind_size;
1493 if (object->dyld_info->export_off != 0){
1494 object->dyld_info->export_off = offset;
1495 offset += object->dyld_info->export_size;
1499 if(object->dyst->nlocrel != 0){
1500 object->output_loc_relocs = (struct relocation_info *)
1501 (object->object_addr + object->dyst->locreloff);
1502 #ifndef NMEDIT
1504 * When stripping out the section contents to create a
1505 * dynamic library stub the relocation info also gets
1506 * stripped.
1508 if(cflag){
1509 object->dyst->nlocrel = 0;
1510 object->dyst->locreloff = 0;
1512 else
1513 #endif /* defined(NMEDIT) */
1515 object->dyst->locreloff = offset;
1516 offset += object->dyst->nlocrel *
1517 sizeof(struct relocation_info);
1520 else
1521 object->dyst->locreloff = 0;
1523 if(object->split_info_cmd != NULL){
1524 object->split_info_cmd->dataoff = offset;
1525 offset += object->split_info_cmd->datasize;
1528 if(object->st->nsyms != 0){
1529 object->st->symoff = offset;
1530 if(object->mh != NULL)
1531 offset += object->st->nsyms * sizeof(struct nlist);
1532 else
1533 offset += object->st->nsyms * sizeof(struct nlist_64);
1535 else
1536 object->st->symoff = 0;
1538 if(object->hints_cmd != NULL){
1539 if(object->hints_cmd->nhints != 0){
1540 object->output_hints = (struct twolevel_hint *)
1541 (object->object_addr + object->hints_cmd->offset);
1542 object->hints_cmd->offset = offset;
1543 offset += object->hints_cmd->nhints *
1544 sizeof(struct twolevel_hint);
1546 else
1547 object->hints_cmd->offset = 0;
1550 if(object->dyst->nextrel != 0){
1551 object->output_ext_relocs = (struct relocation_info *)
1552 (object->object_addr + object->dyst->extreloff);
1553 #ifndef NMEDIT
1555 * When stripping out the section contents to create a
1556 * dynamic library stub the relocation info also gets
1557 * stripped.
1559 if(cflag){
1560 object->dyst->nextrel = 0;
1561 object->dyst->extreloff = 0;
1563 else
1564 #endif /* defined(NMEDIT) */
1566 object->dyst->extreloff = offset;
1567 offset += object->dyst->nextrel *
1568 sizeof(struct relocation_info);
1571 else
1572 object->dyst->extreloff = 0;
1574 if(object->dyst->nindirectsyms != 0){
1575 object->dyst->indirectsymoff = offset;
1576 offset += object->dyst->nindirectsyms * sizeof(uint32_t) +
1577 object->input_indirectsym_pad;
1579 else
1580 object->dyst->indirectsymoff = 0;;
1582 if(object->dyst->ntoc != 0){
1583 object->dyst->tocoff = offset;
1584 offset += object->dyst->ntoc *
1585 sizeof(struct dylib_table_of_contents);
1587 else
1588 object->dyst->tocoff = 0;
1590 if(object->dyst->nmodtab != 0){
1591 #ifndef NMEDIT
1593 * When stripping out the section contents to create a
1594 * dynamic library stub zero out the fields in the module
1595 * table for the sections and relocation information and
1596 * clear Objective-C address and size from modules.
1598 if(cflag){
1599 if(object->mh != NULL){
1600 for(k = 0; k < object->dyst->nmodtab; k++){
1601 mods[k].iinit_iterm = 0;
1602 mods[k].ninit_nterm = 0;
1603 mods[k].iextrel = 0;
1604 mods[k].nextrel = 0;
1605 mods[k].objc_module_info_addr = 0;
1606 mods[k].objc_module_info_size = 0;
1609 else{
1610 for(k = 0; k < object->dyst->nmodtab; k++){
1611 mods64[k].iinit_iterm = 0;
1612 mods64[k].ninit_nterm = 0;
1613 mods64[k].iextrel = 0;
1614 mods64[k].nextrel = 0;
1615 mods64[k].objc_module_info_addr = 0;
1616 mods64[k].objc_module_info_size = 0;
1620 #endif /* !(NMEDIT) */
1621 object->dyst->modtaboff = offset;
1622 if(object->mh != NULL)
1623 offset += object->dyst->nmodtab *
1624 sizeof(struct dylib_module);
1625 else
1626 offset += object->dyst->nmodtab *
1627 sizeof(struct dylib_module_64);
1629 else
1630 object->dyst->modtaboff = 0;
1632 if(object->dyst->nextrefsyms != 0){
1633 object->dyst->extrefsymoff = offset;
1634 offset += object->dyst->nextrefsyms *
1635 sizeof(struct dylib_reference);
1637 else
1638 object->dyst->extrefsymoff = 0;
1640 if(object->st->strsize != 0){
1641 object->st->stroff = offset;
1642 offset += object->st->strsize;
1644 else
1645 object->st->stroff = 0;
1647 if(object->code_sig_cmd != NULL){
1648 offset = round(offset, 16);
1649 object->code_sig_cmd->dataoff = offset;
1650 offset += object->code_sig_cmd->datasize;
1653 else{
1654 if(new_strsize != 0){
1655 if(object->mh != NULL)
1656 object->st->stroff = object->st->symoff +
1657 new_nsyms * sizeof(struct nlist);
1658 else
1659 object->st->stroff = object->st->symoff +
1660 new_nsyms * sizeof(struct nlist_64);
1662 else
1663 object->st->stroff = 0;
1664 if(new_nsyms == 0)
1665 object->st->symoff = 0;
1668 #ifndef NMEDIT
1669 else{
1671 * Here we are doing a full symbol strip. In some cases it may
1672 * leave the local relocation entries as well as LOCAL indirect
1673 * symbol table entries.
1675 if(saves != NULL)
1676 free(saves);
1677 saves = (int32_t *)allocate(object->st->nsyms * sizeof(int32_t));
1678 bzero(saves, object->st->nsyms * sizeof(int32_t));
1681 * Account for the symbolic info in the input file.
1683 if(object->dyst != NULL){
1684 object->input_sym_info_size +=
1685 object->dyst->nlocrel * sizeof(struct relocation_info) +
1686 object->dyst->nextrel * sizeof(struct relocation_info) +
1687 object->dyst->ntoc * sizeof(struct dylib_table_of_contents)+
1688 object->dyst->nextrefsyms * sizeof(struct dylib_reference);
1689 if(object->mh != NULL){
1690 object->input_sym_info_size +=
1691 object->dyst->nmodtab * sizeof(struct dylib_module) +
1692 object->dyst->nindirectsyms * sizeof(uint32_t);
1694 else{
1695 object->input_sym_info_size +=
1696 object->dyst->nmodtab * sizeof(struct dylib_module_64) +
1697 object->dyst->nindirectsyms * sizeof(uint32_t) +
1698 object->input_indirectsym_pad;
1703 * Determine the offset where the remaining symbolic info will start
1704 * in the output file (if any).
1706 offset = get_starting_syminfo_offset(object);
1709 * For a full symbol strip all these values in the output file are
1710 * set to zero.
1712 object->st->symoff = 0;
1713 object->st->nsyms = 0;
1714 object->st->stroff = 0;
1715 object->st->strsize = 0;
1716 if(object->dyst != NULL){
1717 object->dyst->ilocalsym = 0;
1718 object->dyst->nlocalsym = 0;
1719 object->dyst->iextdefsym = 0;
1720 object->dyst->nextdefsym = 0;
1721 object->dyst->iundefsym = 0;
1722 object->dyst->nundefsym = 0;
1726 * This will accumulate any remaining symbolic info size in the
1727 * output file.
1729 object->output_sym_info_size = 0;
1732 * We set these so that checking can be done below to report the
1733 * symbols that can't be stripped because of relocation entries
1734 * or indirect symbol table entries. Normally if these table have a
1735 * non-zero number of entries it will be an error as we are trying
1736 * to strip everything. But it maybe that there are only LOCAL
1737 * indirect entries which is odd but will be OK.
1739 if(object->dyst != NULL){
1740 if(object->dyst->nextrel != 0){
1741 object->output_ext_relocs = (struct relocation_info *)
1742 (object->object_addr + object->dyst->extreloff);
1745 * Since this file has a dynamic symbol table and if this file
1746 * has local relocation entries on input make sure they are
1747 * there on output. This is a rare case that it will not have
1748 * external relocs or indirect symbols but can happen as is the
1749 * case with the dynamic linker itself.
1751 if(object->dyst->nlocrel != 0){
1752 object->output_loc_relocs = (struct relocation_info *)
1753 (object->object_addr + object->dyst->locreloff);
1754 object->output_sym_info_size +=
1755 object->dyst->nlocrel * sizeof(struct relocation_info);
1757 object->dyst->locreloff = offset;
1758 offset += object->dyst->nlocrel *
1759 sizeof(struct relocation_info);
1762 if(object->dyst->nindirectsyms != 0){
1763 object->output_indirect_symtab = (uint32_t *)
1764 (object->object_addr +
1765 object->dyst->indirectsymoff);
1766 if(object->object_byte_sex != host_byte_sex)
1767 swap_indirect_symbols(
1768 object->output_indirect_symtab,
1769 object->dyst->nindirectsyms,
1770 object->object_byte_sex);
1772 object->output_sym_info_size +=
1773 object->dyst->nindirectsyms * sizeof(uint32_t) +
1774 object->input_indirectsym_pad;
1776 object->dyst->indirectsymoff = offset;
1777 offset += object->dyst->nindirectsyms * sizeof(uint32_t) +
1778 object->input_indirectsym_pad;
1782 #endif /* !defined(NMEDIT) */
1785 * Always clear the prebind checksum if any when creating a new file.
1787 if(object->cs != NULL)
1788 object->cs->cksum = 0;
1790 if(object->seg_linkedit != NULL){
1791 object->seg_linkedit->filesize += object->output_sym_info_size -
1792 object->input_sym_info_size;
1793 object->seg_linkedit->vmsize = object->seg_linkedit->filesize;
1795 else if(object->seg_linkedit64 != NULL){
1796 /* Do this in two steps to avoid 32/64-bit casting problems. */
1797 object->seg_linkedit64->filesize -= object->input_sym_info_size;
1798 object->seg_linkedit64->filesize += object->output_sym_info_size;
1799 object->seg_linkedit64->vmsize = object->seg_linkedit64->filesize;
1803 * Check and update the external relocation entries to make sure
1804 * referenced symbols are not stripped and refer to the new symbol
1805 * table indexes.
1807 * The external relocation entries can be located in one of two places,
1808 * first off of the sections or second off of the dynamic symtab.
1810 missing_reloc_symbols = 0;
1811 lc = object->load_commands;
1812 if(object->mh != NULL)
1813 ncmds = object->mh->ncmds;
1814 else
1815 ncmds = object->mh64->ncmds;
1816 for(i = 0; i < ncmds; i++){
1817 if(lc->cmd == LC_SEGMENT &&
1818 object->seg_linkedit != (struct segment_command *)lc){
1819 sg = (struct segment_command *)lc;
1820 s = (struct section *)((char *)sg +
1821 sizeof(struct segment_command));
1822 for(j = 0; j < sg->nsects; j++){
1823 if(s->nreloc != 0){
1824 if(s->reloff + s->nreloc *
1825 sizeof(struct relocation_info) >
1826 object->object_size){
1827 fatal_arch(arch, member, "truncated or malformed "
1828 "object (relocation entries for section (%.16s,"
1829 "%.16s) extends past the end of the file)",
1830 s->segname, s->sectname);
1832 relocs = (struct relocation_info *)
1833 (object->object_addr + s->reloff);
1834 if(object->object_byte_sex != host_byte_sex)
1835 swap_relocation_info(relocs, s->nreloc,
1836 host_byte_sex);
1837 if(s->offset + s->size > object->object_size){
1838 fatal_arch(arch, member, "truncated or malformed "
1839 "object (contents of section (%.16s,"
1840 "%.16s) extends past the end of the file)",
1841 s->segname, s->sectname);
1843 contents = object->object_addr + s->offset;
1844 check_object_relocs(arch, member, object, s->segname,
1845 s->sectname, s->size, contents, relocs, s->nreloc,
1846 symbols, symbols64, nsyms, strings,
1847 &missing_reloc_symbols, host_byte_sex);
1848 if(object->object_byte_sex != host_byte_sex)
1849 swap_relocation_info(relocs, s->nreloc,
1850 object->object_byte_sex);
1852 s++;
1855 else if(lc->cmd == LC_SEGMENT_64 &&
1856 object->seg_linkedit64 != (struct segment_command_64 *)lc){
1857 sg64 = (struct segment_command_64 *)lc;
1858 s64 = (struct section_64 *)((char *)sg64 +
1859 sizeof(struct segment_command_64));
1860 for(j = 0; j < sg64->nsects; j++){
1861 if(s64->nreloc != 0){
1862 if(s64->reloff + s64->nreloc *
1863 sizeof(struct relocation_info) >
1864 object->object_size){
1865 fatal_arch(arch, member, "truncated or malformed "
1866 "object (relocation entries for section (%.16s,"
1867 "%.16s) extends past the end of the file)",
1868 s64->segname, s64->sectname);
1870 relocs = (struct relocation_info *)
1871 (object->object_addr + s64->reloff);
1872 if(object->object_byte_sex != host_byte_sex)
1873 swap_relocation_info(relocs, s64->nreloc,
1874 host_byte_sex);
1875 if(s64->offset + s64->size > object->object_size){
1876 fatal_arch(arch, member, "truncated or malformed "
1877 "object (contents of section (%.16s,"
1878 "%.16s) extends past the end of the file)",
1879 s64->segname, s64->sectname);
1881 contents = object->object_addr + s64->offset;
1882 check_object_relocs(arch, member, object, s64->segname,
1883 s64->sectname, s64->size, contents, relocs,
1884 s64->nreloc, symbols, symbols64, nsyms, strings,
1885 &missing_reloc_symbols, host_byte_sex);
1886 if(object->object_byte_sex != host_byte_sex)
1887 swap_relocation_info(relocs, s64->nreloc,
1888 object->object_byte_sex);
1890 s64++;
1893 lc = (struct load_command *)((char *)lc + lc->cmdsize);
1895 if(object->dyst != NULL && object->dyst->nextrel != 0){
1896 relocs = object->output_ext_relocs;
1897 if(object->object_byte_sex != host_byte_sex)
1898 swap_relocation_info(relocs, object->dyst->nextrel,
1899 host_byte_sex);
1901 for(i = 0; i < object->dyst->nextrel; i++){
1902 if((relocs[i].r_address & R_SCATTERED) == 0 &&
1903 relocs[i].r_extern == 1){
1904 if(relocs[i].r_symbolnum > nsyms){
1905 fatal_arch(arch, member, "bad r_symbolnum for external "
1906 "relocation entry %d in: ", i);
1908 if(saves[relocs[i].r_symbolnum] == 0){
1909 if(missing_reloc_symbols == 0){
1910 error_arch(arch, member, "symbols referenced by "
1911 "relocation entries that can't be stripped in: ");
1912 missing_reloc_symbols = 1;
1914 if(object->mh != NULL){
1915 fprintf(stderr, "%s\n", strings + symbols
1916 [relocs[i].r_symbolnum].n_un.n_strx);
1918 else {
1919 fprintf(stderr, "%s\n", strings + symbols64
1920 [relocs[i].r_symbolnum].n_un.n_strx);
1922 saves[relocs[i].r_symbolnum] = -1;
1924 if(saves[relocs[i].r_symbolnum] != -1){
1925 relocs[i].r_symbolnum =
1926 saves[relocs[i].r_symbolnum] - 1;
1929 else{
1930 fatal_arch(arch, member, "bad external relocation entry "
1931 "%d (not external) in: ", i);
1933 if((relocs[i].r_address & R_SCATTERED) == 0){
1934 if(reloc_has_pair(object->mh_cputype, relocs[i].r_type))
1935 i++;
1937 else{
1938 sreloc = (struct scattered_relocation_info *)relocs + i;
1939 if(reloc_has_pair(object->mh_cputype, sreloc->r_type))
1940 i++;
1943 if(object->object_byte_sex != host_byte_sex)
1944 swap_relocation_info(relocs, object->dyst->nextrel,
1945 object->object_byte_sex);
1949 * Check and update the indirect symbol table entries to make sure
1950 * referenced symbols are not stripped and refer to the new symbol
1951 * table indexes.
1953 if(object->dyst != NULL && object->dyst->nindirectsyms != 0){
1954 if(object->object_byte_sex != host_byte_sex)
1955 swap_indirect_symbols(object->output_indirect_symtab,
1956 object->dyst->nindirectsyms, host_byte_sex);
1958 lc = object->load_commands;
1959 if(object->mh != NULL)
1960 ncmds = object->mh->ncmds;
1961 else
1962 ncmds = object->mh64->ncmds;
1963 for(i = 0; i < ncmds; i++){
1964 if(lc->cmd == LC_SEGMENT &&
1965 object->seg_linkedit != (struct segment_command *)lc){
1966 sg = (struct segment_command *)lc;
1967 s = (struct section *)((char *)sg +
1968 sizeof(struct segment_command));
1969 for(j = 0; j < sg->nsects; j++){
1970 section_type = s->flags & SECTION_TYPE;
1971 if(section_type == S_LAZY_SYMBOL_POINTERS ||
1972 section_type == S_LAZY_DYLIB_SYMBOL_POINTERS ||
1973 section_type == S_NON_LAZY_SYMBOL_POINTERS)
1974 stride = 4;
1975 else if(section_type == S_SYMBOL_STUBS)
1976 stride = s->reserved2;
1977 else{
1978 s++;
1979 continue;
1981 nitems = s->size / stride;
1982 contents = object->object_addr + s->offset;
1983 check_indirect_symtab(arch, member, object, nitems,
1984 s->reserved1, section_type, contents, symbols,
1985 symbols64, nsyms, strings, &missing_reloc_symbols,
1986 host_byte_sex);
1987 s++;
1990 else if(lc->cmd == LC_SEGMENT_64 &&
1991 object->seg_linkedit64 != (struct segment_command_64 *)lc){
1992 sg64 = (struct segment_command_64 *)lc;
1993 s64 = (struct section_64 *)((char *)sg64 +
1994 sizeof(struct segment_command_64));
1995 for(j = 0; j < sg64->nsects; j++){
1996 section_type = s64->flags & SECTION_TYPE;
1997 if(section_type == S_LAZY_SYMBOL_POINTERS ||
1998 section_type == S_LAZY_DYLIB_SYMBOL_POINTERS ||
1999 section_type == S_NON_LAZY_SYMBOL_POINTERS)
2000 stride = 8;
2001 else if(section_type == S_SYMBOL_STUBS)
2002 stride = s64->reserved2;
2003 else{
2004 s64++;
2005 continue;
2007 nitems = s64->size / stride;
2008 contents = object->object_addr + s64->offset;
2009 check_indirect_symtab(arch, member, object, nitems,
2010 s64->reserved1, section_type, contents, symbols,
2011 symbols64, nsyms, strings, &missing_reloc_symbols,
2012 host_byte_sex);
2013 s64++;
2016 lc = (struct load_command *)((char *)lc + lc->cmdsize);
2019 if(object->object_byte_sex != host_byte_sex)
2020 swap_indirect_symbols(object->output_indirect_symtab,
2021 object->dyst->nindirectsyms, object->object_byte_sex);
2025 * Issue a warning if object file has a code signature that the
2026 * operation will invalidate it.
2028 if(object->code_sig_cmd != NULL)
2029 warning_arch(arch, member, "changes being made to the file will "
2030 "invalidate the code signature in: ");
2034 * get_starting_syminfo_offset() returns the starting offset of the symbolic
2035 * info in the object file.
2037 static
2038 uint32_t
2039 get_starting_syminfo_offset(
2040 struct object *object)
2042 uint32_t offset;
2044 if(object->seg_linkedit != NULL ||
2045 object->seg_linkedit64 != NULL){
2046 if(object->mh != NULL)
2047 offset = object->seg_linkedit->fileoff;
2048 else
2049 offset = object->seg_linkedit64->fileoff;
2051 else{
2052 offset = UINT_MAX;
2053 if(object->dyst != NULL &&
2054 object->dyst->nlocrel != 0 &&
2055 object->dyst->locreloff < offset)
2056 offset = object->dyst->locreloff;
2057 if(object->st->nsyms != 0 &&
2058 object->st->symoff < offset)
2059 offset = object->st->symoff;
2060 if(object->dyst != NULL &&
2061 object->dyst->nextrel != 0 &&
2062 object->dyst->extreloff < offset)
2063 offset = object->dyst->extreloff;
2064 if(object->dyst != NULL &&
2065 object->dyst->nindirectsyms != 0 &&
2066 object->dyst->indirectsymoff < offset)
2067 offset = object->dyst->indirectsymoff;
2068 if(object->dyst != NULL &&
2069 object->dyst->ntoc != 0 &&
2070 object->dyst->tocoff < offset)
2071 offset = object->dyst->tocoff;
2072 if(object->dyst != NULL &&
2073 object->dyst->nmodtab != 0 &&
2074 object->dyst->modtaboff < offset)
2075 offset = object->dyst->modtaboff;
2076 if(object->dyst != NULL &&
2077 object->dyst->nextrefsyms != 0 &&
2078 object->dyst->extrefsymoff < offset)
2079 offset = object->dyst->extrefsymoff;
2080 if(object->st->strsize != 0 &&
2081 object->st->stroff < offset)
2082 offset = object->st->stroff;
2084 return(offset);
2088 * check_object_relocs() is used to check and update the external relocation
2089 * entries from a section in an object file, to make sure referenced symbols
2090 * are not stripped and are changed to refer to the new symbol table indexes.
2092 static
2093 void
2094 check_object_relocs(
2095 struct arch *arch,
2096 struct member *member,
2097 struct object *object,
2098 char *segname,
2099 char *sectname,
2100 uint64_t sectsize,
2101 char *contents,
2102 struct relocation_info *relocs,
2103 uint32_t nreloc,
2104 struct nlist *symbols,
2105 struct nlist_64 *symbols64,
2106 uint32_t nsyms,
2107 char *strings,
2108 int32_t *missing_reloc_symbols,
2109 enum byte_sex host_byte_sex)
2111 uint32_t k, n_strx;
2112 uint64_t n_value;
2113 #ifdef NMEDIT
2114 uint32_t value, n_ext;
2115 uint64_t value64;
2116 #endif
2117 struct scattered_relocation_info *sreloc;
2119 for(k = 0; k < nreloc; k++){
2120 if((relocs[k].r_address & R_SCATTERED) == 0 &&
2121 relocs[k].r_extern == 1){
2122 if(relocs[k].r_symbolnum > nsyms){
2123 fatal_arch(arch, member, "bad r_symbolnum for relocation "
2124 "entry %d in section (%.16s,%.16s) in: ", k, segname,
2125 sectname);
2127 if(object->mh != NULL){
2128 n_strx = symbols[relocs[k].r_symbolnum].n_un.n_strx;
2129 n_value = symbols[relocs[k].r_symbolnum].n_value;
2131 else{
2132 n_strx = symbols64[relocs[k].r_symbolnum].n_un.n_strx;
2133 n_value = symbols64[relocs[k].r_symbolnum].n_value;
2135 #ifndef NMEDIT
2136 if(saves[relocs[k].r_symbolnum] == 0){
2137 if(*missing_reloc_symbols == 0){
2138 error_arch(arch, member, "symbols referenced by "
2139 "relocation entries that can't be stripped in: ");
2140 *missing_reloc_symbols = 1;
2142 fprintf(stderr, "%s\n", strings + n_strx);
2143 saves[relocs[k].r_symbolnum] = -1;
2145 #else /* defined(NMEDIT) */
2147 * We are letting nmedit change global coalesed symbols into
2148 * statics in MH_OBJECT file types only. Relocation entries to
2149 * global coalesced symbols are external relocs.
2151 if(object->mh != NULL)
2152 n_ext = new_symbols[saves[relocs[k].r_symbolnum] - 1].
2153 n_type & N_EXT;
2154 else
2155 n_ext = new_symbols64[saves[relocs[k].r_symbolnum] - 1].
2156 n_type & N_EXT;
2157 if(n_ext != N_EXT &&
2158 object->mh_cputype != CPU_TYPE_X86_64){
2160 * We need to do the relocation for this external relocation
2161 * entry so the item to be relocated is correct for a local
2162 * relocation entry. We don't need to do this for x86-64.
2164 if(relocs[k].r_address + sizeof(int32_t) > sectsize){
2165 fatal_arch(arch, member, "truncated or malformed "
2166 "object (r_address of relocation entry %u of "
2167 "section (%.16s,%.16s) extends past the end "
2168 "of the section)", k, segname, sectname);
2170 if(object->mh != NULL){
2171 value = *(uint32_t *)
2172 (contents + relocs[k].r_address);
2173 if(object->object_byte_sex != host_byte_sex)
2174 value = SWAP_INT(value);
2176 * We handle a very limited form here. Only VANILLA
2177 * (r_type == 0) long (r_length==2) absolute or pcrel
2178 * that won't need a scattered relocation entry.
2180 if(relocs[k].r_type != 0 ||
2181 relocs[k].r_length != 2){
2182 fatal_arch(arch, member, "don't have "
2183 "code to convert external relocation "
2184 "entry %d in section (%.16s,%.16s) "
2185 "for global coalesced symbol: %s "
2186 "in: ", k, segname, sectname,
2187 strings + n_strx);
2189 value += n_value;
2190 if(object->object_byte_sex != host_byte_sex)
2191 value = SWAP_INT(value);
2192 *(uint32_t *)(contents + relocs[k].r_address) =
2193 value;
2195 else{
2196 value64 = *(uint64_t *)(contents + relocs[k].r_address);
2197 if(object->object_byte_sex != host_byte_sex)
2198 value64 = SWAP_LONG_LONG(value64);
2200 * We handle a very limited form here. Only VANILLA
2201 * (r_type == 0) quad (r_length==3) absolute or pcrel
2202 * that won't need a scattered relocation entry.
2204 if(relocs[k].r_type != 0 ||
2205 relocs[k].r_length != 3){
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 value64 += n_value;
2214 if(object->object_byte_sex != host_byte_sex)
2215 value64 = SWAP_LONG_LONG(value64);
2216 *(uint64_t *)(contents + relocs[k].r_address) = value64;
2219 * Turn the extern reloc into a local.
2221 if(object->mh != NULL)
2222 relocs[k].r_symbolnum =
2223 new_symbols[saves[relocs[k].r_symbolnum] - 1].n_sect;
2224 else
2225 relocs[k].r_symbolnum =
2226 new_symbols64[saves[relocs[k].r_symbolnum] - 1].n_sect;
2227 relocs[k].r_extern = 0;
2229 #endif /* NMEDIT */
2230 if(relocs[k].r_extern == 1 &&
2231 saves[relocs[k].r_symbolnum] != -1){
2232 relocs[k].r_symbolnum = saves[relocs[k].r_symbolnum] - 1;
2235 if((relocs[k].r_address & R_SCATTERED) == 0){
2236 if(reloc_has_pair(object->mh_cputype, relocs[k].r_type) == TRUE)
2237 k++;
2239 else{
2240 sreloc = (struct scattered_relocation_info *)relocs + k;
2241 if(reloc_has_pair(object->mh_cputype, sreloc->r_type) == TRUE)
2242 k++;
2248 * check_indirect_symtab() checks and updates the indirect symbol table entries
2249 * to make sure referenced symbols are not stripped and refer to the new symbol
2250 * table indexes.
2252 static
2253 void
2254 check_indirect_symtab(
2255 struct arch *arch,
2256 struct member *member,
2257 struct object *object,
2258 uint32_t nitems,
2259 uint32_t reserved1,
2260 uint32_t section_type,
2261 char *contents,
2262 struct nlist *symbols,
2263 struct nlist_64 *symbols64,
2264 uint32_t nsyms,
2265 char *strings,
2266 int32_t *missing_reloc_symbols,
2267 enum byte_sex host_byte_sex)
2269 uint32_t k, index;
2270 uint8_t n_type;
2271 uint32_t n_strx, value;
2272 uint64_t value64;
2273 enum bool made_local;
2275 for(k = 0; k < nitems; k++){
2276 made_local = FALSE;
2277 index = object->output_indirect_symtab[reserved1 + k];
2278 if(index == INDIRECT_SYMBOL_LOCAL ||
2279 index == INDIRECT_SYMBOL_ABS ||
2280 index == (INDIRECT_SYMBOL_LOCAL | INDIRECT_SYMBOL_ABS))
2281 continue;
2282 if(index > nsyms)
2283 fatal_arch(arch, member,"indirect symbol table entry %d (past " "the end of the symbol table) in: ", reserved1 + k);
2284 #ifdef NMEDIT
2285 if(pflag == 0 && nmedits[index] == TRUE && saves[index] != -1)
2286 #else
2287 if(saves[index] == 0)
2288 #endif
2291 * Indirect symbol table entries for defined symbols in a
2292 * non-lazy pointer section that are not saved are changed to
2293 * INDIRECT_SYMBOL_LOCAL which their values just have to be
2294 * slid if the are not absolute symbols.
2296 if(object->mh != NULL){
2297 n_type = symbols[index].n_type;
2298 n_strx = symbols[index].n_un.n_strx;
2300 else{
2301 n_type = symbols64[index].n_type;
2302 n_strx = symbols64[index].n_un.n_strx;
2304 if((n_type && N_TYPE) != N_UNDF &&
2305 (n_type && N_TYPE) != N_PBUD &&
2306 section_type == S_NON_LAZY_SYMBOL_POINTERS){
2307 object->output_indirect_symtab[reserved1 + k] =
2308 INDIRECT_SYMBOL_LOCAL;
2309 if((n_type & N_TYPE) == N_ABS)
2310 object->output_indirect_symtab[reserved1 + k] |=
2311 INDIRECT_SYMBOL_ABS;
2312 made_local = TRUE;
2314 * When creating a stub shared library the section contents
2315 * are not updated since they will be stripped.
2317 if(object->mh_filetype != MH_DYLIB_STUB){
2318 if(object->mh != NULL){
2319 value = symbols[index].n_value;
2320 if (symbols[index].n_desc & N_ARM_THUMB_DEF)
2321 value |= 1;
2322 if(object->object_byte_sex != host_byte_sex)
2323 value = SWAP_INT(value);
2324 *(uint32_t *)(contents + k * 4) = value;
2326 else{
2327 value64 = symbols64[index].n_value;
2328 if(object->object_byte_sex != host_byte_sex)
2329 value64 = SWAP_LONG_LONG(value64);
2330 *(uint64_t *)(contents + k * 8) = value64;
2334 #ifdef NMEDIT
2335 else {
2336 object->output_indirect_symtab[reserved1 + k] =
2337 saves[index] - 1;
2339 #else /* !defined(NMEDIT) */
2340 else{
2341 if(*missing_reloc_symbols == 0){
2342 error_arch(arch, member, "symbols referenced by "
2343 "indirect symbol table entries that can't be "
2344 "stripped in: ");
2345 *missing_reloc_symbols = 1;
2347 fprintf(stderr, "%s\n", strings + n_strx);
2348 saves[index] = -1;
2350 #endif /* !defined(NMEDIT) */
2352 #ifdef NMEDIT
2353 else
2354 #else /* !defined(NMEDIT) */
2355 if(made_local == FALSE && saves[index] != -1)
2356 #endif /* !defined(NMEDIT) */
2358 object->output_indirect_symtab[reserved1+k] = saves[index] - 1;
2363 #ifndef NMEDIT
2365 * This is called if there is a -d option specified. It reads the file with
2366 * the strings in it and places them in the array debug_filenames and sorts
2367 * them by name. The file that contains the file names must have names one
2368 * per line with no white space (except the newlines).
2370 static
2371 void
2372 setup_debug_filenames(
2373 char *dfile)
2375 int fd, i, strings_size;
2376 struct stat stat_buf;
2377 char *strings, *p;
2379 if((fd = open(dfile, O_RDONLY)) < 0){
2380 system_error("can't open: %s", dfile);
2381 return;
2383 if(fstat(fd, &stat_buf) == -1){
2384 system_error("can't stat: %s", dfile);
2385 close(fd);
2386 return;
2388 strings_size = stat_buf.st_size;
2389 strings = (char *)allocate(strings_size + 1);
2390 strings[strings_size] = '\0';
2391 if(read(fd, strings, strings_size) != strings_size){
2392 system_error("can't read: %s", dfile);
2393 close(fd);
2394 return;
2396 p = strings;
2397 for(i = 0; i < strings_size; i++){
2398 if(*p == '\n'){
2399 *p = '\0';
2400 ndebug_filenames++;
2402 p++;
2404 debug_filenames = (char **)allocate(ndebug_filenames * sizeof(char *));
2405 p = strings;
2406 for(i = 0; i < ndebug_filenames; i++){
2407 debug_filenames[i] = p;
2408 p += strlen(p) + 1;
2410 qsort(debug_filenames, ndebug_filenames, sizeof(char *),
2411 (int (*)(const void *, const void *))cmp_qsort_filename);
2413 #ifdef DEBUG
2414 printf("Debug filenames:\n");
2415 for(i = 0; i < ndebug_filenames; i++){
2416 printf("filename = %s\n", debug_filenames[i]);
2418 #endif /* DEBUG */
2422 * Strip the symbol table to the level specified by the command line arguments.
2423 * The new symbol table is built and new_symbols is left pointing to it. The
2424 * number of new symbols is left in new_nsyms, the new string table is built
2425 * and new_stings is left pointing to it and new_strsize is left containing it.
2426 * This routine returns zero if successfull and non-zero otherwise.
2428 static
2429 enum bool
2430 strip_symtab(
2431 struct arch *arch,
2432 struct member *member,
2433 struct object *object,
2434 struct dylib_table_of_contents *tocs,
2435 uint32_t ntoc,
2436 struct dylib_module *mods,
2437 struct dylib_module_64 *mods64,
2438 uint32_t nmodtab,
2439 struct dylib_reference *refs,
2440 uint32_t nextrefsyms)
2442 uint32_t i, j, k, n, inew_syms, save_debug, missing_syms;
2443 uint32_t missing_symbols;
2444 char *p, *q, **pp, *basename;
2445 struct symbol_list *sp;
2446 uint32_t new_ext_strsize, len, *changes, inew_undefsyms;
2447 unsigned char nsects;
2448 struct load_command *lc;
2449 struct segment_command *sg;
2450 struct segment_command_64 *sg64;
2451 struct section *s, **sections;
2452 struct section_64 *s64, **sections64;
2453 uint32_t ncmds, mh_flags, s_flags, n_strx;
2454 struct nlist *sym;
2455 struct undef_map *undef_map;
2456 struct undef_map64 *undef_map64;
2457 uint8_t n_type, n_sect;
2458 uint16_t n_desc;
2459 uint64_t n_value;
2460 uint32_t module_name, iextdefsym, nextdefsym, ilocalsym, nlocalsym;
2461 uint32_t irefsym, nrefsym;
2462 unsigned char text_nsect;
2463 enum bool has_dwarf, hack_5614542;
2465 save_debug = 0;
2466 if(saves != NULL)
2467 free(saves);
2468 changes = NULL;
2469 for(i = 0; i < nsave_symbols; i++)
2470 save_symbols[i].sym = NULL;
2471 for(i = 0; i < nremove_symbols; i++)
2472 remove_symbols[i].sym = NULL;
2473 if(member == NULL){
2474 for(i = 0; i < nsave_symbols; i++)
2475 save_symbols[i].seen = FALSE;
2476 for(i = 0; i < nremove_symbols; i++)
2477 remove_symbols[i].seen = FALSE;
2480 new_nsyms = 0;
2481 if(object->mh != NULL)
2482 new_strsize = sizeof(int32_t);
2483 else
2484 new_strsize = sizeof(int64_t);
2485 new_nlocalsym = 0;
2486 new_nextdefsym = 0;
2487 new_nundefsym = 0;
2488 new_ext_strsize = 0;
2491 * If this an object file that has DWARF debugging sections to strip
2492 * then we have to run ld -r on it.
2494 if(object->mh_filetype == MH_OBJECT && (Sflag || xflag)){
2495 has_dwarf = FALSE;
2496 lc = object->load_commands;
2497 if(object->mh != NULL)
2498 ncmds = object->mh->ncmds;
2499 else
2500 ncmds = object->mh64->ncmds;
2501 for(i = 0; i < ncmds && has_dwarf == FALSE; i++){
2502 if(lc->cmd == LC_SEGMENT){
2503 sg = (struct segment_command *)lc;
2504 s = (struct section *)((char *)sg +
2505 sizeof(struct segment_command));
2506 for(j = 0; j < sg->nsects; j++){
2507 if(s->flags & S_ATTR_DEBUG){
2508 has_dwarf = TRUE;
2509 break;
2511 s++;
2514 else if(lc->cmd == LC_SEGMENT_64){
2515 sg64 = (struct segment_command_64 *)lc;
2516 s64 = (struct section_64 *)((char *)sg64 +
2517 sizeof(struct segment_command_64));
2518 for(j = 0; j < sg64->nsects; j++){
2519 if(s64->flags & S_ATTR_DEBUG){
2520 has_dwarf = TRUE;
2521 break;
2523 s64++;
2526 lc = (struct load_command *)((char *)lc + lc->cmdsize);
2529 * Because of the bugs in ld(1) for:
2530 * radr://5675774 ld64 should preserve JBSR relocations without
2531 * -static
2532 * radr://5658046 cctools-679 creates scattered relocations in
2533 * __TEXT,__const section in kexts, which breaks
2534 * kexts built for older systems
2535 * we can't use ld -r to strip dwarf info in 32-bit objects until
2536 * these are fixed. But if the user as specified the -l flag then
2537 * go ahead and do it and the user will have to be aware of these
2538 * bugs.
2540 if((lflag == TRUE && has_dwarf == TRUE) || object->mh64 != NULL)
2541 make_ld_r_object(arch, member, object);
2544 * Because of the "design" of 64-bit object files and the lack of
2545 * local relocation entries it is not possible for strip(1) to do its
2546 * job without becoming a static link editor. The "design" does not
2547 * actually strip the symbols it simply renames them to things like
2548 * "l1000". And they become static symbols but still have external
2549 * relocation entries. Thus can never actually be stripped. Also some
2550 * symbols, *.eh, symbols are not even changed to these names if there
2551 * corresponding global symbol is not stripped. So strip(1) only
2552 * recourse is to use the unified linker to create an ld -r object then
2553 * save all resulting symbols (both static and global) and hope the user
2554 * does not notice the stripping is not what they asked for.
2556 if(object->mh_filetype == MH_OBJECT &&
2557 (object->mh64 != NULL && object->ld_r_ofile == NULL))
2558 make_ld_r_object(arch, member, object);
2561 * Since make_ld_r_object() may create an object with more symbols
2562 * this has to be done after make_ld_r_object() and nsyms is updated.
2564 saves = (int32_t *)allocate(nsyms * sizeof(int32_t));
2565 bzero(saves, nsyms * sizeof(int32_t));
2568 * Gather an array of section struct pointers so we can later determine
2569 * if we run into a global symbol in a coalesced section and not strip
2570 * those symbols.
2571 * statics.
2573 nsects = 0;
2574 text_nsect = NO_SECT;
2575 lc = object->load_commands;
2576 if(object->mh != NULL)
2577 ncmds = object->mh->ncmds;
2578 else
2579 ncmds = object->mh64->ncmds;
2580 for(i = 0; i < ncmds; i++){
2581 if(lc->cmd == LC_SEGMENT){
2582 sg = (struct segment_command *)lc;
2583 nsects += sg->nsects;
2585 else if(lc->cmd == LC_SEGMENT_64){
2586 sg64 = (struct segment_command_64 *)lc;
2587 nsects += sg64->nsects;
2589 lc = (struct load_command *)((char *)lc + lc->cmdsize);
2591 if(object->mh != NULL){
2592 sections = allocate(nsects * sizeof(struct section *));
2593 sections64 = NULL;
2595 else{
2596 sections = NULL;
2597 sections64 = allocate(nsects * sizeof(struct section_64 *));
2599 nsects = 0;
2600 lc = object->load_commands;
2601 for(i = 0; i < ncmds; i++){
2602 if(lc->cmd == LC_SEGMENT){
2603 sg = (struct segment_command *)lc;
2604 s = (struct section *)((char *)sg +
2605 sizeof(struct segment_command));
2606 for(j = 0; j < sg->nsects; j++){
2607 if(strcmp((s + j)->sectname, SECT_TEXT) == 0 &&
2608 strcmp((s + j)->segname, SEG_TEXT) == 0)
2609 text_nsect = nsects + 1;
2610 sections[nsects++] = s++;
2613 else if(lc->cmd == LC_SEGMENT_64){
2614 sg64 = (struct segment_command_64 *)lc;
2615 s64 = (struct section_64 *)((char *)sg64 +
2616 sizeof(struct segment_command_64));
2617 for(j = 0; j < sg64->nsects; j++){
2618 if(strcmp((s64 + j)->sectname, SECT_TEXT) == 0 &&
2619 strcmp((s64 + j)->segname, SEG_TEXT) == 0)
2620 text_nsect = nsects + 1;
2621 sections64[nsects++] = s64++;
2624 lc = (struct load_command *)((char *)lc + lc->cmdsize);
2627 for(i = 0; i < nsyms; i++){
2628 s_flags = 0;
2629 if(object->mh != NULL){
2630 mh_flags = object->mh->flags;
2631 n_strx = symbols[i].n_un.n_strx;
2632 n_type = symbols[i].n_type;
2633 n_sect = symbols[i].n_sect;
2634 if((n_type & N_TYPE) == N_SECT){
2635 if(n_sect == 0 || n_sect > nsects){
2636 error_arch(arch, member, "bad n_sect for symbol "
2637 "table entry %d in: ", i);
2638 return(FALSE);
2640 s_flags = sections[n_sect - 1]->flags;
2642 n_desc = symbols[i].n_desc;
2643 n_value = symbols[i].n_value;
2645 else{
2646 mh_flags = object->mh64->flags;
2647 n_strx = symbols64[i].n_un.n_strx;
2648 n_type = symbols64[i].n_type;
2649 n_sect = symbols64[i].n_sect;
2650 if((n_type & N_TYPE) == N_SECT){
2651 if(n_sect == 0 || n_sect > nsects){
2652 error_arch(arch, member, "bad n_sect for symbol "
2653 "table entry %d in: ", i);
2654 return(FALSE);
2656 s_flags = sections64[n_sect - 1]->flags;
2658 n_desc = symbols64[i].n_desc;
2659 n_value = symbols64[i].n_value;
2661 if(n_strx != 0){
2662 if(n_strx > strsize){
2663 error_arch(arch, member, "bad string index for symbol "
2664 "table entry %d in: ", i);
2665 return(FALSE);
2668 if((n_type & N_TYPE) == N_INDR){
2669 if(n_value != 0){
2670 if(n_value > strsize){
2671 error_arch(arch, member, "bad string index for "
2672 "indirect symbol table entry %d in: ", i);
2673 return(FALSE);
2677 if((n_type & N_EXT) == 0){ /* local symbol */
2678 if(aflag){
2679 if(n_strx != 0)
2680 new_strsize += strlen(strings + n_strx) + 1;
2681 new_nlocalsym++;
2682 new_nsyms++;
2683 saves[i] = new_nsyms;
2686 * For x86_64 .o files we have run ld -r on them and are stuck
2687 * keeping all resulting symbols.
2689 else if(object->mh == NULL &&
2690 object->mh64->cputype == CPU_TYPE_X86_64 &&
2691 object->mh64->filetype == MH_OBJECT){
2692 if(n_strx != 0)
2693 new_strsize += strlen(strings + n_strx) + 1;
2694 new_nlocalsym++;
2695 new_nsyms++;
2696 saves[i] = new_nsyms;
2699 * The cases a local symbol might be saved are with -X, -S, -t,
2700 * or with -d filename.
2702 else if((!strip_all && (Xflag || tflag || Sflag)) || dfile){
2703 if(n_type & N_STAB){ /* debug symbol */
2704 if(dfile && n_type == N_SO){
2705 if(n_strx != 0){
2706 basename = strrchr(strings + n_strx, '/');
2707 if(basename != NULL)
2708 basename++;
2709 else
2710 basename = strings + n_strx;
2711 pp = bsearch(basename, debug_filenames,
2712 ndebug_filenames, sizeof(char *),
2713 (int (*)(const void *, const void *)
2714 )cmp_bsearch_filename);
2716 * Save the bracketing N_SO. For each N_SO that
2717 * has a filename there is an N_SO that has a
2718 * name of "" which ends the stabs for that file
2720 if(*basename != '\0'){
2721 if(pp != NULL)
2722 save_debug = 1;
2723 else
2724 save_debug = 0;
2726 else{
2728 * This is a bracketing SO so if we are
2729 * currently saving debug symbols save this
2730 * last one and turn off saving debug syms.
2732 if(save_debug){
2733 if(n_strx != 0)
2734 new_strsize += strlen(strings +
2735 n_strx) + 1;
2736 new_nlocalsym++;
2737 new_nsyms++;
2738 saves[i] = new_nsyms;
2740 save_debug = 0;
2743 else{
2744 save_debug = 0;
2747 if(saves[i] == 0 && (!Sflag || save_debug)){
2748 if(n_strx != 0)
2749 new_strsize += strlen(strings + n_strx) + 1;
2750 new_nlocalsym++;
2751 new_nsyms++;
2752 saves[i] = new_nsyms;
2755 else{ /* non-debug local symbol */
2756 if(xflag == 0 && (Sflag || Xflag || tflag)){
2758 * No -x (strip all local), and one of -S (strip
2759 * debug), -X (strip 'L' local), or -t (strip
2760 * local except non-'L' text) was given.
2762 if((Xflag && n_strx != 0 &&
2763 strings[n_strx] != 'L') ||
2764 (tflag && (n_type & N_TYPE) == N_SECT &&
2765 n_sect == text_nsect && n_strx != 0 &&
2766 strings[n_strx] != 'L') ||
2767 (Sflag && !Xflag && !tflag)) {
2769 * If this file is a for the dynamic linker and
2770 * this symbol is in a section marked so that
2771 * static symbols are stripped then don't
2772 * keep this symbol.
2774 if((mh_flags & MH_DYLDLINK) != MH_DYLDLINK ||
2775 (n_type & N_TYPE) != N_SECT ||
2776 (s_flags & S_ATTR_STRIP_STATIC_SYMS) !=
2777 S_ATTR_STRIP_STATIC_SYMS){
2778 new_strsize += strlen(strings + n_strx) + 1;
2779 new_nlocalsym++;
2780 new_nsyms++;
2781 saves[i] = new_nsyms;
2786 * Treat a local symbol that was a private extern as if
2787 * were global if it is referenced by a module and save
2788 * it.
2790 if((n_type & N_PEXT) == N_PEXT){
2791 if(saves[i] == 0 &&
2792 private_extern_reference_by_module(
2793 i, refs ,nextrefsyms) == TRUE){
2794 if(n_strx != 0)
2795 new_strsize += strlen(strings + n_strx) + 1;
2796 new_nlocalsym++;
2797 new_nsyms++;
2798 saves[i] = new_nsyms;
2801 * We need to save symbols that were private externs
2802 * that are used with indirect symbols.
2804 if(saves[i] == 0 &&
2805 symbol_pointer_used(i, indirectsyms,
2806 nindirectsyms) == TRUE){
2807 if(n_strx != 0){
2808 len = strlen(strings + n_strx) + 1;
2809 new_strsize += len;
2811 new_nlocalsym++;
2812 new_nsyms++;
2813 saves[i] = new_nsyms;
2819 * Treat a local symbol that was a private extern as if were
2820 * global if it is not referenced by a module.
2822 else if((n_type & N_PEXT) == N_PEXT){
2823 if(saves[i] == 0 && sfile){
2824 sp = bsearch(strings + n_strx,
2825 save_symbols, nsave_symbols,
2826 sizeof(struct symbol_list),
2827 (int (*)(const void *, const void *))
2828 symbol_list_bsearch);
2829 if(sp != NULL){
2830 if(sp->sym == NULL){
2831 if(object->mh != NULL)
2832 sp->sym = &(symbols[i]);
2833 else
2834 sp->sym = &(symbols64[i]);
2835 sp->seen = TRUE;
2837 if(n_strx != 0)
2838 new_strsize += strlen(strings + n_strx) + 1;
2839 new_nlocalsym++;
2840 new_nsyms++;
2841 saves[i] = new_nsyms;
2844 if(saves[i] == 0 &&
2845 private_extern_reference_by_module(
2846 i, refs ,nextrefsyms) == TRUE){
2847 if(n_strx != 0)
2848 new_strsize += strlen(strings + n_strx) + 1;
2849 new_nlocalsym++;
2850 new_nsyms++;
2851 saves[i] = new_nsyms;
2854 * We need to save symbols that were private externs that
2855 * are used with indirect symbols.
2857 if(saves[i] == 0 &&
2858 symbol_pointer_used(i, indirectsyms, nindirectsyms) ==
2859 TRUE){
2860 if(n_strx != 0){
2861 len = strlen(strings + n_strx) + 1;
2862 new_strsize += len;
2864 new_nlocalsym++;
2865 new_nsyms++;
2866 saves[i] = new_nsyms;
2870 else{ /* global symbol */
2872 * strip -R on an x86_64 .o file should do nothing.
2874 if(Rfile &&
2875 (object->mh != NULL ||
2876 object->mh64->cputype != CPU_TYPE_X86_64 ||
2877 object->mh64->filetype != MH_OBJECT)){
2878 sp = bsearch(strings + n_strx,
2879 remove_symbols, nremove_symbols,
2880 sizeof(struct symbol_list),
2881 (int (*)(const void *, const void *))
2882 symbol_list_bsearch);
2883 if(sp != NULL){
2884 if((n_type & N_TYPE) == N_UNDF ||
2885 (n_type & N_TYPE) == N_PBUD){
2886 error_arch(arch, member, "symbol: %s undefined"
2887 " and can't be stripped from: ",
2888 sp->name);
2890 else if(sp->sym != NULL){
2891 sym = (struct nlist *)sp->sym;
2892 if((sym->n_type & N_PEXT) != N_PEXT)
2893 error_arch(arch, member, "more than one symbol "
2894 "for: %s found in: ", sp->name);
2896 else{
2897 if(object->mh != NULL)
2898 sp->sym = &(symbols[i]);
2899 else
2900 sp->sym = &(symbols64[i]);
2901 sp->seen = TRUE;
2903 if(n_desc & REFERENCED_DYNAMICALLY){
2904 error_arch(arch, member, "symbol: %s is dynamically"
2905 " referenced and can't be stripped "
2906 "from: ", sp->name);
2908 if((n_type & N_TYPE) == N_SECT &&
2909 (s_flags & SECTION_TYPE) == S_COALESCED){
2910 error_arch(arch, member, "symbol: %s is a global "
2911 "coalesced symbol and can't be "
2912 "stripped from: ", sp->name);
2914 /* don't save this symbol */
2915 continue;
2918 if(Aflag && (n_type & N_TYPE) == N_ABS &&
2919 (n_value != 0 ||
2920 (n_strx != 0 &&
2921 strncmp(strings + n_strx,
2922 ".objc_class_name_",
2923 sizeof(".objc_class_name_") - 1) == 0))){
2924 len = strlen(strings + n_strx) + 1;
2925 new_strsize += len;
2926 new_ext_strsize += len;
2927 new_nextdefsym++;
2928 new_nsyms++;
2929 saves[i] = new_nsyms;
2931 if(saves[i] == 0 && (uflag || default_dyld_executable) &&
2932 ((((n_type & N_TYPE) == N_UNDF) &&
2933 n_value == 0) ||
2934 (n_type & N_TYPE) == N_PBUD)){
2935 if(n_strx != 0){
2936 len = strlen(strings + n_strx) + 1;
2937 new_strsize += len;
2938 new_ext_strsize += len;
2940 new_nundefsym++;
2941 new_nsyms++;
2942 saves[i] = new_nsyms;
2944 if(saves[i] == 0 && nflag &&
2945 (n_type & N_TYPE) == N_SECT){
2946 if(n_strx != 0){
2947 len = strlen(strings + n_strx) + 1;
2948 new_strsize += len;
2949 new_ext_strsize += len;
2951 new_nextdefsym++;
2952 new_nsyms++;
2953 saves[i] = new_nsyms;
2955 if(saves[i] == 0 && sfile){
2956 sp = bsearch(strings + n_strx,
2957 save_symbols, nsave_symbols,
2958 sizeof(struct symbol_list),
2959 (int (*)(const void *, const void *))
2960 symbol_list_bsearch);
2961 if(sp != NULL){
2962 if(sp->sym != NULL){
2963 sym = (struct nlist *)sp->sym;
2964 if((sym->n_type & N_PEXT) != N_PEXT)
2965 error_arch(arch, member, "more than one symbol "
2966 "for: %s found in: ", sp->name);
2968 else{
2969 if(object->mh != NULL)
2970 sp->sym = &(symbols[i]);
2971 else
2972 sp->sym = &(symbols64[i]);
2973 sp->seen = TRUE;
2974 len = strlen(strings + n_strx) + 1;
2975 new_strsize += len;
2976 new_ext_strsize += len;
2977 if((n_type & N_TYPE) == N_UNDF ||
2978 (n_type & N_TYPE) == N_PBUD)
2979 new_nundefsym++;
2980 else
2981 new_nextdefsym++;
2982 new_nsyms++;
2983 saves[i] = new_nsyms;
2988 * We only need to save coalesced symbols that are used as
2989 * indirect symbols in 32-bit applications.
2991 * In 64-bit applications, we only need to save coalesced
2992 * symbols that are used as weak definitions.
2994 if(object->mh != NULL &&
2995 saves[i] == 0 &&
2996 (n_type & N_TYPE) == N_SECT &&
2997 (s_flags & SECTION_TYPE) == S_COALESCED &&
2998 symbol_pointer_used(i, indirectsyms, nindirectsyms) == TRUE){
2999 if(n_strx != 0){
3000 len = strlen(strings + n_strx) + 1;
3001 new_strsize += len;
3002 new_ext_strsize += len;
3004 new_nextdefsym++;
3005 new_nsyms++;
3006 saves[i] = new_nsyms;
3008 if(saves[i] == 0 &&
3009 (n_type & N_TYPE) == N_SECT &&
3010 (n_desc & N_WEAK_DEF) != 0){
3011 if(n_strx != 0){
3012 len = strlen(strings + n_strx) + 1;
3013 new_strsize += len;
3014 new_ext_strsize += len;
3016 new_nextdefsym++;
3017 new_nsyms++;
3018 saves[i] = new_nsyms;
3020 if(saves[i] == 0 &&
3021 ((Xflag || Sflag || xflag || tflag || aflag) ||
3022 ((rflag || default_dyld_executable) &&
3023 n_desc & REFERENCED_DYNAMICALLY))){
3024 len = strlen(strings + n_strx) + 1;
3025 new_strsize += len;
3026 new_ext_strsize += len;
3027 if((n_type & N_TYPE) == N_INDR){
3028 len = strlen(strings + n_value) + 1;
3029 new_strsize += len;
3030 new_ext_strsize += len;
3032 if((n_type & N_TYPE) == N_UNDF ||
3033 (n_type & N_TYPE) == N_PBUD)
3034 new_nundefsym++;
3035 else
3036 new_nextdefsym++;
3037 new_nsyms++;
3038 saves[i] = new_nsyms;
3041 * For x86_64 .o files we have run ld -r on them and are stuck
3042 * keeping all resulting symbols.
3044 if(saves[i] == 0 &&
3045 object->mh == NULL &&
3046 object->mh64->cputype == CPU_TYPE_X86_64 &&
3047 object->mh64->filetype == MH_OBJECT){
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;
3067 * The module table's module names are placed with the external strings.
3068 * So size them and add this to the external string size.
3070 for(i = 0; i < nmodtab; i++){
3071 if(object->mh != NULL)
3072 module_name = mods[i].module_name;
3073 else
3074 module_name = mods64[i].module_name;
3075 if(module_name == 0 || module_name > strsize){
3076 error_arch(arch, member, "bad string index for module_name "
3077 "of module table entry %d in: ", i);
3078 return(FALSE);
3080 len = strlen(strings + module_name) + 1;
3081 new_strsize += len;
3082 new_ext_strsize += len;
3086 * Updating the reference table may require a symbol not yet listed as
3087 * as saved to be present in the output file. If a defined external
3088 * symbol is removed and there is a undefined reference to it in the
3089 * reference table an undefined symbol needs to be created for it in
3090 * the output file. If this happens the number of new symbols and size
3091 * of the new strings are adjusted. And the array changes[] is set to
3092 * map the old symbol index to the new symbol index for the symbol that
3093 * is changed to an undefined symbol.
3095 missing_symbols = 0;
3096 if(ref_saves != NULL)
3097 free(ref_saves);
3098 ref_saves = (int32_t *)allocate(nextrefsyms * sizeof(int32_t));
3099 bzero(ref_saves, nextrefsyms * sizeof(int32_t));
3100 changes = (uint32_t *)allocate(nsyms * sizeof(int32_t));
3101 bzero(changes, nsyms * sizeof(int32_t));
3102 new_nextrefsyms = 0;
3103 for(i = 0; i < nextrefsyms; i++){
3104 if(refs[i].isym > nsyms){
3105 error_arch(arch, member, "bad symbol table index for "
3106 "reference table entry %d in: ", i);
3107 return(FALSE);
3109 if(saves[refs[i].isym]){
3110 new_nextrefsyms++;
3111 ref_saves[i] = new_nextrefsyms;
3113 else{
3114 if(refs[i].flags == REFERENCE_FLAG_UNDEFINED_NON_LAZY ||
3115 refs[i].flags == REFERENCE_FLAG_UNDEFINED_LAZY){
3116 if(changes[refs[i].isym] == 0){
3117 if(object->mh != NULL)
3118 n_strx = symbols[refs[i].isym].n_un.n_strx;
3119 else
3120 n_strx = symbols64[refs[i].isym].n_un.n_strx;
3121 len = strlen(strings + n_strx) + 1;
3122 new_strsize += len;
3123 new_ext_strsize += len;
3124 new_nundefsym++;
3125 new_nsyms++;
3126 changes[refs[i].isym] = new_nsyms;
3127 new_nextrefsyms++;
3128 ref_saves[i] = new_nextrefsyms;
3131 else{
3132 if(refs[i].flags ==
3133 REFERENCE_FLAG_PRIVATE_UNDEFINED_NON_LAZY ||
3134 refs[i].flags == REFERENCE_FLAG_PRIVATE_UNDEFINED_LAZY){
3135 if(missing_symbols == 0){
3136 error_arch(arch, member, "private extern symbols "
3137 "referenced by modules can't be stripped in: ");
3138 missing_symbols = 1;
3140 if(object->mh != NULL)
3141 n_strx = symbols[refs[i].isym].n_un.n_strx;
3142 else
3143 n_strx = symbols64[refs[i].isym].n_un.n_strx;
3144 fprintf(stderr, "%s\n", strings + n_strx);
3145 saves[refs[i].isym] = -1;
3150 if(missing_symbols == 1)
3151 return(FALSE);
3153 if(member == NULL){
3154 missing_syms = 0;
3155 if(iflag == 0){
3156 for(i = 0; i < nsave_symbols; i++){
3157 if(save_symbols[i].sym == NULL){
3158 if(missing_syms == 0){
3159 error_arch(arch, member, "symbols names listed "
3160 "in: %s not in: ", sfile);
3161 missing_syms = 1;
3163 fprintf(stderr, "%s\n", save_symbols[i].name);
3167 missing_syms = 0;
3169 * strip -R on an x86_64 .o file should do nothing.
3171 if(iflag == 0 &&
3172 (object->mh != NULL ||
3173 object->mh64->cputype != CPU_TYPE_X86_64 ||
3174 object->mh64->filetype != MH_OBJECT)){
3175 for(i = 0; i < nremove_symbols; i++){
3176 if(remove_symbols[i].sym == NULL){
3177 if(missing_syms == 0){
3178 error_arch(arch, member, "symbols names listed "
3179 "in: %s not in: ", Rfile);
3180 missing_syms = 1;
3182 fprintf(stderr, "%s\n", remove_symbols[i].name);
3189 * If there is a chance that we could end up with an indirect symbol
3190 * with an index of zero we need to avoid that due to a work around
3191 * in the dynamic linker for a bug it is working around that was in
3192 * the old classic static linker. See radar bug 5614542 and the
3193 * related bugs 3685312 and 3534709.
3195 * A reasonable way to do this to know that local symbols are first in
3196 * the symbol table. So if we have any local symbols this won't happen
3197 * and if there are no indirect symbols it will also not happen. Past
3198 * that we'll just add a local symbol so it will end up at symbol index
3199 * zero and avoid any indirect symbol having that index.
3201 * If one really wanted they could build up the new symbol table then
3202 * look at all the indirect symbol table entries to see if any of them
3203 * have an index of zero then in that case throw that new symbol table
3204 * away and rebuild the symbol and string table once again after adding
3205 * a local symbol. This seems not all that resonable to save one symbol
3206 * table entry and a few bytes in the string table for the complexity it
3207 * would add and what it would save.
3209 if(new_nlocalsym == 0 && nindirectsyms != 0){
3210 len = strlen("radr://5614542") + 1;
3211 new_strsize += len;
3212 new_nlocalsym++;
3213 new_nsyms++;
3214 hack_5614542 = TRUE;
3216 else{
3217 hack_5614542 = FALSE;
3220 if(object->mh != NULL){
3221 new_symbols = (struct nlist *)
3222 allocate(new_nsyms * sizeof(struct nlist));
3223 new_symbols64 = NULL;
3225 else{
3226 new_symbols = NULL;
3227 new_symbols64 = (struct nlist_64 *)
3228 allocate(new_nsyms * sizeof(struct nlist_64));
3230 if(object->mh != NULL)
3231 new_strsize = round(new_strsize, sizeof(int32_t));
3232 else
3233 new_strsize = round(new_strsize, sizeof(int64_t));
3234 new_strings = (char *)allocate(new_strsize);
3235 if(object->mh != NULL){
3236 new_strings[new_strsize - 3] = '\0';
3237 new_strings[new_strsize - 2] = '\0';
3238 new_strings[new_strsize - 1] = '\0';
3240 else{
3241 new_strings[new_strsize - 7] = '\0';
3242 new_strings[new_strsize - 6] = '\0';
3243 new_strings[new_strsize - 5] = '\0';
3244 new_strings[new_strsize - 4] = '\0';
3245 new_strings[new_strsize - 3] = '\0';
3246 new_strings[new_strsize - 2] = '\0';
3247 new_strings[new_strsize - 1] = '\0';
3250 memset(new_strings, '\0', sizeof(int32_t));
3251 p = new_strings + sizeof(int32_t);
3252 q = p + new_ext_strsize;
3255 * If all strings were stripped set the size to zero but only for 32-bit
3256 * because the unified linker seems to set the filesize of empty .o
3257 * files to include the string table.
3259 if(object->mh != NULL && new_strsize == sizeof(int32_t))
3260 new_strsize = 0;
3263 * Now create a symbol table and string table in this order
3264 * symbol table
3265 * local symbols
3266 * external defined symbols
3267 * undefined symbols
3268 * string table
3269 * external strings
3270 * local strings
3272 inew_syms = 0;
3275 * If we are doing the hack for radar bug 5614542 (see above) add the
3276 * one local symbol and string.
3278 * We use an N_OPT stab which should be safe to use and not mess any
3279 * thing up. In Mac OS X, gcc(1) writes one N_OPT stab saying the file
3280 * is compiled with gcc(1). Then gdb(1) looks for that stab, but it
3281 * also looks at the name. If the name string is "gcc_compiled" or
3282 * "gcc2_compiled" gdb(1) sets its "compiled by gcc flag. If the N_OPT
3283 * is emitted INSIDE an N_SO section, then gdb(1) thinks that object
3284 * module was compiled by Sun's compiler, which apparently sticks one
3285 * outermost N_LBRAC/N_RBRAC pair, which gdb(1) strips off. But if the
3286 * N_OPT comes before any N_SO stabs, then gdb(1) will just ignore it.
3287 * Since this N_OPT is the first local symbol, it will always come
3288 * before any N_SO stabs that might be around and should be fine.
3290 if(hack_5614542 == TRUE){
3291 if(object->mh != NULL){
3292 new_symbols[inew_syms].n_type = N_OPT;
3293 new_symbols[inew_syms].n_sect = NO_SECT;
3294 new_symbols[inew_syms].n_desc = 0;
3295 new_symbols[inew_syms].n_value = 0x05614542;
3297 else{
3298 new_symbols64[inew_syms].n_type = N_OPT;
3299 new_symbols64[inew_syms].n_sect = NO_SECT;
3300 new_symbols64[inew_syms].n_desc = 0;
3301 new_symbols64[inew_syms].n_value = 0x05614542;
3303 strcpy(q, "radr://5614542");
3304 if(object->mh != NULL)
3305 new_symbols[inew_syms].n_un.n_strx =
3306 q - new_strings;
3307 else
3308 new_symbols64[inew_syms].n_un.n_strx =
3309 q - new_strings;
3310 q += strlen(q) + 1;
3311 inew_syms++;
3314 for(i = 0; i < nsyms; i++){
3315 if(saves[i]){
3316 if(object->mh != NULL){
3317 n_strx = symbols[i].n_un.n_strx;
3318 n_type = symbols[i].n_type;
3320 else{
3321 n_strx = symbols64[i].n_un.n_strx;
3322 n_type = symbols64[i].n_type;
3324 if((n_type & N_EXT) == 0){
3325 if(object->mh != NULL)
3326 new_symbols[inew_syms] = symbols[i];
3327 else
3328 new_symbols64[inew_syms] = symbols64[i];
3329 if(n_strx != 0){
3330 strcpy(q, strings + n_strx);
3331 if(object->mh != NULL)
3332 new_symbols[inew_syms].n_un.n_strx =
3333 q - new_strings;
3334 else
3335 new_symbols64[inew_syms].n_un.n_strx =
3336 q - new_strings;
3337 q += strlen(q) + 1;
3339 inew_syms++;
3340 saves[i] = inew_syms;
3344 inew_nextdefsym = inew_syms;
3345 for(i = 0; i < nsyms; i++){
3346 if(saves[i]){
3347 if(object->mh != NULL){
3348 n_strx = symbols[i].n_un.n_strx;
3349 n_type = symbols[i].n_type;
3350 n_value = symbols[i].n_value;
3352 else{
3353 n_strx = symbols64[i].n_un.n_strx;
3354 n_type = symbols64[i].n_type;
3355 n_value = symbols64[i].n_value;
3357 if((n_type & N_EXT) == N_EXT &&
3358 ((n_type & N_TYPE) != N_UNDF &&
3359 (n_type & N_TYPE) != N_PBUD)){
3360 if(object->mh != NULL)
3361 new_symbols[inew_syms] = symbols[i];
3362 else
3363 new_symbols64[inew_syms] = symbols64[i];
3364 if(n_strx != 0){
3365 strcpy(p, strings + n_strx);
3366 if(object->mh != NULL)
3367 new_symbols[inew_syms].n_un.n_strx =
3368 p - new_strings;
3369 else
3370 new_symbols64[inew_syms].n_un.n_strx =
3371 p - new_strings;
3372 p += strlen(p) + 1;
3374 if((n_type & N_TYPE) == N_INDR){
3375 if(n_value != 0){
3376 strcpy(p, strings + n_value);
3377 if(object->mh != NULL)
3378 new_symbols[inew_syms].n_value =
3379 p - new_strings;
3380 else
3381 new_symbols64[inew_syms].n_value =
3382 p - new_strings;
3383 p += strlen(p) + 1;
3386 inew_syms++;
3387 saves[i] = inew_syms;
3392 * Build the new undefined symbols into a map and sort it.
3394 inew_undefsyms = 0;
3395 if(object->mh != NULL){
3396 undef_map = (struct undef_map *)allocate(new_nundefsym *
3397 sizeof(struct undef_map));
3398 undef_map64 = NULL;
3400 else{
3401 undef_map = NULL;
3402 undef_map64 = (struct undef_map64 *)allocate(new_nundefsym *
3403 sizeof(struct undef_map64));
3405 for(i = 0; i < nsyms; i++){
3406 if(saves[i]){
3407 if(object->mh != NULL){
3408 n_strx = symbols[i].n_un.n_strx;
3409 n_type = symbols[i].n_type;
3411 else{
3412 n_strx = symbols64[i].n_un.n_strx;
3413 n_type = symbols64[i].n_type;
3415 if((n_type & N_EXT) == N_EXT &&
3416 ((n_type & N_TYPE) == N_UNDF ||
3417 (n_type & N_TYPE) == N_PBUD)){
3418 if(object->mh != NULL)
3419 undef_map[inew_undefsyms].symbol = symbols[i];
3420 else
3421 undef_map64[inew_undefsyms].symbol64 = symbols64[i];
3422 if(n_strx != 0){
3423 strcpy(p, strings + n_strx);
3424 if(object->mh != NULL)
3425 undef_map[inew_undefsyms].symbol.n_un.n_strx =
3426 p - new_strings;
3427 else
3428 undef_map64[inew_undefsyms].symbol64.n_un.n_strx =
3429 p - new_strings;
3430 p += strlen(p) + 1;
3432 if(object->mh != NULL)
3433 undef_map[inew_undefsyms].index = i;
3434 else
3435 undef_map64[inew_undefsyms].index = i;
3436 inew_undefsyms++;
3440 for(i = 0; i < nsyms; i++){
3441 if(changes[i]){
3442 if(object->mh != NULL)
3443 n_strx = symbols[i].n_un.n_strx;
3444 else
3445 n_strx = symbols64[i].n_un.n_strx;
3446 if(n_strx != 0){
3447 strcpy(p, strings + n_strx);
3448 if(object->mh != NULL)
3449 undef_map[inew_undefsyms].symbol.n_un.n_strx =
3450 p - new_strings;
3451 else
3452 undef_map64[inew_undefsyms].symbol64.n_un.n_strx =
3453 p - new_strings;
3454 p += strlen(p) + 1;
3456 if(object->mh != NULL){
3457 undef_map[inew_undefsyms].symbol.n_type = N_UNDF | N_EXT;
3458 undef_map[inew_undefsyms].symbol.n_sect = NO_SECT;
3459 undef_map[inew_undefsyms].symbol.n_desc = 0;
3460 undef_map[inew_undefsyms].symbol.n_value = 0;
3461 undef_map[inew_undefsyms].index = i;
3463 else{
3464 undef_map64[inew_undefsyms].symbol64.n_type = N_UNDF |N_EXT;
3465 undef_map64[inew_undefsyms].symbol64.n_sect = NO_SECT;
3466 undef_map64[inew_undefsyms].symbol64.n_desc = 0;
3467 undef_map64[inew_undefsyms].symbol64.n_value = 0;
3468 undef_map64[inew_undefsyms].index = i;
3470 inew_undefsyms++;
3473 /* Sort the undefined symbols by name */
3474 qsort_strings = new_strings;
3475 if(object->mh != NULL)
3476 qsort(undef_map, new_nundefsym, sizeof(struct undef_map),
3477 (int (*)(const void *, const void *))cmp_qsort_undef_map);
3478 else
3479 qsort(undef_map64, new_nundefsym, sizeof(struct undef_map64),
3480 (int (*)(const void *, const void *))cmp_qsort_undef_map_64);
3481 /* Copy the symbols now in sorted order into new_symbols */
3482 for(i = 0; i < new_nundefsym; i++){
3483 if(object->mh != NULL){
3484 new_symbols[inew_syms] = undef_map[i].symbol;
3485 inew_syms++;
3486 saves[undef_map[i].index] = inew_syms;
3488 else{
3489 new_symbols64[inew_syms] = undef_map64[i].symbol64;
3490 inew_syms++;
3491 saves[undef_map64[i].index] = inew_syms;
3496 * Fixup the module table's module name strings adding them to the
3497 * string table. Also fix the indexes into the symbol table for
3498 * external and local symbols. And fix up the indexes into the
3499 * reference table.
3501 for(i = 0; i < nmodtab; i++){
3502 if(object->mh != NULL){
3503 strcpy(p, strings + mods[i].module_name);
3504 mods[i].module_name = p - new_strings;
3505 iextdefsym = mods[i].iextdefsym;
3506 nextdefsym = mods[i].nextdefsym;
3507 ilocalsym = mods[i].ilocalsym;
3508 nlocalsym = mods[i].nlocalsym;
3509 irefsym = mods[i].irefsym;
3510 nrefsym = mods[i].nrefsym;
3512 else{
3513 strcpy(p, strings + mods64[i].module_name);
3514 mods64[i].module_name = p - new_strings;
3515 iextdefsym = mods64[i].iextdefsym;
3516 nextdefsym = mods64[i].nextdefsym;
3517 ilocalsym = mods64[i].ilocalsym;
3518 nlocalsym = mods64[i].nlocalsym;
3519 irefsym = mods64[i].irefsym;
3520 nrefsym = mods64[i].nrefsym;
3522 p += strlen(p) + 1;
3524 if(iextdefsym > nsyms){
3525 error_arch(arch, member, "bad index into externally defined "
3526 "symbols of module table entry %d in: ", i);
3527 return(FALSE);
3529 if(iextdefsym + nextdefsym > nsyms){
3530 error_arch(arch, member, "bad number of externally defined "
3531 "symbols of module table entry %d in: ", i);
3532 return(FALSE);
3534 for(j = iextdefsym; j < iextdefsym + nextdefsym; j++){
3535 if(saves[j] != 0 && changes[j] == 0)
3536 break;
3538 n = 0;
3539 for(k = j; k < iextdefsym + nextdefsym; k++){
3540 if(saves[k] != 0 && changes[k] == 0)
3541 n++;
3543 if(n == 0){
3544 if(object->mh != NULL){
3545 mods[i].iextdefsym = 0;
3546 mods[i].nextdefsym = 0;
3548 else{
3549 mods64[i].iextdefsym = 0;
3550 mods64[i].nextdefsym = 0;
3553 else{
3554 if(object->mh != NULL){
3555 mods[i].iextdefsym = saves[j] - 1;
3556 mods[i].nextdefsym = n;
3558 else{
3559 mods64[i].iextdefsym = saves[j] - 1;
3560 mods64[i].nextdefsym = n;
3564 if(ilocalsym > nsyms){
3565 error_arch(arch, member, "bad index into symbols for local "
3566 "symbols of module table entry %d in: ", i);
3567 return(FALSE);
3569 if(ilocalsym + nlocalsym > nsyms){
3570 error_arch(arch, member, "bad number of local "
3571 "symbols of module table entry %d in: ", i);
3572 return(FALSE);
3574 for(j = ilocalsym; j < ilocalsym + nlocalsym; j++){
3575 if(saves[j] != 0)
3576 break;
3578 n = 0;
3579 for(k = j; k < ilocalsym + nlocalsym; k++){
3580 if(saves[k] != 0)
3581 n++;
3583 if(n == 0){
3584 if(object->mh != NULL){
3585 mods[i].ilocalsym = 0;
3586 mods[i].nlocalsym = 0;
3588 else{
3589 mods64[i].ilocalsym = 0;
3590 mods64[i].nlocalsym = 0;
3593 else{
3594 if(object->mh != NULL){
3595 mods[i].ilocalsym = saves[j] - 1;
3596 mods[i].nlocalsym = n;
3598 else{
3599 mods64[i].ilocalsym = saves[j] - 1;
3600 mods64[i].nlocalsym = n;
3604 if(irefsym > nextrefsyms){
3605 error_arch(arch, member, "bad index into reference table "
3606 "of module table entry %d in: ", i);
3607 return(FALSE);
3609 if(irefsym + nrefsym > nextrefsyms){
3610 error_arch(arch, member, "bad number of reference table "
3611 "entries of module table entry %d in: ", i);
3612 return(FALSE);
3614 for(j = irefsym; j < irefsym + nrefsym; j++){
3615 if(ref_saves[j] != 0)
3616 break;
3618 n = 0;
3619 for(k = j; k < irefsym + nrefsym; k++){
3620 if(ref_saves[k] != 0)
3621 n++;
3623 if(n == 0){
3624 if(object->mh != NULL){
3625 mods[i].irefsym = 0;
3626 mods[i].nrefsym = 0;
3628 else{
3629 mods64[i].irefsym = 0;
3630 mods64[i].nrefsym = 0;
3633 else{
3634 if(object->mh != NULL){
3635 mods[i].irefsym = ref_saves[j] - 1;
3636 mods[i].nrefsym = n;
3638 else{
3639 mods64[i].irefsym = ref_saves[j] - 1;
3640 mods64[i].nrefsym = n;
3646 * Create a new reference table.
3648 new_refs = allocate(new_nextrefsyms * sizeof(struct dylib_reference));
3649 j = 0;
3650 for(i = 0; i < nextrefsyms; i++){
3651 if(ref_saves[i]){
3652 if(saves[refs[i].isym]){
3653 new_refs[j].isym = saves[refs[i].isym] - 1;
3654 new_refs[j].flags = refs[i].flags;
3656 else{
3657 if(refs[i].flags == REFERENCE_FLAG_UNDEFINED_NON_LAZY ||
3658 refs[i].flags == REFERENCE_FLAG_UNDEFINED_LAZY){
3659 new_refs[j].isym = changes[refs[i].isym] - 1;
3660 new_refs[j].flags = refs[i].flags;
3663 j++;
3668 * Create a new dylib table of contents.
3670 new_ntoc = 0;
3671 for(i = 0; i < ntoc; i++){
3672 if(tocs[i].symbol_index >= nsyms){
3673 error_arch(arch, member, "bad symbol index for table of "
3674 "contents table entry %d in: ", i);
3675 return(FALSE);
3677 if(saves[tocs[i].symbol_index] != 0 &&
3678 changes[tocs[i].symbol_index] == 0)
3679 new_ntoc++;
3681 new_tocs = allocate(new_ntoc * sizeof(struct dylib_table_of_contents));
3682 j = 0;
3683 for(i = 0; i < ntoc; i++){
3684 if(saves[tocs[i].symbol_index] != 0 &&
3685 changes[tocs[i].symbol_index] == 0){
3686 new_tocs[j].symbol_index = saves[tocs[i].symbol_index] - 1;
3687 new_tocs[j].module_index = tocs[i].module_index;
3688 j++;
3691 #ifdef TRIE_SUPPORT
3693 * Update the export trie if it has one but only call the the
3694 * prune_trie() routine when we are removing global symbols as is
3695 * done with default stripping of a dyld executable or with the -s
3696 * or -R options.
3698 if(object->dyld_info != NULL &&
3699 object->dyld_info->export_size != 0 &&
3700 (default_dyld_executable || sfile != NULL || Rfile != NULL)){
3701 const char *error_string;
3702 uint32_t trie_new_size;
3704 error_string = prune_trie((uint8_t *)(object->object_addr +
3705 object->dyld_info->export_off),
3706 object->dyld_info->export_size,
3707 prune,
3708 &trie_new_size);
3709 if(error_string != NULL){
3710 error_arch(arch, member, "%s", error_string);
3711 return(FALSE);
3714 #endif /* TRIE_SUPPORT */
3716 if(undef_map != NULL)
3717 free(undef_map);
3718 if(undef_map64 != NULL)
3719 free(undef_map64);
3720 if(changes != NULL)
3721 free(changes);
3722 if(sections != NULL)
3723 free(sections);
3724 if(sections64 != NULL)
3725 free(sections64);
3727 if(errors == 0)
3728 return(TRUE);
3729 else
3730 return(FALSE);
3733 #ifdef TRIE_SUPPORT
3735 * prune() is called by prune_trie() and passed a name of an external symbol
3736 * in the trie. It returns 1 if the symbols is to be pruned out and 0 if the
3737 * symbol is to be kept.
3739 * Note that it may seem like a linear search of the new symbols would not be
3740 * the best approach but in 10.6 the only defined global symbol left in a
3741 * stripped executable is __mh_execute_header and new_nextdefsym is usually 1
3742 * so this never actually loops in practice.
3744 static
3746 prune(
3747 const char *name)
3749 uint32_t i;
3751 for(i = 0; i < new_nextdefsym; i++){
3752 if(new_symbols != NULL){
3753 if(strcmp(name, new_strings + new_symbols[inew_nextdefsym + i]
3754 .n_un.n_strx) == 0)
3755 return(0);
3757 else{
3758 if(strcmp(name, new_strings + new_symbols64[inew_nextdefsym + i]
3759 .n_un.n_strx) == 0)
3760 return(0);
3763 return(1);
3765 #endif /* TRIE_SUPPORT */
3768 * make_ld_r_object() takes the object file contents referenced by the passed
3769 * data structures, writes that to a temporary file, runs "ld -r" plus the
3770 * specified stripping option creating a second temporary file, reads that file
3771 * in and replaces the object file contents with that and resets the variables
3772 * pointing to the symbol, string and indirect tables.
3774 static
3775 void
3776 make_ld_r_object(
3777 struct arch *arch,
3778 struct member *member,
3779 struct object *object)
3781 enum byte_sex host_byte_sex;
3782 char *input_file, *output_file;
3783 int fd;
3784 struct ofile *ld_r_ofile;
3785 struct arch *ld_r_archs;
3786 uint32_t ld_r_narchs, save_errors;
3788 host_byte_sex = get_host_byte_sex();
3791 * Swap the object file back into its bytesex before writing it to the
3792 * temporary file if needed.
3794 if(object->object_byte_sex != host_byte_sex){
3795 if(object->mh != NULL){
3796 if(swap_object_headers(object->mh, object->load_commands) ==
3797 FALSE)
3798 fatal("internal error: swap_object_headers() failed");
3799 swap_nlist(symbols, nsyms, object->object_byte_sex);
3801 else{
3802 if(swap_object_headers(object->mh64, object->load_commands) ==
3803 FALSE)
3804 fatal("internal error: swap_object_headers() failed");
3805 swap_nlist_64(symbols64, nsyms, object->object_byte_sex);
3807 swap_indirect_symbols(indirectsyms, nindirectsyms,
3808 object->object_byte_sex);
3812 * Create an input object file for the ld -r command from the bytes
3813 * of this arch's object file.
3815 input_file = makestr("/tmp/strip.XXXXXX", NULL);
3816 input_file = mktemp(input_file);
3818 if((fd = open(input_file, O_WRONLY|O_CREAT, 0600)) < 0)
3819 system_fatal("can't open temporary file: %s", input_file);
3821 if(write(fd, object->object_addr, object->object_size) !=
3822 object->object_size)
3823 system_fatal("can't write temporary file: %s", input_file);
3825 if(close(fd) == -1)
3826 system_fatal("can't close temporary file: %s", input_file);
3829 * Create a temporary name for the output file of the ld -r
3831 output_file = makestr("/tmp/strip.XXXXXX", NULL);
3832 output_file = mktemp(output_file);
3835 * Create the ld -r command line and execute it.
3837 reset_execute_list();
3838 add_execute_list("ld");
3839 add_execute_list("-keep_private_externs");
3840 add_execute_list("-r");
3841 if(Sflag)
3842 add_execute_list("-S");
3843 if(xflag)
3844 add_execute_list("-x");
3845 add_execute_list(input_file);
3846 add_execute_list("-o");
3847 add_execute_list(output_file);
3848 if(sfile != NULL){
3849 add_execute_list("-x");
3850 add_execute_list("-exported_symbols_list");
3851 add_execute_list(sfile);
3853 if(Rfile != NULL){
3854 add_execute_list("-unexported_symbols_list");
3855 add_execute_list(Rfile);
3857 if(execute_list(vflag) == 0)
3858 fatal("internal link edit command failed");
3860 save_errors = errors;
3861 errors = 0;
3862 /* breakout the output file of the ld -f for processing */
3863 ld_r_ofile = breakout(output_file, &ld_r_archs, &ld_r_narchs, FALSE);
3864 if(errors)
3865 goto make_ld_r_object_cleanup;
3867 /* checkout the file for symbol table replacement processing */
3868 checkout(ld_r_archs, ld_r_narchs);
3871 * Make sure the output of the ld -r is an object file with one arch.
3873 if(ld_r_narchs != 1 ||
3874 ld_r_archs->type != OFILE_Mach_O ||
3875 ld_r_archs->object == NULL ||
3876 ld_r_archs->object->mh_filetype != MH_OBJECT)
3877 fatal("internal link edit command failed to produce a thin Mach-O "
3878 "object file");
3881 * Now reset all the data of the input object with the ld -r output
3882 * object file.
3884 nsyms = ld_r_archs->object->st->nsyms;
3885 if(ld_r_archs->object->mh != NULL){
3886 symbols = (struct nlist *)
3887 (ld_r_archs->object->object_addr +
3888 ld_r_archs->object->st->symoff);
3889 if(ld_r_archs->object->object_byte_sex != host_byte_sex)
3890 swap_nlist(symbols, nsyms, host_byte_sex);
3891 symbols64 = NULL;
3893 else{
3894 symbols = NULL;
3895 symbols64 = (struct nlist_64 *)
3896 (ld_r_archs->object->object_addr +
3897 ld_r_archs->object->st->symoff);
3898 if(ld_r_archs->object->object_byte_sex != host_byte_sex)
3899 swap_nlist_64(symbols64, nsyms, host_byte_sex);
3901 strings = ld_r_archs->object->object_addr +
3902 ld_r_archs->object->st->stroff;
3903 strsize = ld_r_archs->object->st->strsize;
3905 if(ld_r_archs->object->dyst != NULL &&
3906 ld_r_archs->object->dyst->nindirectsyms != 0){
3907 nindirectsyms = ld_r_archs->object->dyst->nindirectsyms;
3908 indirectsyms = (uint32_t *)
3909 (ld_r_archs->object->object_addr +
3910 ld_r_archs->object->dyst->indirectsymoff);
3911 if(ld_r_archs->object->object_byte_sex != host_byte_sex)
3912 swap_indirect_symbols(indirectsyms, nindirectsyms,
3913 host_byte_sex);
3915 else{
3916 indirectsyms = NULL;
3917 nindirectsyms = 0;
3920 if(ld_r_archs->object->mh != NULL)
3921 ld_r_archs->object->input_sym_info_size =
3922 nsyms * sizeof(struct nlist) +
3923 strsize;
3924 else
3925 ld_r_archs->object->input_sym_info_size =
3926 nsyms * sizeof(struct nlist_64) +
3927 strsize;
3930 * Copy over the object struct from the ld -r object file onto the
3931 * input object file.
3933 *object = *ld_r_archs->object;
3936 * Save the ofile struct for the ld -r output so it can be umapped when
3937 * we are done. And free up the ld_r_archs now that we are done with
3938 * them.
3940 object->ld_r_ofile = ld_r_ofile;
3941 free_archs(ld_r_archs, ld_r_narchs);
3943 make_ld_r_object_cleanup:
3944 errors += save_errors;
3946 * Remove the input and output files and clean up.
3948 if(unlink(input_file) == -1)
3949 system_fatal("can't remove temporary file: %s", input_file);
3950 if(unlink(output_file) == -1)
3951 system_fatal("can't remove temporary file: %s", output_file);
3952 free(input_file);
3953 free(output_file);
3957 * strip_LC_UUID_commands() is called when -no_uuid is specified to remove any
3958 * LC_UUID load commands from the object's load commands.
3960 static
3961 void
3962 strip_LC_UUID_commands(
3963 struct arch *arch,
3964 struct member *member,
3965 struct object *object)
3967 uint32_t i, ncmds, nuuids, mh_sizeofcmds, sizeofcmds;
3968 struct load_command *lc1, *lc2, *new_load_commands;
3969 struct segment_command *sg;
3972 * See if there are any LC_UUID load commands.
3974 nuuids = 0;
3975 lc1 = arch->object->load_commands;
3976 if(arch->object->mh != NULL){
3977 ncmds = arch->object->mh->ncmds;
3978 mh_sizeofcmds = arch->object->mh->sizeofcmds;
3980 else{
3981 ncmds = arch->object->mh64->ncmds;
3982 mh_sizeofcmds = arch->object->mh64->sizeofcmds;
3984 for(i = 0; i < ncmds; i++){
3985 if(lc1->cmd == LC_UUID){
3986 nuuids++;
3988 lc1 = (struct load_command *)((char *)lc1 + lc1->cmdsize);
3990 /* if no LC_UUID load commands just return */
3991 if(nuuids == 0)
3992 return;
3995 * Allocate space for the new load commands as zero it out so any holes
3996 * will be zero bytes.
3998 new_load_commands = allocate(mh_sizeofcmds);
3999 memset(new_load_commands, '\0', mh_sizeofcmds);
4002 * Copy all the load commands except the LC_UUID load commands into the
4003 * allocated space for the new load commands.
4005 lc1 = arch->object->load_commands;
4006 lc2 = new_load_commands;
4007 sizeofcmds = 0;
4008 for(i = 0; i < ncmds; i++){
4009 if(lc1->cmd != LC_UUID){
4010 memcpy(lc2, lc1, lc1->cmdsize);
4011 sizeofcmds += lc2->cmdsize;
4012 lc2 = (struct load_command *)((char *)lc2 + lc2->cmdsize);
4014 lc1 = (struct load_command *)((char *)lc1 + lc1->cmdsize);
4018 * Finally copy the updated load commands over the existing load
4019 * commands.
4021 memcpy(arch->object->load_commands, new_load_commands, sizeofcmds);
4022 if(mh_sizeofcmds > sizeofcmds){
4023 memset((char *)arch->object->load_commands + sizeofcmds, '\0',
4024 (mh_sizeofcmds - sizeofcmds));
4026 ncmds -= nuuids;
4027 if(arch->object->mh != NULL) {
4028 arch->object->mh->sizeofcmds = sizeofcmds;
4029 arch->object->mh->ncmds = ncmds;
4030 } else {
4031 arch->object->mh64->sizeofcmds = sizeofcmds;
4032 arch->object->mh64->ncmds = ncmds;
4034 free(new_load_commands);
4036 /* reset the pointers into the load commands */
4037 lc1 = arch->object->load_commands;
4038 for(i = 0; i < ncmds; i++){
4039 switch(lc1->cmd){
4040 case LC_SYMTAB:
4041 arch->object->st = (struct symtab_command *)lc1;
4042 break;
4043 case LC_DYSYMTAB:
4044 arch->object->dyst = (struct dysymtab_command *)lc1;
4045 break;
4046 case LC_TWOLEVEL_HINTS:
4047 arch->object->hints_cmd = (struct twolevel_hints_command *)lc1;
4048 break;
4049 case LC_PREBIND_CKSUM:
4050 arch->object->cs = (struct prebind_cksum_command *)lc1;
4051 break;
4052 case LC_SEGMENT:
4053 sg = (struct segment_command *)lc1;
4054 if(strcmp(sg->segname, SEG_LINKEDIT) == 0)
4055 arch->object->seg_linkedit = sg;
4056 break;
4057 case LC_SEGMENT_SPLIT_INFO:
4058 object->split_info_cmd = (struct linkedit_data_command *)lc1;
4059 break;
4060 case LC_CODE_SIGNATURE:
4061 object->code_sig_cmd = (struct linkedit_data_command *)lc1;
4062 break;
4063 case LC_DYLD_INFO_ONLY:
4064 case LC_DYLD_INFO:
4065 object->dyld_info = (struct dyld_info_command *)lc1;
4067 lc1 = (struct load_command *)((char *)lc1 + lc1->cmdsize);
4071 #ifndef NMEDIT
4073 * strip_LC_CODE_SIGNATURE_commands() is called when -c is specified to remove
4074 * any LC_CODE_SIGNATURE load commands from the object's load commands.
4076 static
4077 void
4078 strip_LC_CODE_SIGNATURE_commands(
4079 struct arch *arch,
4080 struct member *member,
4081 struct object *object)
4083 uint32_t i, ncmds, mh_sizeofcmds, sizeofcmds;
4084 struct load_command *lc1, *lc2, *new_load_commands;
4085 struct segment_command *sg;
4088 * See if there is an LC_CODE_SIGNATURE load command and if no command
4089 * just return.
4091 if(object->code_sig_cmd == NULL)
4092 return;
4095 * Allocate space for the new load commands and zero it out so any holes
4096 * will be zero bytes.
4098 if(arch->object->mh != NULL){
4099 ncmds = arch->object->mh->ncmds;
4100 mh_sizeofcmds = arch->object->mh->sizeofcmds;
4102 else{
4103 ncmds = arch->object->mh64->ncmds;
4104 mh_sizeofcmds = arch->object->mh64->sizeofcmds;
4106 new_load_commands = allocate(mh_sizeofcmds);
4107 memset(new_load_commands, '\0', mh_sizeofcmds);
4110 * Copy all the load commands except the LC_CODE_SIGNATURE load commands
4111 * into the allocated space for the new load commands.
4113 lc1 = arch->object->load_commands;
4114 lc2 = new_load_commands;
4115 sizeofcmds = 0;
4116 for(i = 0; i < ncmds; i++){
4117 if(lc1->cmd != LC_CODE_SIGNATURE){
4118 memcpy(lc2, lc1, lc1->cmdsize);
4119 sizeofcmds += lc2->cmdsize;
4120 lc2 = (struct load_command *)((char *)lc2 + lc2->cmdsize);
4122 lc1 = (struct load_command *)((char *)lc1 + lc1->cmdsize);
4126 * Finally copy the updated load commands over the existing load
4127 * commands.
4129 memcpy(arch->object->load_commands, new_load_commands, sizeofcmds);
4130 if(mh_sizeofcmds > sizeofcmds){
4131 memset((char *)arch->object->load_commands + sizeofcmds, '\0',
4132 (mh_sizeofcmds - sizeofcmds));
4134 ncmds -= 1;
4135 if(arch->object->mh != NULL) {
4136 arch->object->mh->sizeofcmds = sizeofcmds;
4137 arch->object->mh->ncmds = ncmds;
4138 } else {
4139 arch->object->mh64->sizeofcmds = sizeofcmds;
4140 arch->object->mh64->ncmds = ncmds;
4142 free(new_load_commands);
4144 /* reset the pointers into the load commands */
4145 object->code_sig_cmd = NULL;
4146 lc1 = arch->object->load_commands;
4147 for(i = 0; i < ncmds; i++){
4148 switch(lc1->cmd){
4149 case LC_SYMTAB:
4150 arch->object->st = (struct symtab_command *)lc1;
4151 break;
4152 case LC_DYSYMTAB:
4153 arch->object->dyst = (struct dysymtab_command *)lc1;
4154 break;
4155 case LC_TWOLEVEL_HINTS:
4156 arch->object->hints_cmd = (struct twolevel_hints_command *)lc1;
4157 break;
4158 case LC_PREBIND_CKSUM:
4159 arch->object->cs = (struct prebind_cksum_command *)lc1;
4160 break;
4161 case LC_SEGMENT:
4162 sg = (struct segment_command *)lc1;
4163 if(strcmp(sg->segname, SEG_LINKEDIT) == 0)
4164 arch->object->seg_linkedit = sg;
4165 break;
4166 case LC_SEGMENT_SPLIT_INFO:
4167 object->split_info_cmd = (struct linkedit_data_command *)lc1;
4168 break;
4170 lc1 = (struct load_command *)((char *)lc1 + lc1->cmdsize);
4173 if(cflag){
4175 * To get the right amount of the file copied out by writeout() for
4176 * the case when we are stripping out the section contents we
4177 * already reduce the object size by the size of the section
4178 * contents including the padding after the load commands. So here
4179 * we need to further reduce it by the load command for the
4180 * LC_CODE_SIGNATURE (a struct linkedit_data_command) we are
4181 * removing.
4183 object->object_size -= sizeof(struct linkedit_data_command);
4185 * Then this size minus the size of the input symbolic information
4186 * is what is copied out from the file by writeout(). Which in this
4187 * case is just the new headers.
4191 * Finally for -c the file offset to the link edit information is to
4192 * be right after the load commands. So reset this for the updated
4193 * size of the load commands without the LC_CODE_SIGNATURE.
4195 if(object->mh != NULL)
4196 object->seg_linkedit->fileoff = sizeof(struct mach_header) +
4197 sizeofcmds;
4198 else
4199 object->seg_linkedit64->fileoff =
4200 sizeof(struct mach_header_64) + sizeofcmds;
4203 #endif /* !(NMEDIT) */
4206 * private_extern_reference_by_module() is passed a symbol_index of a private
4207 * extern symbol and the module table. If the symbol_index appears in the
4208 * module symbol table this returns TRUE else it returns FALSE.
4210 static
4211 enum bool
4212 private_extern_reference_by_module(
4213 uint32_t symbol_index,
4214 struct dylib_reference *refs,
4215 uint32_t nextrefsyms)
4217 uint32_t i;
4219 for(i = 0; i < nextrefsyms; i++){
4220 if(refs[i].isym == symbol_index){
4221 if(refs[i].flags == REFERENCE_FLAG_PRIVATE_UNDEFINED_NON_LAZY ||
4222 refs[i].flags == REFERENCE_FLAG_PRIVATE_UNDEFINED_LAZY){
4223 return(TRUE);
4227 return(FALSE);
4231 * symbol_pointer_used() is passed a symbol_index and the indirect table. If
4232 * the symbol_index appears in the indirect symbol table this returns TRUE else
4233 * it returns FALSE.
4235 static
4236 enum bool
4237 symbol_pointer_used(
4238 uint32_t symbol_index,
4239 uint32_t *indirectsyms,
4240 uint32_t nindirectsyms)
4242 uint32_t i;
4244 for(i = 0; i < nindirectsyms; i++){
4245 if(indirectsyms[i] == symbol_index)
4246 return(TRUE);
4248 return(FALSE);
4252 * Function for qsort for comparing undefined map entries.
4254 static
4256 cmp_qsort_undef_map(
4257 const struct undef_map *sym1,
4258 const struct undef_map *sym2)
4260 return(strcmp(qsort_strings + sym1->symbol.n_un.n_strx,
4261 qsort_strings + sym2->symbol.n_un.n_strx));
4264 static
4266 cmp_qsort_undef_map_64(
4267 const struct undef_map64 *sym1,
4268 const struct undef_map64 *sym2)
4270 return(strcmp(qsort_strings + sym1->symbol64.n_un.n_strx,
4271 qsort_strings + sym2->symbol64.n_un.n_strx));
4273 #endif /* !defined(NMEDIT) */
4275 #ifndef NMEDIT
4277 * Function for qsort for comparing object names.
4279 static
4281 cmp_qsort_filename(
4282 const char **name1,
4283 const char **name2)
4285 return(strcmp(*name1, *name2));
4289 * Function for bsearch for finding a object name.
4291 static
4293 cmp_bsearch_filename(
4294 const char *name1,
4295 const char **name2)
4297 return(strcmp(name1, *name2));
4299 #endif /* !defined(NMEDIT) */
4301 #ifdef NMEDIT
4302 static
4303 enum bool
4304 edit_symtab(
4305 struct arch *arch,
4306 struct member *member,
4307 struct object *object,
4308 struct nlist *symbols,
4309 struct nlist_64 *symbols64,
4310 uint32_t nsyms,
4311 char *strings,
4312 uint32_t strsize,
4313 struct dylib_table_of_contents *tocs,
4314 uint32_t ntoc,
4315 struct dylib_module *mods,
4316 struct dylib_module_64 *mods64,
4317 uint32_t nmodtab,
4318 struct dylib_reference *refs,
4319 uint32_t nextrefsyms)
4321 uint32_t i, j, k;
4322 unsigned char data_n_sect, nsects;
4323 struct load_command *lc;
4324 struct segment_command *sg;
4325 struct segment_command_64 *sg64;
4326 struct section *s, **sections;
4327 struct section_64 *s64, **sections64;
4329 uint32_t missing_syms;
4330 struct symbol_list *sp;
4331 struct nlist **global_symbol;
4332 struct nlist_64 **global_symbol64;
4333 enum bool global_symbol_found;
4334 char *global_name, save_char;
4335 enum bool dwarf_debug_map;
4336 enum byte_sex host_byte_sex;
4337 int32_t missing_reloc_symbols;
4338 enum bool edit_symtab_return;
4340 char *p, *q;
4341 uint32_t new_ext_strsize, len, inew_syms;
4343 struct nlist **changed_globals;
4344 struct nlist_64 **changed_globals64;
4345 uint32_t nchanged_globals;
4346 uint32_t ncmds, s_flags, n_strx, module_name, ilocalsym, nlocalsym;
4347 uint32_t iextdefsym, nextdefsym;
4348 uint8_t n_type, n_sect, global_symbol_n_sect;
4349 uint64_t n_value;
4350 enum bool warned_about_global_coalesced_symbols;
4352 edit_symtab_return = TRUE;
4353 host_byte_sex = get_host_byte_sex();
4354 missing_reloc_symbols = 0;
4355 warned_about_global_coalesced_symbols = FALSE;
4357 if(nmedits != NULL)
4358 free(nmedits);
4359 nmedits = allocate(nsyms * sizeof(enum bool));
4360 for(i = 0; i < nsyms; i++)
4361 nmedits[i] = FALSE;
4364 * If nmedit is operating on a dynamic library then symbols are turned
4365 * into private externs with the extern bit off not into static symbols.
4367 if(object->mh_filetype == MH_DYLIB && pflag == TRUE){
4368 error_arch(arch, member, "can't use -p with dynamic libraries");
4369 return(FALSE);
4373 * As part of the MAJOR guess for the second pass to fix stabs for the
4374 * globals symbols that get turned into non-global symbols. We need to
4375 * change the stabs. To do this we to know if a N_GSYM is for a data
4376 * symbol or not to know to turn it into an N_STSYM or a N_FUN.
4377 * This logic as determined by compiling test cases with and without
4378 * the key word 'static' and looking at the difference between the STABS
4379 * the compiler generates and trying to match that here.
4381 * We also use this loop and the next to gather an array of section
4382 * struct pointers so we can later determine if we run into a global
4383 * symbol in a coalesced section and not turn those symbols into
4384 * statics.
4386 j = 0;
4387 nsects = 0;
4388 n_sect = 1;
4389 data_n_sect = NO_SECT;
4390 lc = object->load_commands;
4391 if(object->mh != NULL)
4392 ncmds = object->mh->ncmds;
4393 else
4394 ncmds = object->mh64->ncmds;
4395 for(i = 0; i < ncmds; i++){
4396 if(lc->cmd == LC_SEGMENT){
4397 sg = (struct segment_command *)lc;
4398 s = (struct section *)((char *)sg +
4399 sizeof(struct segment_command));
4400 nsects += sg->nsects;
4401 for(j = 0; j < sg->nsects; j++){
4402 if(strcmp(s->segname, SEG_DATA) == 0 &&
4403 strcmp(s->sectname, SECT_DATA) == 0 &&
4404 data_n_sect == NO_SECT){
4405 data_n_sect = n_sect;
4406 break;
4408 n_sect++;
4409 s++;
4412 else if(lc->cmd == LC_SEGMENT_64){
4413 sg64 = (struct segment_command_64 *)lc;
4414 s64 = (struct section_64 *)((char *)sg64 +
4415 sizeof(struct segment_command_64));
4416 nsects += sg64->nsects;
4417 for(j = 0; j < sg64->nsects; j++){
4418 if(strcmp(s64->segname, SEG_DATA) == 0 &&
4419 strcmp(s64->sectname, SECT_DATA) == 0 &&
4420 data_n_sect == NO_SECT){
4421 data_n_sect = n_sect;
4422 break;
4424 n_sect++;
4425 s64++;
4428 lc = (struct load_command *)((char *)lc + lc->cmdsize);
4430 if(object->mh != NULL){
4431 sections = allocate(nsects * sizeof(struct section *));
4432 sections64 = NULL;
4434 else{
4435 sections = NULL;
4436 sections64 = allocate(nsects * sizeof(struct section_64 *));
4438 nsects = 0;
4439 lc = object->load_commands;
4440 for(i = 0; i < ncmds; i++){
4441 if(lc->cmd == LC_SEGMENT){
4442 sg = (struct segment_command *)lc;
4443 s = (struct section *)((char *)sg +
4444 sizeof(struct segment_command));
4445 for(j = 0; j < sg->nsects; j++){
4446 sections[nsects++] = s++;
4449 else if(lc->cmd == LC_SEGMENT_64){
4450 sg64 = (struct segment_command_64 *)lc;
4451 s64 = (struct section_64 *)((char *)sg64 +
4452 sizeof(struct segment_command_64));
4453 for(j = 0; j < sg64->nsects; j++){
4454 sections64[nsects++] = s64++;
4457 lc = (struct load_command *)((char *)lc + lc->cmdsize);
4461 * Zero out the saved symbols so they can be recorded for this file.
4463 for(i = 0; i < nsave_symbols; i++)
4464 save_symbols[i].sym = NULL;
4465 for(i = 0; i < nremove_symbols; i++)
4466 remove_symbols[i].sym = NULL;
4467 if(member == NULL){
4468 for(i = 0; i < nsave_symbols; i++)
4469 save_symbols[i].seen = FALSE;
4470 for(i = 0; i < nremove_symbols; i++)
4471 remove_symbols[i].seen = FALSE;
4474 nchanged_globals = 0;
4475 if(object->mh != NULL){
4476 changed_globals = allocate(nsyms * sizeof(struct nlist *));
4477 changed_globals64 = NULL;
4478 for(i = 0; i < nsyms; i++)
4479 changed_globals[i] = NULL;
4481 else{
4482 changed_globals = NULL;
4483 changed_globals64 = allocate(nsyms * sizeof(struct nlist_64 *));
4484 for(i = 0; i < nsyms; i++)
4485 changed_globals64[i] = NULL;
4489 * These are the variables for the new symbol table and new string
4490 * table. Since this routine only turns globals into non-globals the
4491 * number of symbols does not change. But the count of local, defined
4492 * external symbols does change.
4494 new_nsyms = nsyms;
4495 new_nlocalsym = 0;
4496 new_nextdefsym = 0;
4497 new_nundefsym = 0;
4499 new_strsize = sizeof(int32_t);
4500 new_ext_strsize = 0;
4503 * First pass: turn the globals symbols into non-global symbols.
4505 for(i = 0; i < nsyms; i++){
4506 len = 0;
4507 s_flags = 0;
4508 if(object->mh != NULL){
4509 n_strx = symbols[i].n_un.n_strx;
4510 n_type = symbols[i].n_type;
4511 n_sect = symbols[i].n_sect;
4512 if((n_type & N_TYPE) == N_SECT)
4513 s_flags = sections[n_sect - 1]->flags;
4514 n_value = symbols[i].n_value;
4516 else{
4517 n_strx = symbols64[i].n_un.n_strx;
4518 n_type = symbols64[i].n_type;
4519 n_sect = symbols64[i].n_sect;
4520 if((n_type & N_TYPE) == N_SECT)
4521 s_flags = sections64[n_sect - 1]->flags;
4522 n_value = symbols64[i].n_value;
4524 if(n_strx != 0){
4525 if(n_strx > strsize){
4526 error_arch(arch, member, "bad string index for symbol "
4527 "table entry %u in: ", i);
4528 return(FALSE);
4530 len = strlen(strings + n_strx) + 1;
4532 if(n_type & N_EXT){
4533 if((n_type & N_TYPE) != N_UNDF &&
4534 (n_type & N_TYPE) != N_PBUD){
4535 if((n_type & N_TYPE) == N_SECT){
4536 if(n_sect > nsects){
4537 error_arch(arch, member, "bad n_sect for symbol "
4538 "table entry %u in: ", i);
4539 return(FALSE);
4541 if(((s_flags & SECTION_TYPE) == S_COALESCED) &&
4542 pflag == FALSE &&
4543 object->mh_filetype != MH_OBJECT){
4544 /* this remains a global defined symbol */
4545 if(warned_about_global_coalesced_symbols == FALSE){
4546 warning_arch(arch, member, "can't make global "
4547 "coalesced symbols (like %s) into static "
4548 "symbols (use ld(1)'s "
4549 "-exported_symbols_list option) in a final "
4550 "linked image: ", strings + n_strx);
4551 warned_about_global_coalesced_symbols = TRUE;
4553 new_nextdefsym++;
4554 new_ext_strsize += len;
4555 new_strsize += len;
4556 sp = bsearch(strings + n_strx,
4557 remove_symbols, nremove_symbols,
4558 sizeof(struct symbol_list),
4559 (int (*)(const void *, const void *))
4560 symbol_list_bsearch);
4561 if(sp != NULL){
4562 if(sp->sym != NULL){
4563 error_arch(arch, member, "more than one "
4564 "symbol for: %s found in: ", sp->name);
4565 return(FALSE);
4567 else{
4568 if(object->mh != NULL)
4569 sp->sym = &(symbols[i]);
4570 else
4571 sp->sym = &(symbols64[i]);
4572 sp->seen = TRUE;
4573 warning_arch(arch, member, "can't make "
4574 "global coalesced symbol: %s into a "
4575 "static symbol in: ", sp->name);
4579 * In case the user has listed this coalesced
4580 * symbol in the save list look for it and mark it
4581 * as seen so we don't complain about not seeing it.
4583 sp = bsearch(strings + n_strx,
4584 save_symbols, nsave_symbols,
4585 sizeof(struct symbol_list),
4586 (int (*)(const void *, const void *))
4587 symbol_list_bsearch);
4588 if(sp != NULL){
4589 if(sp->sym != NULL){
4590 error_arch(arch, member, "more than one "
4591 "symbol for: %s found in: ", sp->name);
4592 return(FALSE);
4594 else{
4595 if(object->mh != NULL)
4596 sp->sym = &(symbols[i]);
4597 else
4598 sp->sym = &(symbols64[i]);
4599 sp->seen = TRUE;
4602 continue; /* leave this symbol unchanged */
4605 sp = bsearch(strings + n_strx,
4606 remove_symbols, nremove_symbols,
4607 sizeof(struct symbol_list),
4608 (int (*)(const void *, const void *))
4609 symbol_list_bsearch);
4610 if(sp != NULL){
4611 if(sp->sym != NULL){
4612 error_arch(arch, member, "more than one symbol "
4613 "for: %s found in: ", sp->name);
4614 return(FALSE);
4616 else{
4617 if(object->mh != NULL)
4618 sp->sym = &(symbols[i]);
4619 else
4620 sp->sym = &(symbols64[i]);
4621 sp->seen = TRUE;
4622 goto change_symbol;
4625 else{
4627 * If there is no list of saved symbols, then all
4628 * symbols will be saved unless listed in the remove
4629 * list.
4631 if(sfile == NULL){
4633 * There is no save list, so if there is also no
4634 * remove list but the -p flag is specified or it is
4635 * a dynamic library then change all symbols.
4637 if((pflag || object->mh_filetype == MH_DYLIB)
4638 && nremove_symbols == 0)
4639 goto change_symbol;
4640 /* this remains a global defined symbol */
4641 new_nextdefsym++;
4642 new_ext_strsize += len;
4643 new_strsize += len;
4644 continue; /* leave this symbol unchanged */
4647 sp = bsearch(strings + n_strx,
4648 save_symbols, nsave_symbols,
4649 sizeof(struct symbol_list),
4650 (int (*)(const void *, const void *))
4651 symbol_list_bsearch);
4652 if(sp != NULL){
4653 if(sp->sym != NULL){
4654 error_arch(arch, member, "more than one symbol "
4655 "for: %s found in: ", sp->name);
4656 return(FALSE);
4658 else{
4659 if(object->mh != NULL)
4660 sp->sym = &(symbols[i]);
4661 else
4662 sp->sym = &(symbols64[i]);
4663 sp->seen = TRUE;
4664 /* this remains a global defined symbol */
4665 new_nextdefsym++;
4666 new_ext_strsize += len;
4667 new_strsize += len;
4670 else{
4671 if(Aflag && n_type == (N_EXT | N_ABS) &&
4672 (n_value != 0 ||
4673 (n_strx != 0 &&
4674 strncmp(strings + n_strx,
4675 ".objc_class_name_",
4676 sizeof(".objc_class_name_") - 1) == 0))){
4677 /* this remains a global defined symbol */
4678 new_nextdefsym++;
4679 new_ext_strsize += len;
4680 new_strsize += len;
4682 else{
4683 change_symbol:
4684 if((n_type & N_TYPE) != N_INDR){
4685 nmedits[i] = TRUE;
4686 if(object->mh != NULL)
4687 changed_globals[nchanged_globals++] =
4688 symbols + i;
4689 else
4690 changed_globals64[nchanged_globals++] =
4691 symbols64 + i;
4692 if(pflag){
4693 /* this remains a global defined symbol */
4694 new_nextdefsym++;
4695 new_ext_strsize += len;
4696 new_strsize += len;
4698 else{
4699 /* this will become a non-global symbol */
4700 new_nlocalsym++;
4701 new_strsize += len;
4704 else{
4705 /* this remains a global defined symbol */
4706 new_nextdefsym++;
4707 new_ext_strsize += len;
4708 new_strsize += len;
4713 else{
4714 /* this is an undefined symbol */
4715 new_nundefsym++;
4716 new_ext_strsize += len;
4717 new_strsize += len;
4720 else{
4721 /* this is a local symbol */
4722 new_nlocalsym++;
4723 new_strsize += len;
4728 * The module table's module names are placed with the external
4729 * strings. So size them and add this to the external string size.
4731 for(i = 0; i < nmodtab; i++){
4732 if(object->mh != NULL)
4733 module_name = mods[i].module_name;
4734 else
4735 module_name = mods64[i].module_name;
4736 if(module_name == 0 || module_name > strsize){
4737 error_arch(arch, member, "bad string index for module_name "
4738 "of module table entry %d in: ", i);
4739 return(FALSE);
4741 len = strlen(strings + module_name) + 1;
4742 new_strsize += len;
4743 new_ext_strsize += len;
4747 * Warn about symbols to be saved that were missing.
4749 if(member == NULL){
4750 missing_syms = 0;
4751 if(iflag == 0){
4752 for(i = 0; i < nsave_symbols; i++){
4753 if(save_symbols[i].sym == NULL){
4754 if(missing_syms == 0){
4755 error_arch(arch, member, "symbols names listed "
4756 "in: %s not in: ", sfile);
4757 missing_syms = 1;
4759 fprintf(stderr, "%s\n", save_symbols[i].name);
4762 for(i = 0; i < nremove_symbols; i++){
4763 if(remove_symbols[i].sym == NULL){
4764 if(missing_syms == 0){
4765 error_arch(arch, member, "symbols names listed "
4766 "in: %s not in: ", Rfile);
4767 missing_syms = 1;
4769 fprintf(stderr, "%s\n", remove_symbols[i].name);
4776 * Second pass: fix stabs for the globals symbols that got turned into
4777 * non-global symbols. This is a MAJOR guess. The specific changes
4778 * to do here were determined by compiling test cases with and without
4779 * the key word 'static' and looking at the difference between the STABS
4780 * the compiler generates and trying to match that here.
4782 global_strings = strings;
4783 if(object->mh != NULL)
4784 qsort(changed_globals, nchanged_globals, sizeof(struct nlist *),
4785 (int (*)(const void *, const void *))cmp_qsort_global);
4786 else
4787 qsort(changed_globals64, nchanged_globals,sizeof(struct nlist_64 *),
4788 (int (*)(const void *, const void *))cmp_qsort_global_64);
4789 dwarf_debug_map = FALSE;
4790 for(i = 0; i < nsyms; i++){
4791 uint16_t n_desc;
4792 if(object->mh != NULL){
4793 n_strx = symbols[i].n_un.n_strx;
4794 n_type = symbols[i].n_type;
4795 n_desc = symbols[i].n_desc;
4797 else{
4798 n_strx = symbols64[i].n_un.n_strx;
4799 n_type = symbols64[i].n_type;
4800 n_desc = symbols64[i].n_desc;
4802 if(n_type == N_SO)
4803 dwarf_debug_map = FALSE;
4804 else if (n_type == N_OSO)
4805 dwarf_debug_map = n_desc != 0;
4806 else if (dwarf_debug_map && n_type == N_GSYM){
4807 global_name = strings + n_strx;
4808 if(object->mh != NULL){
4809 global_symbol = bsearch(global_name, changed_globals,
4810 nchanged_globals,sizeof(struct nlist *),
4811 (int (*)(const void *, const void *))
4812 cmp_bsearch_global);
4813 if(global_symbol != NULL){
4814 symbols[i].n_type = N_STSYM;
4815 symbols[i].n_sect = (*global_symbol)->n_sect;
4816 symbols[i].n_value = (*global_symbol)->n_value;
4819 else{
4820 global_symbol64 = bsearch(global_name, changed_globals64,
4821 nchanged_globals,
4822 sizeof(struct nlist_64 *),
4823 (int (*)(const void *, const void *))
4824 cmp_bsearch_global_64);
4825 if(global_symbol64 != NULL){
4826 symbols64[i].n_type = N_STSYM;
4827 symbols64[i].n_sect = (*global_symbol64)->n_sect;
4828 symbols64[i].n_value = (*global_symbol64)->n_value;
4832 else if(! dwarf_debug_map &&
4833 (n_type == N_GSYM || n_type == N_FUN) &&
4834 (n_strx != 0 && strings[n_strx] != '\0')){
4835 global_name = strings + n_strx;
4836 if((global_name[0] == '+' || global_name[0] == '-') &&
4837 global_name[1] == '['){
4838 j = 2;
4839 while(j + n_strx < strsize && global_name[j] != ']')
4840 j++;
4841 if(j + n_strx < strsize && global_name[j] == ']')
4842 j++;
4844 else
4845 j = 0;
4846 while(j + n_strx < strsize && global_name[j] != ':')
4847 j++;
4848 if(j + n_strx >= strsize){
4849 error_arch(arch, member, "bad N_STAB symbol name for entry "
4850 "%u (does not contain ':' separating name from type) "
4851 "in: ", i);
4852 return(FALSE);
4854 save_char = global_name[j];
4855 global_name[j] = '\0';
4857 global_symbol_found = FALSE;
4858 global_symbol_n_sect = 0;
4859 if(object->mh != NULL){
4860 global_symbol = bsearch(global_name, changed_globals,
4861 nchanged_globals,sizeof(struct nlist *),
4862 (int (*)(const void *, const void *))
4863 cmp_bsearch_global_stab);
4864 global_symbol64 = NULL;
4865 if(global_symbol != NULL){
4866 global_symbol_found = TRUE;
4867 global_symbol_n_sect = (*global_symbol)->n_sect;
4870 else{
4871 global_symbol64 = bsearch(global_name, changed_globals64,
4872 nchanged_globals,
4873 sizeof(struct nlist_64 *),
4874 (int (*)(const void *, const void *))
4875 cmp_bsearch_global_stab_64);
4876 global_symbol = NULL;
4877 if(global_symbol64 != NULL){
4878 global_symbol_found = TRUE;
4879 global_symbol_n_sect = (*global_symbol64)->n_sect;
4882 global_name[j] = save_char;
4883 if(global_symbol_found == TRUE){
4884 if(n_type == N_GSYM){
4885 if(global_symbol_n_sect == data_n_sect){
4886 if(object->mh != NULL)
4887 symbols[i].n_type = N_STSYM;
4888 else
4889 symbols64[i].n_type = N_STSYM;
4891 else{
4892 if(object->mh != NULL)
4893 symbols[i].n_type = N_FUN;
4894 else
4895 symbols64[i].n_type = N_FUN;
4897 if(object->mh != NULL){
4898 symbols[i].n_sect = (*global_symbol)->n_sect;
4899 symbols[i].n_value = (*global_symbol)->n_value;
4900 symbols[i].n_desc = (*global_symbol)->n_desc;
4902 else{
4903 symbols64[i].n_sect = (*global_symbol64)->n_sect;
4904 symbols64[i].n_value = (*global_symbol64)->n_value;
4905 symbols64[i].n_desc = (*global_symbol64)->n_desc;
4907 if(j + 1 + n_strx >= strsize ||
4908 global_name[j+1] != 'G'){
4909 error_arch(arch, member, "bad N_GSYM symbol name "
4910 "for entry %u (does not have type 'G' after "
4911 "':' in name) in: ", i);
4912 return(FALSE);
4914 global_name[j+1] = 'S';
4916 else{ /* n_type == N_FUN */
4917 if(j + 1 + n_strx >= strsize ||
4918 global_name[j+1] == 'F'){
4919 global_name[j+1] = 'f';
4925 global_strings = NULL;
4928 * Now what needs to be done is to create the new symbol table moving
4929 * those global symbols being changed into non-globals into the areas
4930 * in the symbol table for local symbols. The symbol table and string
4931 * table must be in this order:
4933 * symbol table
4934 * local symbols
4935 * external defined symbols
4936 * undefined symbols
4937 * string table
4938 * external strings
4939 * local strings
4941 if(saves != NULL)
4942 free(saves);
4943 saves = (int32_t *)allocate(nsyms * sizeof(int32_t));
4944 bzero(saves, nsyms * sizeof(int32_t));
4946 if(object->mh != NULL){
4947 new_symbols = (struct nlist *)
4948 allocate(new_nsyms * sizeof(struct nlist));
4949 new_symbols64 = NULL;
4951 else{
4952 new_symbols = NULL;
4953 new_symbols64 = (struct nlist_64 *)
4954 allocate(new_nsyms * sizeof(struct nlist_64));
4956 new_strsize = round(new_strsize, sizeof(int32_t));
4957 new_strings = (char *)allocate(new_strsize);
4958 new_strings[new_strsize - 3] = '\0';
4959 new_strings[new_strsize - 2] = '\0';
4960 new_strings[new_strsize - 1] = '\0';
4962 memset(new_strings, '\0', sizeof(int32_t));
4963 p = new_strings + sizeof(int32_t);
4964 q = p + new_ext_strsize;
4967 * If this is a dynamic library the movement of the symbols has to be
4968 * done with respect to the modules. As the local symbols, and external
4969 * defined symbols are grouped together for each module. Then a new
4970 * module table needs to be created with the new indexes into the symbol
4971 * table for each module.
4973 new_nmodtab = nmodtab;
4974 new_ntoc = ntoc;
4975 new_nextrefsyms = nextrefsyms;
4976 if(object->mh_filetype == MH_DYLIB && nmodtab != 0){
4977 if(object->mh != NULL){
4978 new_mods = allocate(nmodtab * sizeof(struct dylib_module));
4979 new_mods64 = NULL;
4981 else{
4982 new_mods = NULL;
4983 new_mods64 = allocate(nmodtab * sizeof(struct dylib_module_64));
4986 inew_syms = 0;
4988 * This first loop through the module table sets the index and
4989 * counts of the local symbols for each module.
4991 for(i = 0; i < nmodtab; i++){
4993 * First put the existing local symbols into the new symbol
4994 * table.
4996 if(object->mh != NULL){
4997 new_mods[i].ilocalsym = inew_syms;
4998 new_mods[i].nlocalsym = 0;
4999 ilocalsym = mods[i].ilocalsym;
5000 nlocalsym = mods[i].nlocalsym;
5002 else{
5003 new_mods64[i].ilocalsym = inew_syms;
5004 new_mods64[i].nlocalsym = 0;
5005 ilocalsym = mods64[i].ilocalsym;
5006 nlocalsym = mods64[i].nlocalsym;
5008 for(j = ilocalsym; j < ilocalsym + nlocalsym; j++){
5009 if(object->mh != NULL){
5010 n_strx = symbols[j].n_un.n_strx;
5011 n_type = symbols[j].n_type;
5013 else{
5014 n_strx = symbols64[j].n_un.n_strx;
5015 n_type = symbols64[j].n_type;
5017 if((n_type & N_EXT) == 0){
5018 if(object->mh != NULL)
5019 new_symbols[inew_syms] = symbols[j];
5020 else
5021 new_symbols64[inew_syms] = symbols64[j];
5022 if(n_strx != 0){
5023 strcpy(q, strings + n_strx);
5024 if(object->mh != NULL)
5025 new_symbols[inew_syms].n_un.n_strx =
5026 q - new_strings;
5027 else
5028 new_symbols64[inew_syms].n_un.n_strx =
5029 q - new_strings;
5030 q += strlen(q) + 1;
5032 inew_syms++;
5033 saves[j] = inew_syms;
5034 if(object->mh != NULL)
5035 new_mods[i].nlocalsym++;
5036 else
5037 new_mods64[i].nlocalsym++;
5041 * Next put the global symbols that were changed into
5042 * non-global symbols into the new symbol table and moved their
5043 * counts to the local symbol counts.
5045 if(object->mh != NULL){
5046 iextdefsym = mods[i].iextdefsym;
5047 nextdefsym = mods[i].nextdefsym;
5049 else{
5050 iextdefsym = mods64[i].iextdefsym;
5051 nextdefsym = mods64[i].nextdefsym;
5053 for(j = iextdefsym; j < iextdefsym + nextdefsym; j++){
5054 if(object->mh != NULL){
5055 n_strx = symbols[j].n_un.n_strx;
5056 n_type = symbols[j].n_type;
5058 else{
5059 n_strx = symbols64[j].n_un.n_strx;
5060 n_type = symbols64[j].n_type;
5062 if((n_type & N_EXT) != 0){
5063 if(nmedits[j] == TRUE){
5065 * Change the new symbol to a private extern symbol
5066 * with the extern bit off.
5068 if(object->mh != NULL){
5069 new_symbols[inew_syms] = symbols[j];
5070 new_symbols[inew_syms].n_type |= N_PEXT;
5071 new_symbols[inew_syms].n_type &= ~N_EXT;
5073 else{
5074 new_symbols64[inew_syms] = symbols64[j];
5075 new_symbols64[inew_syms].n_type |= N_PEXT;
5076 new_symbols64[inew_syms].n_type &= ~N_EXT;
5078 if(n_strx != 0){
5079 strcpy(q, strings + n_strx);
5080 if(object->mh != NULL)
5081 new_symbols[inew_syms].n_un.n_strx =
5082 q - new_strings;
5083 else
5084 new_symbols64[inew_syms].n_un.n_strx =
5085 q - new_strings;
5086 q += strlen(q) + 1;
5088 inew_syms++;
5089 saves[j] = inew_syms;
5090 if(object->mh != NULL)
5091 new_mods[i].nlocalsym++;
5092 else
5093 new_mods64[i].nlocalsym++;
5099 * Next put the unchanged defined global symbols into the new
5100 * symbol table.
5102 for(i = 0; i < nmodtab; i++){
5103 if(object->mh != NULL){
5104 new_mods[i].iextdefsym = inew_syms;
5105 new_mods[i].nextdefsym = 0;
5106 iextdefsym = mods[i].iextdefsym;
5107 nextdefsym = mods[i].nextdefsym;
5109 else{
5110 new_mods64[i].iextdefsym = inew_syms;
5111 new_mods64[i].nextdefsym = 0;
5112 iextdefsym = mods64[i].iextdefsym;
5113 nextdefsym = mods64[i].nextdefsym;
5115 for(j = iextdefsym; j < iextdefsym + nextdefsym; j++){
5116 if(object->mh != NULL){
5117 n_strx = symbols[j].n_un.n_strx;
5118 n_type = symbols[j].n_type;
5120 else{
5121 n_strx = symbols64[j].n_un.n_strx;
5122 n_type = symbols64[j].n_type;
5124 if((n_type & N_EXT) != 0){
5125 if(nmedits[j] == FALSE){
5126 if(object->mh != NULL)
5127 new_symbols[inew_syms] = symbols[j];
5128 else
5129 new_symbols64[inew_syms] = symbols64[j];
5130 if(n_strx != 0){
5131 strcpy(p, strings + n_strx);
5132 if(object->mh != NULL)
5133 new_symbols[inew_syms].n_un.n_strx =
5134 p - new_strings;
5135 else
5136 new_symbols64[inew_syms].n_un.n_strx =
5137 p - new_strings;
5138 p += strlen(p) + 1;
5140 inew_syms++;
5141 saves[j] = inew_syms;
5142 if(object->mh != NULL)
5143 new_mods[i].nextdefsym++;
5144 else
5145 new_mods64[i].nextdefsym++;
5151 * Last put the undefined symbols into the new symbol table.
5153 for(i = 0; i < nsyms; i++){
5154 if(object->mh != NULL){
5155 n_strx = symbols[i].n_un.n_strx;
5156 n_type = symbols[i].n_type;
5158 else{
5159 n_strx = symbols64[i].n_un.n_strx;
5160 n_type = symbols64[i].n_type;
5162 if((n_type & N_EXT) != 0 &&
5163 ((n_type & N_TYPE) == N_UNDF ||
5164 (n_type & N_TYPE) == N_PBUD)){
5165 if(object->mh != NULL)
5166 new_symbols[inew_syms] = symbols[i];
5167 else
5168 new_symbols64[inew_syms] = symbols64[i];
5169 if(n_strx != 0){
5170 strcpy(p, strings + n_strx);
5171 if(object->mh != NULL)
5172 new_symbols[inew_syms].n_un.n_strx =
5173 p - new_strings;
5174 else
5175 new_symbols64[inew_syms].n_un.n_strx =
5176 p - new_strings;
5177 p += strlen(p) + 1;
5179 inew_syms++;
5180 saves[i] = inew_syms;
5185 * Place the module table's module names with the external strings
5186 * and set the names in the new module table. And then copy the
5187 * other unchanged fields.
5189 for(i = 0; i < nmodtab; i++){
5190 if(object->mh != NULL){
5191 strcpy(p, strings + mods[i].module_name);
5192 new_mods[i].module_name = p - new_strings;
5193 p += strlen(p) + 1;
5195 new_mods[i].irefsym = mods[i].irefsym;
5196 new_mods[i].nrefsym = mods[i].nrefsym;
5197 new_mods[i].iextrel = mods[i].iextrel;
5198 new_mods[i].nextrel = mods[i].nextrel;
5199 new_mods[i].iinit_iterm = mods[i].iinit_iterm;
5200 new_mods[i].ninit_nterm = mods[i].ninit_nterm;
5201 new_mods[i].objc_module_info_addr =
5202 mods[i].objc_module_info_addr;
5203 new_mods[i].objc_module_info_size =
5204 mods[i].objc_module_info_size;
5206 else{
5207 strcpy(p, strings + mods64[i].module_name);
5208 new_mods64[i].module_name = p - new_strings;
5209 p += strlen(p) + 1;
5211 new_mods64[i].irefsym = mods64[i].irefsym;
5212 new_mods64[i].nrefsym = mods64[i].nrefsym;
5213 new_mods64[i].iextrel = mods64[i].iextrel;
5214 new_mods64[i].nextrel = mods64[i].nextrel;
5215 new_mods64[i].iinit_iterm = mods64[i].iinit_iterm;
5216 new_mods64[i].ninit_nterm = mods64[i].ninit_nterm;
5217 new_mods64[i].objc_module_info_addr =
5218 mods64[i].objc_module_info_addr;
5219 new_mods64[i].objc_module_info_size =
5220 mods64[i].objc_module_info_size;
5225 * Update the reference table with the new symbol indexes for all
5226 * entries and change type of reference (the flags field) for those
5227 * symbols that got changed from globals to non-globals.
5229 new_nextrefsyms = nextrefsyms;
5230 new_refs = allocate(new_nextrefsyms *
5231 sizeof(struct dylib_reference));
5232 j = 0;
5233 for(i = 0; i < nextrefsyms; i++){
5234 if(nmedits[refs[i].isym] == TRUE){
5235 if(refs[i].flags == REFERENCE_FLAG_DEFINED)
5236 new_refs[i].flags =
5237 REFERENCE_FLAG_PRIVATE_DEFINED;
5238 else if(refs[i].flags == REFERENCE_FLAG_UNDEFINED_NON_LAZY)
5239 new_refs[i].flags =
5240 REFERENCE_FLAG_PRIVATE_UNDEFINED_NON_LAZY;
5241 else if(refs[i].flags == REFERENCE_FLAG_UNDEFINED_LAZY)
5242 new_refs[i].flags =
5243 REFERENCE_FLAG_PRIVATE_UNDEFINED_LAZY;
5244 else
5245 new_refs[i].flags = refs[i].flags;
5247 else{
5248 new_refs[i].flags = refs[i].flags;
5250 new_refs[i].isym = saves[refs[i].isym] - 1;
5254 * Create a new dylib table of contents without the global symbols
5255 * that got turned into non-globals.
5257 new_ntoc = ntoc - nchanged_globals;
5258 new_tocs = allocate(new_ntoc *
5259 sizeof(struct dylib_table_of_contents));
5260 k = 0;
5261 for(i = 0; i < ntoc; i++){
5262 if(tocs[i].symbol_index >= nsyms){
5263 error_arch(arch, member, "bad symbol index for table of "
5264 "contents table entry %d in: ", i);
5265 return(FALSE);
5267 if(nmedits[tocs[i].symbol_index] == FALSE){
5268 new_tocs[k].symbol_index = saves[tocs[i].symbol_index] - 1;
5269 new_tocs[k].module_index = tocs[i].module_index;
5270 k++;
5275 * If is not a dynamic library so all global symbols changed into
5276 * statics can be moved to the end of the local symbols. If the pflag
5277 * is set then the changed symbols remain global and just get the
5278 * private extern bit set.
5280 else{
5282 * First put the existing local symbols into the new symbol table.
5284 inew_syms = 0;
5285 for(i = 0; i < nsyms; i++){
5286 if(object->mh != NULL){
5287 n_strx = symbols[i].n_un.n_strx;
5288 n_type = symbols[i].n_type;
5290 else{
5291 n_strx = symbols64[i].n_un.n_strx;
5292 n_type = symbols64[i].n_type;
5294 if((n_type & N_EXT) == 0){
5295 if(object->mh != NULL)
5296 new_symbols[inew_syms] = symbols[i];
5297 else
5298 new_symbols64[inew_syms] = symbols64[i];
5299 if(n_strx != 0){
5300 strcpy(q, strings + n_strx);
5301 if(object->mh != NULL)
5302 new_symbols[inew_syms].n_un.n_strx =
5303 q - new_strings;
5304 else
5305 new_symbols64[inew_syms].n_un.n_strx =
5306 q - new_strings;
5307 q += strlen(q) + 1;
5309 inew_syms++;
5310 saves[i] = inew_syms;
5314 * Next put the global symbols that were changed into statics
5315 * symbols into the new symbol table.
5317 if(pflag == FALSE){
5318 for(i = 0; i < nsyms; i++){
5319 if(object->mh != NULL){
5320 n_strx = symbols[i].n_un.n_strx;
5321 n_type = symbols[i].n_type;
5323 else{
5324 n_strx = symbols64[i].n_un.n_strx;
5325 n_type = symbols64[i].n_type;
5327 if((n_type & N_EXT) != 0){
5328 if(nmedits[i] == TRUE){
5330 * Change the new symbol to not be an extern symbol
5331 * by turning off the extern bit.
5333 if(object->mh != NULL){
5334 new_symbols[inew_syms] = symbols[i];
5335 new_symbols[inew_syms].n_type &= ~N_EXT;
5336 new_symbols[inew_syms].n_desc &= ~N_WEAK_DEF;
5338 else{
5339 new_symbols64[inew_syms] = symbols64[i];
5340 new_symbols64[inew_syms].n_type &= ~N_EXT;
5341 new_symbols64[inew_syms].n_desc &= ~N_WEAK_DEF;
5343 if(n_strx != 0){
5344 strcpy(q, strings + n_strx);
5345 if(object->mh != NULL)
5346 new_symbols[inew_syms].n_un.n_strx =
5347 q - new_strings;
5348 else
5349 new_symbols64[inew_syms].n_un.n_strx =
5350 q - new_strings;
5351 q += strlen(q) + 1;
5353 inew_syms++;
5354 saves[i] = inew_syms;
5360 * Last put the unchanged global symbols into the new symbol table
5361 * and symbols changed into private externs.
5363 for(i = 0; i < nsyms; i++){
5364 if(object->mh != NULL){
5365 n_strx = symbols[i].n_un.n_strx;
5366 n_type = symbols[i].n_type;
5368 else{
5369 n_strx = symbols64[i].n_un.n_strx;
5370 n_type = symbols64[i].n_type;
5372 if((n_type & N_EXT) != 0){
5373 if(nmedits[i] == FALSE || pflag == TRUE){
5374 if(object->mh != NULL)
5375 new_symbols[inew_syms] = symbols[i];
5376 else
5377 new_symbols64[inew_syms] = symbols64[i];
5378 if(nmedits[i] == TRUE && pflag == TRUE){
5380 * Change the new symbol to be a private extern
5381 * symbol by turning on the private extern bit.
5383 if(object->mh != NULL)
5384 new_symbols[inew_syms].n_type |= N_PEXT;
5385 else
5386 new_symbols64[inew_syms].n_type |= N_PEXT;
5388 if(n_strx != 0){
5389 strcpy(p, strings + n_strx);
5390 if(object->mh != NULL)
5391 new_symbols[inew_syms].n_un.n_strx =
5392 p - new_strings;
5393 else
5394 new_symbols64[inew_syms].n_un.n_strx =
5395 p - new_strings;
5396 p += strlen(p) + 1;
5398 inew_syms++;
5399 saves[i] = inew_syms;
5405 if(sections != NULL);
5406 free(sections);
5407 if(sections64 != NULL);
5408 free(sections64);
5410 if(errors == 0)
5411 return(TRUE);
5412 else
5413 return(FALSE);
5417 * Function for qsort for comparing global symbol names.
5419 static
5421 cmp_qsort_global(
5422 const struct nlist **sym1,
5423 const struct nlist **sym2)
5425 return(strcmp(global_strings + (*sym1)->n_un.n_strx,
5426 global_strings + (*sym2)->n_un.n_strx));
5429 static
5431 cmp_qsort_global_64(
5432 const struct nlist_64 **sym1,
5433 const struct nlist_64 **sym2)
5435 return(strcmp(global_strings + (*sym1)->n_un.n_strx,
5436 global_strings + (*sym2)->n_un.n_strx));
5440 * Function for bsearch for finding a global symbol that matches a stab name.
5442 static
5444 cmp_bsearch_global_stab(
5445 const char *name,
5446 const struct nlist **sym)
5449 * The +1 is for the '_' on the global symbol that is not on the
5450 * stab string that is trying to be matched.
5452 return(strcmp(name, global_strings + (*sym)->n_un.n_strx + 1));
5455 static
5457 cmp_bsearch_global_stab_64(
5458 const char *name,
5459 const struct nlist_64 **sym)
5462 * The +1 is for the '_' on the global symbol that is not on the
5463 * stab string that is trying to be matched.
5465 return(strcmp(name, global_strings + (*sym)->n_un.n_strx + 1));
5469 * Function for bsearch for finding a global symbol that matches a stab name
5470 * in the debug map.
5472 static
5474 cmp_bsearch_global(
5475 const char *name,
5476 const struct nlist **sym)
5478 return(strcmp(name, global_strings + (*sym)->n_un.n_strx));
5481 static
5483 cmp_bsearch_global_64(
5484 const char *name,
5485 const struct nlist_64 **sym)
5487 return(strcmp(name, global_strings + (*sym)->n_un.n_strx));
5489 #endif /* defined(NMEDIT) */