Add .gitignore and .gitattributes
[striptease.git] / strip.c
blobe18560dc6dc21424443a21af055e708d1e1c4c06
1 /*
2 * Copyright (c) 1999 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
11 * file.
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
21 * @APPLE_LICENSE_HEADER_END@
24 * The strip(1) and nmedit(l) program. This understands only Mach-O format
25 * files (with the restriction the symbol table is at the end of the file) and
26 * fat files with Mach-O files in them.
28 #include <stdio.h>
29 #include <stdlib.h>
30 #include <string.h>
31 #include <limits.h>
32 #include <ctype.h>
33 #include <libc.h>
34 #include <sys/types.h>
35 #include <sys/stat.h>
36 #include <mach-o/loader.h>
37 #include <mach-o/reloc.h>
38 #include <mach-o/nlist.h>
39 #include <mach-o/stab.h>
40 #include "stuff/breakout.h"
41 #include "stuff/allocate.h"
42 #include "stuff/errors.h"
43 #include "stuff/rnd.h"
44 #include "stuff/reloc.h"
45 #include "stuff/reloc.h"
46 #include "stuff/symbol_list.h"
47 #include "stuff/unix_standard_mode.h"
48 #include "stuff/execute.h"
49 #ifdef TRIE_SUPPORT
50 #include <mach-o/prune_trie.h>
51 #endif /* TRIE_SUPPORT */
53 /* These are set from the command line arguments */
54 __private_extern__
55 char *progname = NULL; /* name of the program for error messages (argv[0]) */
56 static char *output_file;/* name of the output file */
57 static char *sfile; /* filename of global symbol names to keep */
58 static char *Rfile; /* filename of global symbol names to remove */
59 static uint32_t Aflag; /* save only absolute symbols with non-zero value and
60 .objc_class_name_* symbols */
61 static uint32_t iflag; /* -i ignore symbols in -s file not in object */
62 #ifdef NMEDIT
63 static uint32_t pflag; /* make all defined global symbols private extern */
64 #else /* !defined(NMEDIT) */
65 static char *dfile; /* filename of filenames of debugger symbols to keep */
66 static uint32_t uflag; /* save undefined symbols */
67 static uint32_t rflag; /* save symbols referenced dynamically */
68 static uint32_t nflag; /* save N_SECT global symbols */
69 static uint32_t Sflag; /* -S strip only debugger symbols N_STAB */
70 static uint32_t xflag; /* -x strip non-globals */
71 static uint32_t Xflag; /* -X strip local symbols with 'L' names */
72 static uint32_t cflag; /* -c strip section contents from dynamic libraries
73 files to create stub libraries */
74 static uint32_t no_uuid;/* -no_uuid strip LC_UUID load commands */
75 static uint32_t vflag; /* -v for verbose debugging ld -r executions */
76 static uint32_t lflag; /* -l do ld -r executions even if it has bugs */
77 static uint32_t strip_all = 1;
79 * This is set on an object by object basis if the strip_all flag is still set
80 * and the object is an executable that is for use with the dynamic linker.
81 * This has the same effect as -r and -u.
83 static enum bool default_dyld_executable = FALSE;
84 #endif /* NMEDIT */
87 * Data structures to perform selective stripping of symbol table entries.
88 * save_symbols is the names of the symbols from the -s <file> argument.
89 * remove_symbols is the names of the symbols from the -R <file> argument.
91 static struct symbol_list *save_symbols = NULL;
92 static uint32_t nsave_symbols = 0;
93 static struct symbol_list *remove_symbols = NULL;
94 static uint32_t nremove_symbols = 0;
97 * saves points to an array of uint32_t's that is allocated. This array is a
98 * map of old symbol indexes to new symbol indexes. The new symbol indexes are
99 * plus 1 and zero value means that old symbol is not in the new symbol table.
100 * ref_saves is used in the same way but for the reference table.
101 * nmedits is an array and indexed by the symbol index the value indicates if
102 * the symbol was edited and turned into a non-global.
104 static int32_t *saves = NULL;
105 #ifndef NMEDIT
106 static int32_t *ref_saves = NULL;
107 #else
108 static enum bool *nmedits = NULL;
109 #endif
112 * These hold pointers to the symbol, string and indirect tables being worked on
113 * by strip_object and strip_symtab() from an input object file or possiblity
114 * changed to an ld -r (-S or -x) file by make_ld_r_object().
116 static struct nlist *symbols = NULL;
117 static struct nlist_64 *symbols64 = NULL;
118 static uint32_t nsyms = 0;
119 static char *strings = NULL;
120 static uint32_t strsize = 0;
121 static uint32_t *indirectsyms = NULL;
122 static uint32_t nindirectsyms = 0;
125 * These hold the new symbol and string table created by strip_symtab()
126 * and the new counts of local, defined external and undefined symbols.
128 static struct nlist *new_symbols = NULL;
129 static struct nlist_64 *new_symbols64 = NULL;
130 static uint32_t new_nsyms = 0;
131 static char *new_strings = NULL;
132 static uint32_t new_strsize = 0;
133 static uint32_t new_nlocalsym = 0;
134 static uint32_t new_nextdefsym = 0;
135 static uint32_t new_nundefsym = 0;
136 #if defined(TRIE_SUPPORT) && !defined(NMEDIT)
138 * The index into the new symbols where the defined external start.
140 static uint32_t inew_nextdefsym = 0;
141 #endif
144 * These hold the new table of contents, reference table and module table for
145 * dylibs.
147 static struct dylib_table_of_contents *new_tocs = NULL;
148 static uint32_t new_ntoc = 0;
149 static struct dylib_reference *new_refs = NULL;
150 static uint32_t new_nextrefsyms = 0;
151 #ifdef NMEDIT
152 static struct dylib_module *new_mods = NULL;
153 static struct dylib_module_64 *new_mods64 = NULL;
154 static uint32_t new_nmodtab = 0;
155 #endif
157 #ifndef NMEDIT
159 * The list of file names to save debugging symbols from.
161 static char **debug_filenames = NULL;
162 static uint32_t ndebug_filenames = 0;
163 struct undef_map {
164 uint32_t index;
165 struct nlist symbol;
167 struct undef_map64 {
168 uint32_t index;
169 struct nlist_64 symbol64;
171 static char *qsort_strings = NULL;
172 #endif /* !defined(NMEDIT) */
175 /* Internal routines */
176 static void usage(
177 void);
179 static void strip_file(
180 char *input_file,
181 struct arch_flag *arch_flags,
182 uint32_t narch_flags,
183 enum bool all_archs);
185 static void strip_arch(
186 struct arch *archs,
187 uint32_t narchs,
188 struct arch_flag *arch_flags,
189 uint32_t narch_flags,
190 enum bool all_archs);
192 static void strip_object(
193 struct arch *arch,
194 struct member *member,
195 struct object *object);
197 static uint32_t get_starting_syminfo_offset(
198 struct object *object);
200 static void check_object_relocs(
201 struct arch *arch,
202 struct member *member,
203 struct object *object,
204 char *segname,
205 char *sectname,
206 uint64_t sectsize,
207 char *contents,
208 struct relocation_info *relocs,
209 uint32_t nreloc,
210 struct nlist *symbols,
211 struct nlist_64 *symbols64,
212 uint32_t nsyms,
213 char *strings,
214 int32_t *missing_reloc_symbols,
215 enum byte_sex host_byte_sex);
217 static void check_indirect_symtab(
218 struct arch *arch,
219 struct member *member,
220 struct object *object,
221 uint32_t nitems,
222 uint32_t reserved1,
223 uint32_t section_type,
224 char *contents,
225 struct nlist *symbols,
226 struct nlist_64 *symbols64,
227 uint32_t nsyms,
228 char *strings,
229 int32_t *missing_reloc_symbols,
230 enum byte_sex host_byte_sex);
232 #ifndef NMEDIT
233 static enum bool strip_symtab(
234 struct arch *arch,
235 struct member *member,
236 struct object *object,
237 struct dylib_table_of_contents *tocs,
238 uint32_t ntoc,
239 struct dylib_module *mods,
240 struct dylib_module_64 *mods64,
241 uint32_t nmodtab,
242 struct dylib_reference *refs,
243 uint32_t nextrefsyms);
245 #ifdef TRIE_SUPPORT
246 static int prune(
247 const char *name);
248 #endif /* TRIE_SUPPORT */
250 static void make_ld_r_object(
251 struct arch *arch,
252 struct member *member,
253 struct object *object);
255 static void strip_LC_UUID_commands(
256 struct arch *arch,
257 struct member *member,
258 struct object *object);
260 #ifndef NMEDIT
261 static void strip_LC_CODE_SIGNATURE_commands(
262 struct arch *arch,
263 struct member *member,
264 struct object *object);
265 #endif /* !(NMEDIT) */
267 static enum bool private_extern_reference_by_module(
268 uint32_t symbol_index,
269 struct dylib_reference *refs,
270 uint32_t nextrefsyms);
272 static enum bool symbol_pointer_used(
273 uint32_t symbol_index,
274 uint32_t *indirectsyms,
275 uint32_t nindirectsyms);
277 static int cmp_qsort_undef_map(
278 const struct undef_map *sym1,
279 const struct undef_map *sym2);
281 static int cmp_qsort_undef_map_64(
282 const struct undef_map64 *sym1,
283 const struct undef_map64 *sym2);
284 #endif /* !defined(NMEDIT) */
286 #ifdef NMEDIT
287 static enum bool edit_symtab(
288 struct arch *arch,
289 struct member *member,
290 struct object *object,
291 struct nlist *symbols,
292 struct nlist_64 *symbols64,
293 uint32_t nsyms,
294 char *strings,
295 uint32_t strsize,
296 struct dylib_table_of_contents *tocs,
297 uint32_t ntoc,
298 struct dylib_module *mods,
299 struct dylib_module_64 *mods64,
300 uint32_t nmodtab,
301 struct dylib_reference *refs,
302 uint32_t nextrefsyms);
303 #endif /* NMEDIT */
305 #ifndef NMEDIT
306 static void setup_debug_filenames(
307 char *dfile);
309 static int cmp_qsort_filename(
310 const char **name1,
311 const char **name2);
313 static int cmp_bsearch_filename(
314 const char *name1,
315 const char **name2);
316 #endif /* NMEDIT */
318 #ifdef NMEDIT
320 * This variable and routines are used for nmedit(1) only.
322 static char *global_strings = NULL;
324 static int cmp_qsort_global(
325 const struct nlist **sym1,
326 const struct nlist **sym2);
328 static int cmp_qsort_global_64(
329 const struct nlist_64 **sym1,
330 const struct nlist_64 **sym2);
332 static int cmp_bsearch_global_stab(
333 const char *name,
334 const struct nlist **sym);
336 static int cmp_bsearch_global_stab_64(
337 const char *name,
338 const struct nlist_64 **sym);
340 static int cmp_bsearch_global(
341 const char *name,
342 const struct nlist **sym);
344 static int cmp_bsearch_global_64(
345 const char *name,
346 const struct nlist_64 **sym);
347 #endif /* NMEDIT */
350 main(
351 int argc,
352 char *argv[],
353 char *envp[])
355 int i;
356 uint32_t j, args_left, files_specified;
357 struct arch_flag *arch_flags;
358 uint32_t narch_flags;
359 enum bool all_archs;
360 struct symbol_list *sp;
362 progname = argv[0];
364 arch_flags = NULL;
365 narch_flags = 0;
366 all_archs = FALSE;
368 files_specified = 0;
369 args_left = 1;
370 for (i = 1; i < argc; i++){
371 if(argv[i][0] == '-'){
372 if(argv[i][1] == '\0'){
373 args_left = 0;
374 break;
376 if(strcmp(argv[i], "-o") == 0){
377 if(i + 1 >= argc)
378 fatal("-o requires an argument");
379 if(output_file != NULL)
380 fatal("only one -o option allowed");
381 output_file = argv[i + 1];
382 i++;
384 else if(strcmp(argv[i], "-s") == 0){
385 if(i + 1 >= argc)
386 fatal("-s requires an argument");
387 if(sfile != NULL)
388 fatal("only one -s option allowed");
389 sfile = argv[i + 1];
390 i++;
392 else if(strcmp(argv[i], "-R") == 0){
393 if(i + 1 >= argc)
394 fatal("-R requires an argument");
395 if(Rfile != NULL)
396 fatal("only one -R option allowed");
397 Rfile = argv[i + 1];
398 i++;
400 #ifndef NMEDIT
401 else if(strcmp(argv[i], "-d") == 0){
402 if(i + 1 >= argc)
403 fatal("-d requires an argument");
404 if(dfile != NULL)
405 fatal("only one -d option allowed");
406 dfile = argv[i + 1];
407 i++;
409 else if(strcmp(argv[i], "-no_uuid") == 0){
410 no_uuid = 1;
412 #endif /* !defined(NMEDIT) */
413 else if(strcmp(argv[i], "-arch") == 0){
414 if(i + 1 == argc){
415 error("missing argument(s) to %s option", argv[i]);
416 usage();
418 if(strcmp("all", argv[i+1]) == 0){
419 all_archs = TRUE;
421 else{
422 arch_flags = reallocate(arch_flags,
423 (narch_flags + 1) * sizeof(struct arch_flag));
424 if(get_arch_from_flag(argv[i+1],
425 arch_flags + narch_flags) == 0){
426 error("unknown architecture specification flag: "
427 "%s %s", argv[i], argv[i+1]);
428 arch_usage();
429 usage();
431 for(j = 0; j < narch_flags; j++){
432 if(arch_flags[j].cputype ==
433 arch_flags[narch_flags].cputype &&
434 (arch_flags[j].cpusubtype & ~CPU_SUBTYPE_MASK) ==
435 (arch_flags[narch_flags].cpusubtype &
436 ~CPU_SUBTYPE_MASK) &&
437 strcmp(arch_flags[j].name,
438 arch_flags[narch_flags].name) == 0)
439 break;
441 if(j == narch_flags)
442 narch_flags++;
444 i++;
446 else{
447 for(j = 1; argv[i][j] != '\0'; j++){
448 switch(argv[i][j]){
449 #ifdef NMEDIT
450 case 'p':
451 pflag = 1;
452 break;
453 #else /* !defined(NMEDIT) */
454 case 'S':
455 Sflag = 1;
456 strip_all = 0;
457 break;
458 case 'X':
459 Xflag = 1;
460 strip_all = 0;
461 break;
462 case 'x':
463 xflag = 1;
464 strip_all = 0;
465 break;
466 case 'i':
467 iflag = 1;
468 break;
469 case 'u':
470 uflag = 1;
471 strip_all = 0;
472 break;
473 case 'r':
474 rflag = 1;
475 strip_all = 0;
476 break;
477 case 'n':
478 nflag = 1;
479 strip_all = 0;
480 break;
481 #endif /* !defined(NMEDIT) */
482 case 'A':
483 Aflag = 1;
484 #ifndef NMEDIT
485 strip_all = 0;
486 #endif /* !defined(NMEDIT) */
487 break;
488 #ifndef NMEDIT
489 case 'c':
490 cflag = 1;
491 strip_all = 0;
492 break;
493 case 'v':
494 vflag = 1;
495 break;
496 case 'l':
497 lflag = 1;
498 break;
499 #endif /* NMEDIT */
500 default:
501 error("unrecognized option: %s", argv[i]);
502 usage();
507 else
508 files_specified++;
510 if(args_left == 0)
511 files_specified += argc - (i + 1);
513 if(files_specified > 1 && output_file != NULL){
514 error("-o <filename> can only be used when one file is specified");
515 usage();
518 if(sfile){
519 setup_symbol_list(sfile, &save_symbols, &nsave_symbols);
521 #ifdef NMEDIT
522 else{
523 if(Rfile == NULL && pflag == 0){
524 error("-s <filename>, -R <filename> or -p argument required");
525 usage();
528 #endif /* NMEDIT */
530 if(Rfile){
531 setup_symbol_list(Rfile, &remove_symbols, &nremove_symbols);
532 if(sfile){
533 for(j = 0; j < nremove_symbols ; j++){
534 sp = bsearch(remove_symbols[j].name,
535 save_symbols, nsave_symbols,
536 sizeof(struct symbol_list),
537 (int (*)(const void *, const void *))
538 symbol_list_bsearch);
539 if(sp != NULL){
540 error("symbol name: %s is listed in both -s %s and -R "
541 "%s files (can't be both saved and removed)",
542 remove_symbols[j].name, sfile, Rfile);
545 if(errors)
546 exit(EXIT_FAILURE);
550 /* the default when no -arch flags is present is to strip all archs */
551 if(narch_flags == 0)
552 all_archs = TRUE;
554 #ifndef NMEDIT
555 if(dfile){
556 setup_debug_filenames(dfile);
558 #endif /* !defined(NMEDIT) */
560 files_specified = 0;
561 args_left = 1;
562 for (i = 1; i < argc; i++) {
563 if(args_left && argv[i][0] == '-'){
564 if(argv[i][1] == '\0')
565 args_left = 0;
566 else if(strcmp(argv[i], "-o") == 0 ||
567 strcmp(argv[i], "-s") == 0 ||
568 strcmp(argv[i], "-R") == 0 ||
569 #ifndef NMEDIT
570 strcmp(argv[i], "-d") == 0 ||
571 #endif /* !defined(NMEDIT) */
572 strcmp(argv[i], "-arch") == 0)
573 i++;
575 else{
576 char resolved_path[PATH_MAX + 1];
578 if(realpath(argv[i], resolved_path) == NULL)
579 strip_file(argv[i], arch_flags, narch_flags, all_archs);
580 else
581 strip_file(resolved_path, arch_flags,narch_flags,all_archs);
582 files_specified++;
585 if(files_specified == 0)
586 fatal("no files specified");
588 if(errors)
589 return(EXIT_FAILURE);
590 else
591 return(EXIT_SUCCESS);
594 static
595 void
596 usage(
597 void)
599 #ifndef NMEDIT
600 fprintf(stderr, "Usage: %s [-AnuSXx] [-] [-d filename] [-s filename] "
601 "[-R filename] [-o output] file [...] \n", progname);
602 #else /* defined(NMEDIT) */
603 fprintf(stderr, "Usage: %s -s filename [-R filename] [-p] [-A] [-] "
604 "[-o output] file [...] \n",
605 progname);
606 #endif /* NMEDIT */
607 exit(EXIT_FAILURE);
610 static
611 void
612 strip_file(
613 char *input_file,
614 struct arch_flag *arch_flags,
615 uint32_t narch_flags,
616 enum bool all_archs)
618 struct ofile *ofile;
619 struct arch *archs;
620 uint32_t narchs;
621 struct stat stat_buf;
622 uint32_t previous_errors;
623 enum bool unix_standard_mode;
624 int cwd_fd;
625 char *rename_file;
626 #ifndef NMEDIT
627 char *p;
628 #endif
630 archs = NULL;
631 narchs = 0;
632 previous_errors = errors;
633 errors = 0;
635 /* breakout the file for processing */
636 ofile = breakout(input_file, &archs, &narchs, FALSE);
637 if(errors)
638 return;
640 /* checkout the file for symbol table replacement processing */
641 checkout(archs, narchs);
643 /* process the symbols in the input file */
644 strip_arch(archs, narchs, arch_flags, narch_flags, all_archs);
645 if(errors){
646 free_archs(archs, narchs);
647 ofile_unmap(ofile);
648 return;
651 /* create the output file */
652 if(stat(input_file, &stat_buf) == -1)
653 system_error("can't stat input file: %s", input_file);
654 if(output_file != NULL){
655 writeout(archs, narchs, output_file, stat_buf.st_mode & 0777,
656 TRUE, FALSE, FALSE, NULL);
658 else{
659 unix_standard_mode = get_unix_standard_mode();
660 rename_file = NULL;
661 cwd_fd = -1;
662 #ifdef NMEDIT
663 output_file = makestr(input_file, ".nmedit", NULL);
664 #else /* !defined(NMEDIT) */
666 * In UNIX standard conformance mode we are not allowed to replace
667 * a file that is not writeable.
669 if(unix_standard_mode == TRUE &&
670 access(input_file, W_OK) == -1){
671 system_error("file: %s is not writable", input_file);
672 goto strip_file_return;
674 output_file = makestr(input_file, ".strip", NULL);
677 * The UNIX standard conformance test suite expects files of
678 * MAXPATHLEN to work.
680 if(strlen(output_file) >= MAXPATHLEN){
682 * If there is a directory path in the name try to change
683 * the current working directory to that path.
685 if((p = rindex(output_file, '/')) != NULL){
686 if((cwd_fd = open(".", O_RDONLY, 0)) == -1){
687 system_error("can't open current working directory");
688 goto strip_file_return;
690 *p = '\0';
691 if(chdir(output_file) == -1){
692 system_error("can't change current working directory "
693 "to: %s", output_file);
694 goto strip_file_return;
696 p = rindex(input_file, '/');
697 rename_file = makestr(p + 1, NULL);
700 * Create what might be a short enough name.
702 free(output_file);
703 output_file = makestr("strip.XXXXXX", NULL);
704 output_file = mktemp(output_file);
706 #endif /* NMEDIT */
707 writeout(archs, narchs, output_file, stat_buf.st_mode & 0777,
708 TRUE, FALSE, FALSE, NULL);
709 if(rename_file != NULL){
710 if(rename(output_file, rename_file) == -1)
711 system_error("can't move temporary file: %s to file: %s",
712 output_file, rename_file);
713 free(rename_file);
715 else{
716 if(rename(output_file, input_file) == -1)
717 system_error("can't move temporary file: %s to input "
718 "file: %s", output_file, input_file);
720 free(output_file);
721 output_file = NULL;
724 * If we changed the current working directory change back to
725 * the previous working directory.
727 if(cwd_fd != -1){
728 if(fchdir(cwd_fd) == -1)
729 system_error("can't change back to previous working "
730 "directory");
731 if(close(cwd_fd) == -1)
732 system_error("can't close previous working directory");
736 #ifndef NMEDIT
737 strip_file_return:
738 #endif /* !defined(NMEDIT) */
739 /* clean-up data structures */
740 free_archs(archs, narchs);
741 ofile_unmap(ofile);
743 errors += previous_errors;
746 static
747 void
748 strip_arch(
749 struct arch *archs,
750 uint32_t narchs,
751 struct arch_flag *arch_flags,
752 uint32_t narch_flags,
753 enum bool all_archs)
755 uint32_t i, j, k, offset, size, missing_syms;
756 cpu_type_t cputype;
757 cpu_subtype_t cpusubtype;
758 struct arch_flag host_arch_flag;
759 enum bool arch_process, any_processing, *arch_flag_processed, family;
760 const struct arch_flag *family_arch_flag;
763 * Using the specified arch_flags process specified objects for those
764 * architecures.
766 any_processing = FALSE;
767 arch_flag_processed = NULL;
768 if(narch_flags != 0)
769 arch_flag_processed = allocate(narch_flags * sizeof(enum bool));
770 memset(arch_flag_processed, '\0', narch_flags * sizeof(enum bool));
771 for(i = 0; i < narchs; i++){
773 * Determine the architecture (cputype and cpusubtype) of arch[i]
775 cputype = 0;
776 cpusubtype = 0;
777 if(archs[i].type == OFILE_ARCHIVE){
778 for(j = 0; j < archs[i].nmembers; j++){
779 if(archs[i].members[j].type == OFILE_Mach_O){
780 cputype = archs[i].members[j].object->mh_cputype;
781 cpusubtype = archs[i].members[j].object->mh_cpusubtype;
782 break;
786 else if(archs[i].type == OFILE_Mach_O){
787 cputype = archs[i].object->mh_cputype;
788 cpusubtype = archs[i].object->mh_cpusubtype;
790 else if(archs[i].fat_arch != NULL){
791 cputype = archs[i].fat_arch->cputype;
792 cpusubtype = archs[i].fat_arch->cpusubtype;
794 arch_process = FALSE;
795 if(all_archs == TRUE){
796 arch_process = TRUE;
798 else if(narch_flags != 0){
799 family = FALSE;
800 if(narch_flags == 1){
801 family_arch_flag =
802 get_arch_family_from_cputype(arch_flags[0].cputype);
803 if(family_arch_flag != NULL)
804 family = (enum bool)
805 ((family_arch_flag->cpusubtype & ~CPU_SUBTYPE_MASK) ==
806 (arch_flags[0].cpusubtype & ~CPU_SUBTYPE_MASK));
808 for(j = 0; j < narch_flags; j++){
809 if(arch_flags[j].cputype == cputype &&
810 ((arch_flags[j].cpusubtype & ~CPU_SUBTYPE_MASK) ==
811 (cpusubtype & ~CPU_SUBTYPE_MASK) ||
812 family == TRUE)){
813 arch_process = TRUE;
814 arch_flag_processed[j] = TRUE;
815 break;
819 else{
820 (void)get_arch_from_host(&host_arch_flag, NULL);
821 if(host_arch_flag.cputype == cputype &&
822 (host_arch_flag.cpusubtype & ~CPU_SUBTYPE_MASK) ==
823 (cpusubtype & ~CPU_SUBTYPE_MASK))
824 arch_process = TRUE;
826 if(narchs != 1 && arch_process == FALSE)
827 continue;
828 any_processing = TRUE;
831 * Now this arch[i] has been selected to be processed so process it
832 * according to its type.
834 if(archs[i].type == OFILE_ARCHIVE){
835 for(j = 0; j < archs[i].nmembers; j++){
836 if(archs[i].members[j].type == OFILE_Mach_O){
837 strip_object(archs + i, archs[i].members + j,
838 archs[i].members[j].object);
841 missing_syms = 0;
842 if(iflag == 0){
843 for(k = 0; k < nsave_symbols; k++){
844 if(save_symbols[k].seen == FALSE){
845 if(missing_syms == 0){
846 error_arch(archs + i, NULL, "symbols names "
847 "listed in: %s not in: ", sfile);
848 missing_syms = 1;
850 fprintf(stderr, "%s\n", save_symbols[k].name);
854 for(k = 0; k < nsave_symbols; k++){
855 save_symbols[k].seen = FALSE;
857 missing_syms = 0;
858 if(iflag == 0){
859 for(k = 0; k < nremove_symbols; k++){
860 if(remove_symbols[k].seen == FALSE){
861 if(missing_syms == 0){
862 error_arch(archs + i, NULL, "symbols names "
863 "listed in: %s not defined in: ",
864 Rfile);
865 missing_syms = 1;
867 fprintf(stderr, "%s\n", remove_symbols[k].name);
871 for(k = 0; k < nremove_symbols; k++){
872 remove_symbols[k].seen = FALSE;
875 * Reset the library offsets and size.
877 offset = 0;
878 for(j = 0; j < archs[i].nmembers; j++){
879 archs[i].members[j].offset = offset;
880 size = 0;
881 if(archs[i].members[j].member_long_name == TRUE){
882 size = rnd(archs[i].members[j].member_name_size, 8) +
883 (rnd(sizeof(struct ar_hdr), 8) -
884 sizeof(struct ar_hdr));
885 archs[i].toc_long_name = TRUE;
887 if(archs[i].members[j].object != NULL){
888 size +=
889 rnd(archs[i].members[j].object->object_size -
890 archs[i].members[j].object->input_sym_info_size +
891 archs[i].members[j].object->output_sym_info_size,
893 sprintf(archs[i].members[j].ar_hdr->ar_size, "%-*ld",
894 (int)sizeof(archs[i].members[j].ar_hdr->ar_size),
895 (long)(size));
897 * This has to be done by hand because sprintf puts a
898 * null at the end of the buffer.
900 memcpy(archs[i].members[j].ar_hdr->ar_fmag, ARFMAG,
901 (int)sizeof(archs[i].members[j].ar_hdr->ar_fmag));
903 else{
904 size += archs[i].members[j].unknown_size;
906 offset += sizeof(struct ar_hdr) + size;
908 archs[i].library_size = offset;
910 else if(archs[i].type == OFILE_Mach_O){
911 strip_object(archs + i, NULL, archs[i].object);
913 else {
914 warning_arch(archs + i, NULL, "can't process non-object and "
915 "non-archive file: ");
916 return;
919 if(all_archs == FALSE && narch_flags != 0){
920 for(i = 0; i < narch_flags; i++){
921 if(arch_flag_processed[i] == FALSE)
922 error("file: %s does not contain architecture: %s",
923 archs[0].file_name, arch_flags[i].name);
925 free(arch_flag_processed);
927 if(any_processing == FALSE)
928 fatal("no processing done on input file: %s (specify a -arch flag)",
929 archs[0].file_name);
932 static
933 void
934 strip_object(
935 struct arch *arch,
936 struct member *member,
937 struct object *object)
939 enum byte_sex host_byte_sex;
940 uint32_t offset;
941 struct dylib_table_of_contents *tocs;
942 uint32_t ntoc;
943 struct dylib_module *mods;
944 struct dylib_module_64 *mods64;
945 uint32_t nmodtab;
946 struct dylib_reference *refs;
947 uint32_t nextrefsyms;
948 uint32_t i, j;
949 struct load_command *lc;
950 struct segment_command *sg;
951 struct segment_command_64 *sg64;
952 struct section *s;
953 struct section_64 *s64;
954 struct relocation_info *relocs;
955 struct scattered_relocation_info *sreloc;
956 int32_t missing_reloc_symbols;
957 uint32_t stride, section_type, nitems;
958 char *contents;
959 uint32_t dyld_info_start;
960 uint32_t dyld_info_end;
961 #ifndef NMEDIT
962 uint32_t flags;
963 uint32_t k;
964 #endif
965 uint32_t ncmds;
967 host_byte_sex = get_host_byte_sex();
969 /* Don't do anything to stub dylibs which have no load commands. */
970 if(object->mh_filetype == MH_DYLIB_STUB){
971 if((object->mh != NULL && object->mh->ncmds == 0) ||
972 (object->mh64 != NULL && object->mh64->ncmds == 0)){
973 return;
976 if(object->mh_filetype == MH_DSYM)
977 fatal_arch(arch, member, "can't process dSYM companion file: ");
978 if(object->st == NULL || object->st->nsyms == 0){
979 warning_arch(arch, member, "input object file stripped: ");
980 return;
983 nsyms = object->st->nsyms;
984 if(object->mh != NULL){
985 symbols = (struct nlist *)
986 (object->object_addr + object->st->symoff);
987 if(object->object_byte_sex != host_byte_sex)
988 swap_nlist(symbols, nsyms, host_byte_sex);
989 symbols64 = NULL;
991 else{
992 symbols = NULL;
993 symbols64 = (struct nlist_64 *)
994 (object->object_addr + object->st->symoff);
995 if(object->object_byte_sex != host_byte_sex)
996 swap_nlist_64(symbols64, nsyms, host_byte_sex);
998 strings = object->object_addr + object->st->stroff;
999 strsize = object->st->strsize;
1001 #ifndef NMEDIT
1002 if(object->mh != NULL)
1003 flags = object->mh->flags;
1004 else
1005 flags = object->mh64->flags;
1006 if(object->mh_filetype == MH_DYLIB &&
1007 (flags & MH_PREBOUND) != MH_PREBOUND){
1008 arch->dont_update_LC_ID_DYLIB_timestamp = TRUE;
1010 if(object->mh_filetype != MH_DYLIB && cflag)
1011 fatal_arch(arch, member, "-c can't be used on non-dynamic "
1012 "library: ");
1013 #endif /* !(NMEDIT) */
1014 if(object->mh_filetype == MH_DYLIB_STUB)
1015 fatal_arch(arch, member, "dynamic stub library can't be changed "
1016 "once created: ");
1018 if(object->mh_filetype == MH_DYLIB){
1019 tocs = (struct dylib_table_of_contents *)
1020 (object->object_addr + object->dyst->tocoff);
1021 ntoc = object->dyst->ntoc;
1022 nmodtab = object->dyst->nmodtab;
1023 if(object->mh != NULL){
1024 mods = (struct dylib_module *)
1025 (object->object_addr + object->dyst->modtaboff);
1026 if(object->object_byte_sex != host_byte_sex)
1027 swap_dylib_module(mods, nmodtab, host_byte_sex);
1028 mods64 = NULL;
1030 else{
1031 mods = NULL;
1032 mods64 = (struct dylib_module_64 *)
1033 (object->object_addr + object->dyst->modtaboff);
1034 if(object->object_byte_sex != host_byte_sex)
1035 swap_dylib_module_64(mods64, nmodtab, host_byte_sex);
1037 refs = (struct dylib_reference *)
1038 (object->object_addr + object->dyst->extrefsymoff);
1039 nextrefsyms = object->dyst->nextrefsyms;
1040 if(object->object_byte_sex != host_byte_sex){
1041 swap_dylib_table_of_contents(tocs, ntoc, host_byte_sex);
1042 swap_dylib_reference(refs, nextrefsyms, host_byte_sex);
1044 #ifndef NMEDIT
1046 * In the -c flag is specified then strip the section contents of
1047 * this dynamic library and change it into a stub library. When
1048 * creating a stub library the timestamp is not changed.
1050 if(cflag){
1051 arch->dont_update_LC_ID_DYLIB_timestamp = TRUE;
1053 lc = object->load_commands;
1054 if(object->mh != NULL){
1055 ncmds = object->mh->ncmds;
1056 object->mh_filetype = MH_DYLIB_STUB;
1057 object->mh->filetype = MH_DYLIB_STUB;
1059 else{
1060 ncmds = object->mh64->ncmds;
1061 object->mh_filetype = MH_DYLIB_STUB;
1062 object->mh64->filetype = MH_DYLIB_STUB;
1064 for(i = 0; i < ncmds; i++){
1065 if(lc->cmd == LC_SEGMENT){
1066 sg = (struct segment_command *)lc;
1067 if(strcmp(sg->segname, SEG_LINKEDIT) != 0){
1069 * Zero out the section offset, reloff, and size
1070 * fields as the section contents are being removed.
1072 s = (struct section *)
1073 ((char *)sg + sizeof(struct segment_command));
1074 for(j = 0; j < sg->nsects; j++){
1076 * For section types with indirect tables we
1077 * do not zero out the section size in a stub
1078 * library. As the section size is needed to
1079 * know now many indirect table entries the
1080 * section has. This is a bit odd but programs
1081 * dealing with MH_DYLIB_STUB filetypes special
1082 * case this.
1084 section_type = s[j].flags & SECTION_TYPE;
1085 if(section_type != S_SYMBOL_STUBS &&
1086 section_type != S_LAZY_SYMBOL_POINTERS &&
1087 section_type != S_LAZY_DYLIB_SYMBOL_POINTERS &&
1088 section_type != S_NON_LAZY_SYMBOL_POINTERS){
1089 s[j].size = 0;
1091 s[j].addr = 0;
1092 s[j].offset = 0;
1093 s[j].reloff = 0;
1095 /* zero out file offset and size in the segment */
1096 sg->fileoff = 0;
1097 sg->filesize = 0;
1100 else if(lc->cmd == LC_SEGMENT_64){
1101 sg64 = (struct segment_command_64 *)lc;
1102 if(strcmp(sg64->segname, SEG_LINKEDIT) != 0){
1104 * Zero out the section offset, reloff, and size
1105 * fields as the section contents are being removed.
1107 s64 = (struct section_64 *)
1108 ((char *)sg64 +
1109 sizeof(struct segment_command_64));
1110 for(j = 0; j < sg64->nsects; j++){
1112 * For section types with indirect tables we
1113 * do not zero out the section size in a stub
1114 * library. As the section size is needed to
1115 * know now many indirect table entries the
1116 * section has. This is a bit odd but programs
1117 * dealing with MH_DYLIB_STUB filetypes special
1118 * case this.
1120 section_type = s64[j].flags & SECTION_TYPE;
1121 if(section_type != S_SYMBOL_STUBS &&
1122 section_type != S_LAZY_SYMBOL_POINTERS &&
1123 section_type != S_LAZY_DYLIB_SYMBOL_POINTERS &&
1124 section_type != S_NON_LAZY_SYMBOL_POINTERS){
1125 s64[j].size = 0;
1127 s64[j].addr = 0;
1128 s64[j].offset = 0;
1129 s64[j].reloff = 0;
1131 /* zero out file offset and size in the segment */
1132 sg64->fileoff = 0;
1133 sg64->filesize = 0;
1136 lc = (struct load_command *)((char *)lc + lc->cmdsize);
1139 * To get the right amount of the file copied out by writeout()
1140 * for the case when we are stripping out the section contents
1141 * we reduce the object size by the size of the section contents
1142 * including the padding after the load commands. Then this
1143 * size minus the size of the input symbolic information is
1144 * copied out.
1146 if(object->mh != NULL){
1147 object->object_size -= (object->seg_linkedit->fileoff -
1148 (sizeof(struct mach_header) +
1149 object->mh->sizeofcmds));
1151 * Set the file offset to the link edit information to be
1152 * right after the load commands.
1154 object->seg_linkedit->fileoff =
1155 sizeof(struct mach_header) +
1156 object->mh->sizeofcmds;
1158 else{
1159 object->object_size -= (object->seg_linkedit64->fileoff -
1160 (sizeof(struct mach_header_64) +
1161 object->mh64->sizeofcmds));
1163 * Set the file offset to the link edit information to be
1164 * right after the load commands.
1166 object->seg_linkedit64->fileoff =
1167 sizeof(struct mach_header_64) +
1168 object->mh64->sizeofcmds;
1171 #endif /* !(NMEDIT) */
1173 else{
1174 tocs = NULL;
1175 ntoc = 0;
1176 mods = NULL;
1177 mods64 = NULL;
1178 nmodtab = 0;
1179 refs = NULL;
1180 nextrefsyms = 0;
1184 * coalesced symbols can be stripped only if they are not used via an
1185 * symbol pointer. So to know that strip_symtab() needs to be passed
1186 * the indirect symbol table.
1188 if(object->dyst != NULL && object->dyst->nindirectsyms != 0){
1189 nindirectsyms = object->dyst->nindirectsyms;
1190 indirectsyms = (uint32_t *)
1191 (object->object_addr + object->dyst->indirectsymoff);
1192 if(object->object_byte_sex != host_byte_sex)
1193 swap_indirect_symbols(indirectsyms, nindirectsyms,
1194 host_byte_sex);
1196 else{
1197 indirectsyms = NULL;
1198 nindirectsyms = 0;
1201 if(object->mh != NULL)
1202 object->input_sym_info_size =
1203 nsyms * sizeof(struct nlist) +
1204 strsize;
1205 else
1206 object->input_sym_info_size =
1207 nsyms * sizeof(struct nlist_64) +
1208 strsize;
1209 #ifndef NMEDIT
1210 if(object->mh != NULL)
1211 flags = object->mh->flags;
1212 else
1213 flags = object->mh64->flags;
1214 if(strip_all &&
1215 (flags & MH_DYLDLINK) == MH_DYLDLINK &&
1216 object->mh_filetype == MH_EXECUTE)
1217 default_dyld_executable = TRUE;
1218 else
1219 default_dyld_executable = FALSE;
1220 #endif /* !defined(NMEDIT) */
1222 #ifndef NMEDIT
1223 if(sfile != NULL || Rfile != NULL || dfile != NULL || Aflag || uflag ||
1224 Sflag || xflag || Xflag || nflag || rflag ||
1225 default_dyld_executable || object->mh_filetype == MH_DYLIB ||
1226 object->mh_filetype == MH_DYLINKER)
1227 #endif /* !defined(NMEDIT) */
1229 #ifdef NMEDIT
1230 if(edit_symtab(arch, member, object, symbols, symbols64, nsyms,
1231 strings, strsize, tocs, ntoc, mods, mods64, nmodtab, refs,
1232 nextrefsyms) == FALSE)
1233 return;
1234 #else /* !defined(NMEDIT) */
1235 if(strip_symtab(arch, member, object, tocs, ntoc, mods, mods64,
1236 nmodtab, refs, nextrefsyms) == FALSE)
1237 return;
1238 if(no_uuid == TRUE)
1239 strip_LC_UUID_commands(arch, member, object);
1240 #endif /* !defined(NMEDIT) */
1241 if(object->mh != NULL)
1242 object->output_sym_info_size =
1243 new_nsyms * sizeof(struct nlist) +
1244 new_strsize;
1245 else
1246 object->output_sym_info_size =
1247 new_nsyms * sizeof(struct nlist_64) +
1248 new_strsize;
1250 object->st->nsyms = new_nsyms;
1251 object->st->strsize = new_strsize;
1253 if(object->mh != NULL)
1254 object->output_symbols = new_symbols;
1255 else
1256 object->output_symbols64 = new_symbols64;
1257 object->output_nsymbols = new_nsyms;
1258 object->output_strings = new_strings;
1259 object->output_strings_size = new_strsize;
1261 if(object->dyld_info != NULL){
1262 /* there are five parts to the dyld info, but
1263 strip does not alter them, so copy as a block */
1264 dyld_info_start = 0;
1265 if (object->dyld_info->rebase_off != 0)
1266 dyld_info_start = object->dyld_info->rebase_off;
1267 else if (object->dyld_info->bind_off != 0)
1268 dyld_info_start = object->dyld_info->bind_off;
1269 else if (object->dyld_info->weak_bind_off != 0)
1270 dyld_info_start = object->dyld_info->weak_bind_off;
1271 else if (object->dyld_info->lazy_bind_off != 0)
1272 dyld_info_start = object->dyld_info->lazy_bind_off;
1273 else if (object->dyld_info->export_off != 0)
1274 dyld_info_start = object->dyld_info->export_off;
1275 dyld_info_end = 0;
1276 if (object->dyld_info->export_size != 0)
1277 dyld_info_end = object->dyld_info->export_off
1278 + object->dyld_info->export_size;
1279 else if (object->dyld_info->lazy_bind_size != 0)
1280 dyld_info_end = object->dyld_info->lazy_bind_off
1281 + object->dyld_info->lazy_bind_size;
1282 else if (object->dyld_info->weak_bind_size != 0)
1283 dyld_info_end = object->dyld_info->weak_bind_off
1284 + object->dyld_info->weak_bind_size;
1285 else if (object->dyld_info->bind_size != 0)
1286 dyld_info_end = object->dyld_info->bind_off
1287 + object->dyld_info->bind_size;
1288 else if (object->dyld_info->rebase_size != 0)
1289 dyld_info_end = object->dyld_info->rebase_off
1290 + object->dyld_info->rebase_size;
1291 object->output_dyld_info = object->object_addr +dyld_info_start;
1292 object->output_dyld_info_size = dyld_info_end - dyld_info_start;
1293 object->output_sym_info_size += object->output_dyld_info_size;
1295 * Warn about strip -s or -R on a final linked image with
1296 * dyld_info.
1298 if(nsave_symbols != 0){
1299 warning_arch(arch, NULL, "removing global symbols from a "
1300 "final linked no longer supported. Use "
1301 "-exported_symbols_list at link time when "
1302 "building: ");
1305 if(object->split_info_cmd != NULL){
1306 object->output_split_info_data = object->object_addr +
1307 object->split_info_cmd->dataoff;
1308 object->output_split_info_data_size =
1309 object->split_info_cmd->datasize;
1311 if(object->func_starts_info_cmd != NULL){
1312 object->output_func_start_info_data = object->object_addr +
1313 object->func_starts_info_cmd->dataoff;
1314 object->output_func_start_info_data_size =
1315 object->func_starts_info_cmd->datasize;
1317 if(object->code_sig_cmd != NULL){
1318 #ifndef NMEDIT
1319 if(!cflag)
1320 #endif /* !(NMEDIT) */
1322 object->output_code_sig_data = object->object_addr +
1323 object->code_sig_cmd->dataoff;
1324 object->output_code_sig_data_size =
1325 object->code_sig_cmd->datasize;
1329 if(object->dyst != NULL){
1330 object->dyst->ilocalsym = 0;
1331 object->dyst->nlocalsym = new_nlocalsym;
1332 object->dyst->iextdefsym = new_nlocalsym;
1333 object->dyst->nextdefsym = new_nextdefsym;
1334 object->dyst->iundefsym = new_nlocalsym + new_nextdefsym;
1335 object->dyst->nundefsym = new_nundefsym;
1336 if(object->dyst->nindirectsyms != 0){
1337 object->output_indirect_symtab = indirectsyms;
1338 if(object->object_byte_sex != host_byte_sex)
1339 swap_indirect_symbols(indirectsyms, nindirectsyms,
1340 object->object_byte_sex);
1344 * If the -c option is specified the object's filetype will
1345 * have been changed from MH_DYLIB to MH_DYLIB_STUB above.
1347 if(object->mh_filetype == MH_DYLIB ||
1348 object->mh_filetype == MH_DYLIB_STUB){
1349 object->output_tocs = new_tocs;
1350 object->output_ntoc = new_ntoc;
1351 #ifdef NMEDIT
1352 if(object->mh != NULL)
1353 object->output_mods = new_mods;
1354 else
1355 object->output_mods64 = new_mods64;
1356 object->output_nmodtab = new_nmodtab;
1357 #else
1358 object->output_mods = mods;
1359 object->output_nmodtab = nmodtab;
1360 #endif
1361 object->output_refs = new_refs;
1362 object->output_nextrefsyms = new_nextrefsyms;
1363 if(object->object_byte_sex != host_byte_sex){
1364 swap_dylib_table_of_contents(new_tocs, new_ntoc,
1365 object->object_byte_sex);
1366 #ifdef NMEDIT
1367 if(object->mh != NULL)
1368 swap_dylib_module(new_mods, new_nmodtab,
1369 object->object_byte_sex);
1370 else
1371 swap_dylib_module_64(new_mods64, new_nmodtab,
1372 object->object_byte_sex);
1373 #else
1374 if(object->mh != NULL)
1375 swap_dylib_module(mods, nmodtab,
1376 object->object_byte_sex);
1377 else
1378 swap_dylib_module_64(mods64, nmodtab,
1379 object->object_byte_sex);
1380 #endif
1381 swap_dylib_reference(new_refs, new_nextrefsyms,
1382 object->object_byte_sex);
1385 if(object->dyld_info != NULL){
1386 object->input_sym_info_size += object->dyld_info->rebase_size
1387 + object->dyld_info->bind_size
1388 + object->dyld_info->weak_bind_size
1389 + object->dyld_info->lazy_bind_size
1390 + object->dyld_info->export_size;
1392 object->input_sym_info_size +=
1393 object->dyst->nlocrel * sizeof(struct relocation_info) +
1394 object->dyst->nextrel * sizeof(struct relocation_info) +
1395 object->dyst->ntoc * sizeof(struct dylib_table_of_contents)+
1396 object->dyst->nextrefsyms * sizeof(struct dylib_reference);
1397 if(object->mh != NULL){
1398 object->input_sym_info_size +=
1399 object->dyst->nmodtab * sizeof(struct dylib_module) +
1400 object->dyst->nindirectsyms * sizeof(uint32_t);
1402 else{
1403 object->input_sym_info_size +=
1404 object->dyst->nmodtab * sizeof(struct dylib_module_64) +
1405 object->dyst->nindirectsyms * sizeof(uint32_t) +
1406 object->input_indirectsym_pad;
1408 #ifndef NMEDIT
1410 * When stripping out the section contents to create a
1411 * dynamic library stub the relocation info also gets
1412 * stripped.
1414 if(!cflag)
1415 #endif /* !(NMEDIT) */
1417 object->output_sym_info_size +=
1418 object->dyst->nlocrel * sizeof(struct relocation_info) +
1419 object->dyst->nextrel * sizeof(struct relocation_info);
1421 object->output_sym_info_size +=
1422 new_ntoc * sizeof(struct dylib_table_of_contents)+
1423 new_nextrefsyms * sizeof(struct dylib_reference) +
1424 object->dyst->nindirectsyms * sizeof(uint32_t) +
1425 object->input_indirectsym_pad;
1426 if(object->mh != NULL){
1427 object->output_sym_info_size +=
1428 object->dyst->nmodtab * sizeof(struct dylib_module);
1430 else{
1431 object->output_sym_info_size +=
1432 object->dyst->nmodtab * sizeof(struct dylib_module_64);
1434 if(object->hints_cmd != NULL){
1435 object->input_sym_info_size +=
1436 object->hints_cmd->nhints *
1437 sizeof(struct twolevel_hint);
1438 object->output_sym_info_size +=
1439 object->hints_cmd->nhints *
1440 sizeof(struct twolevel_hint);
1442 if(object->split_info_cmd != NULL){
1443 object->input_sym_info_size +=
1444 object->split_info_cmd->datasize;
1445 object->output_sym_info_size +=
1446 object->split_info_cmd->datasize;
1448 if(object->func_starts_info_cmd != NULL){
1449 object->input_sym_info_size +=
1450 object->func_starts_info_cmd->datasize;
1451 object->output_sym_info_size +=
1452 object->func_starts_info_cmd->datasize;
1454 if(object->code_sig_cmd != NULL){
1455 object->input_sym_info_size =
1456 rnd(object->input_sym_info_size, 16);
1457 object->input_sym_info_size +=
1458 object->code_sig_cmd->datasize;
1459 #ifndef NMEDIT
1460 if(cflag){
1461 strip_LC_CODE_SIGNATURE_commands(arch, member, object);
1463 else
1464 #endif /* !(NMEDIT) */
1466 object->output_sym_info_size =
1467 rnd(object->output_sym_info_size, 16);
1468 object->output_sym_info_size +=
1469 object->code_sig_cmd->datasize;
1473 object->dyst->ntoc = new_ntoc;
1474 object->dyst->nextrefsyms = new_nextrefsyms;
1476 offset = get_starting_syminfo_offset(object);
1478 if(object->dyld_info != 0){
1479 if (object->dyld_info->rebase_off != 0){
1480 object->dyld_info->rebase_off = offset;
1481 offset += object->dyld_info->rebase_size;
1483 if (object->dyld_info->bind_off != 0){
1484 object->dyld_info->bind_off = offset;
1485 offset += object->dyld_info->bind_size;
1487 if (object->dyld_info->weak_bind_off != 0){
1488 object->dyld_info->weak_bind_off = offset;
1489 offset += object->dyld_info->weak_bind_size;
1491 if (object->dyld_info->lazy_bind_off != 0){
1492 object->dyld_info->lazy_bind_off = offset;
1493 offset += object->dyld_info->lazy_bind_size;
1495 if (object->dyld_info->export_off != 0){
1496 object->dyld_info->export_off = offset;
1497 offset += object->dyld_info->export_size;
1501 if(object->dyst->nlocrel != 0){
1502 object->output_loc_relocs = (struct relocation_info *)
1503 (object->object_addr + object->dyst->locreloff);
1504 #ifndef NMEDIT
1506 * When stripping out the section contents to create a
1507 * dynamic library stub the relocation info also gets
1508 * stripped.
1510 if(cflag){
1511 object->dyst->nlocrel = 0;
1512 object->dyst->locreloff = 0;
1514 else
1515 #endif /* defined(NMEDIT) */
1517 object->dyst->locreloff = offset;
1518 offset += object->dyst->nlocrel *
1519 sizeof(struct relocation_info);
1522 else
1523 object->dyst->locreloff = 0;
1525 if(object->split_info_cmd != NULL){
1526 object->split_info_cmd->dataoff = offset;
1527 offset += object->split_info_cmd->datasize;
1530 if(object->func_starts_info_cmd != NULL){
1531 object->func_starts_info_cmd->dataoff = offset;
1532 offset += object->func_starts_info_cmd->datasize;
1535 if(object->st->nsyms != 0){
1536 object->st->symoff = offset;
1537 if(object->mh != NULL)
1538 offset += object->st->nsyms * sizeof(struct nlist);
1539 else
1540 offset += object->st->nsyms * sizeof(struct nlist_64);
1542 else
1543 object->st->symoff = 0;
1545 if(object->hints_cmd != NULL){
1546 if(object->hints_cmd->nhints != 0){
1547 object->output_hints = (struct twolevel_hint *)
1548 (object->object_addr + object->hints_cmd->offset);
1549 object->hints_cmd->offset = offset;
1550 offset += object->hints_cmd->nhints *
1551 sizeof(struct twolevel_hint);
1553 else
1554 object->hints_cmd->offset = 0;
1557 if(object->dyst->nextrel != 0){
1558 object->output_ext_relocs = (struct relocation_info *)
1559 (object->object_addr + object->dyst->extreloff);
1560 #ifndef NMEDIT
1562 * When stripping out the section contents to create a
1563 * dynamic library stub the relocation info also gets
1564 * stripped.
1566 if(cflag){
1567 object->dyst->nextrel = 0;
1568 object->dyst->extreloff = 0;
1570 else
1571 #endif /* defined(NMEDIT) */
1573 object->dyst->extreloff = offset;
1574 offset += object->dyst->nextrel *
1575 sizeof(struct relocation_info);
1578 else
1579 object->dyst->extreloff = 0;
1581 if(object->dyst->nindirectsyms != 0){
1582 object->dyst->indirectsymoff = offset;
1583 offset += object->dyst->nindirectsyms * sizeof(uint32_t) +
1584 object->input_indirectsym_pad;
1586 else
1587 object->dyst->indirectsymoff = 0;;
1589 if(object->dyst->ntoc != 0){
1590 object->dyst->tocoff = offset;
1591 offset += object->dyst->ntoc *
1592 sizeof(struct dylib_table_of_contents);
1594 else
1595 object->dyst->tocoff = 0;
1597 if(object->dyst->nmodtab != 0){
1598 #ifndef NMEDIT
1600 * When stripping out the section contents to create a
1601 * dynamic library stub zero out the fields in the module
1602 * table for the sections and relocation information and
1603 * clear Objective-C address and size from modules.
1605 if(cflag){
1606 if(object->mh != NULL){
1607 for(k = 0; k < object->dyst->nmodtab; k++){
1608 mods[k].iinit_iterm = 0;
1609 mods[k].ninit_nterm = 0;
1610 mods[k].iextrel = 0;
1611 mods[k].nextrel = 0;
1612 mods[k].objc_module_info_addr = 0;
1613 mods[k].objc_module_info_size = 0;
1616 else{
1617 for(k = 0; k < object->dyst->nmodtab; k++){
1618 mods64[k].iinit_iterm = 0;
1619 mods64[k].ninit_nterm = 0;
1620 mods64[k].iextrel = 0;
1621 mods64[k].nextrel = 0;
1622 mods64[k].objc_module_info_addr = 0;
1623 mods64[k].objc_module_info_size = 0;
1627 #endif /* !(NMEDIT) */
1628 object->dyst->modtaboff = offset;
1629 if(object->mh != NULL)
1630 offset += object->dyst->nmodtab *
1631 sizeof(struct dylib_module);
1632 else
1633 offset += object->dyst->nmodtab *
1634 sizeof(struct dylib_module_64);
1636 else
1637 object->dyst->modtaboff = 0;
1639 if(object->dyst->nextrefsyms != 0){
1640 object->dyst->extrefsymoff = offset;
1641 offset += object->dyst->nextrefsyms *
1642 sizeof(struct dylib_reference);
1644 else
1645 object->dyst->extrefsymoff = 0;
1647 if(object->st->strsize != 0){
1648 object->st->stroff = offset;
1649 offset += object->st->strsize;
1651 else
1652 object->st->stroff = 0;
1654 if(object->code_sig_cmd != NULL){
1655 offset = rnd(offset, 16);
1656 object->code_sig_cmd->dataoff = offset;
1657 offset += object->code_sig_cmd->datasize;
1660 else{
1661 if(new_strsize != 0){
1662 if(object->mh != NULL)
1663 object->st->stroff = object->st->symoff +
1664 new_nsyms * sizeof(struct nlist);
1665 else
1666 object->st->stroff = object->st->symoff +
1667 new_nsyms * sizeof(struct nlist_64);
1669 else
1670 object->st->stroff = 0;
1671 if(new_nsyms == 0)
1672 object->st->symoff = 0;
1675 #ifndef NMEDIT
1676 else{
1678 * Here we are doing a full symbol strip. In some cases it may
1679 * leave the local relocation entries as well as LOCAL indirect
1680 * symbol table entries.
1682 if(saves != NULL)
1683 free(saves);
1684 saves = (int32_t *)allocate(object->st->nsyms * sizeof(int32_t));
1685 bzero(saves, object->st->nsyms * sizeof(int32_t));
1688 * Account for the symbolic info in the input file.
1690 if(object->dyst != NULL){
1691 object->input_sym_info_size +=
1692 object->dyst->nlocrel * sizeof(struct relocation_info) +
1693 object->dyst->nextrel * sizeof(struct relocation_info) +
1694 object->dyst->ntoc * sizeof(struct dylib_table_of_contents)+
1695 object->dyst->nextrefsyms * sizeof(struct dylib_reference);
1696 if(object->mh != NULL){
1697 object->input_sym_info_size +=
1698 object->dyst->nmodtab * sizeof(struct dylib_module) +
1699 object->dyst->nindirectsyms * sizeof(uint32_t);
1701 else{
1702 object->input_sym_info_size +=
1703 object->dyst->nmodtab * sizeof(struct dylib_module_64) +
1704 object->dyst->nindirectsyms * sizeof(uint32_t) +
1705 object->input_indirectsym_pad;
1710 * Determine the offset where the remaining symbolic info will start
1711 * in the output file (if any).
1713 offset = get_starting_syminfo_offset(object);
1716 * For a full symbol strip all these values in the output file are
1717 * set to zero.
1719 object->st->symoff = 0;
1720 object->st->nsyms = 0;
1721 object->st->stroff = 0;
1722 object->st->strsize = 0;
1723 if(object->dyst != NULL){
1724 object->dyst->ilocalsym = 0;
1725 object->dyst->nlocalsym = 0;
1726 object->dyst->iextdefsym = 0;
1727 object->dyst->nextdefsym = 0;
1728 object->dyst->iundefsym = 0;
1729 object->dyst->nundefsym = 0;
1733 * This will accumulate any remaining symbolic info size in the
1734 * output file.
1736 object->output_sym_info_size = 0;
1739 * We set these so that checking can be done below to report the
1740 * symbols that can't be stripped because of relocation entries
1741 * or indirect symbol table entries. Normally if these table have a
1742 * non-zero number of entries it will be an error as we are trying
1743 * to strip everything. But it maybe that there are only LOCAL
1744 * indirect entries which is odd but will be OK.
1746 if(object->dyst != NULL){
1747 if(object->dyst->nextrel != 0){
1748 object->output_ext_relocs = (struct relocation_info *)
1749 (object->object_addr + object->dyst->extreloff);
1752 * Since this file has a dynamic symbol table and if this file
1753 * has local relocation entries on input make sure they are
1754 * there on output. This is a rare case that it will not have
1755 * external relocs or indirect symbols but can happen as is the
1756 * case with the dynamic linker itself.
1758 if(object->dyst->nlocrel != 0){
1759 object->output_loc_relocs = (struct relocation_info *)
1760 (object->object_addr + object->dyst->locreloff);
1761 object->output_sym_info_size +=
1762 object->dyst->nlocrel * sizeof(struct relocation_info);
1764 object->dyst->locreloff = offset;
1765 offset += object->dyst->nlocrel *
1766 sizeof(struct relocation_info);
1769 if(object->dyst->nindirectsyms != 0){
1770 object->output_indirect_symtab = (uint32_t *)
1771 (object->object_addr +
1772 object->dyst->indirectsymoff);
1773 if(object->object_byte_sex != host_byte_sex)
1774 swap_indirect_symbols(
1775 object->output_indirect_symtab,
1776 object->dyst->nindirectsyms,
1777 object->object_byte_sex);
1779 object->output_sym_info_size +=
1780 object->dyst->nindirectsyms * sizeof(uint32_t) +
1781 object->input_indirectsym_pad;
1783 object->dyst->indirectsymoff = offset;
1784 offset += object->dyst->nindirectsyms * sizeof(uint32_t) +
1785 object->input_indirectsym_pad;
1789 #endif /* !defined(NMEDIT) */
1792 * Always clear the prebind checksum if any when creating a new file.
1794 if(object->cs != NULL)
1795 object->cs->cksum = 0;
1797 if(object->seg_linkedit != NULL){
1798 object->seg_linkedit->filesize += object->output_sym_info_size -
1799 object->input_sym_info_size;
1800 object->seg_linkedit->vmsize = object->seg_linkedit->filesize;
1802 else if(object->seg_linkedit64 != NULL){
1803 /* Do this in two steps to avoid 32/64-bit casting problems. */
1804 object->seg_linkedit64->filesize -= object->input_sym_info_size;
1805 object->seg_linkedit64->filesize += object->output_sym_info_size;
1806 object->seg_linkedit64->vmsize = object->seg_linkedit64->filesize;
1810 * Check and update the external relocation entries to make sure
1811 * referenced symbols are not stripped and refer to the new symbol
1812 * table indexes.
1814 * The external relocation entries can be located in one of two places,
1815 * first off of the sections or second off of the dynamic symtab.
1817 missing_reloc_symbols = 0;
1818 lc = object->load_commands;
1819 if(object->mh != NULL)
1820 ncmds = object->mh->ncmds;
1821 else
1822 ncmds = object->mh64->ncmds;
1823 for(i = 0; i < ncmds; i++){
1824 if(lc->cmd == LC_SEGMENT &&
1825 object->seg_linkedit != (struct segment_command *)lc){
1826 sg = (struct segment_command *)lc;
1827 s = (struct section *)((char *)sg +
1828 sizeof(struct segment_command));
1829 for(j = 0; j < sg->nsects; j++){
1830 if(s->nreloc != 0){
1831 if(s->reloff + s->nreloc *
1832 sizeof(struct relocation_info) >
1833 object->object_size){
1834 fatal_arch(arch, member, "truncated or malformed "
1835 "object (relocation entries for section (%.16s,"
1836 "%.16s) extends past the end of the file)",
1837 s->segname, s->sectname);
1839 relocs = (struct relocation_info *)
1840 (object->object_addr + s->reloff);
1841 if(object->object_byte_sex != host_byte_sex)
1842 swap_relocation_info(relocs, s->nreloc,
1843 host_byte_sex);
1844 if(s->offset + s->size > object->object_size){
1845 fatal_arch(arch, member, "truncated or malformed "
1846 "object (contents of section (%.16s,"
1847 "%.16s) extends past the end of the file)",
1848 s->segname, s->sectname);
1850 contents = object->object_addr + s->offset;
1851 check_object_relocs(arch, member, object, s->segname,
1852 s->sectname, s->size, contents, relocs, s->nreloc,
1853 symbols, symbols64, nsyms, strings,
1854 &missing_reloc_symbols, host_byte_sex);
1855 if(object->object_byte_sex != host_byte_sex)
1856 swap_relocation_info(relocs, s->nreloc,
1857 object->object_byte_sex);
1859 s++;
1862 else if(lc->cmd == LC_SEGMENT_64 &&
1863 object->seg_linkedit64 != (struct segment_command_64 *)lc){
1864 sg64 = (struct segment_command_64 *)lc;
1865 s64 = (struct section_64 *)((char *)sg64 +
1866 sizeof(struct segment_command_64));
1867 for(j = 0; j < sg64->nsects; j++){
1868 if(s64->nreloc != 0){
1869 if(s64->reloff + s64->nreloc *
1870 sizeof(struct relocation_info) >
1871 object->object_size){
1872 fatal_arch(arch, member, "truncated or malformed "
1873 "object (relocation entries for section (%.16s,"
1874 "%.16s) extends past the end of the file)",
1875 s64->segname, s64->sectname);
1877 relocs = (struct relocation_info *)
1878 (object->object_addr + s64->reloff);
1879 if(object->object_byte_sex != host_byte_sex)
1880 swap_relocation_info(relocs, s64->nreloc,
1881 host_byte_sex);
1882 if(s64->offset + s64->size > object->object_size){
1883 fatal_arch(arch, member, "truncated or malformed "
1884 "object (contents of section (%.16s,"
1885 "%.16s) extends past the end of the file)",
1886 s64->segname, s64->sectname);
1888 contents = object->object_addr + s64->offset;
1889 check_object_relocs(arch, member, object, s64->segname,
1890 s64->sectname, s64->size, contents, relocs,
1891 s64->nreloc, symbols, symbols64, nsyms, strings,
1892 &missing_reloc_symbols, host_byte_sex);
1893 if(object->object_byte_sex != host_byte_sex)
1894 swap_relocation_info(relocs, s64->nreloc,
1895 object->object_byte_sex);
1897 s64++;
1900 lc = (struct load_command *)((char *)lc + lc->cmdsize);
1902 if(object->dyst != NULL && object->dyst->nextrel != 0){
1903 relocs = object->output_ext_relocs;
1904 if(object->object_byte_sex != host_byte_sex)
1905 swap_relocation_info(relocs, object->dyst->nextrel,
1906 host_byte_sex);
1908 for(i = 0; i < object->dyst->nextrel; i++){
1909 if((relocs[i].r_address & R_SCATTERED) == 0 &&
1910 relocs[i].r_extern == 1){
1911 if(relocs[i].r_symbolnum > nsyms){
1912 fatal_arch(arch, member, "bad r_symbolnum for external "
1913 "relocation entry %d in: ", i);
1915 if(saves[relocs[i].r_symbolnum] == 0){
1916 if(missing_reloc_symbols == 0){
1917 error_arch(arch, member, "symbols referenced by "
1918 "relocation entries that can't be stripped in: ");
1919 missing_reloc_symbols = 1;
1921 if(object->mh != NULL){
1922 fprintf(stderr, "%s\n", strings + symbols
1923 [relocs[i].r_symbolnum].n_un.n_strx);
1925 else {
1926 fprintf(stderr, "%s\n", strings + symbols64
1927 [relocs[i].r_symbolnum].n_un.n_strx);
1929 saves[relocs[i].r_symbolnum] = -1;
1931 if(saves[relocs[i].r_symbolnum] != -1){
1932 relocs[i].r_symbolnum =
1933 saves[relocs[i].r_symbolnum] - 1;
1936 else{
1937 fatal_arch(arch, member, "bad external relocation entry "
1938 "%d (not external) in: ", i);
1940 if((relocs[i].r_address & R_SCATTERED) == 0){
1941 if(reloc_has_pair(object->mh_cputype, relocs[i].r_type))
1942 i++;
1944 else{
1945 sreloc = (struct scattered_relocation_info *)relocs + i;
1946 if(reloc_has_pair(object->mh_cputype, sreloc->r_type))
1947 i++;
1950 if(object->object_byte_sex != host_byte_sex)
1951 swap_relocation_info(relocs, object->dyst->nextrel,
1952 object->object_byte_sex);
1956 * Check and update the indirect symbol table entries to make sure
1957 * referenced symbols are not stripped and refer to the new symbol
1958 * table indexes.
1960 if(object->dyst != NULL && object->dyst->nindirectsyms != 0){
1961 if(object->object_byte_sex != host_byte_sex)
1962 swap_indirect_symbols(object->output_indirect_symtab,
1963 object->dyst->nindirectsyms, host_byte_sex);
1965 lc = object->load_commands;
1966 if(object->mh != NULL)
1967 ncmds = object->mh->ncmds;
1968 else
1969 ncmds = object->mh64->ncmds;
1970 for(i = 0; i < ncmds; i++){
1971 if(lc->cmd == LC_SEGMENT &&
1972 object->seg_linkedit != (struct segment_command *)lc){
1973 sg = (struct segment_command *)lc;
1974 s = (struct section *)((char *)sg +
1975 sizeof(struct segment_command));
1976 for(j = 0; j < sg->nsects; j++){
1977 section_type = s->flags & SECTION_TYPE;
1978 if(section_type == S_LAZY_SYMBOL_POINTERS ||
1979 section_type == S_LAZY_DYLIB_SYMBOL_POINTERS ||
1980 section_type == S_NON_LAZY_SYMBOL_POINTERS)
1981 stride = 4;
1982 else if(section_type == S_SYMBOL_STUBS)
1983 stride = s->reserved2;
1984 else{
1985 s++;
1986 continue;
1988 nitems = s->size / stride;
1989 contents = object->object_addr + s->offset;
1990 check_indirect_symtab(arch, member, object, nitems,
1991 s->reserved1, section_type, contents, symbols,
1992 symbols64, nsyms, strings, &missing_reloc_symbols,
1993 host_byte_sex);
1994 s++;
1997 else if(lc->cmd == LC_SEGMENT_64 &&
1998 object->seg_linkedit64 != (struct segment_command_64 *)lc){
1999 sg64 = (struct segment_command_64 *)lc;
2000 s64 = (struct section_64 *)((char *)sg64 +
2001 sizeof(struct segment_command_64));
2002 for(j = 0; j < sg64->nsects; j++){
2003 section_type = s64->flags & SECTION_TYPE;
2004 if(section_type == S_LAZY_SYMBOL_POINTERS ||
2005 section_type == S_LAZY_DYLIB_SYMBOL_POINTERS ||
2006 section_type == S_NON_LAZY_SYMBOL_POINTERS)
2007 stride = 8;
2008 else if(section_type == S_SYMBOL_STUBS)
2009 stride = s64->reserved2;
2010 else{
2011 s64++;
2012 continue;
2014 nitems = s64->size / stride;
2015 contents = object->object_addr + s64->offset;
2016 check_indirect_symtab(arch, member, object, nitems,
2017 s64->reserved1, section_type, contents, symbols,
2018 symbols64, nsyms, strings, &missing_reloc_symbols,
2019 host_byte_sex);
2020 s64++;
2023 lc = (struct load_command *)((char *)lc + lc->cmdsize);
2026 if(object->object_byte_sex != host_byte_sex)
2027 swap_indirect_symbols(object->output_indirect_symtab,
2028 object->dyst->nindirectsyms, object->object_byte_sex);
2032 * Issue a warning if object file has a code signature that the
2033 * operation will invalidate it.
2035 if(object->code_sig_cmd != NULL)
2036 warning_arch(arch, member, "changes being made to the file will "
2037 "invalidate the code signature in: ");
2041 * get_starting_syminfo_offset() returns the starting offset of the symbolic
2042 * info in the object file.
2044 static
2045 uint32_t
2046 get_starting_syminfo_offset(
2047 struct object *object)
2049 uint32_t offset;
2051 if(object->seg_linkedit != NULL ||
2052 object->seg_linkedit64 != NULL){
2053 if(object->mh != NULL)
2054 offset = object->seg_linkedit->fileoff;
2055 else
2056 offset = object->seg_linkedit64->fileoff;
2058 else{
2059 offset = UINT_MAX;
2060 if(object->dyst != NULL &&
2061 object->dyst->nlocrel != 0 &&
2062 object->dyst->locreloff < offset)
2063 offset = object->dyst->locreloff;
2064 if(object->st->nsyms != 0 &&
2065 object->st->symoff < offset)
2066 offset = object->st->symoff;
2067 if(object->dyst != NULL &&
2068 object->dyst->nextrel != 0 &&
2069 object->dyst->extreloff < offset)
2070 offset = object->dyst->extreloff;
2071 if(object->dyst != NULL &&
2072 object->dyst->nindirectsyms != 0 &&
2073 object->dyst->indirectsymoff < offset)
2074 offset = object->dyst->indirectsymoff;
2075 if(object->dyst != NULL &&
2076 object->dyst->ntoc != 0 &&
2077 object->dyst->tocoff < offset)
2078 offset = object->dyst->tocoff;
2079 if(object->dyst != NULL &&
2080 object->dyst->nmodtab != 0 &&
2081 object->dyst->modtaboff < offset)
2082 offset = object->dyst->modtaboff;
2083 if(object->dyst != NULL &&
2084 object->dyst->nextrefsyms != 0 &&
2085 object->dyst->extrefsymoff < offset)
2086 offset = object->dyst->extrefsymoff;
2087 if(object->st->strsize != 0 &&
2088 object->st->stroff < offset)
2089 offset = object->st->stroff;
2091 return(offset);
2095 * check_object_relocs() is used to check and update the external relocation
2096 * entries from a section in an object file, to make sure referenced symbols
2097 * are not stripped and are changed to refer to the new symbol table indexes.
2099 static
2100 void
2101 check_object_relocs(
2102 struct arch *arch,
2103 struct member *member,
2104 struct object *object,
2105 char *segname,
2106 char *sectname,
2107 uint64_t sectsize,
2108 char *contents,
2109 struct relocation_info *relocs,
2110 uint32_t nreloc,
2111 struct nlist *symbols,
2112 struct nlist_64 *symbols64,
2113 uint32_t nsyms,
2114 char *strings,
2115 int32_t *missing_reloc_symbols,
2116 enum byte_sex host_byte_sex)
2118 uint32_t k, n_strx;
2119 uint64_t n_value;
2120 #ifdef NMEDIT
2121 uint32_t value, n_ext;
2122 uint64_t value64;
2123 #endif
2124 struct scattered_relocation_info *sreloc;
2126 for(k = 0; k < nreloc; k++){
2127 if((relocs[k].r_address & R_SCATTERED) == 0 &&
2128 relocs[k].r_extern == 1){
2129 if(relocs[k].r_symbolnum > nsyms){
2130 fatal_arch(arch, member, "bad r_symbolnum for relocation "
2131 "entry %d in section (%.16s,%.16s) in: ", k, segname,
2132 sectname);
2134 if(object->mh != NULL){
2135 n_strx = symbols[relocs[k].r_symbolnum].n_un.n_strx;
2136 n_value = symbols[relocs[k].r_symbolnum].n_value;
2138 else{
2139 n_strx = symbols64[relocs[k].r_symbolnum].n_un.n_strx;
2140 n_value = symbols64[relocs[k].r_symbolnum].n_value;
2142 #ifndef NMEDIT
2143 if(saves[relocs[k].r_symbolnum] == 0){
2144 if(*missing_reloc_symbols == 0){
2145 error_arch(arch, member, "symbols referenced by "
2146 "relocation entries that can't be stripped in: ");
2147 *missing_reloc_symbols = 1;
2149 fprintf(stderr, "%s\n", strings + n_strx);
2150 saves[relocs[k].r_symbolnum] = -1;
2152 #else /* defined(NMEDIT) */
2154 * We are letting nmedit change global coalesed symbols into
2155 * statics in MH_OBJECT file types only. Relocation entries to
2156 * global coalesced symbols are external relocs.
2158 if(object->mh != NULL)
2159 n_ext = new_symbols[saves[relocs[k].r_symbolnum] - 1].
2160 n_type & N_EXT;
2161 else
2162 n_ext = new_symbols64[saves[relocs[k].r_symbolnum] - 1].
2163 n_type & N_EXT;
2164 if(n_ext != N_EXT &&
2165 object->mh_cputype != CPU_TYPE_X86_64){
2167 * We need to do the relocation for this external relocation
2168 * entry so the item to be relocated is correct for a local
2169 * relocation entry. We don't need to do this for x86-64.
2171 if(relocs[k].r_address + sizeof(int32_t) > sectsize){
2172 fatal_arch(arch, member, "truncated or malformed "
2173 "object (r_address of relocation entry %u of "
2174 "section (%.16s,%.16s) extends past the end "
2175 "of the section)", k, segname, sectname);
2177 if(object->mh != NULL){
2178 value = *(uint32_t *)
2179 (contents + relocs[k].r_address);
2180 if(object->object_byte_sex != host_byte_sex)
2181 value = SWAP_INT(value);
2183 * We handle a very limited form here. Only VANILLA
2184 * (r_type == 0) long (r_length==2) absolute or pcrel
2185 * that won't need a scattered relocation entry.
2187 if(relocs[k].r_type != 0 ||
2188 relocs[k].r_length != 2){
2189 fatal_arch(arch, member, "don't have "
2190 "code to convert external relocation "
2191 "entry %d in section (%.16s,%.16s) "
2192 "for global coalesced symbol: %s "
2193 "in: ", k, segname, sectname,
2194 strings + n_strx);
2196 value += n_value;
2197 if(object->object_byte_sex != host_byte_sex)
2198 value = SWAP_INT(value);
2199 *(uint32_t *)(contents + relocs[k].r_address) =
2200 value;
2202 else{
2203 value64 = *(uint64_t *)(contents + relocs[k].r_address);
2204 if(object->object_byte_sex != host_byte_sex)
2205 value64 = SWAP_LONG_LONG(value64);
2207 * We handle a very limited form here. Only VANILLA
2208 * (r_type == 0) quad (r_length==3) absolute or pcrel
2209 * that won't need a scattered relocation entry.
2211 if(relocs[k].r_type != 0 ||
2212 relocs[k].r_length != 3){
2213 fatal_arch(arch, member, "don't have "
2214 "code to convert external relocation "
2215 "entry %d in section (%.16s,%.16s) "
2216 "for global coalesced symbol: %s "
2217 "in: ", k, segname, sectname,
2218 strings + n_strx);
2220 value64 += n_value;
2221 if(object->object_byte_sex != host_byte_sex)
2222 value64 = SWAP_LONG_LONG(value64);
2223 *(uint64_t *)(contents + relocs[k].r_address) = value64;
2226 * Turn the extern reloc into a local.
2228 if(object->mh != NULL)
2229 relocs[k].r_symbolnum =
2230 new_symbols[saves[relocs[k].r_symbolnum] - 1].n_sect;
2231 else
2232 relocs[k].r_symbolnum =
2233 new_symbols64[saves[relocs[k].r_symbolnum] - 1].n_sect;
2234 relocs[k].r_extern = 0;
2236 #endif /* NMEDIT */
2237 if(relocs[k].r_extern == 1 &&
2238 saves[relocs[k].r_symbolnum] != -1){
2239 relocs[k].r_symbolnum = saves[relocs[k].r_symbolnum] - 1;
2242 if((relocs[k].r_address & R_SCATTERED) == 0){
2243 if(reloc_has_pair(object->mh_cputype, relocs[k].r_type) == TRUE)
2244 k++;
2246 else{
2247 sreloc = (struct scattered_relocation_info *)relocs + k;
2248 if(reloc_has_pair(object->mh_cputype, sreloc->r_type) == TRUE)
2249 k++;
2255 * check_indirect_symtab() checks and updates the indirect symbol table entries
2256 * to make sure referenced symbols are not stripped and refer to the new symbol
2257 * table indexes.
2259 static
2260 void
2261 check_indirect_symtab(
2262 struct arch *arch,
2263 struct member *member,
2264 struct object *object,
2265 uint32_t nitems,
2266 uint32_t reserved1,
2267 uint32_t section_type,
2268 char *contents,
2269 struct nlist *symbols,
2270 struct nlist_64 *symbols64,
2271 uint32_t nsyms,
2272 char *strings,
2273 int32_t *missing_reloc_symbols,
2274 enum byte_sex host_byte_sex)
2276 uint32_t k, index;
2277 uint8_t n_type;
2278 uint32_t n_strx, value;
2279 uint64_t value64;
2280 enum bool made_local;
2282 for(k = 0; k < nitems; k++){
2283 made_local = FALSE;
2284 index = object->output_indirect_symtab[reserved1 + k];
2285 if(index == INDIRECT_SYMBOL_LOCAL ||
2286 index == INDIRECT_SYMBOL_ABS ||
2287 index == (INDIRECT_SYMBOL_LOCAL | INDIRECT_SYMBOL_ABS))
2288 continue;
2289 if(index > nsyms)
2290 fatal_arch(arch, member,"indirect symbol table entry %d (past " "the end of the symbol table) in: ", reserved1 + k);
2291 #ifdef NMEDIT
2292 if(pflag == 0 && nmedits[index] == TRUE && saves[index] != -1)
2293 #else
2294 if(saves[index] == 0)
2295 #endif
2298 * Indirect symbol table entries for defined symbols in a
2299 * non-lazy pointer section that are not saved are changed to
2300 * INDIRECT_SYMBOL_LOCAL which their values just have to be
2301 * slid if the are not absolute symbols.
2303 if(object->mh != NULL){
2304 n_type = symbols[index].n_type;
2305 n_strx = symbols[index].n_un.n_strx;
2307 else{
2308 n_type = symbols64[index].n_type;
2309 n_strx = symbols64[index].n_un.n_strx;
2311 if((n_type && N_TYPE) != N_UNDF &&
2312 (n_type && N_TYPE) != N_PBUD &&
2313 section_type == S_NON_LAZY_SYMBOL_POINTERS){
2314 object->output_indirect_symtab[reserved1 + k] =
2315 INDIRECT_SYMBOL_LOCAL;
2316 if((n_type & N_TYPE) == N_ABS)
2317 object->output_indirect_symtab[reserved1 + k] |=
2318 INDIRECT_SYMBOL_ABS;
2319 made_local = TRUE;
2321 * When creating a stub shared library the section contents
2322 * are not updated since they will be stripped.
2324 if(object->mh_filetype != MH_DYLIB_STUB){
2325 if(object->mh != NULL){
2326 value = symbols[index].n_value;
2327 if (symbols[index].n_desc & N_ARM_THUMB_DEF)
2328 value |= 1;
2329 if(object->object_byte_sex != host_byte_sex)
2330 value = SWAP_INT(value);
2331 *(uint32_t *)(contents + k * 4) = value;
2333 else{
2334 value64 = symbols64[index].n_value;
2335 if(object->object_byte_sex != host_byte_sex)
2336 value64 = SWAP_LONG_LONG(value64);
2337 *(uint64_t *)(contents + k * 8) = value64;
2341 #ifdef NMEDIT
2342 else {
2343 object->output_indirect_symtab[reserved1 + k] =
2344 saves[index] - 1;
2346 #else /* !defined(NMEDIT) */
2347 else{
2348 if(*missing_reloc_symbols == 0){
2349 error_arch(arch, member, "symbols referenced by "
2350 "indirect symbol table entries that can't be "
2351 "stripped in: ");
2352 *missing_reloc_symbols = 1;
2354 fprintf(stderr, "%s\n", strings + n_strx);
2355 saves[index] = -1;
2357 #endif /* !defined(NMEDIT) */
2359 #ifdef NMEDIT
2360 else
2361 #else /* !defined(NMEDIT) */
2362 if(made_local == FALSE && saves[index] != -1)
2363 #endif /* !defined(NMEDIT) */
2365 object->output_indirect_symtab[reserved1+k] = saves[index] - 1;
2370 #ifndef NMEDIT
2372 * This is called if there is a -d option specified. It reads the file with
2373 * the strings in it and places them in the array debug_filenames and sorts
2374 * them by name. The file that contains the file names must have names one
2375 * per line with no white space (except the newlines).
2377 static
2378 void
2379 setup_debug_filenames(
2380 char *dfile)
2382 int fd, i, strings_size;
2383 struct stat stat_buf;
2384 char *strings, *p;
2386 if((fd = open(dfile, O_RDONLY)) < 0){
2387 system_error("can't open: %s", dfile);
2388 return;
2390 if(fstat(fd, &stat_buf) == -1){
2391 system_error("can't stat: %s", dfile);
2392 close(fd);
2393 return;
2395 strings_size = stat_buf.st_size;
2396 strings = (char *)allocate(strings_size + 1);
2397 strings[strings_size] = '\0';
2398 if(read(fd, strings, strings_size) != strings_size){
2399 system_error("can't read: %s", dfile);
2400 close(fd);
2401 return;
2403 p = strings;
2404 for(i = 0; i < strings_size; i++){
2405 if(*p == '\n'){
2406 *p = '\0';
2407 ndebug_filenames++;
2409 p++;
2411 debug_filenames = (char **)allocate(ndebug_filenames * sizeof(char *));
2412 p = strings;
2413 for(i = 0; i < ndebug_filenames; i++){
2414 debug_filenames[i] = p;
2415 p += strlen(p) + 1;
2417 qsort(debug_filenames, ndebug_filenames, sizeof(char *),
2418 (int (*)(const void *, const void *))cmp_qsort_filename);
2420 #ifdef DEBUG
2421 printf("Debug filenames:\n");
2422 for(i = 0; i < ndebug_filenames; i++){
2423 printf("filename = %s\n", debug_filenames[i]);
2425 #endif /* DEBUG */
2429 * Strip the symbol table to the level specified by the command line arguments.
2430 * The new symbol table is built and new_symbols is left pointing to it. The
2431 * number of new symbols is left in new_nsyms, the new string table is built
2432 * and new_stings is left pointing to it and new_strsize is left containing it.
2433 * This routine returns zero if successfull and non-zero otherwise.
2435 static
2436 enum bool
2437 strip_symtab(
2438 struct arch *arch,
2439 struct member *member,
2440 struct object *object,
2441 struct dylib_table_of_contents *tocs,
2442 uint32_t ntoc,
2443 struct dylib_module *mods,
2444 struct dylib_module_64 *mods64,
2445 uint32_t nmodtab,
2446 struct dylib_reference *refs,
2447 uint32_t nextrefsyms)
2449 uint32_t i, j, k, n, inew_syms, save_debug, missing_syms;
2450 uint32_t missing_symbols;
2451 char *p, *q, **pp, *basename;
2452 struct symbol_list *sp;
2453 uint32_t new_ext_strsize, len, *changes, inew_undefsyms;
2454 unsigned char nsects;
2455 struct load_command *lc;
2456 struct segment_command *sg;
2457 struct segment_command_64 *sg64;
2458 struct section *s, **sections;
2459 struct section_64 *s64, **sections64;
2460 uint32_t ncmds, mh_flags, s_flags, n_strx;
2461 struct nlist *sym;
2462 struct undef_map *undef_map;
2463 struct undef_map64 *undef_map64;
2464 uint8_t n_type, n_sect;
2465 uint16_t n_desc;
2466 uint64_t n_value;
2467 uint32_t module_name, iextdefsym, nextdefsym, ilocalsym, nlocalsym;
2468 uint32_t irefsym, nrefsym;
2469 enum bool has_dwarf, hack_5614542;
2471 save_debug = 0;
2472 if(saves != NULL)
2473 free(saves);
2474 changes = NULL;
2475 for(i = 0; i < nsave_symbols; i++)
2476 save_symbols[i].sym = NULL;
2477 for(i = 0; i < nremove_symbols; i++)
2478 remove_symbols[i].sym = NULL;
2479 if(member == NULL){
2480 for(i = 0; i < nsave_symbols; i++)
2481 save_symbols[i].seen = FALSE;
2482 for(i = 0; i < nremove_symbols; i++)
2483 remove_symbols[i].seen = FALSE;
2486 new_nsyms = 0;
2487 if(object->mh != NULL)
2488 new_strsize = sizeof(int32_t);
2489 else
2490 new_strsize = sizeof(int64_t);
2491 new_nlocalsym = 0;
2492 new_nextdefsym = 0;
2493 new_nundefsym = 0;
2494 new_ext_strsize = 0;
2497 * If this an object file that has DWARF debugging sections to strip
2498 * then we have to run ld -r on it.
2500 if(object->mh_filetype == MH_OBJECT && (Sflag || xflag)){
2501 has_dwarf = FALSE;
2502 lc = object->load_commands;
2503 if(object->mh != NULL)
2504 ncmds = object->mh->ncmds;
2505 else
2506 ncmds = object->mh64->ncmds;
2507 for(i = 0; i < ncmds && has_dwarf == FALSE; i++){
2508 if(lc->cmd == LC_SEGMENT){
2509 sg = (struct segment_command *)lc;
2510 s = (struct section *)((char *)sg +
2511 sizeof(struct segment_command));
2512 for(j = 0; j < sg->nsects; j++){
2513 if(s->flags & S_ATTR_DEBUG){
2514 has_dwarf = TRUE;
2515 break;
2517 s++;
2520 else if(lc->cmd == LC_SEGMENT_64){
2521 sg64 = (struct segment_command_64 *)lc;
2522 s64 = (struct section_64 *)((char *)sg64 +
2523 sizeof(struct segment_command_64));
2524 for(j = 0; j < sg64->nsects; j++){
2525 if(s64->flags & S_ATTR_DEBUG){
2526 has_dwarf = TRUE;
2527 break;
2529 s64++;
2532 lc = (struct load_command *)((char *)lc + lc->cmdsize);
2535 * Because of the bugs in ld(1) for:
2536 * radr://5675774 ld64 should preserve JBSR relocations without
2537 * -static
2538 * radr://5658046 cctools-679 creates scattered relocations in
2539 * __TEXT,__const section in kexts, which breaks
2540 * kexts built for older systems
2541 * we can't use ld -r to strip dwarf info in 32-bit objects until
2542 * these are fixed. But if the user as specified the -l flag then
2543 * go ahead and do it and the user will have to be aware of these
2544 * bugs.
2546 if((lflag == TRUE && has_dwarf == TRUE) || object->mh64 != NULL)
2547 make_ld_r_object(arch, member, object);
2550 * Because of the "design" of 64-bit object files and the lack of
2551 * local relocation entries it is not possible for strip(1) to do its
2552 * job without becoming a static link editor. The "design" does not
2553 * actually strip the symbols it simply renames them to things like
2554 * "l1000". And they become static symbols but still have external
2555 * relocation entries. Thus can never actually be stripped. Also some
2556 * symbols, *.eh, symbols are not even changed to these names if there
2557 * corresponding global symbol is not stripped. So strip(1) only
2558 * recourse is to use the unified linker to create an ld -r object then
2559 * save all resulting symbols (both static and global) and hope the user
2560 * does not notice the stripping is not what they asked for.
2562 if(object->mh_filetype == MH_OBJECT &&
2563 (object->mh64 != NULL && object->ld_r_ofile == NULL))
2564 make_ld_r_object(arch, member, object);
2567 * Since make_ld_r_object() may create an object with more symbols
2568 * this has to be done after make_ld_r_object() and nsyms is updated.
2570 saves = (int32_t *)allocate(nsyms * sizeof(int32_t));
2571 bzero(saves, nsyms * sizeof(int32_t));
2574 * Gather an array of section struct pointers so we can later determine
2575 * if we run into a global symbol in a coalesced section and not strip
2576 * those symbols.
2577 * statics.
2579 nsects = 0;
2580 lc = object->load_commands;
2581 if(object->mh != NULL)
2582 ncmds = object->mh->ncmds;
2583 else
2584 ncmds = object->mh64->ncmds;
2585 for(i = 0; i < ncmds; i++){
2586 if(lc->cmd == LC_SEGMENT){
2587 sg = (struct segment_command *)lc;
2588 nsects += sg->nsects;
2590 else if(lc->cmd == LC_SEGMENT_64){
2591 sg64 = (struct segment_command_64 *)lc;
2592 nsects += sg64->nsects;
2594 lc = (struct load_command *)((char *)lc + lc->cmdsize);
2596 if(object->mh != NULL){
2597 sections = allocate(nsects * sizeof(struct section *));
2598 sections64 = NULL;
2600 else{
2601 sections = NULL;
2602 sections64 = allocate(nsects * sizeof(struct section_64 *));
2604 nsects = 0;
2605 lc = object->load_commands;
2606 for(i = 0; i < ncmds; i++){
2607 if(lc->cmd == LC_SEGMENT){
2608 sg = (struct segment_command *)lc;
2609 s = (struct section *)((char *)sg +
2610 sizeof(struct segment_command));
2611 for(j = 0; j < sg->nsects; j++)
2612 sections[nsects++] = s++;
2614 else if(lc->cmd == LC_SEGMENT_64){
2615 sg64 = (struct segment_command_64 *)lc;
2616 s64 = (struct section_64 *)((char *)sg64 +
2617 sizeof(struct segment_command_64));
2618 for(j = 0; j < sg64->nsects; j++)
2619 sections64[nsects++] = s64++;
2621 lc = (struct load_command *)((char *)lc + lc->cmdsize);
2624 for(i = 0; i < nsyms; i++){
2625 s_flags = 0;
2626 if(object->mh != NULL){
2627 mh_flags = object->mh->flags;
2628 n_strx = symbols[i].n_un.n_strx;
2629 n_type = symbols[i].n_type;
2630 n_sect = symbols[i].n_sect;
2631 if((n_type & N_TYPE) == N_SECT){
2632 if(n_sect == 0 || n_sect > nsects){
2633 error_arch(arch, member, "bad n_sect for symbol "
2634 "table entry %d in: ", i);
2635 return(FALSE);
2637 s_flags = sections[n_sect - 1]->flags;
2639 n_desc = symbols[i].n_desc;
2640 n_value = symbols[i].n_value;
2642 else{
2643 mh_flags = object->mh64->flags;
2644 n_strx = symbols64[i].n_un.n_strx;
2645 n_type = symbols64[i].n_type;
2646 n_sect = symbols64[i].n_sect;
2647 if((n_type & N_TYPE) == N_SECT){
2648 if(n_sect == 0 || n_sect > nsects){
2649 error_arch(arch, member, "bad n_sect for symbol "
2650 "table entry %d in: ", i);
2651 return(FALSE);
2653 s_flags = sections64[n_sect - 1]->flags;
2655 n_desc = symbols64[i].n_desc;
2656 n_value = symbols64[i].n_value;
2658 if(n_strx != 0){
2659 if(n_strx > strsize){
2660 error_arch(arch, member, "bad string index for symbol "
2661 "table entry %d in: ", i);
2662 return(FALSE);
2665 if((n_type & N_TYPE) == N_INDR){
2666 if(n_value != 0){
2667 if(n_value > strsize){
2668 error_arch(arch, member, "bad string index for "
2669 "indirect symbol table entry %d in: ", i);
2670 return(FALSE);
2674 if((n_type & N_EXT) == 0){ /* local symbol */
2676 * For x86_64 .o files we have run ld -r on them and are stuck
2677 * keeping all resulting symbols.
2679 if(object->mh == NULL && (
2680 object->mh64->cputype == CPU_TYPE_X86_64) &&
2681 object->mh64->filetype == MH_OBJECT){
2682 if(n_strx != 0)
2683 new_strsize += strlen(strings + n_strx) + 1;
2684 new_nlocalsym++;
2685 new_nsyms++;
2686 saves[i] = new_nsyms;
2689 * The cases a local symbol might be saved is with -X -S or
2690 * with -d filename.
2692 else if((!strip_all && (Xflag || Sflag)) || dfile){
2693 if(n_type & N_STAB){ /* debug symbol */
2694 if(dfile && n_type == N_SO){
2695 if(n_strx != 0){
2696 basename = strrchr(strings + n_strx, '/');
2697 if(basename != NULL)
2698 basename++;
2699 else
2700 basename = strings + n_strx;
2701 pp = bsearch(basename, debug_filenames,
2702 ndebug_filenames, sizeof(char *),
2703 (int (*)(const void *, const void *)
2704 )cmp_bsearch_filename);
2706 * Save the bracketing N_SO. For each N_SO that
2707 * has a filename there is an N_SO that has a
2708 * name of "" which ends the stabs for that file
2710 if(*basename != '\0'){
2711 if(pp != NULL)
2712 save_debug = 1;
2713 else
2714 save_debug = 0;
2716 else{
2718 * This is a bracketing SO so if we are
2719 * currently saving debug symbols save this
2720 * last one and turn off saving debug syms.
2722 if(save_debug){
2723 if(n_strx != 0)
2724 new_strsize += strlen(strings +
2725 n_strx) + 1;
2726 new_nlocalsym++;
2727 new_nsyms++;
2728 saves[i] = new_nsyms;
2730 save_debug = 0;
2733 else{
2734 save_debug = 0;
2737 if(saves[i] == 0 && (!Sflag || save_debug)){
2738 if(n_strx != 0)
2739 new_strsize += strlen(strings + n_strx) + 1;
2740 new_nlocalsym++;
2741 new_nsyms++;
2742 saves[i] = new_nsyms;
2745 else{ /* non-debug local symbol */
2746 if(xflag == 0 && (Sflag || Xflag)){
2747 if(Xflag == 0 ||
2748 (n_strx != 0 &&
2749 strings[n_strx] != 'L')){
2751 * If this file is a for the dynamic linker and
2752 * this symbol is in a section marked so that
2753 * static symbols are stripped then don't
2754 * keep this symbol.
2756 if((mh_flags & MH_DYLDLINK) != MH_DYLDLINK ||
2757 (n_type & N_TYPE) != N_SECT ||
2758 (s_flags & S_ATTR_STRIP_STATIC_SYMS) !=
2759 S_ATTR_STRIP_STATIC_SYMS){
2760 new_strsize += strlen(strings + n_strx) + 1;
2761 new_nlocalsym++;
2762 new_nsyms++;
2763 saves[i] = new_nsyms;
2768 * Treat a local symbol that was a private extern as if
2769 * were global if it is referenced by a module and save
2770 * it.
2772 if((n_type & N_PEXT) == N_PEXT){
2773 if(saves[i] == 0 &&
2774 private_extern_reference_by_module(
2775 i, refs ,nextrefsyms) == TRUE){
2776 if(n_strx != 0)
2777 new_strsize += strlen(strings + n_strx) + 1;
2778 new_nlocalsym++;
2779 new_nsyms++;
2780 saves[i] = new_nsyms;
2783 * We need to save symbols that were private externs
2784 * that are used with indirect symbols.
2786 if(saves[i] == 0 &&
2787 symbol_pointer_used(i, indirectsyms,
2788 nindirectsyms) == TRUE){
2789 if(n_strx != 0){
2790 len = strlen(strings + n_strx) + 1;
2791 new_strsize += len;
2793 new_nlocalsym++;
2794 new_nsyms++;
2795 saves[i] = new_nsyms;
2801 * Treat a local symbol that was a private extern as if were
2802 * global if it is not referenced by a module.
2804 else if((n_type & N_PEXT) == N_PEXT){
2805 if(saves[i] == 0 && sfile){
2806 sp = bsearch(strings + n_strx,
2807 save_symbols, nsave_symbols,
2808 sizeof(struct symbol_list),
2809 (int (*)(const void *, const void *))
2810 symbol_list_bsearch);
2811 if(sp != NULL){
2812 if(sp->sym == NULL){
2813 if(object->mh != NULL)
2814 sp->sym = &(symbols[i]);
2815 else
2816 sp->sym = &(symbols64[i]);
2817 sp->seen = TRUE;
2819 if(n_strx != 0)
2820 new_strsize += strlen(strings + n_strx) + 1;
2821 new_nlocalsym++;
2822 new_nsyms++;
2823 saves[i] = new_nsyms;
2826 if(saves[i] == 0 &&
2827 private_extern_reference_by_module(
2828 i, refs ,nextrefsyms) == TRUE){
2829 if(n_strx != 0)
2830 new_strsize += strlen(strings + n_strx) + 1;
2831 new_nlocalsym++;
2832 new_nsyms++;
2833 saves[i] = new_nsyms;
2836 * We need to save symbols that were private externs that
2837 * are used with indirect symbols.
2839 if(saves[i] == 0 &&
2840 symbol_pointer_used(i, indirectsyms, nindirectsyms) ==
2841 TRUE){
2842 if(n_strx != 0){
2843 len = strlen(strings + n_strx) + 1;
2844 new_strsize += len;
2846 new_nlocalsym++;
2847 new_nsyms++;
2848 saves[i] = new_nsyms;
2852 else{ /* global symbol */
2854 * strip -R on an x86_64 .o file should do nothing.
2856 if(Rfile &&
2857 (object->mh != NULL ||
2858 object->mh64->cputype != CPU_TYPE_X86_64 ||
2859 object->mh64->filetype != MH_OBJECT)){
2860 sp = bsearch(strings + n_strx,
2861 remove_symbols, nremove_symbols,
2862 sizeof(struct symbol_list),
2863 (int (*)(const void *, const void *))
2864 symbol_list_bsearch);
2865 if(sp != NULL){
2866 if((n_type & N_TYPE) == N_UNDF ||
2867 (n_type & N_TYPE) == N_PBUD){
2868 error_arch(arch, member, "symbol: %s undefined"
2869 " and can't be stripped from: ",
2870 sp->name);
2872 else if(sp->sym != NULL){
2873 sym = (struct nlist *)sp->sym;
2874 if((sym->n_type & N_PEXT) != N_PEXT)
2875 error_arch(arch, member, "more than one symbol "
2876 "for: %s found in: ", sp->name);
2878 else{
2879 if(object->mh != NULL)
2880 sp->sym = &(symbols[i]);
2881 else
2882 sp->sym = &(symbols64[i]);
2883 sp->seen = TRUE;
2885 if(n_desc & REFERENCED_DYNAMICALLY){
2886 error_arch(arch, member, "symbol: %s is dynamically"
2887 " referenced and can't be stripped "
2888 "from: ", sp->name);
2890 if((n_type & N_TYPE) == N_SECT &&
2891 (s_flags & SECTION_TYPE) == S_COALESCED){
2892 error_arch(arch, member, "symbol: %s is a global "
2893 "coalesced symbol and can't be "
2894 "stripped from: ", sp->name);
2896 /* don't save this symbol */
2897 continue;
2900 if(Aflag && (n_type & N_TYPE) == N_ABS &&
2901 (n_value != 0 ||
2902 (n_strx != 0 &&
2903 strncmp(strings + n_strx,
2904 ".objc_class_name_",
2905 sizeof(".objc_class_name_") - 1) == 0))){
2906 len = strlen(strings + n_strx) + 1;
2907 new_strsize += len;
2908 new_ext_strsize += len;
2909 new_nextdefsym++;
2910 new_nsyms++;
2911 saves[i] = new_nsyms;
2913 if(saves[i] == 0 && (uflag || default_dyld_executable) &&
2914 ((((n_type & N_TYPE) == N_UNDF) &&
2915 n_value == 0) ||
2916 (n_type & N_TYPE) == N_PBUD)){
2917 if(n_strx != 0){
2918 len = strlen(strings + n_strx) + 1;
2919 new_strsize += len;
2920 new_ext_strsize += len;
2922 new_nundefsym++;
2923 new_nsyms++;
2924 saves[i] = new_nsyms;
2926 if(saves[i] == 0 && nflag &&
2927 (n_type & N_TYPE) == N_SECT){
2928 if(n_strx != 0){
2929 len = strlen(strings + n_strx) + 1;
2930 new_strsize += len;
2931 new_ext_strsize += len;
2933 new_nextdefsym++;
2934 new_nsyms++;
2935 saves[i] = new_nsyms;
2937 if(saves[i] == 0 && sfile){
2938 sp = bsearch(strings + n_strx,
2939 save_symbols, nsave_symbols,
2940 sizeof(struct symbol_list),
2941 (int (*)(const void *, const void *))
2942 symbol_list_bsearch);
2943 if(sp != NULL){
2944 if(sp->sym != NULL){
2945 sym = (struct nlist *)sp->sym;
2946 if((sym->n_type & N_PEXT) != N_PEXT)
2947 error_arch(arch, member, "more than one symbol "
2948 "for: %s found in: ", sp->name);
2950 else{
2951 if(object->mh != NULL)
2952 sp->sym = &(symbols[i]);
2953 else
2954 sp->sym = &(symbols64[i]);
2955 sp->seen = TRUE;
2956 len = strlen(strings + n_strx) + 1;
2957 new_strsize += len;
2958 new_ext_strsize += len;
2959 if((n_type & N_TYPE) == N_UNDF ||
2960 (n_type & N_TYPE) == N_PBUD)
2961 new_nundefsym++;
2962 else
2963 new_nextdefsym++;
2964 new_nsyms++;
2965 saves[i] = new_nsyms;
2970 * We only need to save coalesced symbols that are used as
2971 * indirect symbols in 32-bit applications.
2973 * In 64-bit applications, we only need to save coalesced
2974 * symbols that are used as weak definitions.
2976 if(object->mh != NULL &&
2977 saves[i] == 0 &&
2978 (n_type & N_TYPE) == N_SECT &&
2979 (s_flags & SECTION_TYPE) == S_COALESCED &&
2980 symbol_pointer_used(i, indirectsyms, nindirectsyms) == TRUE){
2981 if(n_strx != 0){
2982 len = strlen(strings + n_strx) + 1;
2983 new_strsize += len;
2984 new_ext_strsize += len;
2986 new_nextdefsym++;
2987 new_nsyms++;
2988 saves[i] = new_nsyms;
2990 if(saves[i] == 0 &&
2991 (n_type & N_TYPE) == N_SECT &&
2992 (n_desc & N_WEAK_DEF) != 0){
2993 if(n_strx != 0){
2994 len = strlen(strings + n_strx) + 1;
2995 new_strsize += len;
2996 new_ext_strsize += len;
2998 new_nextdefsym++;
2999 new_nsyms++;
3000 saves[i] = new_nsyms;
3002 if(saves[i] == 0 && ((Xflag || Sflag || xflag) ||
3003 ((rflag || default_dyld_executable) &&
3004 n_desc & REFERENCED_DYNAMICALLY))){
3005 len = strlen(strings + n_strx) + 1;
3006 new_strsize += len;
3007 new_ext_strsize += len;
3008 if((n_type & N_TYPE) == N_INDR){
3009 len = strlen(strings + n_value) + 1;
3010 new_strsize += len;
3011 new_ext_strsize += len;
3013 if((n_type & N_TYPE) == N_UNDF ||
3014 (n_type & N_TYPE) == N_PBUD)
3015 new_nundefsym++;
3016 else
3017 new_nextdefsym++;
3018 new_nsyms++;
3019 saves[i] = new_nsyms;
3022 * For x86_64 .o files we have run ld -r on them and are stuck
3023 * keeping all resulting symbols.
3025 if(saves[i] == 0 &&
3026 object->mh == NULL &&
3027 object->mh64->cputype == CPU_TYPE_X86_64 &&
3028 object->mh64->filetype == MH_OBJECT){
3029 len = strlen(strings + n_strx) + 1;
3030 new_strsize += len;
3031 new_ext_strsize += len;
3032 if((n_type & N_TYPE) == N_INDR){
3033 len = strlen(strings + n_value) + 1;
3034 new_strsize += len;
3035 new_ext_strsize += len;
3037 if((n_type & N_TYPE) == N_UNDF ||
3038 (n_type & N_TYPE) == N_PBUD)
3039 new_nundefsym++;
3040 else
3041 new_nextdefsym++;
3042 new_nsyms++;
3043 saves[i] = new_nsyms;
3048 * The module table's module names are placed with the external strings.
3049 * So size them and add this to the external string size.
3051 for(i = 0; i < nmodtab; i++){
3052 if(object->mh != NULL)
3053 module_name = mods[i].module_name;
3054 else
3055 module_name = mods64[i].module_name;
3056 if(module_name == 0 || module_name > strsize){
3057 error_arch(arch, member, "bad string index for module_name "
3058 "of module table entry %d in: ", i);
3059 return(FALSE);
3061 len = strlen(strings + module_name) + 1;
3062 new_strsize += len;
3063 new_ext_strsize += len;
3067 * Updating the reference table may require a symbol not yet listed as
3068 * as saved to be present in the output file. If a defined external
3069 * symbol is removed and there is a undefined reference to it in the
3070 * reference table an undefined symbol needs to be created for it in
3071 * the output file. If this happens the number of new symbols and size
3072 * of the new strings are adjusted. And the array changes[] is set to
3073 * map the old symbol index to the new symbol index for the symbol that
3074 * is changed to an undefined symbol.
3076 missing_symbols = 0;
3077 if(ref_saves != NULL)
3078 free(ref_saves);
3079 ref_saves = (int32_t *)allocate(nextrefsyms * sizeof(int32_t));
3080 bzero(ref_saves, nextrefsyms * sizeof(int32_t));
3081 changes = (uint32_t *)allocate(nsyms * sizeof(int32_t));
3082 bzero(changes, nsyms * sizeof(int32_t));
3083 new_nextrefsyms = 0;
3084 for(i = 0; i < nextrefsyms; i++){
3085 if(refs[i].isym > nsyms){
3086 error_arch(arch, member, "bad symbol table index for "
3087 "reference table entry %d in: ", i);
3088 return(FALSE);
3090 if(saves[refs[i].isym]){
3091 new_nextrefsyms++;
3092 ref_saves[i] = new_nextrefsyms;
3094 else{
3095 if(refs[i].flags == REFERENCE_FLAG_UNDEFINED_NON_LAZY ||
3096 refs[i].flags == REFERENCE_FLAG_UNDEFINED_LAZY){
3097 if(changes[refs[i].isym] == 0){
3098 if(object->mh != NULL)
3099 n_strx = symbols[refs[i].isym].n_un.n_strx;
3100 else
3101 n_strx = symbols64[refs[i].isym].n_un.n_strx;
3102 len = strlen(strings + n_strx) + 1;
3103 new_strsize += len;
3104 new_ext_strsize += len;
3105 new_nundefsym++;
3106 new_nsyms++;
3107 changes[refs[i].isym] = new_nsyms;
3108 new_nextrefsyms++;
3109 ref_saves[i] = new_nextrefsyms;
3112 else{
3113 if(refs[i].flags ==
3114 REFERENCE_FLAG_PRIVATE_UNDEFINED_NON_LAZY ||
3115 refs[i].flags == REFERENCE_FLAG_PRIVATE_UNDEFINED_LAZY){
3116 if(missing_symbols == 0){
3117 error_arch(arch, member, "private extern symbols "
3118 "referenced by modules can't be stripped in: ");
3119 missing_symbols = 1;
3121 if(object->mh != NULL)
3122 n_strx = symbols[refs[i].isym].n_un.n_strx;
3123 else
3124 n_strx = symbols64[refs[i].isym].n_un.n_strx;
3125 fprintf(stderr, "%s\n", strings + n_strx);
3126 saves[refs[i].isym] = -1;
3131 if(missing_symbols == 1)
3132 return(FALSE);
3134 if(member == NULL){
3135 missing_syms = 0;
3136 if(iflag == 0){
3137 for(i = 0; i < nsave_symbols; i++){
3138 if(save_symbols[i].sym == NULL){
3139 if(missing_syms == 0){
3140 error_arch(arch, member, "symbols names listed "
3141 "in: %s not in: ", sfile);
3142 missing_syms = 1;
3144 fprintf(stderr, "%s\n", save_symbols[i].name);
3148 missing_syms = 0;
3150 * strip -R on an x86_64 .o file should do nothing.
3152 if(iflag == 0 &&
3153 (object->mh != NULL ||
3154 object->mh64->cputype != CPU_TYPE_X86_64 ||
3155 object->mh64->filetype != MH_OBJECT)){
3156 for(i = 0; i < nremove_symbols; i++){
3157 if(remove_symbols[i].sym == NULL){
3158 if(missing_syms == 0){
3159 error_arch(arch, member, "symbols names listed "
3160 "in: %s not in: ", Rfile);
3161 missing_syms = 1;
3163 fprintf(stderr, "%s\n", remove_symbols[i].name);
3170 * If there is a chance that we could end up with an indirect symbol
3171 * with an index of zero we need to avoid that due to a work around
3172 * in the dynamic linker for a bug it is working around that was in
3173 * the old classic static linker. See radar bug 5614542 and the
3174 * related bugs 3685312 and 3534709.
3176 * A reasonable way to do this to know that local symbols are first in
3177 * the symbol table. So if we have any local symbols this won't happen
3178 * and if there are no indirect symbols it will also not happen. Past
3179 * that we'll just add a local symbol so it will end up at symbol index
3180 * zero and avoid any indirect symbol having that index.
3182 * If one really wanted they could build up the new symbol table then
3183 * look at all the indirect symbol table entries to see if any of them
3184 * have an index of zero then in that case throw that new symbol table
3185 * away and rebuild the symbol and string table once again after adding
3186 * a local symbol. This seems not all that resonable to save one symbol
3187 * table entry and a few bytes in the string table for the complexity it
3188 * would add and what it would save.
3190 if(new_nlocalsym == 0 && nindirectsyms != 0){
3191 len = strlen("radr://5614542") + 1;
3192 new_strsize += len;
3193 new_nlocalsym++;
3194 new_nsyms++;
3195 hack_5614542 = TRUE;
3197 else{
3198 hack_5614542 = FALSE;
3201 if(object->mh != NULL){
3202 new_symbols = (struct nlist *)
3203 allocate(new_nsyms * sizeof(struct nlist));
3204 new_symbols64 = NULL;
3206 else{
3207 new_symbols = NULL;
3208 new_symbols64 = (struct nlist_64 *)
3209 allocate(new_nsyms * sizeof(struct nlist_64));
3211 if(object->mh != NULL)
3212 new_strsize = rnd(new_strsize, sizeof(int32_t));
3213 else
3214 new_strsize = rnd(new_strsize, sizeof(int64_t));
3215 new_strings = (char *)allocate(new_strsize);
3216 if(object->mh != NULL){
3217 new_strings[new_strsize - 3] = '\0';
3218 new_strings[new_strsize - 2] = '\0';
3219 new_strings[new_strsize - 1] = '\0';
3221 else{
3222 new_strings[new_strsize - 7] = '\0';
3223 new_strings[new_strsize - 6] = '\0';
3224 new_strings[new_strsize - 5] = '\0';
3225 new_strings[new_strsize - 4] = '\0';
3226 new_strings[new_strsize - 3] = '\0';
3227 new_strings[new_strsize - 2] = '\0';
3228 new_strings[new_strsize - 1] = '\0';
3231 memset(new_strings, '\0', sizeof(int32_t));
3232 p = new_strings + sizeof(int32_t);
3233 q = p + new_ext_strsize;
3236 * If all strings were stripped set the size to zero but only for 32-bit
3237 * because the unified linker seems to set the filesize of empty .o
3238 * files to include the string table.
3240 if(object->mh != NULL && new_strsize == sizeof(int32_t))
3241 new_strsize = 0;
3244 * Now create a symbol table and string table in this order
3245 * symbol table
3246 * local symbols
3247 * external defined symbols
3248 * undefined symbols
3249 * string table
3250 * external strings
3251 * local strings
3253 inew_syms = 0;
3256 * If we are doing the hack for radar bug 5614542 (see above) add the
3257 * one local symbol and string.
3259 * We use an N_OPT stab which should be safe to use and not mess any
3260 * thing up. In Mac OS X, gcc(1) writes one N_OPT stab saying the file
3261 * is compiled with gcc(1). Then gdb(1) looks for that stab, but it
3262 * also looks at the name. If the name string is "gcc_compiled" or
3263 * "gcc2_compiled" gdb(1) sets its "compiled by gcc flag. If the N_OPT
3264 * is emitted INSIDE an N_SO section, then gdb(1) thinks that object
3265 * module was compiled by Sun's compiler, which apparently sticks one
3266 * outermost N_LBRAC/N_RBRAC pair, which gdb(1) strips off. But if the
3267 * N_OPT comes before any N_SO stabs, then gdb(1) will just ignore it.
3268 * Since this N_OPT is the first local symbol, it will always come
3269 * before any N_SO stabs that might be around and should be fine.
3271 if(hack_5614542 == TRUE){
3272 if(object->mh != NULL){
3273 new_symbols[inew_syms].n_type = N_OPT;
3274 new_symbols[inew_syms].n_sect = NO_SECT;
3275 new_symbols[inew_syms].n_desc = 0;
3276 new_symbols[inew_syms].n_value = 0x05614542;
3278 else{
3279 new_symbols64[inew_syms].n_type = N_OPT;
3280 new_symbols64[inew_syms].n_sect = NO_SECT;
3281 new_symbols64[inew_syms].n_desc = 0;
3282 new_symbols64[inew_syms].n_value = 0x05614542;
3284 strcpy(q, "radr://5614542");
3285 if(object->mh != NULL)
3286 new_symbols[inew_syms].n_un.n_strx =
3287 q - new_strings;
3288 else
3289 new_symbols64[inew_syms].n_un.n_strx =
3290 q - new_strings;
3291 q += strlen(q) + 1;
3292 inew_syms++;
3295 for(i = 0; i < nsyms; i++){
3296 if(saves[i]){
3297 if(object->mh != NULL){
3298 n_strx = symbols[i].n_un.n_strx;
3299 n_type = symbols[i].n_type;
3301 else{
3302 n_strx = symbols64[i].n_un.n_strx;
3303 n_type = symbols64[i].n_type;
3305 if((n_type & N_EXT) == 0){
3306 if(object->mh != NULL)
3307 new_symbols[inew_syms] = symbols[i];
3308 else
3309 new_symbols64[inew_syms] = symbols64[i];
3310 if(n_strx != 0){
3311 strcpy(q, strings + n_strx);
3312 if(object->mh != NULL)
3313 new_symbols[inew_syms].n_un.n_strx =
3314 q - new_strings;
3315 else
3316 new_symbols64[inew_syms].n_un.n_strx =
3317 q - new_strings;
3318 q += strlen(q) + 1;
3320 inew_syms++;
3321 saves[i] = inew_syms;
3325 #ifdef TRIE_SUPPORT
3326 inew_nextdefsym = inew_syms;
3327 #endif /* TRIE_SUPPORT */
3328 for(i = 0; i < nsyms; i++){
3329 if(saves[i]){
3330 if(object->mh != NULL){
3331 n_strx = symbols[i].n_un.n_strx;
3332 n_type = symbols[i].n_type;
3333 n_value = symbols[i].n_value;
3335 else{
3336 n_strx = symbols64[i].n_un.n_strx;
3337 n_type = symbols64[i].n_type;
3338 n_value = symbols64[i].n_value;
3340 if((n_type & N_EXT) == N_EXT &&
3341 ((n_type & N_TYPE) != N_UNDF &&
3342 (n_type & N_TYPE) != N_PBUD)){
3343 if(object->mh != NULL)
3344 new_symbols[inew_syms] = symbols[i];
3345 else
3346 new_symbols64[inew_syms] = symbols64[i];
3347 if(n_strx != 0){
3348 strcpy(p, strings + n_strx);
3349 if(object->mh != NULL)
3350 new_symbols[inew_syms].n_un.n_strx =
3351 p - new_strings;
3352 else
3353 new_symbols64[inew_syms].n_un.n_strx =
3354 p - new_strings;
3355 p += strlen(p) + 1;
3357 if((n_type & N_TYPE) == N_INDR){
3358 if(n_value != 0){
3359 strcpy(p, strings + n_value);
3360 if(object->mh != NULL)
3361 new_symbols[inew_syms].n_value =
3362 p - new_strings;
3363 else
3364 new_symbols64[inew_syms].n_value =
3365 p - new_strings;
3366 p += strlen(p) + 1;
3369 inew_syms++;
3370 saves[i] = inew_syms;
3375 * Build the new undefined symbols into a map and sort it.
3377 inew_undefsyms = 0;
3378 if(object->mh != NULL){
3379 undef_map = (struct undef_map *)allocate(new_nundefsym *
3380 sizeof(struct undef_map));
3381 undef_map64 = NULL;
3383 else{
3384 undef_map = NULL;
3385 undef_map64 = (struct undef_map64 *)allocate(new_nundefsym *
3386 sizeof(struct undef_map64));
3388 for(i = 0; i < nsyms; i++){
3389 if(saves[i]){
3390 if(object->mh != NULL){
3391 n_strx = symbols[i].n_un.n_strx;
3392 n_type = symbols[i].n_type;
3394 else{
3395 n_strx = symbols64[i].n_un.n_strx;
3396 n_type = symbols64[i].n_type;
3398 if((n_type & N_EXT) == N_EXT &&
3399 ((n_type & N_TYPE) == N_UNDF ||
3400 (n_type & N_TYPE) == N_PBUD)){
3401 if(object->mh != NULL)
3402 undef_map[inew_undefsyms].symbol = symbols[i];
3403 else
3404 undef_map64[inew_undefsyms].symbol64 = symbols64[i];
3405 if(n_strx != 0){
3406 strcpy(p, strings + n_strx);
3407 if(object->mh != NULL)
3408 undef_map[inew_undefsyms].symbol.n_un.n_strx =
3409 p - new_strings;
3410 else
3411 undef_map64[inew_undefsyms].symbol64.n_un.n_strx =
3412 p - new_strings;
3413 p += strlen(p) + 1;
3415 if(object->mh != NULL)
3416 undef_map[inew_undefsyms].index = i;
3417 else
3418 undef_map64[inew_undefsyms].index = i;
3419 inew_undefsyms++;
3423 for(i = 0; i < nsyms; i++){
3424 if(changes[i]){
3425 if(object->mh != NULL)
3426 n_strx = symbols[i].n_un.n_strx;
3427 else
3428 n_strx = symbols64[i].n_un.n_strx;
3429 if(n_strx != 0){
3430 strcpy(p, strings + n_strx);
3431 if(object->mh != NULL)
3432 undef_map[inew_undefsyms].symbol.n_un.n_strx =
3433 p - new_strings;
3434 else
3435 undef_map64[inew_undefsyms].symbol64.n_un.n_strx =
3436 p - new_strings;
3437 p += strlen(p) + 1;
3439 if(object->mh != NULL){
3440 undef_map[inew_undefsyms].symbol.n_type = N_UNDF | N_EXT;
3441 undef_map[inew_undefsyms].symbol.n_sect = NO_SECT;
3442 undef_map[inew_undefsyms].symbol.n_desc = 0;
3443 undef_map[inew_undefsyms].symbol.n_value = 0;
3444 undef_map[inew_undefsyms].index = i;
3446 else{
3447 undef_map64[inew_undefsyms].symbol64.n_type = N_UNDF |N_EXT;
3448 undef_map64[inew_undefsyms].symbol64.n_sect = NO_SECT;
3449 undef_map64[inew_undefsyms].symbol64.n_desc = 0;
3450 undef_map64[inew_undefsyms].symbol64.n_value = 0;
3451 undef_map64[inew_undefsyms].index = i;
3453 inew_undefsyms++;
3456 /* Sort the undefined symbols by name */
3457 qsort_strings = new_strings;
3458 if(object->mh != NULL)
3459 qsort(undef_map, new_nundefsym, sizeof(struct undef_map),
3460 (int (*)(const void *, const void *))cmp_qsort_undef_map);
3461 else
3462 qsort(undef_map64, new_nundefsym, sizeof(struct undef_map64),
3463 (int (*)(const void *, const void *))cmp_qsort_undef_map_64);
3464 /* Copy the symbols now in sorted order into new_symbols */
3465 for(i = 0; i < new_nundefsym; i++){
3466 if(object->mh != NULL){
3467 new_symbols[inew_syms] = undef_map[i].symbol;
3468 inew_syms++;
3469 saves[undef_map[i].index] = inew_syms;
3471 else{
3472 new_symbols64[inew_syms] = undef_map64[i].symbol64;
3473 inew_syms++;
3474 saves[undef_map64[i].index] = inew_syms;
3479 * Fixup the module table's module name strings adding them to the
3480 * string table. Also fix the indexes into the symbol table for
3481 * external and local symbols. And fix up the indexes into the
3482 * reference table.
3484 for(i = 0; i < nmodtab; i++){
3485 if(object->mh != NULL){
3486 strcpy(p, strings + mods[i].module_name);
3487 mods[i].module_name = p - new_strings;
3488 iextdefsym = mods[i].iextdefsym;
3489 nextdefsym = mods[i].nextdefsym;
3490 ilocalsym = mods[i].ilocalsym;
3491 nlocalsym = mods[i].nlocalsym;
3492 irefsym = mods[i].irefsym;
3493 nrefsym = mods[i].nrefsym;
3495 else{
3496 strcpy(p, strings + mods64[i].module_name);
3497 mods64[i].module_name = p - new_strings;
3498 iextdefsym = mods64[i].iextdefsym;
3499 nextdefsym = mods64[i].nextdefsym;
3500 ilocalsym = mods64[i].ilocalsym;
3501 nlocalsym = mods64[i].nlocalsym;
3502 irefsym = mods64[i].irefsym;
3503 nrefsym = mods64[i].nrefsym;
3505 p += strlen(p) + 1;
3507 if(iextdefsym > nsyms){
3508 error_arch(arch, member, "bad index into externally defined "
3509 "symbols of module table entry %d in: ", i);
3510 return(FALSE);
3512 if(iextdefsym + nextdefsym > nsyms){
3513 error_arch(arch, member, "bad number of externally defined "
3514 "symbols of module table entry %d in: ", i);
3515 return(FALSE);
3517 for(j = iextdefsym; j < iextdefsym + nextdefsym; j++){
3518 if(saves[j] != 0 && changes[j] == 0)
3519 break;
3521 n = 0;
3522 for(k = j; k < iextdefsym + nextdefsym; k++){
3523 if(saves[k] != 0 && changes[k] == 0)
3524 n++;
3526 if(n == 0){
3527 if(object->mh != NULL){
3528 mods[i].iextdefsym = 0;
3529 mods[i].nextdefsym = 0;
3531 else{
3532 mods64[i].iextdefsym = 0;
3533 mods64[i].nextdefsym = 0;
3536 else{
3537 if(object->mh != NULL){
3538 mods[i].iextdefsym = saves[j] - 1;
3539 mods[i].nextdefsym = n;
3541 else{
3542 mods64[i].iextdefsym = saves[j] - 1;
3543 mods64[i].nextdefsym = n;
3547 if(ilocalsym > nsyms){
3548 error_arch(arch, member, "bad index into symbols for local "
3549 "symbols of module table entry %d in: ", i);
3550 return(FALSE);
3552 if(ilocalsym + nlocalsym > nsyms){
3553 error_arch(arch, member, "bad number of local "
3554 "symbols of module table entry %d in: ", i);
3555 return(FALSE);
3557 for(j = ilocalsym; j < ilocalsym + nlocalsym; j++){
3558 if(saves[j] != 0)
3559 break;
3561 n = 0;
3562 for(k = j; k < ilocalsym + nlocalsym; k++){
3563 if(saves[k] != 0)
3564 n++;
3566 if(n == 0){
3567 if(object->mh != NULL){
3568 mods[i].ilocalsym = 0;
3569 mods[i].nlocalsym = 0;
3571 else{
3572 mods64[i].ilocalsym = 0;
3573 mods64[i].nlocalsym = 0;
3576 else{
3577 if(object->mh != NULL){
3578 mods[i].ilocalsym = saves[j] - 1;
3579 mods[i].nlocalsym = n;
3581 else{
3582 mods64[i].ilocalsym = saves[j] - 1;
3583 mods64[i].nlocalsym = n;
3587 if(irefsym > nextrefsyms){
3588 error_arch(arch, member, "bad index into reference table "
3589 "of module table entry %d in: ", i);
3590 return(FALSE);
3592 if(irefsym + nrefsym > nextrefsyms){
3593 error_arch(arch, member, "bad number of reference table "
3594 "entries of module table entry %d in: ", i);
3595 return(FALSE);
3597 for(j = irefsym; j < irefsym + nrefsym; j++){
3598 if(ref_saves[j] != 0)
3599 break;
3601 n = 0;
3602 for(k = j; k < irefsym + nrefsym; k++){
3603 if(ref_saves[k] != 0)
3604 n++;
3606 if(n == 0){
3607 if(object->mh != NULL){
3608 mods[i].irefsym = 0;
3609 mods[i].nrefsym = 0;
3611 else{
3612 mods64[i].irefsym = 0;
3613 mods64[i].nrefsym = 0;
3616 else{
3617 if(object->mh != NULL){
3618 mods[i].irefsym = ref_saves[j] - 1;
3619 mods[i].nrefsym = n;
3621 else{
3622 mods64[i].irefsym = ref_saves[j] - 1;
3623 mods64[i].nrefsym = n;
3629 * Create a new reference table.
3631 new_refs = allocate(new_nextrefsyms * sizeof(struct dylib_reference));
3632 j = 0;
3633 for(i = 0; i < nextrefsyms; i++){
3634 if(ref_saves[i]){
3635 if(saves[refs[i].isym]){
3636 new_refs[j].isym = saves[refs[i].isym] - 1;
3637 new_refs[j].flags = refs[i].flags;
3639 else{
3640 if(refs[i].flags == REFERENCE_FLAG_UNDEFINED_NON_LAZY ||
3641 refs[i].flags == REFERENCE_FLAG_UNDEFINED_LAZY){
3642 new_refs[j].isym = changes[refs[i].isym] - 1;
3643 new_refs[j].flags = refs[i].flags;
3646 j++;
3651 * Create a new dylib table of contents.
3653 new_ntoc = 0;
3654 for(i = 0; i < ntoc; i++){
3655 if(tocs[i].symbol_index >= nsyms){
3656 error_arch(arch, member, "bad symbol index for table of "
3657 "contents table entry %d in: ", i);
3658 return(FALSE);
3660 if(saves[tocs[i].symbol_index] != 0 &&
3661 changes[tocs[i].symbol_index] == 0)
3662 new_ntoc++;
3664 new_tocs = allocate(new_ntoc * sizeof(struct dylib_table_of_contents));
3665 j = 0;
3666 for(i = 0; i < ntoc; i++){
3667 if(saves[tocs[i].symbol_index] != 0 &&
3668 changes[tocs[i].symbol_index] == 0){
3669 new_tocs[j].symbol_index = saves[tocs[i].symbol_index] - 1;
3670 new_tocs[j].module_index = tocs[i].module_index;
3671 j++;
3674 #ifdef TRIE_SUPPORT
3676 * Update the export trie if it has one but only call the the
3677 * prune_trie() routine when we are removing global symbols as is
3678 * done with default stripping of a dyld executable or with the -s
3679 * or -R options.
3681 if(object->dyld_info != NULL &&
3682 object->dyld_info->export_size != 0 &&
3683 (default_dyld_executable || sfile != NULL || Rfile != NULL)){
3684 const char *error_string;
3685 uint32_t trie_new_size;
3687 error_string = prune_trie((uint8_t *)(object->object_addr +
3688 object->dyld_info->export_off),
3689 object->dyld_info->export_size,
3690 prune,
3691 &trie_new_size);
3692 if(error_string != NULL){
3693 error_arch(arch, member, "%s", error_string);
3694 return(FALSE);
3697 #endif /* TRIE_SUPPORT */
3699 if(undef_map != NULL)
3700 free(undef_map);
3701 if(undef_map64 != NULL)
3702 free(undef_map64);
3703 if(changes != NULL)
3704 free(changes);
3705 if(sections != NULL)
3706 free(sections);
3707 if(sections64 != NULL)
3708 free(sections64);
3710 if(errors == 0)
3711 return(TRUE);
3712 else
3713 return(FALSE);
3716 #ifdef TRIE_SUPPORT
3718 * prune() is called by prune_trie() and passed a name of an external symbol
3719 * in the trie. It returns 1 if the symbols is to be pruned out and 0 if the
3720 * symbol is to be kept.
3722 * Note that it may seem like a linear search of the new symbols would not be
3723 * the best approach but in 10.6 the only defined global symbol left in a
3724 * stripped executable is __mh_execute_header and new_nextdefsym is usually 1
3725 * so this never actually loops in practice.
3727 static
3729 prune(
3730 const char *name)
3732 uint32_t i;
3734 for(i = 0; i < new_nextdefsym; i++){
3735 if(new_symbols != NULL){
3736 if(strcmp(name, new_strings + new_symbols[inew_nextdefsym + i]
3737 .n_un.n_strx) == 0)
3738 return(0);
3740 else{
3741 if(strcmp(name, new_strings + new_symbols64[inew_nextdefsym + i]
3742 .n_un.n_strx) == 0)
3743 return(0);
3746 return(1);
3748 #endif /* TRIE_SUPPORT */
3751 * make_ld_r_object() takes the object file contents referenced by the passed
3752 * data structures, writes that to a temporary file, runs "ld -r" plus the
3753 * specified stripping option creating a second temporary file, reads that file
3754 * in and replaces the object file contents with that and resets the variables
3755 * pointing to the symbol, string and indirect tables.
3757 static
3758 void
3759 make_ld_r_object(
3760 struct arch *arch,
3761 struct member *member,
3762 struct object *object)
3764 enum byte_sex host_byte_sex;
3765 char *input_file, *output_file;
3766 int fd;
3767 struct ofile *ld_r_ofile;
3768 struct arch *ld_r_archs;
3769 uint32_t ld_r_narchs, save_errors;
3771 host_byte_sex = get_host_byte_sex();
3774 * Swap the object file back into its bytesex before writing it to the
3775 * temporary file if needed.
3777 if(object->object_byte_sex != host_byte_sex){
3778 if(object->mh != NULL){
3779 if(swap_object_headers(object->mh, object->load_commands) ==
3780 FALSE)
3781 fatal("internal error: swap_object_headers() failed");
3782 swap_nlist(symbols, nsyms, object->object_byte_sex);
3784 else{
3785 if(swap_object_headers(object->mh64, object->load_commands) ==
3786 FALSE)
3787 fatal("internal error: swap_object_headers() failed");
3788 swap_nlist_64(symbols64, nsyms, object->object_byte_sex);
3790 swap_indirect_symbols(indirectsyms, nindirectsyms,
3791 object->object_byte_sex);
3795 * Create an input object file for the ld -r command from the bytes
3796 * of this arch's object file.
3798 input_file = makestr("/tmp/strip.XXXXXX", NULL);
3799 input_file = mktemp(input_file);
3801 if((fd = open(input_file, O_WRONLY|O_CREAT, 0600)) < 0)
3802 system_fatal("can't open temporary file: %s", input_file);
3804 if(write(fd, object->object_addr, object->object_size) !=
3805 object->object_size)
3806 system_fatal("can't write temporary file: %s", input_file);
3808 if(close(fd) == -1)
3809 system_fatal("can't close temporary file: %s", input_file);
3812 * Create a temporary name for the output file of the ld -r
3814 output_file = makestr("/tmp/strip.XXXXXX", NULL);
3815 output_file = mktemp(output_file);
3818 * Create the ld -r command line and execute it.
3820 reset_execute_list();
3821 add_execute_list_with_prefix("ld");
3822 add_execute_list("-keep_private_externs");
3823 add_execute_list("-r");
3824 if(Sflag)
3825 add_execute_list("-S");
3826 if(xflag)
3827 add_execute_list("-x");
3828 add_execute_list(input_file);
3829 add_execute_list("-o");
3830 add_execute_list(output_file);
3831 if(sfile != NULL){
3832 add_execute_list("-x");
3833 add_execute_list("-exported_symbols_list");
3834 add_execute_list(sfile);
3836 if(Rfile != NULL){
3837 add_execute_list("-unexported_symbols_list");
3838 add_execute_list(Rfile);
3840 if(execute_list(vflag) == 0)
3841 fatal("internal link edit command failed");
3843 save_errors = errors;
3844 errors = 0;
3845 /* breakout the output file of the ld -f for processing */
3846 ld_r_ofile = breakout(output_file, &ld_r_archs, &ld_r_narchs, FALSE);
3847 if(errors)
3848 goto make_ld_r_object_cleanup;
3850 /* checkout the file for symbol table replacement processing */
3851 checkout(ld_r_archs, ld_r_narchs);
3854 * Make sure the output of the ld -r is an object file with one arch.
3856 if(ld_r_narchs != 1 ||
3857 ld_r_archs->type != OFILE_Mach_O ||
3858 ld_r_archs->object == NULL ||
3859 ld_r_archs->object->mh_filetype != MH_OBJECT)
3860 fatal("internal link edit command failed to produce a thin Mach-O "
3861 "object file");
3864 * Now reset all the data of the input object with the ld -r output
3865 * object file.
3867 nsyms = ld_r_archs->object->st->nsyms;
3868 if(ld_r_archs->object->mh != NULL){
3869 symbols = (struct nlist *)
3870 (ld_r_archs->object->object_addr +
3871 ld_r_archs->object->st->symoff);
3872 if(ld_r_archs->object->object_byte_sex != host_byte_sex)
3873 swap_nlist(symbols, nsyms, host_byte_sex);
3874 symbols64 = NULL;
3876 else{
3877 symbols = NULL;
3878 symbols64 = (struct nlist_64 *)
3879 (ld_r_archs->object->object_addr +
3880 ld_r_archs->object->st->symoff);
3881 if(ld_r_archs->object->object_byte_sex != host_byte_sex)
3882 swap_nlist_64(symbols64, nsyms, host_byte_sex);
3884 strings = ld_r_archs->object->object_addr +
3885 ld_r_archs->object->st->stroff;
3886 strsize = ld_r_archs->object->st->strsize;
3888 if(ld_r_archs->object->dyst != NULL &&
3889 ld_r_archs->object->dyst->nindirectsyms != 0){
3890 nindirectsyms = ld_r_archs->object->dyst->nindirectsyms;
3891 indirectsyms = (uint32_t *)
3892 (ld_r_archs->object->object_addr +
3893 ld_r_archs->object->dyst->indirectsymoff);
3894 if(ld_r_archs->object->object_byte_sex != host_byte_sex)
3895 swap_indirect_symbols(indirectsyms, nindirectsyms,
3896 host_byte_sex);
3898 else{
3899 indirectsyms = NULL;
3900 nindirectsyms = 0;
3903 if(ld_r_archs->object->mh != NULL)
3904 ld_r_archs->object->input_sym_info_size =
3905 nsyms * sizeof(struct nlist) +
3906 strsize;
3907 else
3908 ld_r_archs->object->input_sym_info_size =
3909 nsyms * sizeof(struct nlist_64) +
3910 strsize;
3913 * Copy over the object struct from the ld -r object file onto the
3914 * input object file.
3916 *object = *ld_r_archs->object;
3919 * Save the ofile struct for the ld -r output so it can be umapped when
3920 * we are done. And free up the ld_r_archs now that we are done with
3921 * them.
3923 object->ld_r_ofile = ld_r_ofile;
3924 free_archs(ld_r_archs, ld_r_narchs);
3926 make_ld_r_object_cleanup:
3927 errors += save_errors;
3929 * Remove the input and output files and clean up.
3931 if(unlink(input_file) == -1)
3932 system_fatal("can't remove temporary file: %s", input_file);
3933 if(unlink(output_file) == -1)
3934 system_fatal("can't remove temporary file: %s", output_file);
3935 free(input_file);
3936 free(output_file);
3940 * strip_LC_UUID_commands() is called when -no_uuid is specified to remove any
3941 * LC_UUID load commands from the object's load commands.
3943 static
3944 void
3945 strip_LC_UUID_commands(
3946 struct arch *arch,
3947 struct member *member,
3948 struct object *object)
3950 uint32_t i, ncmds, nuuids, mh_sizeofcmds, sizeofcmds;
3951 struct load_command *lc1, *lc2, *new_load_commands;
3952 struct segment_command *sg;
3955 * See if there are any LC_UUID load commands.
3957 nuuids = 0;
3958 lc1 = arch->object->load_commands;
3959 if(arch->object->mh != NULL){
3960 ncmds = arch->object->mh->ncmds;
3961 mh_sizeofcmds = arch->object->mh->sizeofcmds;
3963 else{
3964 ncmds = arch->object->mh64->ncmds;
3965 mh_sizeofcmds = arch->object->mh64->sizeofcmds;
3967 for(i = 0; i < ncmds; i++){
3968 if(lc1->cmd == LC_UUID){
3969 nuuids++;
3971 lc1 = (struct load_command *)((char *)lc1 + lc1->cmdsize);
3973 /* if no LC_UUID load commands just return */
3974 if(nuuids == 0)
3975 return;
3978 * Allocate space for the new load commands as zero it out so any holes
3979 * will be zero bytes.
3981 new_load_commands = allocate(mh_sizeofcmds);
3982 memset(new_load_commands, '\0', mh_sizeofcmds);
3985 * Copy all the load commands except the LC_UUID load commands into the
3986 * allocated space for the new load commands.
3988 lc1 = arch->object->load_commands;
3989 lc2 = new_load_commands;
3990 sizeofcmds = 0;
3991 for(i = 0; i < ncmds; i++){
3992 if(lc1->cmd != LC_UUID){
3993 memcpy(lc2, lc1, lc1->cmdsize);
3994 sizeofcmds += lc2->cmdsize;
3995 lc2 = (struct load_command *)((char *)lc2 + lc2->cmdsize);
3997 lc1 = (struct load_command *)((char *)lc1 + lc1->cmdsize);
4001 * Finally copy the updated load commands over the existing load
4002 * commands.
4004 memcpy(arch->object->load_commands, new_load_commands, sizeofcmds);
4005 if(mh_sizeofcmds > sizeofcmds){
4006 memset((char *)arch->object->load_commands + sizeofcmds, '\0',
4007 (mh_sizeofcmds - sizeofcmds));
4009 ncmds -= nuuids;
4010 if(arch->object->mh != NULL) {
4011 arch->object->mh->sizeofcmds = sizeofcmds;
4012 arch->object->mh->ncmds = ncmds;
4013 } else {
4014 arch->object->mh64->sizeofcmds = sizeofcmds;
4015 arch->object->mh64->ncmds = ncmds;
4017 free(new_load_commands);
4019 /* reset the pointers into the load commands */
4020 lc1 = arch->object->load_commands;
4021 for(i = 0; i < ncmds; i++){
4022 switch(lc1->cmd){
4023 case LC_SYMTAB:
4024 arch->object->st = (struct symtab_command *)lc1;
4025 break;
4026 case LC_DYSYMTAB:
4027 arch->object->dyst = (struct dysymtab_command *)lc1;
4028 break;
4029 case LC_TWOLEVEL_HINTS:
4030 arch->object->hints_cmd = (struct twolevel_hints_command *)lc1;
4031 break;
4032 case LC_PREBIND_CKSUM:
4033 arch->object->cs = (struct prebind_cksum_command *)lc1;
4034 break;
4035 case LC_SEGMENT:
4036 sg = (struct segment_command *)lc1;
4037 if(strcmp(sg->segname, SEG_LINKEDIT) == 0)
4038 arch->object->seg_linkedit = sg;
4039 break;
4040 case LC_SEGMENT_SPLIT_INFO:
4041 object->split_info_cmd = (struct linkedit_data_command *)lc1;
4042 break;
4043 case LC_FUNCTION_STARTS:
4044 object->func_starts_info_cmd =
4045 (struct linkedit_data_command *)lc1;
4046 break;
4047 case LC_CODE_SIGNATURE:
4048 object->code_sig_cmd = (struct linkedit_data_command *)lc1;
4049 break;
4050 case LC_DYLD_INFO_ONLY:
4051 case LC_DYLD_INFO:
4052 object->dyld_info = (struct dyld_info_command *)lc1;
4054 lc1 = (struct load_command *)((char *)lc1 + lc1->cmdsize);
4058 #ifndef NMEDIT
4060 * strip_LC_CODE_SIGNATURE_commands() is called when -c is specified to remove
4061 * any LC_CODE_SIGNATURE load commands from the object's load commands.
4063 static
4064 void
4065 strip_LC_CODE_SIGNATURE_commands(
4066 struct arch *arch,
4067 struct member *member,
4068 struct object *object)
4070 uint32_t i, ncmds, mh_sizeofcmds, sizeofcmds;
4071 struct load_command *lc1, *lc2, *new_load_commands;
4072 struct segment_command *sg;
4075 * See if there is an LC_CODE_SIGNATURE load command and if no command
4076 * just return.
4078 if(object->code_sig_cmd == NULL)
4079 return;
4082 * Allocate space for the new load commands and zero it out so any holes
4083 * will be zero bytes.
4085 if(arch->object->mh != NULL){
4086 ncmds = arch->object->mh->ncmds;
4087 mh_sizeofcmds = arch->object->mh->sizeofcmds;
4089 else{
4090 ncmds = arch->object->mh64->ncmds;
4091 mh_sizeofcmds = arch->object->mh64->sizeofcmds;
4093 new_load_commands = allocate(mh_sizeofcmds);
4094 memset(new_load_commands, '\0', mh_sizeofcmds);
4097 * Copy all the load commands except the LC_CODE_SIGNATURE load commands
4098 * into the allocated space for the new load commands.
4100 lc1 = arch->object->load_commands;
4101 lc2 = new_load_commands;
4102 sizeofcmds = 0;
4103 for(i = 0; i < ncmds; i++){
4104 if(lc1->cmd != LC_CODE_SIGNATURE){
4105 memcpy(lc2, lc1, lc1->cmdsize);
4106 sizeofcmds += lc2->cmdsize;
4107 lc2 = (struct load_command *)((char *)lc2 + lc2->cmdsize);
4109 lc1 = (struct load_command *)((char *)lc1 + lc1->cmdsize);
4113 * Finally copy the updated load commands over the existing load
4114 * commands.
4116 memcpy(arch->object->load_commands, new_load_commands, sizeofcmds);
4117 if(mh_sizeofcmds > sizeofcmds){
4118 memset((char *)arch->object->load_commands + sizeofcmds, '\0',
4119 (mh_sizeofcmds - sizeofcmds));
4121 ncmds -= 1;
4122 if(arch->object->mh != NULL) {
4123 arch->object->mh->sizeofcmds = sizeofcmds;
4124 arch->object->mh->ncmds = ncmds;
4125 } else {
4126 arch->object->mh64->sizeofcmds = sizeofcmds;
4127 arch->object->mh64->ncmds = ncmds;
4129 free(new_load_commands);
4131 /* reset the pointers into the load commands */
4132 object->code_sig_cmd = NULL;
4133 lc1 = arch->object->load_commands;
4134 for(i = 0; i < ncmds; i++){
4135 switch(lc1->cmd){
4136 case LC_SYMTAB:
4137 arch->object->st = (struct symtab_command *)lc1;
4138 break;
4139 case LC_DYSYMTAB:
4140 arch->object->dyst = (struct dysymtab_command *)lc1;
4141 break;
4142 case LC_TWOLEVEL_HINTS:
4143 arch->object->hints_cmd = (struct twolevel_hints_command *)lc1;
4144 break;
4145 case LC_PREBIND_CKSUM:
4146 arch->object->cs = (struct prebind_cksum_command *)lc1;
4147 break;
4148 case LC_SEGMENT:
4149 sg = (struct segment_command *)lc1;
4150 if(strcmp(sg->segname, SEG_LINKEDIT) == 0)
4151 arch->object->seg_linkedit = sg;
4152 break;
4153 case LC_SEGMENT_SPLIT_INFO:
4154 object->split_info_cmd = (struct linkedit_data_command *)lc1;
4155 break;
4156 case LC_FUNCTION_STARTS:
4157 object->func_starts_info_cmd =
4158 (struct linkedit_data_command *)lc1;
4159 break;
4161 lc1 = (struct load_command *)((char *)lc1 + lc1->cmdsize);
4165 * To get the right amount of the file copied out by writeout() for the
4166 * case when we are stripping out the section contents we already reduce
4167 * the object size by the size of the section contents including the
4168 * padding after the load commands. So here we need to further reduce
4169 * it by the load command for the LC_CODE_SIGNATURE (a struct
4170 * linkedit_data_command) we are removing.
4172 object->object_size -= sizeof(struct linkedit_data_command);
4174 * Then this size minus the size of the input symbolic information is
4175 * what is copied out from the file by writeout(). Which in this case
4176 * is just the new headers.
4180 * Finally for -c the file offset to the link edit information is to be
4181 * right after the load commands. So reset this for the updated size
4182 * of the load commands without the LC_CODE_SIGNATURE.
4184 if(object->mh != NULL)
4185 object->seg_linkedit->fileoff = sizeof(struct mach_header) +
4186 sizeofcmds;
4187 else
4188 object->seg_linkedit64->fileoff = sizeof(struct mach_header_64) +
4189 sizeofcmds;
4191 #endif /* !(NMEDIT) */
4194 * private_extern_reference_by_module() is passed a symbol_index of a private
4195 * extern symbol and the module table. If the symbol_index appears in the
4196 * module symbol table this returns TRUE else it returns FALSE.
4198 static
4199 enum bool
4200 private_extern_reference_by_module(
4201 uint32_t symbol_index,
4202 struct dylib_reference *refs,
4203 uint32_t nextrefsyms)
4205 uint32_t i;
4207 for(i = 0; i < nextrefsyms; i++){
4208 if(refs[i].isym == symbol_index){
4209 if(refs[i].flags == REFERENCE_FLAG_PRIVATE_UNDEFINED_NON_LAZY ||
4210 refs[i].flags == REFERENCE_FLAG_PRIVATE_UNDEFINED_LAZY){
4211 return(TRUE);
4215 return(FALSE);
4219 * symbol_pointer_used() is passed a symbol_index and the indirect table. If
4220 * the symbol_index appears in the indirect symbol table this returns TRUE else
4221 * it returns FALSE.
4223 static
4224 enum bool
4225 symbol_pointer_used(
4226 uint32_t symbol_index,
4227 uint32_t *indirectsyms,
4228 uint32_t nindirectsyms)
4230 uint32_t i;
4232 for(i = 0; i < nindirectsyms; i++){
4233 if(indirectsyms[i] == symbol_index)
4234 return(TRUE);
4236 return(FALSE);
4240 * Function for qsort for comparing undefined map entries.
4242 static
4244 cmp_qsort_undef_map(
4245 const struct undef_map *sym1,
4246 const struct undef_map *sym2)
4248 return(strcmp(qsort_strings + sym1->symbol.n_un.n_strx,
4249 qsort_strings + sym2->symbol.n_un.n_strx));
4252 static
4254 cmp_qsort_undef_map_64(
4255 const struct undef_map64 *sym1,
4256 const struct undef_map64 *sym2)
4258 return(strcmp(qsort_strings + sym1->symbol64.n_un.n_strx,
4259 qsort_strings + sym2->symbol64.n_un.n_strx));
4261 #endif /* !defined(NMEDIT) */
4263 #ifndef NMEDIT
4265 * Function for qsort for comparing object names.
4267 static
4269 cmp_qsort_filename(
4270 const char **name1,
4271 const char **name2)
4273 return(strcmp(*name1, *name2));
4277 * Function for bsearch for finding a object name.
4279 static
4281 cmp_bsearch_filename(
4282 const char *name1,
4283 const char **name2)
4285 return(strcmp(name1, *name2));
4287 #endif /* !defined(NMEDIT) */
4289 #ifdef NMEDIT
4290 static
4291 enum bool
4292 edit_symtab(
4293 struct arch *arch,
4294 struct member *member,
4295 struct object *object,
4296 struct nlist *symbols,
4297 struct nlist_64 *symbols64,
4298 uint32_t nsyms,
4299 char *strings,
4300 uint32_t strsize,
4301 struct dylib_table_of_contents *tocs,
4302 uint32_t ntoc,
4303 struct dylib_module *mods,
4304 struct dylib_module_64 *mods64,
4305 uint32_t nmodtab,
4306 struct dylib_reference *refs,
4307 uint32_t nextrefsyms)
4309 uint32_t i, j, k;
4310 unsigned char data_n_sect, nsects;
4311 struct load_command *lc;
4312 struct segment_command *sg;
4313 struct segment_command_64 *sg64;
4314 struct section *s, **sections;
4315 struct section_64 *s64, **sections64;
4317 uint32_t missing_syms;
4318 struct symbol_list *sp;
4319 struct nlist **global_symbol;
4320 struct nlist_64 **global_symbol64;
4321 enum bool global_symbol_found;
4322 char *global_name, save_char;
4323 enum bool dwarf_debug_map;
4324 enum byte_sex host_byte_sex;
4325 int32_t missing_reloc_symbols;
4326 enum bool edit_symtab_return;
4328 char *p, *q;
4329 uint32_t new_ext_strsize, len, inew_syms;
4331 struct nlist **changed_globals;
4332 struct nlist_64 **changed_globals64;
4333 uint32_t nchanged_globals;
4334 uint32_t ncmds, s_flags, n_strx, module_name, ilocalsym, nlocalsym;
4335 uint32_t iextdefsym, nextdefsym;
4336 uint8_t n_type, n_sect, global_symbol_n_sect;
4337 uint64_t n_value;
4338 enum bool warned_about_global_coalesced_symbols;
4340 edit_symtab_return = TRUE;
4341 host_byte_sex = get_host_byte_sex();
4342 missing_reloc_symbols = 0;
4343 warned_about_global_coalesced_symbols = FALSE;
4345 if(nmedits != NULL)
4346 free(nmedits);
4347 nmedits = allocate(nsyms * sizeof(enum bool));
4348 for(i = 0; i < nsyms; i++)
4349 nmedits[i] = FALSE;
4352 * If nmedit is operating on a dynamic library then symbols are turned
4353 * into private externs with the extern bit off not into static symbols.
4355 if(object->mh_filetype == MH_DYLIB && pflag == TRUE){
4356 error_arch(arch, member, "can't use -p with dynamic libraries");
4357 return(FALSE);
4361 * As part of the MAJOR guess for the second pass to fix stabs for the
4362 * globals symbols that get turned into non-global symbols. We need to
4363 * change the stabs. To do this we to know if a N_GSYM is for a data
4364 * symbol or not to know to turn it into an N_STSYM or a N_FUN.
4365 * This logic as determined by compiling test cases with and without
4366 * the key word 'static' and looking at the difference between the STABS
4367 * the compiler generates and trying to match that here.
4369 * We also use this loop and the next to gather an array of section
4370 * struct pointers so we can later determine if we run into a global
4371 * symbol in a coalesced section and not turn those symbols into
4372 * statics.
4374 j = 0;
4375 nsects = 0;
4376 n_sect = 1;
4377 data_n_sect = NO_SECT;
4378 lc = object->load_commands;
4379 if(object->mh != NULL)
4380 ncmds = object->mh->ncmds;
4381 else
4382 ncmds = object->mh64->ncmds;
4383 for(i = 0; i < ncmds; i++){
4384 if(lc->cmd == LC_SEGMENT){
4385 sg = (struct segment_command *)lc;
4386 s = (struct section *)((char *)sg +
4387 sizeof(struct segment_command));
4388 nsects += sg->nsects;
4389 for(j = 0; j < sg->nsects; j++){
4390 if(strcmp(s->segname, SEG_DATA) == 0 &&
4391 strcmp(s->sectname, SECT_DATA) == 0 &&
4392 data_n_sect == NO_SECT){
4393 data_n_sect = n_sect;
4394 break;
4396 n_sect++;
4397 s++;
4400 else if(lc->cmd == LC_SEGMENT_64){
4401 sg64 = (struct segment_command_64 *)lc;
4402 s64 = (struct section_64 *)((char *)sg64 +
4403 sizeof(struct segment_command_64));
4404 nsects += sg64->nsects;
4405 for(j = 0; j < sg64->nsects; j++){
4406 if(strcmp(s64->segname, SEG_DATA) == 0 &&
4407 strcmp(s64->sectname, SECT_DATA) == 0 &&
4408 data_n_sect == NO_SECT){
4409 data_n_sect = n_sect;
4410 break;
4412 n_sect++;
4413 s64++;
4416 lc = (struct load_command *)((char *)lc + lc->cmdsize);
4418 if(object->mh != NULL){
4419 sections = allocate(nsects * sizeof(struct section *));
4420 sections64 = NULL;
4422 else{
4423 sections = NULL;
4424 sections64 = allocate(nsects * sizeof(struct section_64 *));
4426 nsects = 0;
4427 lc = object->load_commands;
4428 for(i = 0; i < ncmds; i++){
4429 if(lc->cmd == LC_SEGMENT){
4430 sg = (struct segment_command *)lc;
4431 s = (struct section *)((char *)sg +
4432 sizeof(struct segment_command));
4433 for(j = 0; j < sg->nsects; j++){
4434 sections[nsects++] = s++;
4437 else if(lc->cmd == LC_SEGMENT_64){
4438 sg64 = (struct segment_command_64 *)lc;
4439 s64 = (struct section_64 *)((char *)sg64 +
4440 sizeof(struct segment_command_64));
4441 for(j = 0; j < sg64->nsects; j++){
4442 sections64[nsects++] = s64++;
4445 lc = (struct load_command *)((char *)lc + lc->cmdsize);
4449 * Zero out the saved symbols so they can be recorded for this file.
4451 for(i = 0; i < nsave_symbols; i++)
4452 save_symbols[i].sym = NULL;
4453 for(i = 0; i < nremove_symbols; i++)
4454 remove_symbols[i].sym = NULL;
4455 if(member == NULL){
4456 for(i = 0; i < nsave_symbols; i++)
4457 save_symbols[i].seen = FALSE;
4458 for(i = 0; i < nremove_symbols; i++)
4459 remove_symbols[i].seen = FALSE;
4462 nchanged_globals = 0;
4463 if(object->mh != NULL){
4464 changed_globals = allocate(nsyms * sizeof(struct nlist *));
4465 changed_globals64 = NULL;
4466 for(i = 0; i < nsyms; i++)
4467 changed_globals[i] = NULL;
4469 else{
4470 changed_globals = NULL;
4471 changed_globals64 = allocate(nsyms * sizeof(struct nlist_64 *));
4472 for(i = 0; i < nsyms; i++)
4473 changed_globals64[i] = NULL;
4477 * These are the variables for the new symbol table and new string
4478 * table. Since this routine only turns globals into non-globals the
4479 * number of symbols does not change. But the count of local, defined
4480 * external symbols does change.
4482 new_nsyms = nsyms;
4483 new_nlocalsym = 0;
4484 new_nextdefsym = 0;
4485 new_nundefsym = 0;
4487 new_strsize = sizeof(int32_t);
4488 new_ext_strsize = 0;
4491 * First pass: turn the globals symbols into non-global symbols.
4493 for(i = 0; i < nsyms; i++){
4494 len = 0;
4495 s_flags = 0;
4496 if(object->mh != NULL){
4497 n_strx = symbols[i].n_un.n_strx;
4498 n_type = symbols[i].n_type;
4499 n_sect = symbols[i].n_sect;
4500 if((n_type & N_TYPE) == N_SECT)
4501 s_flags = sections[n_sect - 1]->flags;
4502 n_value = symbols[i].n_value;
4504 else{
4505 n_strx = symbols64[i].n_un.n_strx;
4506 n_type = symbols64[i].n_type;
4507 n_sect = symbols64[i].n_sect;
4508 if((n_type & N_TYPE) == N_SECT)
4509 s_flags = sections64[n_sect - 1]->flags;
4510 n_value = symbols64[i].n_value;
4512 if(n_strx != 0){
4513 if(n_strx > strsize){
4514 error_arch(arch, member, "bad string index for symbol "
4515 "table entry %u in: ", i);
4516 return(FALSE);
4518 len = strlen(strings + n_strx) + 1;
4520 if(n_type & N_EXT){
4521 if((n_type & N_TYPE) != N_UNDF &&
4522 (n_type & N_TYPE) != N_PBUD){
4523 if((n_type & N_TYPE) == N_SECT){
4524 if(n_sect > nsects){
4525 error_arch(arch, member, "bad n_sect for symbol "
4526 "table entry %u in: ", i);
4527 return(FALSE);
4529 if(((s_flags & SECTION_TYPE) == S_COALESCED) &&
4530 pflag == FALSE &&
4531 object->mh_filetype != MH_OBJECT){
4532 /* this remains a global defined symbol */
4533 if(warned_about_global_coalesced_symbols == FALSE){
4534 warning_arch(arch, member, "can't make global "
4535 "coalesced symbols (like %s) into static "
4536 "symbols (use ld(1)'s "
4537 "-exported_symbols_list option) in a final "
4538 "linked image: ", strings + n_strx);
4539 warned_about_global_coalesced_symbols = TRUE;
4541 new_nextdefsym++;
4542 new_ext_strsize += len;
4543 new_strsize += len;
4544 sp = bsearch(strings + n_strx,
4545 remove_symbols, nremove_symbols,
4546 sizeof(struct symbol_list),
4547 (int (*)(const void *, const void *))
4548 symbol_list_bsearch);
4549 if(sp != NULL){
4550 if(sp->sym != NULL){
4551 error_arch(arch, member, "more than one "
4552 "symbol for: %s found in: ", sp->name);
4553 return(FALSE);
4555 else{
4556 if(object->mh != NULL)
4557 sp->sym = &(symbols[i]);
4558 else
4559 sp->sym = &(symbols64[i]);
4560 sp->seen = TRUE;
4561 warning_arch(arch, member, "can't make "
4562 "global coalesced symbol: %s into a "
4563 "static symbol in: ", sp->name);
4567 * In case the user has listed this coalesced
4568 * symbol in the save list look for it and mark it
4569 * as seen so we don't complain about not seeing it.
4571 sp = bsearch(strings + n_strx,
4572 save_symbols, nsave_symbols,
4573 sizeof(struct symbol_list),
4574 (int (*)(const void *, const void *))
4575 symbol_list_bsearch);
4576 if(sp != NULL){
4577 if(sp->sym != NULL){
4578 error_arch(arch, member, "more than one "
4579 "symbol for: %s found in: ", sp->name);
4580 return(FALSE);
4582 else{
4583 if(object->mh != NULL)
4584 sp->sym = &(symbols[i]);
4585 else
4586 sp->sym = &(symbols64[i]);
4587 sp->seen = TRUE;
4590 continue; /* leave this symbol unchanged */
4593 sp = bsearch(strings + n_strx,
4594 remove_symbols, nremove_symbols,
4595 sizeof(struct symbol_list),
4596 (int (*)(const void *, const void *))
4597 symbol_list_bsearch);
4598 if(sp != NULL){
4599 if(sp->sym != NULL){
4600 error_arch(arch, member, "more than one symbol "
4601 "for: %s found in: ", sp->name);
4602 return(FALSE);
4604 else{
4605 if(object->mh != NULL)
4606 sp->sym = &(symbols[i]);
4607 else
4608 sp->sym = &(symbols64[i]);
4609 sp->seen = TRUE;
4610 goto change_symbol;
4613 else{
4615 * If there is no list of saved symbols, then all
4616 * symbols will be saved unless listed in the remove
4617 * list.
4619 if(sfile == NULL){
4621 * There is no save list, so if there is also no
4622 * remove list but the -p flag is specified or it is
4623 * a dynamic library then change all symbols.
4625 if((pflag || object->mh_filetype == MH_DYLIB)
4626 && nremove_symbols == 0)
4627 goto change_symbol;
4628 /* this remains a global defined symbol */
4629 new_nextdefsym++;
4630 new_ext_strsize += len;
4631 new_strsize += len;
4632 continue; /* leave this symbol unchanged */
4635 sp = bsearch(strings + n_strx,
4636 save_symbols, nsave_symbols,
4637 sizeof(struct symbol_list),
4638 (int (*)(const void *, const void *))
4639 symbol_list_bsearch);
4640 if(sp != NULL){
4641 if(sp->sym != NULL){
4642 error_arch(arch, member, "more than one symbol "
4643 "for: %s found in: ", sp->name);
4644 return(FALSE);
4646 else{
4647 if(object->mh != NULL)
4648 sp->sym = &(symbols[i]);
4649 else
4650 sp->sym = &(symbols64[i]);
4651 sp->seen = TRUE;
4652 /* this remains a global defined symbol */
4653 new_nextdefsym++;
4654 new_ext_strsize += len;
4655 new_strsize += len;
4658 else{
4659 if(Aflag && n_type == (N_EXT | N_ABS) &&
4660 (n_value != 0 ||
4661 (n_strx != 0 &&
4662 strncmp(strings + n_strx,
4663 ".objc_class_name_",
4664 sizeof(".objc_class_name_") - 1) == 0))){
4665 /* this remains a global defined symbol */
4666 new_nextdefsym++;
4667 new_ext_strsize += len;
4668 new_strsize += len;
4670 else{
4671 change_symbol:
4672 if((n_type & N_TYPE) != N_INDR){
4673 nmedits[i] = TRUE;
4674 if(object->mh != NULL)
4675 changed_globals[nchanged_globals++] =
4676 symbols + i;
4677 else
4678 changed_globals64[nchanged_globals++] =
4679 symbols64 + i;
4680 if(pflag){
4681 /* this remains a global defined symbol */
4682 new_nextdefsym++;
4683 new_ext_strsize += len;
4684 new_strsize += len;
4686 else{
4687 /* this will become a non-global symbol */
4688 new_nlocalsym++;
4689 new_strsize += len;
4692 else{
4693 /* this remains a global defined symbol */
4694 new_nextdefsym++;
4695 new_ext_strsize += len;
4696 new_strsize += len;
4701 else{
4702 /* this is an undefined symbol */
4703 new_nundefsym++;
4704 new_ext_strsize += len;
4705 new_strsize += len;
4708 else{
4709 /* this is a local symbol */
4710 new_nlocalsym++;
4711 new_strsize += len;
4716 * The module table's module names are placed with the external
4717 * strings. So size them and add this to the external string size.
4719 for(i = 0; i < nmodtab; i++){
4720 if(object->mh != NULL)
4721 module_name = mods[i].module_name;
4722 else
4723 module_name = mods64[i].module_name;
4724 if(module_name == 0 || module_name > strsize){
4725 error_arch(arch, member, "bad string index for module_name "
4726 "of module table entry %d in: ", i);
4727 return(FALSE);
4729 len = strlen(strings + module_name) + 1;
4730 new_strsize += len;
4731 new_ext_strsize += len;
4735 * Warn about symbols to be saved that were missing.
4737 if(member == NULL){
4738 missing_syms = 0;
4739 if(iflag == 0){
4740 for(i = 0; i < nsave_symbols; i++){
4741 if(save_symbols[i].sym == NULL){
4742 if(missing_syms == 0){
4743 error_arch(arch, member, "symbols names listed "
4744 "in: %s not in: ", sfile);
4745 missing_syms = 1;
4747 fprintf(stderr, "%s\n", save_symbols[i].name);
4750 for(i = 0; i < nremove_symbols; i++){
4751 if(remove_symbols[i].sym == NULL){
4752 if(missing_syms == 0){
4753 error_arch(arch, member, "symbols names listed "
4754 "in: %s not in: ", Rfile);
4755 missing_syms = 1;
4757 fprintf(stderr, "%s\n", remove_symbols[i].name);
4764 * Second pass: fix stabs for the globals symbols that got turned into
4765 * non-global symbols. This is a MAJOR guess. The specific changes
4766 * to do here were determined by compiling test cases with and without
4767 * the key word 'static' and looking at the difference between the STABS
4768 * the compiler generates and trying to match that here.
4770 global_strings = strings;
4771 if(object->mh != NULL)
4772 qsort(changed_globals, nchanged_globals, sizeof(struct nlist *),
4773 (int (*)(const void *, const void *))cmp_qsort_global);
4774 else
4775 qsort(changed_globals64, nchanged_globals,sizeof(struct nlist_64 *),
4776 (int (*)(const void *, const void *))cmp_qsort_global_64);
4777 dwarf_debug_map = FALSE;
4778 for(i = 0; i < nsyms; i++){
4779 uint16_t n_desc;
4780 if(object->mh != NULL){
4781 n_strx = symbols[i].n_un.n_strx;
4782 n_type = symbols[i].n_type;
4783 n_desc = symbols[i].n_desc;
4785 else{
4786 n_strx = symbols64[i].n_un.n_strx;
4787 n_type = symbols64[i].n_type;
4788 n_desc = symbols64[i].n_desc;
4790 if(n_type == N_SO)
4791 dwarf_debug_map = FALSE;
4792 else if (n_type == N_OSO)
4793 dwarf_debug_map = n_desc != 0;
4794 else if (dwarf_debug_map && n_type == N_GSYM){
4795 global_name = strings + n_strx;
4796 if(object->mh != NULL){
4797 global_symbol = bsearch(global_name, changed_globals,
4798 nchanged_globals,sizeof(struct nlist *),
4799 (int (*)(const void *, const void *))
4800 cmp_bsearch_global);
4801 if(global_symbol != NULL){
4802 symbols[i].n_type = N_STSYM;
4803 symbols[i].n_sect = (*global_symbol)->n_sect;
4804 symbols[i].n_value = (*global_symbol)->n_value;
4807 else{
4808 global_symbol64 = bsearch(global_name, changed_globals64,
4809 nchanged_globals,
4810 sizeof(struct nlist_64 *),
4811 (int (*)(const void *, const void *))
4812 cmp_bsearch_global_64);
4813 if(global_symbol64 != NULL){
4814 symbols64[i].n_type = N_STSYM;
4815 symbols64[i].n_sect = (*global_symbol64)->n_sect;
4816 symbols64[i].n_value = (*global_symbol64)->n_value;
4820 else if(! dwarf_debug_map &&
4821 (n_type == N_GSYM || n_type == N_FUN) &&
4822 (n_strx != 0 && strings[n_strx] != '\0')){
4823 global_name = strings + n_strx;
4824 if((global_name[0] == '+' || global_name[0] == '-') &&
4825 global_name[1] == '['){
4826 j = 2;
4827 while(j + n_strx < strsize && global_name[j] != ']')
4828 j++;
4829 if(j + n_strx < strsize && global_name[j] == ']')
4830 j++;
4832 else
4833 j = 0;
4834 while(j + n_strx < strsize && global_name[j] != ':')
4835 j++;
4836 if(j + n_strx >= strsize){
4837 error_arch(arch, member, "bad N_STAB symbol name for entry "
4838 "%u (does not contain ':' separating name from type) "
4839 "in: ", i);
4840 return(FALSE);
4842 save_char = global_name[j];
4843 global_name[j] = '\0';
4845 global_symbol_found = FALSE;
4846 global_symbol_n_sect = 0;
4847 if(object->mh != NULL){
4848 global_symbol = bsearch(global_name, changed_globals,
4849 nchanged_globals,sizeof(struct nlist *),
4850 (int (*)(const void *, const void *))
4851 cmp_bsearch_global_stab);
4852 global_symbol64 = NULL;
4853 if(global_symbol != NULL){
4854 global_symbol_found = TRUE;
4855 global_symbol_n_sect = (*global_symbol)->n_sect;
4858 else{
4859 global_symbol64 = bsearch(global_name, changed_globals64,
4860 nchanged_globals,
4861 sizeof(struct nlist_64 *),
4862 (int (*)(const void *, const void *))
4863 cmp_bsearch_global_stab_64);
4864 global_symbol = NULL;
4865 if(global_symbol64 != NULL){
4866 global_symbol_found = TRUE;
4867 global_symbol_n_sect = (*global_symbol64)->n_sect;
4870 global_name[j] = save_char;
4871 if(global_symbol_found == TRUE){
4872 if(n_type == N_GSYM){
4873 if(global_symbol_n_sect == data_n_sect){
4874 if(object->mh != NULL)
4875 symbols[i].n_type = N_STSYM;
4876 else
4877 symbols64[i].n_type = N_STSYM;
4879 else{
4880 if(object->mh != NULL)
4881 symbols[i].n_type = N_FUN;
4882 else
4883 symbols64[i].n_type = N_FUN;
4885 if(object->mh != NULL){
4886 symbols[i].n_sect = (*global_symbol)->n_sect;
4887 symbols[i].n_value = (*global_symbol)->n_value;
4888 symbols[i].n_desc = (*global_symbol)->n_desc;
4890 else{
4891 symbols64[i].n_sect = (*global_symbol64)->n_sect;
4892 symbols64[i].n_value = (*global_symbol64)->n_value;
4893 symbols64[i].n_desc = (*global_symbol64)->n_desc;
4895 if(j + 1 + n_strx >= strsize ||
4896 global_name[j+1] != 'G'){
4897 error_arch(arch, member, "bad N_GSYM symbol name "
4898 "for entry %u (does not have type 'G' after "
4899 "':' in name) in: ", i);
4900 return(FALSE);
4902 global_name[j+1] = 'S';
4904 else{ /* n_type == N_FUN */
4905 if(j + 1 + n_strx >= strsize ||
4906 global_name[j+1] == 'F'){
4907 global_name[j+1] = 'f';
4913 global_strings = NULL;
4916 * Now what needs to be done is to create the new symbol table moving
4917 * those global symbols being changed into non-globals into the areas
4918 * in the symbol table for local symbols. The symbol table and string
4919 * table must be in this order:
4921 * symbol table
4922 * local symbols
4923 * external defined symbols
4924 * undefined symbols
4925 * string table
4926 * external strings
4927 * local strings
4929 if(saves != NULL)
4930 free(saves);
4931 saves = (int32_t *)allocate(nsyms * sizeof(int32_t));
4932 bzero(saves, nsyms * sizeof(int32_t));
4934 if(object->mh != NULL){
4935 new_symbols = (struct nlist *)
4936 allocate(new_nsyms * sizeof(struct nlist));
4937 new_symbols64 = NULL;
4939 else{
4940 new_symbols = NULL;
4941 new_symbols64 = (struct nlist_64 *)
4942 allocate(new_nsyms * sizeof(struct nlist_64));
4944 new_strsize = rnd(new_strsize, sizeof(int32_t));
4945 new_strings = (char *)allocate(new_strsize);
4946 new_strings[new_strsize - 3] = '\0';
4947 new_strings[new_strsize - 2] = '\0';
4948 new_strings[new_strsize - 1] = '\0';
4950 memset(new_strings, '\0', sizeof(int32_t));
4951 p = new_strings + sizeof(int32_t);
4952 q = p + new_ext_strsize;
4955 * If this is a dynamic library the movement of the symbols has to be
4956 * done with respect to the modules. As the local symbols, and external
4957 * defined symbols are grouped together for each module. Then a new
4958 * module table needs to be created with the new indexes into the symbol
4959 * table for each module.
4961 new_nmodtab = nmodtab;
4962 new_ntoc = ntoc;
4963 new_nextrefsyms = nextrefsyms;
4964 if(object->mh_filetype == MH_DYLIB && nmodtab != 0){
4965 if(object->mh != NULL){
4966 new_mods = allocate(nmodtab * sizeof(struct dylib_module));
4967 new_mods64 = NULL;
4969 else{
4970 new_mods = NULL;
4971 new_mods64 = allocate(nmodtab * sizeof(struct dylib_module_64));
4974 inew_syms = 0;
4976 * This first loop through the module table sets the index and
4977 * counts of the local symbols for each module.
4979 for(i = 0; i < nmodtab; i++){
4981 * First put the existing local symbols into the new symbol
4982 * table.
4984 if(object->mh != NULL){
4985 new_mods[i].ilocalsym = inew_syms;
4986 new_mods[i].nlocalsym = 0;
4987 ilocalsym = mods[i].ilocalsym;
4988 nlocalsym = mods[i].nlocalsym;
4990 else{
4991 new_mods64[i].ilocalsym = inew_syms;
4992 new_mods64[i].nlocalsym = 0;
4993 ilocalsym = mods64[i].ilocalsym;
4994 nlocalsym = mods64[i].nlocalsym;
4996 for(j = ilocalsym; j < ilocalsym + nlocalsym; j++){
4997 if(object->mh != NULL){
4998 n_strx = symbols[j].n_un.n_strx;
4999 n_type = symbols[j].n_type;
5001 else{
5002 n_strx = symbols64[j].n_un.n_strx;
5003 n_type = symbols64[j].n_type;
5005 if((n_type & N_EXT) == 0){
5006 if(object->mh != NULL)
5007 new_symbols[inew_syms] = symbols[j];
5008 else
5009 new_symbols64[inew_syms] = symbols64[j];
5010 if(n_strx != 0){
5011 strcpy(q, strings + n_strx);
5012 if(object->mh != NULL)
5013 new_symbols[inew_syms].n_un.n_strx =
5014 q - new_strings;
5015 else
5016 new_symbols64[inew_syms].n_un.n_strx =
5017 q - new_strings;
5018 q += strlen(q) + 1;
5020 inew_syms++;
5021 saves[j] = inew_syms;
5022 if(object->mh != NULL)
5023 new_mods[i].nlocalsym++;
5024 else
5025 new_mods64[i].nlocalsym++;
5029 * Next put the global symbols that were changed into
5030 * non-global symbols into the new symbol table and moved their
5031 * counts to the local symbol counts.
5033 if(object->mh != NULL){
5034 iextdefsym = mods[i].iextdefsym;
5035 nextdefsym = mods[i].nextdefsym;
5037 else{
5038 iextdefsym = mods64[i].iextdefsym;
5039 nextdefsym = mods64[i].nextdefsym;
5041 for(j = iextdefsym; j < iextdefsym + nextdefsym; j++){
5042 if(object->mh != NULL){
5043 n_strx = symbols[j].n_un.n_strx;
5044 n_type = symbols[j].n_type;
5046 else{
5047 n_strx = symbols64[j].n_un.n_strx;
5048 n_type = symbols64[j].n_type;
5050 if((n_type & N_EXT) != 0){
5051 if(nmedits[j] == TRUE){
5053 * Change the new symbol to a private extern symbol
5054 * with the extern bit off.
5056 if(object->mh != NULL){
5057 new_symbols[inew_syms] = symbols[j];
5058 new_symbols[inew_syms].n_type |= N_PEXT;
5059 new_symbols[inew_syms].n_type &= ~N_EXT;
5061 else{
5062 new_symbols64[inew_syms] = symbols64[j];
5063 new_symbols64[inew_syms].n_type |= N_PEXT;
5064 new_symbols64[inew_syms].n_type &= ~N_EXT;
5066 if(n_strx != 0){
5067 strcpy(q, strings + n_strx);
5068 if(object->mh != NULL)
5069 new_symbols[inew_syms].n_un.n_strx =
5070 q - new_strings;
5071 else
5072 new_symbols64[inew_syms].n_un.n_strx =
5073 q - new_strings;
5074 q += strlen(q) + 1;
5076 inew_syms++;
5077 saves[j] = inew_syms;
5078 if(object->mh != NULL)
5079 new_mods[i].nlocalsym++;
5080 else
5081 new_mods64[i].nlocalsym++;
5087 * Next put the unchanged defined global symbols into the new
5088 * symbol table.
5090 for(i = 0; i < nmodtab; i++){
5091 if(object->mh != NULL){
5092 new_mods[i].iextdefsym = inew_syms;
5093 new_mods[i].nextdefsym = 0;
5094 iextdefsym = mods[i].iextdefsym;
5095 nextdefsym = mods[i].nextdefsym;
5097 else{
5098 new_mods64[i].iextdefsym = inew_syms;
5099 new_mods64[i].nextdefsym = 0;
5100 iextdefsym = mods64[i].iextdefsym;
5101 nextdefsym = mods64[i].nextdefsym;
5103 for(j = iextdefsym; j < iextdefsym + nextdefsym; j++){
5104 if(object->mh != NULL){
5105 n_strx = symbols[j].n_un.n_strx;
5106 n_type = symbols[j].n_type;
5108 else{
5109 n_strx = symbols64[j].n_un.n_strx;
5110 n_type = symbols64[j].n_type;
5112 if((n_type & N_EXT) != 0){
5113 if(nmedits[j] == FALSE){
5114 if(object->mh != NULL)
5115 new_symbols[inew_syms] = symbols[j];
5116 else
5117 new_symbols64[inew_syms] = symbols64[j];
5118 if(n_strx != 0){
5119 strcpy(p, strings + n_strx);
5120 if(object->mh != NULL)
5121 new_symbols[inew_syms].n_un.n_strx =
5122 p - new_strings;
5123 else
5124 new_symbols64[inew_syms].n_un.n_strx =
5125 p - new_strings;
5126 p += strlen(p) + 1;
5128 inew_syms++;
5129 saves[j] = inew_syms;
5130 if(object->mh != NULL)
5131 new_mods[i].nextdefsym++;
5132 else
5133 new_mods64[i].nextdefsym++;
5139 * Last put the undefined symbols into the new symbol table.
5141 for(i = 0; i < nsyms; i++){
5142 if(object->mh != NULL){
5143 n_strx = symbols[i].n_un.n_strx;
5144 n_type = symbols[i].n_type;
5146 else{
5147 n_strx = symbols64[i].n_un.n_strx;
5148 n_type = symbols64[i].n_type;
5150 if((n_type & N_EXT) != 0 &&
5151 ((n_type & N_TYPE) == N_UNDF ||
5152 (n_type & N_TYPE) == N_PBUD)){
5153 if(object->mh != NULL)
5154 new_symbols[inew_syms] = symbols[i];
5155 else
5156 new_symbols64[inew_syms] = symbols64[i];
5157 if(n_strx != 0){
5158 strcpy(p, strings + n_strx);
5159 if(object->mh != NULL)
5160 new_symbols[inew_syms].n_un.n_strx =
5161 p - new_strings;
5162 else
5163 new_symbols64[inew_syms].n_un.n_strx =
5164 p - new_strings;
5165 p += strlen(p) + 1;
5167 inew_syms++;
5168 saves[i] = inew_syms;
5173 * Place the module table's module names with the external strings
5174 * and set the names in the new module table. And then copy the
5175 * other unchanged fields.
5177 for(i = 0; i < nmodtab; i++){
5178 if(object->mh != NULL){
5179 strcpy(p, strings + mods[i].module_name);
5180 new_mods[i].module_name = p - new_strings;
5181 p += strlen(p) + 1;
5183 new_mods[i].irefsym = mods[i].irefsym;
5184 new_mods[i].nrefsym = mods[i].nrefsym;
5185 new_mods[i].iextrel = mods[i].iextrel;
5186 new_mods[i].nextrel = mods[i].nextrel;
5187 new_mods[i].iinit_iterm = mods[i].iinit_iterm;
5188 new_mods[i].ninit_nterm = mods[i].ninit_nterm;
5189 new_mods[i].objc_module_info_addr =
5190 mods[i].objc_module_info_addr;
5191 new_mods[i].objc_module_info_size =
5192 mods[i].objc_module_info_size;
5194 else{
5195 strcpy(p, strings + mods64[i].module_name);
5196 new_mods64[i].module_name = p - new_strings;
5197 p += strlen(p) + 1;
5199 new_mods64[i].irefsym = mods64[i].irefsym;
5200 new_mods64[i].nrefsym = mods64[i].nrefsym;
5201 new_mods64[i].iextrel = mods64[i].iextrel;
5202 new_mods64[i].nextrel = mods64[i].nextrel;
5203 new_mods64[i].iinit_iterm = mods64[i].iinit_iterm;
5204 new_mods64[i].ninit_nterm = mods64[i].ninit_nterm;
5205 new_mods64[i].objc_module_info_addr =
5206 mods64[i].objc_module_info_addr;
5207 new_mods64[i].objc_module_info_size =
5208 mods64[i].objc_module_info_size;
5213 * Update the reference table with the new symbol indexes for all
5214 * entries and change type of reference (the flags field) for those
5215 * symbols that got changed from globals to non-globals.
5217 new_nextrefsyms = nextrefsyms;
5218 new_refs = allocate(new_nextrefsyms *
5219 sizeof(struct dylib_reference));
5220 j = 0;
5221 for(i = 0; i < nextrefsyms; i++){
5222 if(nmedits[refs[i].isym] == TRUE){
5223 if(refs[i].flags == REFERENCE_FLAG_DEFINED)
5224 new_refs[i].flags =
5225 REFERENCE_FLAG_PRIVATE_DEFINED;
5226 else if(refs[i].flags == REFERENCE_FLAG_UNDEFINED_NON_LAZY)
5227 new_refs[i].flags =
5228 REFERENCE_FLAG_PRIVATE_UNDEFINED_NON_LAZY;
5229 else if(refs[i].flags == REFERENCE_FLAG_UNDEFINED_LAZY)
5230 new_refs[i].flags =
5231 REFERENCE_FLAG_PRIVATE_UNDEFINED_LAZY;
5232 else
5233 new_refs[i].flags = refs[i].flags;
5235 else{
5236 new_refs[i].flags = refs[i].flags;
5238 new_refs[i].isym = saves[refs[i].isym] - 1;
5242 * Create a new dylib table of contents without the global symbols
5243 * that got turned into non-globals.
5245 new_ntoc = ntoc - nchanged_globals;
5246 new_tocs = allocate(new_ntoc *
5247 sizeof(struct dylib_table_of_contents));
5248 k = 0;
5249 for(i = 0; i < ntoc; i++){
5250 if(tocs[i].symbol_index >= nsyms){
5251 error_arch(arch, member, "bad symbol index for table of "
5252 "contents table entry %d in: ", i);
5253 return(FALSE);
5255 if(nmedits[tocs[i].symbol_index] == FALSE){
5256 new_tocs[k].symbol_index = saves[tocs[i].symbol_index] - 1;
5257 new_tocs[k].module_index = tocs[i].module_index;
5258 k++;
5263 * If is not a dynamic library so all global symbols changed into
5264 * statics can be moved to the end of the local symbols. If the pflag
5265 * is set then the changed symbols remain global and just get the
5266 * private extern bit set.
5268 else{
5270 * First put the existing local symbols into the new symbol table.
5272 inew_syms = 0;
5273 for(i = 0; i < nsyms; i++){
5274 if(object->mh != NULL){
5275 n_strx = symbols[i].n_un.n_strx;
5276 n_type = symbols[i].n_type;
5278 else{
5279 n_strx = symbols64[i].n_un.n_strx;
5280 n_type = symbols64[i].n_type;
5282 if((n_type & N_EXT) == 0){
5283 if(object->mh != NULL)
5284 new_symbols[inew_syms] = symbols[i];
5285 else
5286 new_symbols64[inew_syms] = symbols64[i];
5287 if(n_strx != 0){
5288 strcpy(q, strings + n_strx);
5289 if(object->mh != NULL)
5290 new_symbols[inew_syms].n_un.n_strx =
5291 q - new_strings;
5292 else
5293 new_symbols64[inew_syms].n_un.n_strx =
5294 q - new_strings;
5295 q += strlen(q) + 1;
5297 inew_syms++;
5298 saves[i] = inew_syms;
5302 * Next put the global symbols that were changed into statics
5303 * symbols into the new symbol table.
5305 if(pflag == FALSE){
5306 for(i = 0; i < nsyms; i++){
5307 if(object->mh != NULL){
5308 n_strx = symbols[i].n_un.n_strx;
5309 n_type = symbols[i].n_type;
5311 else{
5312 n_strx = symbols64[i].n_un.n_strx;
5313 n_type = symbols64[i].n_type;
5315 if((n_type & N_EXT) != 0){
5316 if(nmedits[i] == TRUE){
5318 * Change the new symbol to not be an extern symbol
5319 * by turning off the extern bit.
5321 if(object->mh != NULL){
5322 new_symbols[inew_syms] = symbols[i];
5323 new_symbols[inew_syms].n_type &= ~N_EXT;
5324 new_symbols[inew_syms].n_desc &= ~N_WEAK_DEF;
5326 else{
5327 new_symbols64[inew_syms] = symbols64[i];
5328 new_symbols64[inew_syms].n_type &= ~N_EXT;
5329 new_symbols64[inew_syms].n_desc &= ~N_WEAK_DEF;
5331 if(n_strx != 0){
5332 strcpy(q, strings + n_strx);
5333 if(object->mh != NULL)
5334 new_symbols[inew_syms].n_un.n_strx =
5335 q - new_strings;
5336 else
5337 new_symbols64[inew_syms].n_un.n_strx =
5338 q - new_strings;
5339 q += strlen(q) + 1;
5341 inew_syms++;
5342 saves[i] = inew_syms;
5348 * Last put the unchanged global symbols into the new symbol table
5349 * and symbols changed into private externs.
5351 for(i = 0; i < nsyms; i++){
5352 if(object->mh != NULL){
5353 n_strx = symbols[i].n_un.n_strx;
5354 n_type = symbols[i].n_type;
5356 else{
5357 n_strx = symbols64[i].n_un.n_strx;
5358 n_type = symbols64[i].n_type;
5360 if((n_type & N_EXT) != 0){
5361 if(nmedits[i] == FALSE || pflag == TRUE){
5362 if(object->mh != NULL)
5363 new_symbols[inew_syms] = symbols[i];
5364 else
5365 new_symbols64[inew_syms] = symbols64[i];
5366 if(nmedits[i] == TRUE && pflag == TRUE){
5368 * Change the new symbol to be a private extern
5369 * symbol by turning on the private extern bit.
5371 if(object->mh != NULL)
5372 new_symbols[inew_syms].n_type |= N_PEXT;
5373 else
5374 new_symbols64[inew_syms].n_type |= N_PEXT;
5376 if(n_strx != 0){
5377 strcpy(p, strings + n_strx);
5378 if(object->mh != NULL)
5379 new_symbols[inew_syms].n_un.n_strx =
5380 p - new_strings;
5381 else
5382 new_symbols64[inew_syms].n_un.n_strx =
5383 p - new_strings;
5384 p += strlen(p) + 1;
5386 inew_syms++;
5387 saves[i] = inew_syms;
5393 if(sections != NULL)
5394 free(sections);
5395 if(sections64 != NULL)
5396 free(sections64);
5398 if(errors == 0)
5399 return(TRUE);
5400 else
5401 return(FALSE);
5405 * Function for qsort for comparing global symbol names.
5407 static
5409 cmp_qsort_global(
5410 const struct nlist **sym1,
5411 const struct nlist **sym2)
5413 return(strcmp(global_strings + (*sym1)->n_un.n_strx,
5414 global_strings + (*sym2)->n_un.n_strx));
5417 static
5419 cmp_qsort_global_64(
5420 const struct nlist_64 **sym1,
5421 const struct nlist_64 **sym2)
5423 return(strcmp(global_strings + (*sym1)->n_un.n_strx,
5424 global_strings + (*sym2)->n_un.n_strx));
5428 * Function for bsearch for finding a global symbol that matches a stab name.
5430 static
5432 cmp_bsearch_global_stab(
5433 const char *name,
5434 const struct nlist **sym)
5437 * The +1 is for the '_' on the global symbol that is not on the
5438 * stab string that is trying to be matched.
5440 return(strcmp(name, global_strings + (*sym)->n_un.n_strx + 1));
5443 static
5445 cmp_bsearch_global_stab_64(
5446 const char *name,
5447 const struct nlist_64 **sym)
5450 * The +1 is for the '_' on the global symbol that is not on the
5451 * stab string that is trying to be matched.
5453 return(strcmp(name, global_strings + (*sym)->n_un.n_strx + 1));
5457 * Function for bsearch for finding a global symbol that matches a stab name
5458 * in the debug map.
5460 static
5462 cmp_bsearch_global(
5463 const char *name,
5464 const struct nlist **sym)
5466 return(strcmp(name, global_strings + (*sym)->n_un.n_strx));
5469 static
5471 cmp_bsearch_global_64(
5472 const char *name,
5473 const struct nlist_64 **sym)
5475 return(strcmp(name, global_strings + (*sym)->n_un.n_strx));
5477 #endif /* defined(NMEDIT) */