Integrate cctools-758 changes
[striptease.git] / strip.c
blobfce87366720cd6ee43eb22934b11f991aef5c84c
1 /*
2 * Copyright (c) 1999 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
11 * file.
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
21 * @APPLE_LICENSE_HEADER_END@
24 * The strip(1) and nmedit(l) program. This understands only Mach-O format
25 * files (with the restriction the symbol table is at the end of the file) and
26 * fat files with Mach-O files in them.
28 #include <stdio.h>
29 #include <stdlib.h>
30 #include <string.h>
31 #include <limits.h>
32 #include <ctype.h>
33 #include <libc.h>
34 #include <sys/types.h>
35 #include <sys/stat.h>
36 #include <mach-o/loader.h>
37 #include <mach-o/reloc.h>
38 #include <mach-o/nlist.h>
39 #include <mach-o/stab.h>
40 #include "stuff/breakout.h"
41 #include "stuff/allocate.h"
42 #include "stuff/errors.h"
43 #include "stuff/round.h"
44 #include "stuff/reloc.h"
45 #include "stuff/reloc.h"
46 #include "stuff/symbol_list.h"
47 #include "stuff/unix_standard_mode.h"
48 #include "stuff/execute.h"
49 #ifdef TRIE_SUPPORT
50 #include <mach-o/prune_trie.h>
51 #endif /* TRIE_SUPPORT */
53 /* These are set from the command line arguments */
54 __private_extern__
55 char *progname = NULL; /* name of the program for error messages (argv[0]) */
56 static char *output_file;/* name of the output file */
57 static char *sfile; /* filename of global symbol names to keep */
58 static char *Rfile; /* filename of global symbol names to remove */
59 static uint32_t Aflag; /* save only absolute symbols with non-zero value and
60 .objc_class_name_* symbols */
61 static uint32_t 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 = round(archs[i].members[j].member_name_size, 8) +
883 (round(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 round(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;
1294 /* warn about strip -s or -R on a final linked image with dyld_info */
1295 if(nsave_symbols != 0){
1296 warning_arch(arch, NULL, "removing global symbols from a final linked"
1297 " no longer supported. Use -exported_symbols_list at link time when building: ");
1300 if(object->split_info_cmd != NULL){
1301 object->output_split_info_data = object->object_addr +
1302 object->split_info_cmd->dataoff;
1303 object->output_split_info_data_size =
1304 object->split_info_cmd->datasize;
1306 if(object->code_sig_cmd != NULL){
1307 #ifndef NMEDIT
1308 if(!cflag)
1309 #endif /* !(NMEDIT) */
1311 object->output_code_sig_data = object->object_addr +
1312 object->code_sig_cmd->dataoff;
1313 object->output_code_sig_data_size =
1314 object->code_sig_cmd->datasize;
1318 if(object->dyst != NULL){
1319 object->dyst->ilocalsym = 0;
1320 object->dyst->nlocalsym = new_nlocalsym;
1321 object->dyst->iextdefsym = new_nlocalsym;
1322 object->dyst->nextdefsym = new_nextdefsym;
1323 object->dyst->iundefsym = new_nlocalsym + new_nextdefsym;
1324 object->dyst->nundefsym = new_nundefsym;
1325 if(object->dyst->nindirectsyms != 0){
1326 object->output_indirect_symtab = indirectsyms;
1327 if(object->object_byte_sex != host_byte_sex)
1328 swap_indirect_symbols(indirectsyms, nindirectsyms,
1329 object->object_byte_sex);
1333 * If the -c option is specified the object's filetype will
1334 * have been changed from MH_DYLIB to MH_DYLIB_STUB above.
1336 if(object->mh_filetype == MH_DYLIB ||
1337 object->mh_filetype == MH_DYLIB_STUB){
1338 object->output_tocs = new_tocs;
1339 object->output_ntoc = new_ntoc;
1340 #ifdef NMEDIT
1341 if(object->mh != NULL)
1342 object->output_mods = new_mods;
1343 else
1344 object->output_mods64 = new_mods64;
1345 object->output_nmodtab = new_nmodtab;
1346 #else
1347 object->output_mods = mods;
1348 object->output_nmodtab = nmodtab;
1349 #endif
1350 object->output_refs = new_refs;
1351 object->output_nextrefsyms = new_nextrefsyms;
1352 if(object->object_byte_sex != host_byte_sex){
1353 swap_dylib_table_of_contents(new_tocs, new_ntoc,
1354 object->object_byte_sex);
1355 #ifdef NMEDIT
1356 if(object->mh != NULL)
1357 swap_dylib_module(new_mods, new_nmodtab,
1358 object->object_byte_sex);
1359 else
1360 swap_dylib_module_64(new_mods64, new_nmodtab,
1361 object->object_byte_sex);
1362 #else
1363 if(object->mh != NULL)
1364 swap_dylib_module(mods, nmodtab,
1365 object->object_byte_sex);
1366 else
1367 swap_dylib_module_64(mods64, nmodtab,
1368 object->object_byte_sex);
1369 #endif
1370 swap_dylib_reference(new_refs, new_nextrefsyms,
1371 object->object_byte_sex);
1374 if(object->dyld_info != NULL){
1375 object->input_sym_info_size += object->dyld_info->rebase_size
1376 + object->dyld_info->bind_size
1377 + object->dyld_info->weak_bind_size
1378 + object->dyld_info->lazy_bind_size
1379 + object->dyld_info->export_size;
1381 object->input_sym_info_size +=
1382 object->dyst->nlocrel * sizeof(struct relocation_info) +
1383 object->dyst->nextrel * sizeof(struct relocation_info) +
1384 object->dyst->ntoc * sizeof(struct dylib_table_of_contents)+
1385 object->dyst->nextrefsyms * sizeof(struct dylib_reference);
1386 if(object->mh != NULL){
1387 object->input_sym_info_size +=
1388 object->dyst->nmodtab * sizeof(struct dylib_module) +
1389 object->dyst->nindirectsyms * sizeof(uint32_t);
1391 else{
1392 object->input_sym_info_size +=
1393 object->dyst->nmodtab * sizeof(struct dylib_module_64) +
1394 object->dyst->nindirectsyms * sizeof(uint32_t) +
1395 object->input_indirectsym_pad;
1397 #ifndef NMEDIT
1399 * When stripping out the section contents to create a
1400 * dynamic library stub the relocation info also gets
1401 * stripped.
1403 if(!cflag)
1404 #endif /* !(NMEDIT) */
1406 object->output_sym_info_size +=
1407 object->dyst->nlocrel * sizeof(struct relocation_info) +
1408 object->dyst->nextrel * sizeof(struct relocation_info);
1410 object->output_sym_info_size +=
1411 new_ntoc * sizeof(struct dylib_table_of_contents)+
1412 new_nextrefsyms * sizeof(struct dylib_reference) +
1413 object->dyst->nindirectsyms * sizeof(uint32_t) +
1414 object->input_indirectsym_pad;
1415 if(object->mh != NULL){
1416 object->output_sym_info_size +=
1417 object->dyst->nmodtab * sizeof(struct dylib_module);
1419 else{
1420 object->output_sym_info_size +=
1421 object->dyst->nmodtab * sizeof(struct dylib_module_64);
1423 if(object->hints_cmd != NULL){
1424 object->input_sym_info_size +=
1425 object->hints_cmd->nhints *
1426 sizeof(struct twolevel_hint);
1427 object->output_sym_info_size +=
1428 object->hints_cmd->nhints *
1429 sizeof(struct twolevel_hint);
1431 if(object->split_info_cmd != NULL){
1432 object->input_sym_info_size +=
1433 object->split_info_cmd->datasize;
1434 object->output_sym_info_size +=
1435 object->split_info_cmd->datasize;
1437 if(object->code_sig_cmd != NULL){
1438 object->input_sym_info_size =
1439 round(object->input_sym_info_size, 16);
1440 object->input_sym_info_size +=
1441 object->code_sig_cmd->datasize;
1442 #ifndef NMEDIT
1443 if(cflag){
1444 strip_LC_CODE_SIGNATURE_commands(arch, member, object);
1446 else
1447 #endif /* !(NMEDIT) */
1449 object->output_sym_info_size =
1450 round(object->output_sym_info_size, 16);
1451 object->output_sym_info_size +=
1452 object->code_sig_cmd->datasize;
1456 object->dyst->ntoc = new_ntoc;
1457 object->dyst->nextrefsyms = new_nextrefsyms;
1459 offset = get_starting_syminfo_offset(object);
1461 if(object->dyld_info != 0){
1462 if (object->dyld_info->rebase_off != 0){
1463 object->dyld_info->rebase_off = offset;
1464 offset += object->dyld_info->rebase_size;
1466 if (object->dyld_info->bind_off != 0){
1467 object->dyld_info->bind_off = offset;
1468 offset += object->dyld_info->bind_size;
1470 if (object->dyld_info->weak_bind_off != 0){
1471 object->dyld_info->weak_bind_off = offset;
1472 offset += object->dyld_info->weak_bind_size;
1474 if (object->dyld_info->lazy_bind_off != 0){
1475 object->dyld_info->lazy_bind_off = offset;
1476 offset += object->dyld_info->lazy_bind_size;
1478 if (object->dyld_info->export_off != 0){
1479 object->dyld_info->export_off = offset;
1480 offset += object->dyld_info->export_size;
1484 if(object->dyst->nlocrel != 0){
1485 object->output_loc_relocs = (struct relocation_info *)
1486 (object->object_addr + object->dyst->locreloff);
1487 #ifndef NMEDIT
1489 * When stripping out the section contents to create a
1490 * dynamic library stub the relocation info also gets
1491 * stripped.
1493 if(cflag){
1494 object->dyst->nlocrel = 0;
1495 object->dyst->locreloff = 0;
1497 else
1498 #endif /* defined(NMEDIT) */
1500 object->dyst->locreloff = offset;
1501 offset += object->dyst->nlocrel *
1502 sizeof(struct relocation_info);
1505 else
1506 object->dyst->locreloff = 0;
1508 if(object->split_info_cmd != NULL){
1509 object->split_info_cmd->dataoff = offset;
1510 offset += object->split_info_cmd->datasize;
1513 if(object->st->nsyms != 0){
1514 object->st->symoff = offset;
1515 if(object->mh != NULL)
1516 offset += object->st->nsyms * sizeof(struct nlist);
1517 else
1518 offset += object->st->nsyms * sizeof(struct nlist_64);
1520 else
1521 object->st->symoff = 0;
1523 if(object->hints_cmd != NULL){
1524 if(object->hints_cmd->nhints != 0){
1525 object->output_hints = (struct twolevel_hint *)
1526 (object->object_addr + object->hints_cmd->offset);
1527 object->hints_cmd->offset = offset;
1528 offset += object->hints_cmd->nhints *
1529 sizeof(struct twolevel_hint);
1531 else
1532 object->hints_cmd->offset = 0;
1535 if(object->dyst->nextrel != 0){
1536 object->output_ext_relocs = (struct relocation_info *)
1537 (object->object_addr + object->dyst->extreloff);
1538 #ifndef NMEDIT
1540 * When stripping out the section contents to create a
1541 * dynamic library stub the relocation info also gets
1542 * stripped.
1544 if(cflag){
1545 object->dyst->nextrel = 0;
1546 object->dyst->extreloff = 0;
1548 else
1549 #endif /* defined(NMEDIT) */
1551 object->dyst->extreloff = offset;
1552 offset += object->dyst->nextrel *
1553 sizeof(struct relocation_info);
1556 else
1557 object->dyst->extreloff = 0;
1559 if(object->dyst->nindirectsyms != 0){
1560 object->dyst->indirectsymoff = offset;
1561 offset += object->dyst->nindirectsyms * sizeof(uint32_t) +
1562 object->input_indirectsym_pad;
1564 else
1565 object->dyst->indirectsymoff = 0;;
1567 if(object->dyst->ntoc != 0){
1568 object->dyst->tocoff = offset;
1569 offset += object->dyst->ntoc *
1570 sizeof(struct dylib_table_of_contents);
1572 else
1573 object->dyst->tocoff = 0;
1575 if(object->dyst->nmodtab != 0){
1576 #ifndef NMEDIT
1578 * When stripping out the section contents to create a
1579 * dynamic library stub zero out the fields in the module
1580 * table for the sections and relocation information and
1581 * clear Objective-C address and size from modules.
1583 if(cflag){
1584 if(object->mh != NULL){
1585 for(k = 0; k < object->dyst->nmodtab; k++){
1586 mods[k].iinit_iterm = 0;
1587 mods[k].ninit_nterm = 0;
1588 mods[k].iextrel = 0;
1589 mods[k].nextrel = 0;
1590 mods[k].objc_module_info_addr = 0;
1591 mods[k].objc_module_info_size = 0;
1594 else{
1595 for(k = 0; k < object->dyst->nmodtab; k++){
1596 mods64[k].iinit_iterm = 0;
1597 mods64[k].ninit_nterm = 0;
1598 mods64[k].iextrel = 0;
1599 mods64[k].nextrel = 0;
1600 mods64[k].objc_module_info_addr = 0;
1601 mods64[k].objc_module_info_size = 0;
1605 #endif /* !(NMEDIT) */
1606 object->dyst->modtaboff = offset;
1607 if(object->mh != NULL)
1608 offset += object->dyst->nmodtab *
1609 sizeof(struct dylib_module);
1610 else
1611 offset += object->dyst->nmodtab *
1612 sizeof(struct dylib_module_64);
1614 else
1615 object->dyst->modtaboff = 0;
1617 if(object->dyst->nextrefsyms != 0){
1618 object->dyst->extrefsymoff = offset;
1619 offset += object->dyst->nextrefsyms *
1620 sizeof(struct dylib_reference);
1622 else
1623 object->dyst->extrefsymoff = 0;
1625 if(object->st->strsize != 0){
1626 object->st->stroff = offset;
1627 offset += object->st->strsize;
1629 else
1630 object->st->stroff = 0;
1632 if(object->code_sig_cmd != NULL){
1633 offset = round(offset, 16);
1634 object->code_sig_cmd->dataoff = offset;
1635 offset += object->code_sig_cmd->datasize;
1638 else{
1639 if(new_strsize != 0){
1640 if(object->mh != NULL)
1641 object->st->stroff = object->st->symoff +
1642 new_nsyms * sizeof(struct nlist);
1643 else
1644 object->st->stroff = object->st->symoff +
1645 new_nsyms * sizeof(struct nlist_64);
1647 else
1648 object->st->stroff = 0;
1649 if(new_nsyms == 0)
1650 object->st->symoff = 0;
1653 #ifndef NMEDIT
1654 else{
1656 * Here we are doing a full symbol strip. In some cases it may
1657 * leave the local relocation entries as well as LOCAL indirect
1658 * symbol table entries.
1660 if(saves != NULL)
1661 free(saves);
1662 saves = (int32_t *)allocate(object->st->nsyms * sizeof(int32_t));
1663 bzero(saves, object->st->nsyms * sizeof(int32_t));
1666 * Account for the symbolic info in the input file.
1668 if(object->dyst != NULL){
1669 object->input_sym_info_size +=
1670 object->dyst->nlocrel * sizeof(struct relocation_info) +
1671 object->dyst->nextrel * sizeof(struct relocation_info) +
1672 object->dyst->ntoc * sizeof(struct dylib_table_of_contents)+
1673 object->dyst->nextrefsyms * sizeof(struct dylib_reference);
1674 if(object->mh != NULL){
1675 object->input_sym_info_size +=
1676 object->dyst->nmodtab * sizeof(struct dylib_module) +
1677 object->dyst->nindirectsyms * sizeof(uint32_t);
1679 else{
1680 object->input_sym_info_size +=
1681 object->dyst->nmodtab * sizeof(struct dylib_module_64) +
1682 object->dyst->nindirectsyms * sizeof(uint32_t) +
1683 object->input_indirectsym_pad;
1688 * Determine the offset where the remaining symbolic info will start
1689 * in the output file (if any).
1691 offset = get_starting_syminfo_offset(object);
1694 * For a full symbol strip all these values in the output file are
1695 * set to zero.
1697 object->st->symoff = 0;
1698 object->st->nsyms = 0;
1699 object->st->stroff = 0;
1700 object->st->strsize = 0;
1701 if(object->dyst != NULL){
1702 object->dyst->ilocalsym = 0;
1703 object->dyst->nlocalsym = 0;
1704 object->dyst->iextdefsym = 0;
1705 object->dyst->nextdefsym = 0;
1706 object->dyst->iundefsym = 0;
1707 object->dyst->nundefsym = 0;
1711 * This will accumulate any remaining symbolic info size in the
1712 * output file.
1714 object->output_sym_info_size = 0;
1717 * We set these so that checking can be done below to report the
1718 * symbols that can't be stripped because of relocation entries
1719 * or indirect symbol table entries. Normally if these table have a
1720 * non-zero number of entries it will be an error as we are trying
1721 * to strip everything. But it maybe that there are only LOCAL
1722 * indirect entries which is odd but will be OK.
1724 if(object->dyst != NULL){
1725 if(object->dyst->nextrel != 0){
1726 object->output_ext_relocs = (struct relocation_info *)
1727 (object->object_addr + object->dyst->extreloff);
1730 * Since this file has a dynamic symbol table and if this file
1731 * has local relocation entries on input make sure they are
1732 * there on output. This is a rare case that it will not have
1733 * external relocs or indirect symbols but can happen as is the
1734 * case with the dynamic linker itself.
1736 if(object->dyst->nlocrel != 0){
1737 object->output_loc_relocs = (struct relocation_info *)
1738 (object->object_addr + object->dyst->locreloff);
1739 object->output_sym_info_size +=
1740 object->dyst->nlocrel * sizeof(struct relocation_info);
1742 object->dyst->locreloff = offset;
1743 offset += object->dyst->nlocrel *
1744 sizeof(struct relocation_info);
1747 if(object->dyst->nindirectsyms != 0){
1748 object->output_indirect_symtab = (uint32_t *)
1749 (object->object_addr +
1750 object->dyst->indirectsymoff);
1751 if(object->object_byte_sex != host_byte_sex)
1752 swap_indirect_symbols(
1753 object->output_indirect_symtab,
1754 object->dyst->nindirectsyms,
1755 object->object_byte_sex);
1757 object->output_sym_info_size +=
1758 object->dyst->nindirectsyms * sizeof(uint32_t) +
1759 object->input_indirectsym_pad;
1761 object->dyst->indirectsymoff = offset;
1762 offset += object->dyst->nindirectsyms * sizeof(uint32_t) +
1763 object->input_indirectsym_pad;
1767 #endif /* !defined(NMEDIT) */
1770 * Always clear the prebind checksum if any when creating a new file.
1772 if(object->cs != NULL)
1773 object->cs->cksum = 0;
1775 if(object->seg_linkedit != NULL){
1776 object->seg_linkedit->filesize += object->output_sym_info_size -
1777 object->input_sym_info_size;
1778 object->seg_linkedit->vmsize = object->seg_linkedit->filesize;
1780 else if(object->seg_linkedit64 != NULL){
1781 /* Do this in two steps to avoid 32/64-bit casting problems. */
1782 object->seg_linkedit64->filesize -= object->input_sym_info_size;
1783 object->seg_linkedit64->filesize += object->output_sym_info_size;
1784 object->seg_linkedit64->vmsize = object->seg_linkedit64->filesize;
1788 * Check and update the external relocation entries to make sure
1789 * referenced symbols are not stripped and refer to the new symbol
1790 * table indexes.
1792 * The external relocation entries can be located in one of two places,
1793 * first off of the sections or second off of the dynamic symtab.
1795 missing_reloc_symbols = 0;
1796 lc = object->load_commands;
1797 if(object->mh != NULL)
1798 ncmds = object->mh->ncmds;
1799 else
1800 ncmds = object->mh64->ncmds;
1801 for(i = 0; i < ncmds; i++){
1802 if(lc->cmd == LC_SEGMENT &&
1803 object->seg_linkedit != (struct segment_command *)lc){
1804 sg = (struct segment_command *)lc;
1805 s = (struct section *)((char *)sg +
1806 sizeof(struct segment_command));
1807 for(j = 0; j < sg->nsects; j++){
1808 if(s->nreloc != 0){
1809 if(s->reloff + s->nreloc *
1810 sizeof(struct relocation_info) >
1811 object->object_size){
1812 fatal_arch(arch, member, "truncated or malformed "
1813 "object (relocation entries for section (%.16s,"
1814 "%.16s) extends past the end of the file)",
1815 s->segname, s->sectname);
1817 relocs = (struct relocation_info *)
1818 (object->object_addr + s->reloff);
1819 if(object->object_byte_sex != host_byte_sex)
1820 swap_relocation_info(relocs, s->nreloc,
1821 host_byte_sex);
1822 if(s->offset + s->size > object->object_size){
1823 fatal_arch(arch, member, "truncated or malformed "
1824 "object (contents of section (%.16s,"
1825 "%.16s) extends past the end of the file)",
1826 s->segname, s->sectname);
1828 contents = object->object_addr + s->offset;
1829 check_object_relocs(arch, member, object, s->segname,
1830 s->sectname, s->size, contents, relocs, s->nreloc,
1831 symbols, symbols64, nsyms, strings,
1832 &missing_reloc_symbols, host_byte_sex);
1833 if(object->object_byte_sex != host_byte_sex)
1834 swap_relocation_info(relocs, s->nreloc,
1835 object->object_byte_sex);
1837 s++;
1840 else if(lc->cmd == LC_SEGMENT_64 &&
1841 object->seg_linkedit64 != (struct segment_command_64 *)lc){
1842 sg64 = (struct segment_command_64 *)lc;
1843 s64 = (struct section_64 *)((char *)sg64 +
1844 sizeof(struct segment_command_64));
1845 for(j = 0; j < sg64->nsects; j++){
1846 if(s64->nreloc != 0){
1847 if(s64->reloff + s64->nreloc *
1848 sizeof(struct relocation_info) >
1849 object->object_size){
1850 fatal_arch(arch, member, "truncated or malformed "
1851 "object (relocation entries for section (%.16s,"
1852 "%.16s) extends past the end of the file)",
1853 s64->segname, s64->sectname);
1855 relocs = (struct relocation_info *)
1856 (object->object_addr + s64->reloff);
1857 if(object->object_byte_sex != host_byte_sex)
1858 swap_relocation_info(relocs, s64->nreloc,
1859 host_byte_sex);
1860 if(s64->offset + s64->size > object->object_size){
1861 fatal_arch(arch, member, "truncated or malformed "
1862 "object (contents of section (%.16s,"
1863 "%.16s) extends past the end of the file)",
1864 s64->segname, s64->sectname);
1866 contents = object->object_addr + s64->offset;
1867 check_object_relocs(arch, member, object, s64->segname,
1868 s64->sectname, s64->size, contents, relocs,
1869 s64->nreloc, symbols, symbols64, nsyms, strings,
1870 &missing_reloc_symbols, host_byte_sex);
1871 if(object->object_byte_sex != host_byte_sex)
1872 swap_relocation_info(relocs, s64->nreloc,
1873 object->object_byte_sex);
1875 s64++;
1878 lc = (struct load_command *)((char *)lc + lc->cmdsize);
1880 if(object->dyst != NULL && object->dyst->nextrel != 0){
1881 relocs = object->output_ext_relocs;
1882 if(object->object_byte_sex != host_byte_sex)
1883 swap_relocation_info(relocs, object->dyst->nextrel,
1884 host_byte_sex);
1886 for(i = 0; i < object->dyst->nextrel; i++){
1887 if((relocs[i].r_address & R_SCATTERED) == 0 &&
1888 relocs[i].r_extern == 1){
1889 if(relocs[i].r_symbolnum > nsyms){
1890 fatal_arch(arch, member, "bad r_symbolnum for external "
1891 "relocation entry %d in: ", i);
1893 if(saves[relocs[i].r_symbolnum] == 0){
1894 if(missing_reloc_symbols == 0){
1895 error_arch(arch, member, "symbols referenced by "
1896 "relocation entries that can't be stripped in: ");
1897 missing_reloc_symbols = 1;
1899 if(object->mh != NULL){
1900 fprintf(stderr, "%s\n", strings + symbols
1901 [relocs[i].r_symbolnum].n_un.n_strx);
1903 else {
1904 fprintf(stderr, "%s\n", strings + symbols64
1905 [relocs[i].r_symbolnum].n_un.n_strx);
1907 saves[relocs[i].r_symbolnum] = -1;
1909 if(saves[relocs[i].r_symbolnum] != -1){
1910 relocs[i].r_symbolnum =
1911 saves[relocs[i].r_symbolnum] - 1;
1914 else{
1915 fatal_arch(arch, member, "bad external relocation entry "
1916 "%d (not external) in: ", i);
1918 if((relocs[i].r_address & R_SCATTERED) == 0){
1919 if(reloc_has_pair(object->mh_cputype, relocs[i].r_type))
1920 i++;
1922 else{
1923 sreloc = (struct scattered_relocation_info *)relocs + i;
1924 if(reloc_has_pair(object->mh_cputype, sreloc->r_type))
1925 i++;
1928 if(object->object_byte_sex != host_byte_sex)
1929 swap_relocation_info(relocs, object->dyst->nextrel,
1930 object->object_byte_sex);
1934 * Check and update the indirect symbol table entries to make sure
1935 * referenced symbols are not stripped and refer to the new symbol
1936 * table indexes.
1938 if(object->dyst != NULL && object->dyst->nindirectsyms != 0){
1939 if(object->object_byte_sex != host_byte_sex)
1940 swap_indirect_symbols(object->output_indirect_symtab,
1941 object->dyst->nindirectsyms, host_byte_sex);
1943 lc = object->load_commands;
1944 if(object->mh != NULL)
1945 ncmds = object->mh->ncmds;
1946 else
1947 ncmds = object->mh64->ncmds;
1948 for(i = 0; i < ncmds; i++){
1949 if(lc->cmd == LC_SEGMENT &&
1950 object->seg_linkedit != (struct segment_command *)lc){
1951 sg = (struct segment_command *)lc;
1952 s = (struct section *)((char *)sg +
1953 sizeof(struct segment_command));
1954 for(j = 0; j < sg->nsects; j++){
1955 section_type = s->flags & SECTION_TYPE;
1956 if(section_type == S_LAZY_SYMBOL_POINTERS ||
1957 section_type == S_LAZY_DYLIB_SYMBOL_POINTERS ||
1958 section_type == S_NON_LAZY_SYMBOL_POINTERS)
1959 stride = 4;
1960 else if(section_type == S_SYMBOL_STUBS)
1961 stride = s->reserved2;
1962 else{
1963 s++;
1964 continue;
1966 nitems = s->size / stride;
1967 contents = object->object_addr + s->offset;
1968 check_indirect_symtab(arch, member, object, nitems,
1969 s->reserved1, section_type, contents, symbols,
1970 symbols64, nsyms, strings, &missing_reloc_symbols,
1971 host_byte_sex);
1972 s++;
1975 else if(lc->cmd == LC_SEGMENT_64 &&
1976 object->seg_linkedit64 != (struct segment_command_64 *)lc){
1977 sg64 = (struct segment_command_64 *)lc;
1978 s64 = (struct section_64 *)((char *)sg64 +
1979 sizeof(struct segment_command_64));
1980 for(j = 0; j < sg64->nsects; j++){
1981 section_type = s64->flags & SECTION_TYPE;
1982 if(section_type == S_LAZY_SYMBOL_POINTERS ||
1983 section_type == S_LAZY_DYLIB_SYMBOL_POINTERS ||
1984 section_type == S_NON_LAZY_SYMBOL_POINTERS)
1985 stride = 8;
1986 else if(section_type == S_SYMBOL_STUBS)
1987 stride = s64->reserved2;
1988 else{
1989 s64++;
1990 continue;
1992 nitems = s64->size / stride;
1993 contents = object->object_addr + s64->offset;
1994 check_indirect_symtab(arch, member, object, nitems,
1995 s64->reserved1, section_type, contents, symbols,
1996 symbols64, nsyms, strings, &missing_reloc_symbols,
1997 host_byte_sex);
1998 s64++;
2001 lc = (struct load_command *)((char *)lc + lc->cmdsize);
2004 if(object->object_byte_sex != host_byte_sex)
2005 swap_indirect_symbols(object->output_indirect_symtab,
2006 object->dyst->nindirectsyms, object->object_byte_sex);
2010 * Issue a warning if object file has a code signature that the
2011 * operation will invalidate it.
2013 if(object->code_sig_cmd != NULL)
2014 warning_arch(arch, member, "changes being made to the file will "
2015 "invalidate the code signature in: ");
2019 * get_starting_syminfo_offset() returns the starting offset of the symbolic
2020 * info in the object file.
2022 static
2023 uint32_t
2024 get_starting_syminfo_offset(
2025 struct object *object)
2027 uint32_t offset;
2029 if(object->seg_linkedit != NULL ||
2030 object->seg_linkedit64 != NULL){
2031 if(object->mh != NULL)
2032 offset = object->seg_linkedit->fileoff;
2033 else
2034 offset = object->seg_linkedit64->fileoff;
2036 else{
2037 offset = UINT_MAX;
2038 if(object->dyst != NULL &&
2039 object->dyst->nlocrel != 0 &&
2040 object->dyst->locreloff < offset)
2041 offset = object->dyst->locreloff;
2042 if(object->st->nsyms != 0 &&
2043 object->st->symoff < offset)
2044 offset = object->st->symoff;
2045 if(object->dyst != NULL &&
2046 object->dyst->nextrel != 0 &&
2047 object->dyst->extreloff < offset)
2048 offset = object->dyst->extreloff;
2049 if(object->dyst != NULL &&
2050 object->dyst->nindirectsyms != 0 &&
2051 object->dyst->indirectsymoff < offset)
2052 offset = object->dyst->indirectsymoff;
2053 if(object->dyst != NULL &&
2054 object->dyst->ntoc != 0 &&
2055 object->dyst->tocoff < offset)
2056 offset = object->dyst->tocoff;
2057 if(object->dyst != NULL &&
2058 object->dyst->nmodtab != 0 &&
2059 object->dyst->modtaboff < offset)
2060 offset = object->dyst->modtaboff;
2061 if(object->dyst != NULL &&
2062 object->dyst->nextrefsyms != 0 &&
2063 object->dyst->extrefsymoff < offset)
2064 offset = object->dyst->extrefsymoff;
2065 if(object->st->strsize != 0 &&
2066 object->st->stroff < offset)
2067 offset = object->st->stroff;
2069 return(offset);
2073 * check_object_relocs() is used to check and update the external relocation
2074 * entries from a section in an object file, to make sure referenced symbols
2075 * are not stripped and are changed to refer to the new symbol table indexes.
2077 static
2078 void
2079 check_object_relocs(
2080 struct arch *arch,
2081 struct member *member,
2082 struct object *object,
2083 char *segname,
2084 char *sectname,
2085 uint64_t sectsize,
2086 char *contents,
2087 struct relocation_info *relocs,
2088 uint32_t nreloc,
2089 struct nlist *symbols,
2090 struct nlist_64 *symbols64,
2091 uint32_t nsyms,
2092 char *strings,
2093 int32_t *missing_reloc_symbols,
2094 enum byte_sex host_byte_sex)
2096 uint32_t k, n_strx;
2097 uint64_t n_value;
2098 #ifdef NMEDIT
2099 uint32_t value, n_ext;
2100 uint64_t value64;
2101 #endif
2102 struct scattered_relocation_info *sreloc;
2104 for(k = 0; k < nreloc; k++){
2105 if((relocs[k].r_address & R_SCATTERED) == 0 &&
2106 relocs[k].r_extern == 1){
2107 if(relocs[k].r_symbolnum > nsyms){
2108 fatal_arch(arch, member, "bad r_symbolnum for relocation "
2109 "entry %d in section (%.16s,%.16s) in: ", k, segname,
2110 sectname);
2112 if(object->mh != NULL){
2113 n_strx = symbols[relocs[k].r_symbolnum].n_un.n_strx;
2114 n_value = symbols[relocs[k].r_symbolnum].n_value;
2116 else{
2117 n_strx = symbols64[relocs[k].r_symbolnum].n_un.n_strx;
2118 n_value = symbols64[relocs[k].r_symbolnum].n_value;
2120 #ifndef NMEDIT
2121 if(saves[relocs[k].r_symbolnum] == 0){
2122 if(*missing_reloc_symbols == 0){
2123 error_arch(arch, member, "symbols referenced by "
2124 "relocation entries that can't be stripped in: ");
2125 *missing_reloc_symbols = 1;
2127 fprintf(stderr, "%s\n", strings + n_strx);
2128 saves[relocs[k].r_symbolnum] = -1;
2130 #else /* defined(NMEDIT) */
2132 * We are letting nmedit change global coalesed symbols into
2133 * statics in MH_OBJECT file types only. Relocation entries to
2134 * global coalesced symbols are external relocs.
2136 if(object->mh != NULL)
2137 n_ext = new_symbols[saves[relocs[k].r_symbolnum] - 1].
2138 n_type & N_EXT;
2139 else
2140 n_ext = new_symbols64[saves[relocs[k].r_symbolnum] - 1].
2141 n_type & N_EXT;
2142 if(n_ext != N_EXT &&
2143 object->mh_cputype != CPU_TYPE_X86_64){
2145 * We need to do the relocation for this external relocation
2146 * entry so the item to be relocated is correct for a local
2147 * relocation entry. We don't need to do this for x86-64.
2149 if(relocs[k].r_address + sizeof(int32_t) > sectsize){
2150 fatal_arch(arch, member, "truncated or malformed "
2151 "object (r_address of relocation entry %u of "
2152 "section (%.16s,%.16s) extends past the end "
2153 "of the section)", k, segname, sectname);
2155 if(object->mh != NULL){
2156 value = *(uint32_t *)
2157 (contents + relocs[k].r_address);
2158 if(object->object_byte_sex != host_byte_sex)
2159 value = SWAP_INT(value);
2161 * We handle a very limited form here. Only VANILLA
2162 * (r_type == 0) long (r_length==2) absolute or pcrel
2163 * that won't need a scattered relocation entry.
2165 if(relocs[k].r_type != 0 ||
2166 relocs[k].r_length != 2){
2167 fatal_arch(arch, member, "don't have "
2168 "code to convert external relocation "
2169 "entry %d in section (%.16s,%.16s) "
2170 "for global coalesced symbol: %s "
2171 "in: ", k, segname, sectname,
2172 strings + n_strx);
2174 value += n_value;
2175 if(object->object_byte_sex != host_byte_sex)
2176 value = SWAP_INT(value);
2177 *(uint32_t *)(contents + relocs[k].r_address) =
2178 value;
2180 else{
2181 value64 = *(uint64_t *)(contents + relocs[k].r_address);
2182 if(object->object_byte_sex != host_byte_sex)
2183 value64 = SWAP_LONG_LONG(value64);
2185 * We handle a very limited form here. Only VANILLA
2186 * (r_type == 0) quad (r_length==3) absolute or pcrel
2187 * that won't need a scattered relocation entry.
2189 if(relocs[k].r_type != 0 ||
2190 relocs[k].r_length != 3){
2191 fatal_arch(arch, member, "don't have "
2192 "code to convert external relocation "
2193 "entry %d in section (%.16s,%.16s) "
2194 "for global coalesced symbol: %s "
2195 "in: ", k, segname, sectname,
2196 strings + n_strx);
2198 value64 += n_value;
2199 if(object->object_byte_sex != host_byte_sex)
2200 value64 = SWAP_LONG_LONG(value64);
2201 *(uint64_t *)(contents + relocs[k].r_address) = value64;
2204 * Turn the extern reloc into a local.
2206 if(object->mh != NULL)
2207 relocs[k].r_symbolnum =
2208 new_symbols[saves[relocs[k].r_symbolnum] - 1].n_sect;
2209 else
2210 relocs[k].r_symbolnum =
2211 new_symbols64[saves[relocs[k].r_symbolnum] - 1].n_sect;
2212 relocs[k].r_extern = 0;
2214 #endif /* NMEDIT */
2215 if(relocs[k].r_extern == 1 &&
2216 saves[relocs[k].r_symbolnum] != -1){
2217 relocs[k].r_symbolnum = saves[relocs[k].r_symbolnum] - 1;
2220 if((relocs[k].r_address & R_SCATTERED) == 0){
2221 if(reloc_has_pair(object->mh_cputype, relocs[k].r_type) == TRUE)
2222 k++;
2224 else{
2225 sreloc = (struct scattered_relocation_info *)relocs + k;
2226 if(reloc_has_pair(object->mh_cputype, sreloc->r_type) == TRUE)
2227 k++;
2233 * check_indirect_symtab() checks and updates the indirect symbol table entries
2234 * to make sure referenced symbols are not stripped and refer to the new symbol
2235 * table indexes.
2237 static
2238 void
2239 check_indirect_symtab(
2240 struct arch *arch,
2241 struct member *member,
2242 struct object *object,
2243 uint32_t nitems,
2244 uint32_t reserved1,
2245 uint32_t section_type,
2246 char *contents,
2247 struct nlist *symbols,
2248 struct nlist_64 *symbols64,
2249 uint32_t nsyms,
2250 char *strings,
2251 int32_t *missing_reloc_symbols,
2252 enum byte_sex host_byte_sex)
2254 uint32_t k, index;
2255 uint8_t n_type;
2256 uint32_t n_strx, value;
2257 uint64_t value64;
2258 enum bool made_local;
2260 for(k = 0; k < nitems; k++){
2261 made_local = FALSE;
2262 index = object->output_indirect_symtab[reserved1 + k];
2263 if(index == INDIRECT_SYMBOL_LOCAL ||
2264 index == INDIRECT_SYMBOL_ABS ||
2265 index == (INDIRECT_SYMBOL_LOCAL | INDIRECT_SYMBOL_ABS))
2266 continue;
2267 if(index > nsyms)
2268 fatal_arch(arch, member,"indirect symbol table entry %d (past " "the end of the symbol table) in: ", reserved1 + k);
2269 #ifdef NMEDIT
2270 if(pflag == 0 && nmedits[index] == TRUE && saves[index] != -1)
2271 #else
2272 if(saves[index] == 0)
2273 #endif
2276 * Indirect symbol table entries for defined symbols in a
2277 * non-lazy pointer section that are not saved are changed to
2278 * INDIRECT_SYMBOL_LOCAL which their values just have to be
2279 * slid if the are not absolute symbols.
2281 if(object->mh != NULL){
2282 n_type = symbols[index].n_type;
2283 n_strx = symbols[index].n_un.n_strx;
2285 else{
2286 n_type = symbols64[index].n_type;
2287 n_strx = symbols64[index].n_un.n_strx;
2289 if((n_type && N_TYPE) != N_UNDF &&
2290 (n_type && N_TYPE) != N_PBUD &&
2291 section_type == S_NON_LAZY_SYMBOL_POINTERS){
2292 object->output_indirect_symtab[reserved1 + k] =
2293 INDIRECT_SYMBOL_LOCAL;
2294 if((n_type & N_TYPE) == N_ABS)
2295 object->output_indirect_symtab[reserved1 + k] |=
2296 INDIRECT_SYMBOL_ABS;
2297 made_local = TRUE;
2299 * When creating a stub shared library the section contents
2300 * are not updated since they will be stripped.
2302 if(object->mh_filetype != MH_DYLIB_STUB){
2303 if(object->mh != NULL){
2304 value = symbols[index].n_value;
2305 if (symbols[index].n_desc & N_ARM_THUMB_DEF)
2306 value |= 1;
2307 if(object->object_byte_sex != host_byte_sex)
2308 value = SWAP_INT(value);
2309 *(uint32_t *)(contents + k * 4) = value;
2311 else{
2312 value64 = symbols64[index].n_value;
2313 if(object->object_byte_sex != host_byte_sex)
2314 value64 = SWAP_LONG_LONG(value64);
2315 *(uint64_t *)(contents + k * 8) = value64;
2319 #ifdef NMEDIT
2320 else {
2321 object->output_indirect_symtab[reserved1 + k] =
2322 saves[index] - 1;
2324 #else /* !defined(NMEDIT) */
2325 else{
2326 if(*missing_reloc_symbols == 0){
2327 error_arch(arch, member, "symbols referenced by "
2328 "indirect symbol table entries that can't be "
2329 "stripped in: ");
2330 *missing_reloc_symbols = 1;
2332 fprintf(stderr, "%s\n", strings + n_strx);
2333 saves[index] = -1;
2335 #endif /* !defined(NMEDIT) */
2337 #ifdef NMEDIT
2338 else
2339 #else /* !defined(NMEDIT) */
2340 if(made_local == FALSE && saves[index] != -1)
2341 #endif /* !defined(NMEDIT) */
2343 object->output_indirect_symtab[reserved1+k] = saves[index] - 1;
2348 #ifndef NMEDIT
2350 * This is called if there is a -d option specified. It reads the file with
2351 * the strings in it and places them in the array debug_filenames and sorts
2352 * them by name. The file that contains the file names must have names one
2353 * per line with no white space (except the newlines).
2355 static
2356 void
2357 setup_debug_filenames(
2358 char *dfile)
2360 int fd, i, strings_size;
2361 struct stat stat_buf;
2362 char *strings, *p;
2364 if((fd = open(dfile, O_RDONLY)) < 0){
2365 system_error("can't open: %s", dfile);
2366 return;
2368 if(fstat(fd, &stat_buf) == -1){
2369 system_error("can't stat: %s", dfile);
2370 close(fd);
2371 return;
2373 strings_size = stat_buf.st_size;
2374 strings = (char *)allocate(strings_size + 1);
2375 strings[strings_size] = '\0';
2376 if(read(fd, strings, strings_size) != strings_size){
2377 system_error("can't read: %s", dfile);
2378 close(fd);
2379 return;
2381 p = strings;
2382 for(i = 0; i < strings_size; i++){
2383 if(*p == '\n'){
2384 *p = '\0';
2385 ndebug_filenames++;
2387 p++;
2389 debug_filenames = (char **)allocate(ndebug_filenames * sizeof(char *));
2390 p = strings;
2391 for(i = 0; i < ndebug_filenames; i++){
2392 debug_filenames[i] = p;
2393 p += strlen(p) + 1;
2395 qsort(debug_filenames, ndebug_filenames, sizeof(char *),
2396 (int (*)(const void *, const void *))cmp_qsort_filename);
2398 #ifdef DEBUG
2399 printf("Debug filenames:\n");
2400 for(i = 0; i < ndebug_filenames; i++){
2401 printf("filename = %s\n", debug_filenames[i]);
2403 #endif /* DEBUG */
2407 * Strip the symbol table to the level specified by the command line arguments.
2408 * The new symbol table is built and new_symbols is left pointing to it. The
2409 * number of new symbols is left in new_nsyms, the new string table is built
2410 * and new_stings is left pointing to it and new_strsize is left containing it.
2411 * This routine returns zero if successfull and non-zero otherwise.
2413 static
2414 enum bool
2415 strip_symtab(
2416 struct arch *arch,
2417 struct member *member,
2418 struct object *object,
2419 struct dylib_table_of_contents *tocs,
2420 uint32_t ntoc,
2421 struct dylib_module *mods,
2422 struct dylib_module_64 *mods64,
2423 uint32_t nmodtab,
2424 struct dylib_reference *refs,
2425 uint32_t nextrefsyms)
2427 uint32_t i, j, k, n, inew_syms, save_debug, missing_syms;
2428 uint32_t missing_symbols;
2429 char *p, *q, **pp, *basename;
2430 struct symbol_list *sp;
2431 uint32_t new_ext_strsize, len, *changes, inew_undefsyms;
2432 unsigned char nsects;
2433 struct load_command *lc;
2434 struct segment_command *sg;
2435 struct segment_command_64 *sg64;
2436 struct section *s, **sections;
2437 struct section_64 *s64, **sections64;
2438 uint32_t ncmds, mh_flags, s_flags, n_strx;
2439 struct nlist *sym;
2440 struct undef_map *undef_map;
2441 struct undef_map64 *undef_map64;
2442 uint8_t n_type, n_sect;
2443 uint16_t n_desc;
2444 uint64_t n_value;
2445 uint32_t module_name, iextdefsym, nextdefsym, ilocalsym, nlocalsym;
2446 uint32_t irefsym, nrefsym;
2447 enum bool has_dwarf, hack_5614542;
2449 save_debug = 0;
2450 if(saves != NULL)
2451 free(saves);
2452 changes = NULL;
2453 for(i = 0; i < nsave_symbols; i++)
2454 save_symbols[i].sym = NULL;
2455 for(i = 0; i < nremove_symbols; i++)
2456 remove_symbols[i].sym = NULL;
2457 if(member == NULL){
2458 for(i = 0; i < nsave_symbols; i++)
2459 save_symbols[i].seen = FALSE;
2460 for(i = 0; i < nremove_symbols; i++)
2461 remove_symbols[i].seen = FALSE;
2464 new_nsyms = 0;
2465 if(object->mh != NULL)
2466 new_strsize = sizeof(int32_t);
2467 else
2468 new_strsize = sizeof(int64_t);
2469 new_nlocalsym = 0;
2470 new_nextdefsym = 0;
2471 new_nundefsym = 0;
2472 new_ext_strsize = 0;
2475 * If this an object file that has DWARF debugging sections to strip
2476 * then we have to run ld -r on it.
2478 if(object->mh_filetype == MH_OBJECT && (Sflag || xflag)){
2479 has_dwarf = FALSE;
2480 lc = object->load_commands;
2481 if(object->mh != NULL)
2482 ncmds = object->mh->ncmds;
2483 else
2484 ncmds = object->mh64->ncmds;
2485 for(i = 0; i < ncmds && has_dwarf == FALSE; i++){
2486 if(lc->cmd == LC_SEGMENT){
2487 sg = (struct segment_command *)lc;
2488 s = (struct section *)((char *)sg +
2489 sizeof(struct segment_command));
2490 for(j = 0; j < sg->nsects; j++){
2491 if(s->flags & S_ATTR_DEBUG){
2492 has_dwarf = TRUE;
2493 break;
2495 s++;
2498 else if(lc->cmd == LC_SEGMENT_64){
2499 sg64 = (struct segment_command_64 *)lc;
2500 s64 = (struct section_64 *)((char *)sg64 +
2501 sizeof(struct segment_command_64));
2502 for(j = 0; j < sg64->nsects; j++){
2503 if(s64->flags & S_ATTR_DEBUG){
2504 has_dwarf = TRUE;
2505 break;
2507 s64++;
2510 lc = (struct load_command *)((char *)lc + lc->cmdsize);
2513 * Because of the bugs in ld(1) for:
2514 * radr://5675774 ld64 should preserve JBSR relocations without
2515 * -static
2516 * radr://5658046 cctools-679 creates scattered relocations in
2517 * __TEXT,__const section in kexts, which breaks
2518 * kexts built for older systems
2519 * we can't use ld -r to strip dwarf info in 32-bit objects until
2520 * these are fixed. But if the user as specified the -l flag then
2521 * go ahead and do it and the user will have to be aware of these
2522 * bugs.
2524 if((lflag == TRUE && has_dwarf == TRUE) || object->mh64 != NULL)
2525 make_ld_r_object(arch, member, object);
2528 * Because of the "design" of 64-bit object files and the lack of
2529 * local relocation entries it is not possible for strip(1) to do its
2530 * job without becoming a static link editor. The "design" does not
2531 * actually strip the symbols it simply renames them to things like
2532 * "l1000". And they become static symbols but still have external
2533 * relocation entries. Thus can never actually be stripped. Also some
2534 * symbols, *.eh, symbols are not even changed to these names if there
2535 * corresponding global symbol is not stripped. So strip(1) only
2536 * recourse is to use the unified linker to create an ld -r object then
2537 * save all resulting symbols (both static and global) and hope the user
2538 * does not notice the stripping is not what they asked for.
2540 if(object->mh_filetype == MH_OBJECT &&
2541 (object->mh64 != NULL && object->ld_r_ofile == NULL))
2542 make_ld_r_object(arch, member, object);
2545 * Since make_ld_r_object() may create an object with more symbols
2546 * this has to be done after make_ld_r_object() and nsyms is updated.
2548 saves = (int32_t *)allocate(nsyms * sizeof(int32_t));
2549 bzero(saves, nsyms * sizeof(int32_t));
2552 * Gather an array of section struct pointers so we can later determine
2553 * if we run into a global symbol in a coalesced section and not strip
2554 * those symbols.
2555 * statics.
2557 nsects = 0;
2558 lc = object->load_commands;
2559 if(object->mh != NULL)
2560 ncmds = object->mh->ncmds;
2561 else
2562 ncmds = object->mh64->ncmds;
2563 for(i = 0; i < ncmds; i++){
2564 if(lc->cmd == LC_SEGMENT){
2565 sg = (struct segment_command *)lc;
2566 nsects += sg->nsects;
2568 else if(lc->cmd == LC_SEGMENT_64){
2569 sg64 = (struct segment_command_64 *)lc;
2570 nsects += sg64->nsects;
2572 lc = (struct load_command *)((char *)lc + lc->cmdsize);
2574 if(object->mh != NULL){
2575 sections = allocate(nsects * sizeof(struct section *));
2576 sections64 = NULL;
2578 else{
2579 sections = NULL;
2580 sections64 = allocate(nsects * sizeof(struct section_64 *));
2582 nsects = 0;
2583 lc = object->load_commands;
2584 for(i = 0; i < ncmds; i++){
2585 if(lc->cmd == LC_SEGMENT){
2586 sg = (struct segment_command *)lc;
2587 s = (struct section *)((char *)sg +
2588 sizeof(struct segment_command));
2589 for(j = 0; j < sg->nsects; j++)
2590 sections[nsects++] = s++;
2592 else if(lc->cmd == LC_SEGMENT_64){
2593 sg64 = (struct segment_command_64 *)lc;
2594 s64 = (struct section_64 *)((char *)sg64 +
2595 sizeof(struct segment_command_64));
2596 for(j = 0; j < sg64->nsects; j++)
2597 sections64[nsects++] = s64++;
2599 lc = (struct load_command *)((char *)lc + lc->cmdsize);
2602 for(i = 0; i < nsyms; i++){
2603 s_flags = 0;
2604 if(object->mh != NULL){
2605 mh_flags = object->mh->flags;
2606 n_strx = symbols[i].n_un.n_strx;
2607 n_type = symbols[i].n_type;
2608 n_sect = symbols[i].n_sect;
2609 if((n_type & N_TYPE) == N_SECT){
2610 if(n_sect == 0 || n_sect > nsects){
2611 error_arch(arch, member, "bad n_sect for symbol "
2612 "table entry %d in: ", i);
2613 return(FALSE);
2615 s_flags = sections[n_sect - 1]->flags;
2617 n_desc = symbols[i].n_desc;
2618 n_value = symbols[i].n_value;
2620 else{
2621 mh_flags = object->mh64->flags;
2622 n_strx = symbols64[i].n_un.n_strx;
2623 n_type = symbols64[i].n_type;
2624 n_sect = symbols64[i].n_sect;
2625 if((n_type & N_TYPE) == N_SECT){
2626 if(n_sect == 0 || n_sect > nsects){
2627 error_arch(arch, member, "bad n_sect for symbol "
2628 "table entry %d in: ", i);
2629 return(FALSE);
2631 s_flags = sections64[n_sect - 1]->flags;
2633 n_desc = symbols64[i].n_desc;
2634 n_value = symbols64[i].n_value;
2636 if(n_strx != 0){
2637 if(n_strx > strsize){
2638 error_arch(arch, member, "bad string index for symbol "
2639 "table entry %d in: ", i);
2640 return(FALSE);
2643 if((n_type & N_TYPE) == N_INDR){
2644 if(n_value != 0){
2645 if(n_value > strsize){
2646 error_arch(arch, member, "bad string index for "
2647 "indirect symbol table entry %d in: ", i);
2648 return(FALSE);
2652 if((n_type & N_EXT) == 0){ /* local symbol */
2654 * For x86_64 .o files we have run ld -r on them and are stuck
2655 * keeping all resulting symbols.
2657 if(object->mh == NULL &&
2658 object->mh64->cputype == CPU_TYPE_X86_64 &&
2659 object->mh64->filetype == MH_OBJECT){
2660 if(n_strx != 0)
2661 new_strsize += strlen(strings + n_strx) + 1;
2662 new_nlocalsym++;
2663 new_nsyms++;
2664 saves[i] = new_nsyms;
2667 * The cases a local symbol might be saved is with -X -S or
2668 * with -d filename.
2670 else if((!strip_all && (Xflag || Sflag)) || dfile){
2671 if(n_type & N_STAB){ /* debug symbol */
2672 if(dfile && n_type == N_SO){
2673 if(n_strx != 0){
2674 basename = strrchr(strings + n_strx, '/');
2675 if(basename != NULL)
2676 basename++;
2677 else
2678 basename = strings + n_strx;
2679 pp = bsearch(basename, debug_filenames,
2680 ndebug_filenames, sizeof(char *),
2681 (int (*)(const void *, const void *)
2682 )cmp_bsearch_filename);
2684 * Save the bracketing N_SO. For each N_SO that
2685 * has a filename there is an N_SO that has a
2686 * name of "" which ends the stabs for that file
2688 if(*basename != '\0'){
2689 if(pp != NULL)
2690 save_debug = 1;
2691 else
2692 save_debug = 0;
2694 else{
2696 * This is a bracketing SO so if we are
2697 * currently saving debug symbols save this
2698 * last one and turn off saving debug syms.
2700 if(save_debug){
2701 if(n_strx != 0)
2702 new_strsize += strlen(strings +
2703 n_strx) + 1;
2704 new_nlocalsym++;
2705 new_nsyms++;
2706 saves[i] = new_nsyms;
2708 save_debug = 0;
2711 else{
2712 save_debug = 0;
2715 if(saves[i] == 0 && (!Sflag || save_debug)){
2716 if(n_strx != 0)
2717 new_strsize += strlen(strings + n_strx) + 1;
2718 new_nlocalsym++;
2719 new_nsyms++;
2720 saves[i] = new_nsyms;
2723 else{ /* non-debug local symbol */
2724 if(xflag == 0 && (Sflag || Xflag)){
2725 if(Xflag == 0 ||
2726 (n_strx != 0 &&
2727 strings[n_strx] != 'L')){
2729 * If this file is a for the dynamic linker and
2730 * this symbol is in a section marked so that
2731 * static symbols are stripped then don't
2732 * keep this symbol.
2734 if((mh_flags & MH_DYLDLINK) != MH_DYLDLINK ||
2735 (n_type & N_TYPE) != N_SECT ||
2736 (s_flags & S_ATTR_STRIP_STATIC_SYMS) !=
2737 S_ATTR_STRIP_STATIC_SYMS){
2738 new_strsize += strlen(strings + n_strx) + 1;
2739 new_nlocalsym++;
2740 new_nsyms++;
2741 saves[i] = new_nsyms;
2746 * Treat a local symbol that was a private extern as if
2747 * were global if it is referenced by a module and save
2748 * it.
2750 if((n_type & N_PEXT) == N_PEXT){
2751 if(saves[i] == 0 &&
2752 private_extern_reference_by_module(
2753 i, refs ,nextrefsyms) == TRUE){
2754 if(n_strx != 0)
2755 new_strsize += strlen(strings + n_strx) + 1;
2756 new_nlocalsym++;
2757 new_nsyms++;
2758 saves[i] = new_nsyms;
2761 * We need to save symbols that were private externs
2762 * that are used with indirect symbols.
2764 if(saves[i] == 0 &&
2765 symbol_pointer_used(i, indirectsyms,
2766 nindirectsyms) == TRUE){
2767 if(n_strx != 0){
2768 len = strlen(strings + n_strx) + 1;
2769 new_strsize += len;
2771 new_nlocalsym++;
2772 new_nsyms++;
2773 saves[i] = new_nsyms;
2779 * Treat a local symbol that was a private extern as if were
2780 * global if it is not referenced by a module.
2782 else if((n_type & N_PEXT) == N_PEXT){
2783 if(saves[i] == 0 && sfile){
2784 sp = bsearch(strings + n_strx,
2785 save_symbols, nsave_symbols,
2786 sizeof(struct symbol_list),
2787 (int (*)(const void *, const void *))
2788 symbol_list_bsearch);
2789 if(sp != NULL){
2790 if(sp->sym == NULL){
2791 if(object->mh != NULL)
2792 sp->sym = &(symbols[i]);
2793 else
2794 sp->sym = &(symbols64[i]);
2795 sp->seen = TRUE;
2797 if(n_strx != 0)
2798 new_strsize += strlen(strings + n_strx) + 1;
2799 new_nlocalsym++;
2800 new_nsyms++;
2801 saves[i] = new_nsyms;
2804 if(saves[i] == 0 &&
2805 private_extern_reference_by_module(
2806 i, refs ,nextrefsyms) == TRUE){
2807 if(n_strx != 0)
2808 new_strsize += strlen(strings + n_strx) + 1;
2809 new_nlocalsym++;
2810 new_nsyms++;
2811 saves[i] = new_nsyms;
2814 * We need to save symbols that were private externs that
2815 * are used with indirect symbols.
2817 if(saves[i] == 0 &&
2818 symbol_pointer_used(i, indirectsyms, nindirectsyms) ==
2819 TRUE){
2820 if(n_strx != 0){
2821 len = strlen(strings + n_strx) + 1;
2822 new_strsize += len;
2824 new_nlocalsym++;
2825 new_nsyms++;
2826 saves[i] = new_nsyms;
2830 else{ /* global symbol */
2832 * strip -R on an x86_64 .o file should do nothing.
2834 if(Rfile &&
2835 (object->mh != NULL ||
2836 object->mh64->cputype != CPU_TYPE_X86_64 ||
2837 object->mh64->filetype != MH_OBJECT)){
2838 sp = bsearch(strings + n_strx,
2839 remove_symbols, nremove_symbols,
2840 sizeof(struct symbol_list),
2841 (int (*)(const void *, const void *))
2842 symbol_list_bsearch);
2843 if(sp != NULL){
2844 if((n_type & N_TYPE) == N_UNDF ||
2845 (n_type & N_TYPE) == N_PBUD){
2846 error_arch(arch, member, "symbol: %s undefined"
2847 " and can't be stripped from: ",
2848 sp->name);
2850 else if(sp->sym != NULL){
2851 sym = (struct nlist *)sp->sym;
2852 if((sym->n_type & N_PEXT) != N_PEXT)
2853 error_arch(arch, member, "more than one symbol "
2854 "for: %s found in: ", sp->name);
2856 else{
2857 if(object->mh != NULL)
2858 sp->sym = &(symbols[i]);
2859 else
2860 sp->sym = &(symbols64[i]);
2861 sp->seen = TRUE;
2863 if(n_desc & REFERENCED_DYNAMICALLY){
2864 error_arch(arch, member, "symbol: %s is dynamically"
2865 " referenced and can't be stripped "
2866 "from: ", sp->name);
2868 if((n_type & N_TYPE) == N_SECT &&
2869 (s_flags & SECTION_TYPE) == S_COALESCED){
2870 error_arch(arch, member, "symbol: %s is a global "
2871 "coalesced symbol and can't be "
2872 "stripped from: ", sp->name);
2874 /* don't save this symbol */
2875 continue;
2878 if(Aflag && (n_type & N_TYPE) == N_ABS &&
2879 (n_value != 0 ||
2880 (n_strx != 0 &&
2881 strncmp(strings + n_strx,
2882 ".objc_class_name_",
2883 sizeof(".objc_class_name_") - 1) == 0))){
2884 len = strlen(strings + n_strx) + 1;
2885 new_strsize += len;
2886 new_ext_strsize += len;
2887 new_nextdefsym++;
2888 new_nsyms++;
2889 saves[i] = new_nsyms;
2891 if(saves[i] == 0 && (uflag || default_dyld_executable) &&
2892 ((((n_type & N_TYPE) == N_UNDF) &&
2893 n_value == 0) ||
2894 (n_type & N_TYPE) == N_PBUD)){
2895 if(n_strx != 0){
2896 len = strlen(strings + n_strx) + 1;
2897 new_strsize += len;
2898 new_ext_strsize += len;
2900 new_nundefsym++;
2901 new_nsyms++;
2902 saves[i] = new_nsyms;
2904 if(saves[i] == 0 && nflag &&
2905 (n_type & N_TYPE) == N_SECT){
2906 if(n_strx != 0){
2907 len = strlen(strings + n_strx) + 1;
2908 new_strsize += len;
2909 new_ext_strsize += len;
2911 new_nextdefsym++;
2912 new_nsyms++;
2913 saves[i] = new_nsyms;
2915 if(saves[i] == 0 && sfile){
2916 sp = bsearch(strings + n_strx,
2917 save_symbols, nsave_symbols,
2918 sizeof(struct symbol_list),
2919 (int (*)(const void *, const void *))
2920 symbol_list_bsearch);
2921 if(sp != NULL){
2922 if(sp->sym != NULL){
2923 sym = (struct nlist *)sp->sym;
2924 if((sym->n_type & N_PEXT) != N_PEXT)
2925 error_arch(arch, member, "more than one symbol "
2926 "for: %s found in: ", sp->name);
2928 else{
2929 if(object->mh != NULL)
2930 sp->sym = &(symbols[i]);
2931 else
2932 sp->sym = &(symbols64[i]);
2933 sp->seen = TRUE;
2934 len = strlen(strings + n_strx) + 1;
2935 new_strsize += len;
2936 new_ext_strsize += len;
2937 if((n_type & N_TYPE) == N_UNDF ||
2938 (n_type & N_TYPE) == N_PBUD)
2939 new_nundefsym++;
2940 else
2941 new_nextdefsym++;
2942 new_nsyms++;
2943 saves[i] = new_nsyms;
2948 * We only need to save coalesced symbols that are used as
2949 * indirect symbols in 32-bit applications.
2951 * In 64-bit applications, we only need to save coalesced
2952 * symbols that are used as weak definitions.
2954 if(object->mh != NULL &&
2955 saves[i] == 0 &&
2956 (n_type & N_TYPE) == N_SECT &&
2957 (s_flags & SECTION_TYPE) == S_COALESCED &&
2958 symbol_pointer_used(i, indirectsyms, nindirectsyms) == TRUE){
2959 if(n_strx != 0){
2960 len = strlen(strings + n_strx) + 1;
2961 new_strsize += len;
2962 new_ext_strsize += len;
2964 new_nextdefsym++;
2965 new_nsyms++;
2966 saves[i] = new_nsyms;
2968 if(saves[i] == 0 &&
2969 (n_type & N_TYPE) == N_SECT &&
2970 (n_desc & N_WEAK_DEF) != 0){
2971 if(n_strx != 0){
2972 len = strlen(strings + n_strx) + 1;
2973 new_strsize += len;
2974 new_ext_strsize += len;
2976 new_nextdefsym++;
2977 new_nsyms++;
2978 saves[i] = new_nsyms;
2980 if(saves[i] == 0 && ((Xflag || Sflag || xflag) ||
2981 ((rflag || default_dyld_executable) &&
2982 n_desc & REFERENCED_DYNAMICALLY))){
2983 len = strlen(strings + n_strx) + 1;
2984 new_strsize += len;
2985 new_ext_strsize += len;
2986 if((n_type & N_TYPE) == N_INDR){
2987 len = strlen(strings + n_value) + 1;
2988 new_strsize += len;
2989 new_ext_strsize += len;
2991 if((n_type & N_TYPE) == N_UNDF ||
2992 (n_type & N_TYPE) == N_PBUD)
2993 new_nundefsym++;
2994 else
2995 new_nextdefsym++;
2996 new_nsyms++;
2997 saves[i] = new_nsyms;
3000 * For x86_64 .o files we have run ld -r on them and are stuck
3001 * keeping all resulting symbols.
3003 if(saves[i] == 0 &&
3004 object->mh == NULL &&
3005 object->mh64->cputype == CPU_TYPE_X86_64 &&
3006 object->mh64->filetype == MH_OBJECT){
3007 len = strlen(strings + n_strx) + 1;
3008 new_strsize += len;
3009 new_ext_strsize += len;
3010 if((n_type & N_TYPE) == N_INDR){
3011 len = strlen(strings + n_value) + 1;
3012 new_strsize += len;
3013 new_ext_strsize += len;
3015 if((n_type & N_TYPE) == N_UNDF ||
3016 (n_type & N_TYPE) == N_PBUD)
3017 new_nundefsym++;
3018 else
3019 new_nextdefsym++;
3020 new_nsyms++;
3021 saves[i] = new_nsyms;
3026 * The module table's module names are placed with the external strings.
3027 * So size them and add this to the external string size.
3029 for(i = 0; i < nmodtab; i++){
3030 if(object->mh != NULL)
3031 module_name = mods[i].module_name;
3032 else
3033 module_name = mods64[i].module_name;
3034 if(module_name == 0 || module_name > strsize){
3035 error_arch(arch, member, "bad string index for module_name "
3036 "of module table entry %d in: ", i);
3037 return(FALSE);
3039 len = strlen(strings + module_name) + 1;
3040 new_strsize += len;
3041 new_ext_strsize += len;
3045 * Updating the reference table may require a symbol not yet listed as
3046 * as saved to be present in the output file. If a defined external
3047 * symbol is removed and there is a undefined reference to it in the
3048 * reference table an undefined symbol needs to be created for it in
3049 * the output file. If this happens the number of new symbols and size
3050 * of the new strings are adjusted. And the array changes[] is set to
3051 * map the old symbol index to the new symbol index for the symbol that
3052 * is changed to an undefined symbol.
3054 missing_symbols = 0;
3055 if(ref_saves != NULL)
3056 free(ref_saves);
3057 ref_saves = (int32_t *)allocate(nextrefsyms * sizeof(int32_t));
3058 bzero(ref_saves, nextrefsyms * sizeof(int32_t));
3059 changes = (uint32_t *)allocate(nsyms * sizeof(int32_t));
3060 bzero(changes, nsyms * sizeof(int32_t));
3061 new_nextrefsyms = 0;
3062 for(i = 0; i < nextrefsyms; i++){
3063 if(refs[i].isym > nsyms){
3064 error_arch(arch, member, "bad symbol table index for "
3065 "reference table entry %d in: ", i);
3066 return(FALSE);
3068 if(saves[refs[i].isym]){
3069 new_nextrefsyms++;
3070 ref_saves[i] = new_nextrefsyms;
3072 else{
3073 if(refs[i].flags == REFERENCE_FLAG_UNDEFINED_NON_LAZY ||
3074 refs[i].flags == REFERENCE_FLAG_UNDEFINED_LAZY){
3075 if(changes[refs[i].isym] == 0){
3076 if(object->mh != NULL)
3077 n_strx = symbols[refs[i].isym].n_un.n_strx;
3078 else
3079 n_strx = symbols64[refs[i].isym].n_un.n_strx;
3080 len = strlen(strings + n_strx) + 1;
3081 new_strsize += len;
3082 new_ext_strsize += len;
3083 new_nundefsym++;
3084 new_nsyms++;
3085 changes[refs[i].isym] = new_nsyms;
3086 new_nextrefsyms++;
3087 ref_saves[i] = new_nextrefsyms;
3090 else{
3091 if(refs[i].flags ==
3092 REFERENCE_FLAG_PRIVATE_UNDEFINED_NON_LAZY ||
3093 refs[i].flags == REFERENCE_FLAG_PRIVATE_UNDEFINED_LAZY){
3094 if(missing_symbols == 0){
3095 error_arch(arch, member, "private extern symbols "
3096 "referenced by modules can't be stripped in: ");
3097 missing_symbols = 1;
3099 if(object->mh != NULL)
3100 n_strx = symbols[refs[i].isym].n_un.n_strx;
3101 else
3102 n_strx = symbols64[refs[i].isym].n_un.n_strx;
3103 fprintf(stderr, "%s\n", strings + n_strx);
3104 saves[refs[i].isym] = -1;
3109 if(missing_symbols == 1)
3110 return(FALSE);
3112 if(member == NULL){
3113 missing_syms = 0;
3114 if(iflag == 0){
3115 for(i = 0; i < nsave_symbols; i++){
3116 if(save_symbols[i].sym == NULL){
3117 if(missing_syms == 0){
3118 error_arch(arch, member, "symbols names listed "
3119 "in: %s not in: ", sfile);
3120 missing_syms = 1;
3122 fprintf(stderr, "%s\n", save_symbols[i].name);
3126 missing_syms = 0;
3128 * strip -R on an x86_64 .o file should do nothing.
3130 if(iflag == 0 &&
3131 (object->mh != NULL ||
3132 object->mh64->cputype != CPU_TYPE_X86_64 ||
3133 object->mh64->filetype != MH_OBJECT)){
3134 for(i = 0; i < nremove_symbols; i++){
3135 if(remove_symbols[i].sym == NULL){
3136 if(missing_syms == 0){
3137 error_arch(arch, member, "symbols names listed "
3138 "in: %s not in: ", Rfile);
3139 missing_syms = 1;
3141 fprintf(stderr, "%s\n", remove_symbols[i].name);
3148 * If there is a chance that we could end up with an indirect symbol
3149 * with an index of zero we need to avoid that due to a work around
3150 * in the dynamic linker for a bug it is working around that was in
3151 * the old classic static linker. See radar bug 5614542 and the
3152 * related bugs 3685312 and 3534709.
3154 * A reasonable way to do this to know that local symbols are first in
3155 * the symbol table. So if we have any local symbols this won't happen
3156 * and if there are no indirect symbols it will also not happen. Past
3157 * that we'll just add a local symbol so it will end up at symbol index
3158 * zero and avoid any indirect symbol having that index.
3160 * If one really wanted they could build up the new symbol table then
3161 * look at all the indirect symbol table entries to see if any of them
3162 * have an index of zero then in that case throw that new symbol table
3163 * away and rebuild the symbol and string table once again after adding
3164 * a local symbol. This seems not all that resonable to save one symbol
3165 * table entry and a few bytes in the string table for the complexity it
3166 * would add and what it would save.
3168 if(new_nlocalsym == 0 && nindirectsyms != 0){
3169 len = strlen("radr://5614542") + 1;
3170 new_strsize += len;
3171 new_nlocalsym++;
3172 new_nsyms++;
3173 hack_5614542 = TRUE;
3175 else{
3176 hack_5614542 = FALSE;
3179 if(object->mh != NULL){
3180 new_symbols = (struct nlist *)
3181 allocate(new_nsyms * sizeof(struct nlist));
3182 new_symbols64 = NULL;
3184 else{
3185 new_symbols = NULL;
3186 new_symbols64 = (struct nlist_64 *)
3187 allocate(new_nsyms * sizeof(struct nlist_64));
3189 if(object->mh != NULL)
3190 new_strsize = round(new_strsize, sizeof(int32_t));
3191 else
3192 new_strsize = round(new_strsize, sizeof(int64_t));
3193 new_strings = (char *)allocate(new_strsize);
3194 if(object->mh != NULL){
3195 new_strings[new_strsize - 3] = '\0';
3196 new_strings[new_strsize - 2] = '\0';
3197 new_strings[new_strsize - 1] = '\0';
3199 else{
3200 new_strings[new_strsize - 7] = '\0';
3201 new_strings[new_strsize - 6] = '\0';
3202 new_strings[new_strsize - 5] = '\0';
3203 new_strings[new_strsize - 4] = '\0';
3204 new_strings[new_strsize - 3] = '\0';
3205 new_strings[new_strsize - 2] = '\0';
3206 new_strings[new_strsize - 1] = '\0';
3209 memset(new_strings, '\0', sizeof(int32_t));
3210 p = new_strings + sizeof(int32_t);
3211 q = p + new_ext_strsize;
3214 * If all strings were stripped set the size to zero but only for 32-bit
3215 * because the unified linker seems to set the filesize of empty .o
3216 * files to include the string table.
3218 if(object->mh != NULL && new_strsize == sizeof(int32_t))
3219 new_strsize = 0;
3222 * Now create a symbol table and string table in this order
3223 * symbol table
3224 * local symbols
3225 * external defined symbols
3226 * undefined symbols
3227 * string table
3228 * external strings
3229 * local strings
3231 inew_syms = 0;
3234 * If we are doing the hack for radar bug 5614542 (see above) add the
3235 * one local symbol and string.
3237 * We use an N_OPT stab which should be safe to use and not mess any
3238 * thing up. In Mac OS X, gcc(1) writes one N_OPT stab saying the file
3239 * is compiled with gcc(1). Then gdb(1) looks for that stab, but it
3240 * also looks at the name. If the name string is "gcc_compiled" or
3241 * "gcc2_compiled" gdb(1) sets its "compiled by gcc flag. If the N_OPT
3242 * is emitted INSIDE an N_SO section, then gdb(1) thinks that object
3243 * module was compiled by Sun's compiler, which apparently sticks one
3244 * outermost N_LBRAC/N_RBRAC pair, which gdb(1) strips off. But if the
3245 * N_OPT comes before any N_SO stabs, then gdb(1) will just ignore it.
3246 * Since this N_OPT is the first local symbol, it will always come
3247 * before any N_SO stabs that might be around and should be fine.
3249 if(hack_5614542 == TRUE){
3250 if(object->mh != NULL){
3251 new_symbols[inew_syms].n_type = N_OPT;
3252 new_symbols[inew_syms].n_sect = NO_SECT;
3253 new_symbols[inew_syms].n_desc = 0;
3254 new_symbols[inew_syms].n_value = 0x05614542;
3256 else{
3257 new_symbols64[inew_syms].n_type = N_OPT;
3258 new_symbols64[inew_syms].n_sect = NO_SECT;
3259 new_symbols64[inew_syms].n_desc = 0;
3260 new_symbols64[inew_syms].n_value = 0x05614542;
3262 strcpy(q, "radr://5614542");
3263 if(object->mh != NULL)
3264 new_symbols[inew_syms].n_un.n_strx =
3265 q - new_strings;
3266 else
3267 new_symbols64[inew_syms].n_un.n_strx =
3268 q - new_strings;
3269 q += strlen(q) + 1;
3270 inew_syms++;
3273 for(i = 0; i < nsyms; i++){
3274 if(saves[i]){
3275 if(object->mh != NULL){
3276 n_strx = symbols[i].n_un.n_strx;
3277 n_type = symbols[i].n_type;
3279 else{
3280 n_strx = symbols64[i].n_un.n_strx;
3281 n_type = symbols64[i].n_type;
3283 if((n_type & N_EXT) == 0){
3284 if(object->mh != NULL)
3285 new_symbols[inew_syms] = symbols[i];
3286 else
3287 new_symbols64[inew_syms] = symbols64[i];
3288 if(n_strx != 0){
3289 strcpy(q, strings + n_strx);
3290 if(object->mh != NULL)
3291 new_symbols[inew_syms].n_un.n_strx =
3292 q - new_strings;
3293 else
3294 new_symbols64[inew_syms].n_un.n_strx =
3295 q - new_strings;
3296 q += strlen(q) + 1;
3298 inew_syms++;
3299 saves[i] = inew_syms;
3303 #ifdef TRIE_SUPPORT
3304 inew_nextdefsym = inew_syms;
3305 #endif /* TRIE_SUPPORT */
3306 for(i = 0; i < nsyms; i++){
3307 if(saves[i]){
3308 if(object->mh != NULL){
3309 n_strx = symbols[i].n_un.n_strx;
3310 n_type = symbols[i].n_type;
3311 n_value = symbols[i].n_value;
3313 else{
3314 n_strx = symbols64[i].n_un.n_strx;
3315 n_type = symbols64[i].n_type;
3316 n_value = symbols64[i].n_value;
3318 if((n_type & N_EXT) == N_EXT &&
3319 ((n_type & N_TYPE) != N_UNDF &&
3320 (n_type & N_TYPE) != N_PBUD)){
3321 if(object->mh != NULL)
3322 new_symbols[inew_syms] = symbols[i];
3323 else
3324 new_symbols64[inew_syms] = symbols64[i];
3325 if(n_strx != 0){
3326 strcpy(p, strings + n_strx);
3327 if(object->mh != NULL)
3328 new_symbols[inew_syms].n_un.n_strx =
3329 p - new_strings;
3330 else
3331 new_symbols64[inew_syms].n_un.n_strx =
3332 p - new_strings;
3333 p += strlen(p) + 1;
3335 if((n_type & N_TYPE) == N_INDR){
3336 if(n_value != 0){
3337 strcpy(p, strings + n_value);
3338 if(object->mh != NULL)
3339 new_symbols[inew_syms].n_value =
3340 p - new_strings;
3341 else
3342 new_symbols64[inew_syms].n_value =
3343 p - new_strings;
3344 p += strlen(p) + 1;
3347 inew_syms++;
3348 saves[i] = inew_syms;
3353 * Build the new undefined symbols into a map and sort it.
3355 inew_undefsyms = 0;
3356 if(object->mh != NULL){
3357 undef_map = (struct undef_map *)allocate(new_nundefsym *
3358 sizeof(struct undef_map));
3359 undef_map64 = NULL;
3361 else{
3362 undef_map = NULL;
3363 undef_map64 = (struct undef_map64 *)allocate(new_nundefsym *
3364 sizeof(struct undef_map64));
3366 for(i = 0; i < nsyms; i++){
3367 if(saves[i]){
3368 if(object->mh != NULL){
3369 n_strx = symbols[i].n_un.n_strx;
3370 n_type = symbols[i].n_type;
3372 else{
3373 n_strx = symbols64[i].n_un.n_strx;
3374 n_type = symbols64[i].n_type;
3376 if((n_type & N_EXT) == N_EXT &&
3377 ((n_type & N_TYPE) == N_UNDF ||
3378 (n_type & N_TYPE) == N_PBUD)){
3379 if(object->mh != NULL)
3380 undef_map[inew_undefsyms].symbol = symbols[i];
3381 else
3382 undef_map64[inew_undefsyms].symbol64 = symbols64[i];
3383 if(n_strx != 0){
3384 strcpy(p, strings + n_strx);
3385 if(object->mh != NULL)
3386 undef_map[inew_undefsyms].symbol.n_un.n_strx =
3387 p - new_strings;
3388 else
3389 undef_map64[inew_undefsyms].symbol64.n_un.n_strx =
3390 p - new_strings;
3391 p += strlen(p) + 1;
3393 if(object->mh != NULL)
3394 undef_map[inew_undefsyms].index = i;
3395 else
3396 undef_map64[inew_undefsyms].index = i;
3397 inew_undefsyms++;
3401 for(i = 0; i < nsyms; i++){
3402 if(changes[i]){
3403 if(object->mh != NULL)
3404 n_strx = symbols[i].n_un.n_strx;
3405 else
3406 n_strx = symbols64[i].n_un.n_strx;
3407 if(n_strx != 0){
3408 strcpy(p, strings + n_strx);
3409 if(object->mh != NULL)
3410 undef_map[inew_undefsyms].symbol.n_un.n_strx =
3411 p - new_strings;
3412 else
3413 undef_map64[inew_undefsyms].symbol64.n_un.n_strx =
3414 p - new_strings;
3415 p += strlen(p) + 1;
3417 if(object->mh != NULL){
3418 undef_map[inew_undefsyms].symbol.n_type = N_UNDF | N_EXT;
3419 undef_map[inew_undefsyms].symbol.n_sect = NO_SECT;
3420 undef_map[inew_undefsyms].symbol.n_desc = 0;
3421 undef_map[inew_undefsyms].symbol.n_value = 0;
3422 undef_map[inew_undefsyms].index = i;
3424 else{
3425 undef_map64[inew_undefsyms].symbol64.n_type = N_UNDF |N_EXT;
3426 undef_map64[inew_undefsyms].symbol64.n_sect = NO_SECT;
3427 undef_map64[inew_undefsyms].symbol64.n_desc = 0;
3428 undef_map64[inew_undefsyms].symbol64.n_value = 0;
3429 undef_map64[inew_undefsyms].index = i;
3431 inew_undefsyms++;
3434 /* Sort the undefined symbols by name */
3435 qsort_strings = new_strings;
3436 if(object->mh != NULL)
3437 qsort(undef_map, new_nundefsym, sizeof(struct undef_map),
3438 (int (*)(const void *, const void *))cmp_qsort_undef_map);
3439 else
3440 qsort(undef_map64, new_nundefsym, sizeof(struct undef_map64),
3441 (int (*)(const void *, const void *))cmp_qsort_undef_map_64);
3442 /* Copy the symbols now in sorted order into new_symbols */
3443 for(i = 0; i < new_nundefsym; i++){
3444 if(object->mh != NULL){
3445 new_symbols[inew_syms] = undef_map[i].symbol;
3446 inew_syms++;
3447 saves[undef_map[i].index] = inew_syms;
3449 else{
3450 new_symbols64[inew_syms] = undef_map64[i].symbol64;
3451 inew_syms++;
3452 saves[undef_map64[i].index] = inew_syms;
3457 * Fixup the module table's module name strings adding them to the
3458 * string table. Also fix the indexes into the symbol table for
3459 * external and local symbols. And fix up the indexes into the
3460 * reference table.
3462 for(i = 0; i < nmodtab; i++){
3463 if(object->mh != NULL){
3464 strcpy(p, strings + mods[i].module_name);
3465 mods[i].module_name = p - new_strings;
3466 iextdefsym = mods[i].iextdefsym;
3467 nextdefsym = mods[i].nextdefsym;
3468 ilocalsym = mods[i].ilocalsym;
3469 nlocalsym = mods[i].nlocalsym;
3470 irefsym = mods[i].irefsym;
3471 nrefsym = mods[i].nrefsym;
3473 else{
3474 strcpy(p, strings + mods64[i].module_name);
3475 mods64[i].module_name = p - new_strings;
3476 iextdefsym = mods64[i].iextdefsym;
3477 nextdefsym = mods64[i].nextdefsym;
3478 ilocalsym = mods64[i].ilocalsym;
3479 nlocalsym = mods64[i].nlocalsym;
3480 irefsym = mods64[i].irefsym;
3481 nrefsym = mods64[i].nrefsym;
3483 p += strlen(p) + 1;
3485 if(iextdefsym > nsyms){
3486 error_arch(arch, member, "bad index into externally defined "
3487 "symbols of module table entry %d in: ", i);
3488 return(FALSE);
3490 if(iextdefsym + nextdefsym > nsyms){
3491 error_arch(arch, member, "bad number of externally defined "
3492 "symbols of module table entry %d in: ", i);
3493 return(FALSE);
3495 for(j = iextdefsym; j < iextdefsym + nextdefsym; j++){
3496 if(saves[j] != 0 && changes[j] == 0)
3497 break;
3499 n = 0;
3500 for(k = j; k < iextdefsym + nextdefsym; k++){
3501 if(saves[k] != 0 && changes[k] == 0)
3502 n++;
3504 if(n == 0){
3505 if(object->mh != NULL){
3506 mods[i].iextdefsym = 0;
3507 mods[i].nextdefsym = 0;
3509 else{
3510 mods64[i].iextdefsym = 0;
3511 mods64[i].nextdefsym = 0;
3514 else{
3515 if(object->mh != NULL){
3516 mods[i].iextdefsym = saves[j] - 1;
3517 mods[i].nextdefsym = n;
3519 else{
3520 mods64[i].iextdefsym = saves[j] - 1;
3521 mods64[i].nextdefsym = n;
3525 if(ilocalsym > nsyms){
3526 error_arch(arch, member, "bad index into symbols for local "
3527 "symbols of module table entry %d in: ", i);
3528 return(FALSE);
3530 if(ilocalsym + nlocalsym > nsyms){
3531 error_arch(arch, member, "bad number of local "
3532 "symbols of module table entry %d in: ", i);
3533 return(FALSE);
3535 for(j = ilocalsym; j < ilocalsym + nlocalsym; j++){
3536 if(saves[j] != 0)
3537 break;
3539 n = 0;
3540 for(k = j; k < ilocalsym + nlocalsym; k++){
3541 if(saves[k] != 0)
3542 n++;
3544 if(n == 0){
3545 if(object->mh != NULL){
3546 mods[i].ilocalsym = 0;
3547 mods[i].nlocalsym = 0;
3549 else{
3550 mods64[i].ilocalsym = 0;
3551 mods64[i].nlocalsym = 0;
3554 else{
3555 if(object->mh != NULL){
3556 mods[i].ilocalsym = saves[j] - 1;
3557 mods[i].nlocalsym = n;
3559 else{
3560 mods64[i].ilocalsym = saves[j] - 1;
3561 mods64[i].nlocalsym = n;
3565 if(irefsym > nextrefsyms){
3566 error_arch(arch, member, "bad index into reference table "
3567 "of module table entry %d in: ", i);
3568 return(FALSE);
3570 if(irefsym + nrefsym > nextrefsyms){
3571 error_arch(arch, member, "bad number of reference table "
3572 "entries of module table entry %d in: ", i);
3573 return(FALSE);
3575 for(j = irefsym; j < irefsym + nrefsym; j++){
3576 if(ref_saves[j] != 0)
3577 break;
3579 n = 0;
3580 for(k = j; k < irefsym + nrefsym; k++){
3581 if(ref_saves[k] != 0)
3582 n++;
3584 if(n == 0){
3585 if(object->mh != NULL){
3586 mods[i].irefsym = 0;
3587 mods[i].nrefsym = 0;
3589 else{
3590 mods64[i].irefsym = 0;
3591 mods64[i].nrefsym = 0;
3594 else{
3595 if(object->mh != NULL){
3596 mods[i].irefsym = ref_saves[j] - 1;
3597 mods[i].nrefsym = n;
3599 else{
3600 mods64[i].irefsym = ref_saves[j] - 1;
3601 mods64[i].nrefsym = n;
3607 * Create a new reference table.
3609 new_refs = allocate(new_nextrefsyms * sizeof(struct dylib_reference));
3610 j = 0;
3611 for(i = 0; i < nextrefsyms; i++){
3612 if(ref_saves[i]){
3613 if(saves[refs[i].isym]){
3614 new_refs[j].isym = saves[refs[i].isym] - 1;
3615 new_refs[j].flags = refs[i].flags;
3617 else{
3618 if(refs[i].flags == REFERENCE_FLAG_UNDEFINED_NON_LAZY ||
3619 refs[i].flags == REFERENCE_FLAG_UNDEFINED_LAZY){
3620 new_refs[j].isym = changes[refs[i].isym] - 1;
3621 new_refs[j].flags = refs[i].flags;
3624 j++;
3629 * Create a new dylib table of contents.
3631 new_ntoc = 0;
3632 for(i = 0; i < ntoc; i++){
3633 if(tocs[i].symbol_index >= nsyms){
3634 error_arch(arch, member, "bad symbol index for table of "
3635 "contents table entry %d in: ", i);
3636 return(FALSE);
3638 if(saves[tocs[i].symbol_index] != 0 &&
3639 changes[tocs[i].symbol_index] == 0)
3640 new_ntoc++;
3642 new_tocs = allocate(new_ntoc * sizeof(struct dylib_table_of_contents));
3643 j = 0;
3644 for(i = 0; i < ntoc; i++){
3645 if(saves[tocs[i].symbol_index] != 0 &&
3646 changes[tocs[i].symbol_index] == 0){
3647 new_tocs[j].symbol_index = saves[tocs[i].symbol_index] - 1;
3648 new_tocs[j].module_index = tocs[i].module_index;
3649 j++;
3652 #ifdef TRIE_SUPPORT
3654 * Update the export trie if it has one but only call the the
3655 * prune_trie() routine when we are removing global symbols as is
3656 * done with default stripping of a dyld executable or with the -s
3657 * or -R options.
3659 if(object->dyld_info != NULL &&
3660 object->dyld_info->export_size != 0 &&
3661 (default_dyld_executable || sfile != NULL || Rfile != NULL)){
3662 const char *error_string;
3663 uint32_t trie_new_size;
3665 error_string = prune_trie((uint8_t *)(object->object_addr +
3666 object->dyld_info->export_off),
3667 object->dyld_info->export_size,
3668 prune,
3669 &trie_new_size);
3670 if(error_string != NULL){
3671 error_arch(arch, member, "%s", error_string);
3672 return(FALSE);
3675 #endif /* TRIE_SUPPORT */
3677 if(undef_map != NULL)
3678 free(undef_map);
3679 if(undef_map64 != NULL)
3680 free(undef_map64);
3681 if(changes != NULL)
3682 free(changes);
3683 if(sections != NULL)
3684 free(sections);
3685 if(sections64 != NULL)
3686 free(sections64);
3688 if(errors == 0)
3689 return(TRUE);
3690 else
3691 return(FALSE);
3694 #ifdef TRIE_SUPPORT
3696 * prune() is called by prune_trie() and passed a name of an external symbol
3697 * in the trie. It returns 1 if the symbols is to be pruned out and 0 if the
3698 * symbol is to be kept.
3700 * Note that it may seem like a linear search of the new symbols would not be
3701 * the best approach but in 10.6 the only defined global symbol left in a
3702 * stripped executable is __mh_execute_header and new_nextdefsym is usually 1
3703 * so this never actually loops in practice.
3705 static
3707 prune(
3708 const char *name)
3710 uint32_t i;
3712 for(i = 0; i < new_nextdefsym; i++){
3713 if(new_symbols != NULL){
3714 if(strcmp(name, new_strings + new_symbols[inew_nextdefsym + i]
3715 .n_un.n_strx) == 0)
3716 return(0);
3718 else{
3719 if(strcmp(name, new_strings + new_symbols64[inew_nextdefsym + i]
3720 .n_un.n_strx) == 0)
3721 return(0);
3724 return(1);
3726 #endif /* TRIE_SUPPORT */
3729 * make_ld_r_object() takes the object file contents referenced by the passed
3730 * data structures, writes that to a temporary file, runs "ld -r" plus the
3731 * specified stripping option creating a second temporary file, reads that file
3732 * in and replaces the object file contents with that and resets the variables
3733 * pointing to the symbol, string and indirect tables.
3735 static
3736 void
3737 make_ld_r_object(
3738 struct arch *arch,
3739 struct member *member,
3740 struct object *object)
3742 enum byte_sex host_byte_sex;
3743 char *input_file, *output_file;
3744 int fd;
3745 struct ofile *ld_r_ofile;
3746 struct arch *ld_r_archs;
3747 uint32_t ld_r_narchs, save_errors;
3749 host_byte_sex = get_host_byte_sex();
3752 * Swap the object file back into its bytesex before writing it to the
3753 * temporary file if needed.
3755 if(object->object_byte_sex != host_byte_sex){
3756 if(object->mh != NULL){
3757 if(swap_object_headers(object->mh, object->load_commands) ==
3758 FALSE)
3759 fatal("internal error: swap_object_headers() failed");
3760 swap_nlist(symbols, nsyms, object->object_byte_sex);
3762 else{
3763 if(swap_object_headers(object->mh64, object->load_commands) ==
3764 FALSE)
3765 fatal("internal error: swap_object_headers() failed");
3766 swap_nlist_64(symbols64, nsyms, object->object_byte_sex);
3768 swap_indirect_symbols(indirectsyms, nindirectsyms,
3769 object->object_byte_sex);
3773 * Create an input object file for the ld -r command from the bytes
3774 * of this arch's object file.
3776 input_file = makestr("/tmp/strip.XXXXXX", NULL);
3777 input_file = mktemp(input_file);
3779 if((fd = open(input_file, O_WRONLY|O_CREAT, 0600)) < 0)
3780 system_fatal("can't open temporary file: %s", input_file);
3782 if(write(fd, object->object_addr, object->object_size) !=
3783 object->object_size)
3784 system_fatal("can't write temporary file: %s", input_file);
3786 if(close(fd) == -1)
3787 system_fatal("can't close temporary file: %s", input_file);
3790 * Create a temporary name for the output file of the ld -r
3792 output_file = makestr("/tmp/strip.XXXXXX", NULL);
3793 output_file = mktemp(output_file);
3796 * Create the ld -r command line and execute it.
3798 reset_execute_list();
3799 add_execute_list_with_prefix("ld");
3800 add_execute_list("-keep_private_externs");
3801 add_execute_list("-r");
3802 if(Sflag)
3803 add_execute_list("-S");
3804 if(xflag)
3805 add_execute_list("-x");
3806 add_execute_list(input_file);
3807 add_execute_list("-o");
3808 add_execute_list(output_file);
3809 if(sfile != NULL){
3810 add_execute_list("-x");
3811 add_execute_list("-exported_symbols_list");
3812 add_execute_list(sfile);
3814 if(Rfile != NULL){
3815 add_execute_list("-unexported_symbols_list");
3816 add_execute_list(Rfile);
3818 if(execute_list(vflag) == 0)
3819 fatal("internal link edit command failed");
3821 save_errors = errors;
3822 errors = 0;
3823 /* breakout the output file of the ld -f for processing */
3824 ld_r_ofile = breakout(output_file, &ld_r_archs, &ld_r_narchs, FALSE);
3825 if(errors)
3826 goto make_ld_r_object_cleanup;
3828 /* checkout the file for symbol table replacement processing */
3829 checkout(ld_r_archs, ld_r_narchs);
3832 * Make sure the output of the ld -r is an object file with one arch.
3834 if(ld_r_narchs != 1 ||
3835 ld_r_archs->type != OFILE_Mach_O ||
3836 ld_r_archs->object == NULL ||
3837 ld_r_archs->object->mh_filetype != MH_OBJECT)
3838 fatal("internal link edit command failed to produce a thin Mach-O "
3839 "object file");
3842 * Now reset all the data of the input object with the ld -r output
3843 * object file.
3845 nsyms = ld_r_archs->object->st->nsyms;
3846 if(ld_r_archs->object->mh != NULL){
3847 symbols = (struct nlist *)
3848 (ld_r_archs->object->object_addr +
3849 ld_r_archs->object->st->symoff);
3850 if(ld_r_archs->object->object_byte_sex != host_byte_sex)
3851 swap_nlist(symbols, nsyms, host_byte_sex);
3852 symbols64 = NULL;
3854 else{
3855 symbols = NULL;
3856 symbols64 = (struct nlist_64 *)
3857 (ld_r_archs->object->object_addr +
3858 ld_r_archs->object->st->symoff);
3859 if(ld_r_archs->object->object_byte_sex != host_byte_sex)
3860 swap_nlist_64(symbols64, nsyms, host_byte_sex);
3862 strings = ld_r_archs->object->object_addr +
3863 ld_r_archs->object->st->stroff;
3864 strsize = ld_r_archs->object->st->strsize;
3866 if(ld_r_archs->object->dyst != NULL &&
3867 ld_r_archs->object->dyst->nindirectsyms != 0){
3868 nindirectsyms = ld_r_archs->object->dyst->nindirectsyms;
3869 indirectsyms = (uint32_t *)
3870 (ld_r_archs->object->object_addr +
3871 ld_r_archs->object->dyst->indirectsymoff);
3872 if(ld_r_archs->object->object_byte_sex != host_byte_sex)
3873 swap_indirect_symbols(indirectsyms, nindirectsyms,
3874 host_byte_sex);
3876 else{
3877 indirectsyms = NULL;
3878 nindirectsyms = 0;
3881 if(ld_r_archs->object->mh != NULL)
3882 ld_r_archs->object->input_sym_info_size =
3883 nsyms * sizeof(struct nlist) +
3884 strsize;
3885 else
3886 ld_r_archs->object->input_sym_info_size =
3887 nsyms * sizeof(struct nlist_64) +
3888 strsize;
3891 * Copy over the object struct from the ld -r object file onto the
3892 * input object file.
3894 *object = *ld_r_archs->object;
3897 * Save the ofile struct for the ld -r output so it can be umapped when
3898 * we are done. And free up the ld_r_archs now that we are done with
3899 * them.
3901 object->ld_r_ofile = ld_r_ofile;
3902 free_archs(ld_r_archs, ld_r_narchs);
3904 make_ld_r_object_cleanup:
3905 errors += save_errors;
3907 * Remove the input and output files and clean up.
3909 if(unlink(input_file) == -1)
3910 system_fatal("can't remove temporary file: %s", input_file);
3911 if(unlink(output_file) == -1)
3912 system_fatal("can't remove temporary file: %s", output_file);
3913 free(input_file);
3914 free(output_file);
3918 * strip_LC_UUID_commands() is called when -no_uuid is specified to remove any
3919 * LC_UUID load commands from the object's load commands.
3921 static
3922 void
3923 strip_LC_UUID_commands(
3924 struct arch *arch,
3925 struct member *member,
3926 struct object *object)
3928 uint32_t i, ncmds, nuuids, mh_sizeofcmds, sizeofcmds;
3929 struct load_command *lc1, *lc2, *new_load_commands;
3930 struct segment_command *sg;
3933 * See if there are any LC_UUID load commands.
3935 nuuids = 0;
3936 lc1 = arch->object->load_commands;
3937 if(arch->object->mh != NULL){
3938 ncmds = arch->object->mh->ncmds;
3939 mh_sizeofcmds = arch->object->mh->sizeofcmds;
3941 else{
3942 ncmds = arch->object->mh64->ncmds;
3943 mh_sizeofcmds = arch->object->mh64->sizeofcmds;
3945 for(i = 0; i < ncmds; i++){
3946 if(lc1->cmd == LC_UUID){
3947 nuuids++;
3949 lc1 = (struct load_command *)((char *)lc1 + lc1->cmdsize);
3951 /* if no LC_UUID load commands just return */
3952 if(nuuids == 0)
3953 return;
3956 * Allocate space for the new load commands as zero it out so any holes
3957 * will be zero bytes.
3959 new_load_commands = allocate(mh_sizeofcmds);
3960 memset(new_load_commands, '\0', mh_sizeofcmds);
3963 * Copy all the load commands except the LC_UUID load commands into the
3964 * allocated space for the new load commands.
3966 lc1 = arch->object->load_commands;
3967 lc2 = new_load_commands;
3968 sizeofcmds = 0;
3969 for(i = 0; i < ncmds; i++){
3970 if(lc1->cmd != LC_UUID){
3971 memcpy(lc2, lc1, lc1->cmdsize);
3972 sizeofcmds += lc2->cmdsize;
3973 lc2 = (struct load_command *)((char *)lc2 + lc2->cmdsize);
3975 lc1 = (struct load_command *)((char *)lc1 + lc1->cmdsize);
3979 * Finally copy the updated load commands over the existing load
3980 * commands.
3982 memcpy(arch->object->load_commands, new_load_commands, sizeofcmds);
3983 if(mh_sizeofcmds > sizeofcmds){
3984 memset((char *)arch->object->load_commands + sizeofcmds, '\0',
3985 (mh_sizeofcmds - sizeofcmds));
3987 ncmds -= nuuids;
3988 if(arch->object->mh != NULL) {
3989 arch->object->mh->sizeofcmds = sizeofcmds;
3990 arch->object->mh->ncmds = ncmds;
3991 } else {
3992 arch->object->mh64->sizeofcmds = sizeofcmds;
3993 arch->object->mh64->ncmds = ncmds;
3995 free(new_load_commands);
3997 /* reset the pointers into the load commands */
3998 lc1 = arch->object->load_commands;
3999 for(i = 0; i < ncmds; i++){
4000 switch(lc1->cmd){
4001 case LC_SYMTAB:
4002 arch->object->st = (struct symtab_command *)lc1;
4003 break;
4004 case LC_DYSYMTAB:
4005 arch->object->dyst = (struct dysymtab_command *)lc1;
4006 break;
4007 case LC_TWOLEVEL_HINTS:
4008 arch->object->hints_cmd = (struct twolevel_hints_command *)lc1;
4009 break;
4010 case LC_PREBIND_CKSUM:
4011 arch->object->cs = (struct prebind_cksum_command *)lc1;
4012 break;
4013 case LC_SEGMENT:
4014 sg = (struct segment_command *)lc1;
4015 if(strcmp(sg->segname, SEG_LINKEDIT) == 0)
4016 arch->object->seg_linkedit = sg;
4017 break;
4018 case LC_SEGMENT_SPLIT_INFO:
4019 object->split_info_cmd = (struct linkedit_data_command *)lc1;
4020 break;
4021 case LC_CODE_SIGNATURE:
4022 object->code_sig_cmd = (struct linkedit_data_command *)lc1;
4023 break;
4024 case LC_DYLD_INFO_ONLY:
4025 case LC_DYLD_INFO:
4026 object->dyld_info = (struct dyld_info_command *)lc1;
4028 lc1 = (struct load_command *)((char *)lc1 + lc1->cmdsize);
4032 #ifndef NMEDIT
4034 * strip_LC_CODE_SIGNATURE_commands() is called when -c is specified to remove
4035 * any LC_CODE_SIGNATURE load commands from the object's load commands.
4037 static
4038 void
4039 strip_LC_CODE_SIGNATURE_commands(
4040 struct arch *arch,
4041 struct member *member,
4042 struct object *object)
4044 uint32_t i, ncmds, mh_sizeofcmds, sizeofcmds;
4045 struct load_command *lc1, *lc2, *new_load_commands;
4046 struct segment_command *sg;
4049 * See if there is an LC_CODE_SIGNATURE load command and if no command
4050 * just return.
4052 if(object->code_sig_cmd == NULL)
4053 return;
4056 * Allocate space for the new load commands and zero it out so any holes
4057 * will be zero bytes.
4059 if(arch->object->mh != NULL){
4060 ncmds = arch->object->mh->ncmds;
4061 mh_sizeofcmds = arch->object->mh->sizeofcmds;
4063 else{
4064 ncmds = arch->object->mh64->ncmds;
4065 mh_sizeofcmds = arch->object->mh64->sizeofcmds;
4067 new_load_commands = allocate(mh_sizeofcmds);
4068 memset(new_load_commands, '\0', mh_sizeofcmds);
4071 * Copy all the load commands except the LC_CODE_SIGNATURE load commands
4072 * into the allocated space for the new load commands.
4074 lc1 = arch->object->load_commands;
4075 lc2 = new_load_commands;
4076 sizeofcmds = 0;
4077 for(i = 0; i < ncmds; i++){
4078 if(lc1->cmd != LC_CODE_SIGNATURE){
4079 memcpy(lc2, lc1, lc1->cmdsize);
4080 sizeofcmds += lc2->cmdsize;
4081 lc2 = (struct load_command *)((char *)lc2 + lc2->cmdsize);
4083 lc1 = (struct load_command *)((char *)lc1 + lc1->cmdsize);
4087 * Finally copy the updated load commands over the existing load
4088 * commands.
4090 memcpy(arch->object->load_commands, new_load_commands, sizeofcmds);
4091 if(mh_sizeofcmds > sizeofcmds){
4092 memset((char *)arch->object->load_commands + sizeofcmds, '\0',
4093 (mh_sizeofcmds - sizeofcmds));
4095 ncmds -= 1;
4096 if(arch->object->mh != NULL) {
4097 arch->object->mh->sizeofcmds = sizeofcmds;
4098 arch->object->mh->ncmds = ncmds;
4099 } else {
4100 arch->object->mh64->sizeofcmds = sizeofcmds;
4101 arch->object->mh64->ncmds = ncmds;
4103 free(new_load_commands);
4105 /* reset the pointers into the load commands */
4106 object->code_sig_cmd = NULL;
4107 lc1 = arch->object->load_commands;
4108 for(i = 0; i < ncmds; i++){
4109 switch(lc1->cmd){
4110 case LC_SYMTAB:
4111 arch->object->st = (struct symtab_command *)lc1;
4112 break;
4113 case LC_DYSYMTAB:
4114 arch->object->dyst = (struct dysymtab_command *)lc1;
4115 break;
4116 case LC_TWOLEVEL_HINTS:
4117 arch->object->hints_cmd = (struct twolevel_hints_command *)lc1;
4118 break;
4119 case LC_PREBIND_CKSUM:
4120 arch->object->cs = (struct prebind_cksum_command *)lc1;
4121 break;
4122 case LC_SEGMENT:
4123 sg = (struct segment_command *)lc1;
4124 if(strcmp(sg->segname, SEG_LINKEDIT) == 0)
4125 arch->object->seg_linkedit = sg;
4126 break;
4127 case LC_SEGMENT_SPLIT_INFO:
4128 object->split_info_cmd = (struct linkedit_data_command *)lc1;
4129 break;
4131 lc1 = (struct load_command *)((char *)lc1 + lc1->cmdsize);
4135 * To get the right amount of the file copied out by writeout() for the
4136 * case when we are stripping out the section contents we already reduce
4137 * the object size by the size of the section contents including the
4138 * padding after the load commands. So here we need to further reduce
4139 * it by the load command for the LC_CODE_SIGNATURE (a struct
4140 * linkedit_data_command) we are removing.
4142 object->object_size -= sizeof(struct linkedit_data_command);
4144 * Then this size minus the size of the input symbolic information is
4145 * what is copied out from the file by writeout(). Which in this case
4146 * is just the new headers.
4150 * Finally for -c the file offset to the link edit information is to be
4151 * right after the load commands. So reset this for the updated size
4152 * of the load commands without the LC_CODE_SIGNATURE.
4154 if(object->mh != NULL)
4155 object->seg_linkedit->fileoff = sizeof(struct mach_header) +
4156 sizeofcmds;
4157 else
4158 object->seg_linkedit64->fileoff = sizeof(struct mach_header_64) +
4159 sizeofcmds;
4161 #endif /* !(NMEDIT) */
4164 * private_extern_reference_by_module() is passed a symbol_index of a private
4165 * extern symbol and the module table. If the symbol_index appears in the
4166 * module symbol table this returns TRUE else it returns FALSE.
4168 static
4169 enum bool
4170 private_extern_reference_by_module(
4171 uint32_t symbol_index,
4172 struct dylib_reference *refs,
4173 uint32_t nextrefsyms)
4175 uint32_t i;
4177 for(i = 0; i < nextrefsyms; i++){
4178 if(refs[i].isym == symbol_index){
4179 if(refs[i].flags == REFERENCE_FLAG_PRIVATE_UNDEFINED_NON_LAZY ||
4180 refs[i].flags == REFERENCE_FLAG_PRIVATE_UNDEFINED_LAZY){
4181 return(TRUE);
4185 return(FALSE);
4189 * symbol_pointer_used() is passed a symbol_index and the indirect table. If
4190 * the symbol_index appears in the indirect symbol table this returns TRUE else
4191 * it returns FALSE.
4193 static
4194 enum bool
4195 symbol_pointer_used(
4196 uint32_t symbol_index,
4197 uint32_t *indirectsyms,
4198 uint32_t nindirectsyms)
4200 uint32_t i;
4202 for(i = 0; i < nindirectsyms; i++){
4203 if(indirectsyms[i] == symbol_index)
4204 return(TRUE);
4206 return(FALSE);
4210 * Function for qsort for comparing undefined map entries.
4212 static
4214 cmp_qsort_undef_map(
4215 const struct undef_map *sym1,
4216 const struct undef_map *sym2)
4218 return(strcmp(qsort_strings + sym1->symbol.n_un.n_strx,
4219 qsort_strings + sym2->symbol.n_un.n_strx));
4222 static
4224 cmp_qsort_undef_map_64(
4225 const struct undef_map64 *sym1,
4226 const struct undef_map64 *sym2)
4228 return(strcmp(qsort_strings + sym1->symbol64.n_un.n_strx,
4229 qsort_strings + sym2->symbol64.n_un.n_strx));
4231 #endif /* !defined(NMEDIT) */
4233 #ifndef NMEDIT
4235 * Function for qsort for comparing object names.
4237 static
4239 cmp_qsort_filename(
4240 const char **name1,
4241 const char **name2)
4243 return(strcmp(*name1, *name2));
4247 * Function for bsearch for finding a object name.
4249 static
4251 cmp_bsearch_filename(
4252 const char *name1,
4253 const char **name2)
4255 return(strcmp(name1, *name2));
4257 #endif /* !defined(NMEDIT) */
4259 #ifdef NMEDIT
4260 static
4261 enum bool
4262 edit_symtab(
4263 struct arch *arch,
4264 struct member *member,
4265 struct object *object,
4266 struct nlist *symbols,
4267 struct nlist_64 *symbols64,
4268 uint32_t nsyms,
4269 char *strings,
4270 uint32_t strsize,
4271 struct dylib_table_of_contents *tocs,
4272 uint32_t ntoc,
4273 struct dylib_module *mods,
4274 struct dylib_module_64 *mods64,
4275 uint32_t nmodtab,
4276 struct dylib_reference *refs,
4277 uint32_t nextrefsyms)
4279 uint32_t i, j, k;
4280 unsigned char data_n_sect, nsects;
4281 struct load_command *lc;
4282 struct segment_command *sg;
4283 struct segment_command_64 *sg64;
4284 struct section *s, **sections;
4285 struct section_64 *s64, **sections64;
4287 uint32_t missing_syms;
4288 struct symbol_list *sp;
4289 struct nlist **global_symbol;
4290 struct nlist_64 **global_symbol64;
4291 enum bool global_symbol_found;
4292 char *global_name, save_char;
4293 enum bool dwarf_debug_map;
4294 enum byte_sex host_byte_sex;
4295 int32_t missing_reloc_symbols;
4296 enum bool edit_symtab_return;
4298 char *p, *q;
4299 uint32_t new_ext_strsize, len, inew_syms;
4301 struct nlist **changed_globals;
4302 struct nlist_64 **changed_globals64;
4303 uint32_t nchanged_globals;
4304 uint32_t ncmds, s_flags, n_strx, module_name, ilocalsym, nlocalsym;
4305 uint32_t iextdefsym, nextdefsym;
4306 uint8_t n_type, n_sect, global_symbol_n_sect;
4307 uint64_t n_value;
4308 enum bool warned_about_global_coalesced_symbols;
4310 edit_symtab_return = TRUE;
4311 host_byte_sex = get_host_byte_sex();
4312 missing_reloc_symbols = 0;
4313 warned_about_global_coalesced_symbols = FALSE;
4315 if(nmedits != NULL)
4316 free(nmedits);
4317 nmedits = allocate(nsyms * sizeof(enum bool));
4318 for(i = 0; i < nsyms; i++)
4319 nmedits[i] = FALSE;
4322 * If nmedit is operating on a dynamic library then symbols are turned
4323 * into private externs with the extern bit off not into static symbols.
4325 if(object->mh_filetype == MH_DYLIB && pflag == TRUE){
4326 error_arch(arch, member, "can't use -p with dynamic libraries");
4327 return(FALSE);
4331 * As part of the MAJOR guess for the second pass to fix stabs for the
4332 * globals symbols that get turned into non-global symbols. We need to
4333 * change the stabs. To do this we to know if a N_GSYM is for a data
4334 * symbol or not to know to turn it into an N_STSYM or a N_FUN.
4335 * This logic as determined by compiling test cases with and without
4336 * the key word 'static' and looking at the difference between the STABS
4337 * the compiler generates and trying to match that here.
4339 * We also use this loop and the next to gather an array of section
4340 * struct pointers so we can later determine if we run into a global
4341 * symbol in a coalesced section and not turn those symbols into
4342 * statics.
4344 j = 0;
4345 nsects = 0;
4346 n_sect = 1;
4347 data_n_sect = NO_SECT;
4348 lc = object->load_commands;
4349 if(object->mh != NULL)
4350 ncmds = object->mh->ncmds;
4351 else
4352 ncmds = object->mh64->ncmds;
4353 for(i = 0; i < ncmds; i++){
4354 if(lc->cmd == LC_SEGMENT){
4355 sg = (struct segment_command *)lc;
4356 s = (struct section *)((char *)sg +
4357 sizeof(struct segment_command));
4358 nsects += sg->nsects;
4359 for(j = 0; j < sg->nsects; j++){
4360 if(strcmp(s->segname, SEG_DATA) == 0 &&
4361 strcmp(s->sectname, SECT_DATA) == 0 &&
4362 data_n_sect == NO_SECT){
4363 data_n_sect = n_sect;
4364 break;
4366 n_sect++;
4367 s++;
4370 else if(lc->cmd == LC_SEGMENT_64){
4371 sg64 = (struct segment_command_64 *)lc;
4372 s64 = (struct section_64 *)((char *)sg64 +
4373 sizeof(struct segment_command_64));
4374 nsects += sg64->nsects;
4375 for(j = 0; j < sg64->nsects; j++){
4376 if(strcmp(s64->segname, SEG_DATA) == 0 &&
4377 strcmp(s64->sectname, SECT_DATA) == 0 &&
4378 data_n_sect == NO_SECT){
4379 data_n_sect = n_sect;
4380 break;
4382 n_sect++;
4383 s64++;
4386 lc = (struct load_command *)((char *)lc + lc->cmdsize);
4388 if(object->mh != NULL){
4389 sections = allocate(nsects * sizeof(struct section *));
4390 sections64 = NULL;
4392 else{
4393 sections = NULL;
4394 sections64 = allocate(nsects * sizeof(struct section_64 *));
4396 nsects = 0;
4397 lc = object->load_commands;
4398 for(i = 0; i < ncmds; i++){
4399 if(lc->cmd == LC_SEGMENT){
4400 sg = (struct segment_command *)lc;
4401 s = (struct section *)((char *)sg +
4402 sizeof(struct segment_command));
4403 for(j = 0; j < sg->nsects; j++){
4404 sections[nsects++] = s++;
4407 else if(lc->cmd == LC_SEGMENT_64){
4408 sg64 = (struct segment_command_64 *)lc;
4409 s64 = (struct section_64 *)((char *)sg64 +
4410 sizeof(struct segment_command_64));
4411 for(j = 0; j < sg64->nsects; j++){
4412 sections64[nsects++] = s64++;
4415 lc = (struct load_command *)((char *)lc + lc->cmdsize);
4419 * Zero out the saved symbols so they can be recorded for this file.
4421 for(i = 0; i < nsave_symbols; i++)
4422 save_symbols[i].sym = NULL;
4423 for(i = 0; i < nremove_symbols; i++)
4424 remove_symbols[i].sym = NULL;
4425 if(member == NULL){
4426 for(i = 0; i < nsave_symbols; i++)
4427 save_symbols[i].seen = FALSE;
4428 for(i = 0; i < nremove_symbols; i++)
4429 remove_symbols[i].seen = FALSE;
4432 nchanged_globals = 0;
4433 if(object->mh != NULL){
4434 changed_globals = allocate(nsyms * sizeof(struct nlist *));
4435 changed_globals64 = NULL;
4436 for(i = 0; i < nsyms; i++)
4437 changed_globals[i] = NULL;
4439 else{
4440 changed_globals = NULL;
4441 changed_globals64 = allocate(nsyms * sizeof(struct nlist_64 *));
4442 for(i = 0; i < nsyms; i++)
4443 changed_globals64[i] = NULL;
4447 * These are the variables for the new symbol table and new string
4448 * table. Since this routine only turns globals into non-globals the
4449 * number of symbols does not change. But the count of local, defined
4450 * external symbols does change.
4452 new_nsyms = nsyms;
4453 new_nlocalsym = 0;
4454 new_nextdefsym = 0;
4455 new_nundefsym = 0;
4457 new_strsize = sizeof(int32_t);
4458 new_ext_strsize = 0;
4461 * First pass: turn the globals symbols into non-global symbols.
4463 for(i = 0; i < nsyms; i++){
4464 len = 0;
4465 s_flags = 0;
4466 if(object->mh != NULL){
4467 n_strx = symbols[i].n_un.n_strx;
4468 n_type = symbols[i].n_type;
4469 n_sect = symbols[i].n_sect;
4470 if((n_type & N_TYPE) == N_SECT)
4471 s_flags = sections[n_sect - 1]->flags;
4472 n_value = symbols[i].n_value;
4474 else{
4475 n_strx = symbols64[i].n_un.n_strx;
4476 n_type = symbols64[i].n_type;
4477 n_sect = symbols64[i].n_sect;
4478 if((n_type & N_TYPE) == N_SECT)
4479 s_flags = sections64[n_sect - 1]->flags;
4480 n_value = symbols64[i].n_value;
4482 if(n_strx != 0){
4483 if(n_strx > strsize){
4484 error_arch(arch, member, "bad string index for symbol "
4485 "table entry %u in: ", i);
4486 return(FALSE);
4488 len = strlen(strings + n_strx) + 1;
4490 if(n_type & N_EXT){
4491 if((n_type & N_TYPE) != N_UNDF &&
4492 (n_type & N_TYPE) != N_PBUD){
4493 if((n_type & N_TYPE) == N_SECT){
4494 if(n_sect > nsects){
4495 error_arch(arch, member, "bad n_sect for symbol "
4496 "table entry %u in: ", i);
4497 return(FALSE);
4499 if(((s_flags & SECTION_TYPE) == S_COALESCED) &&
4500 pflag == FALSE &&
4501 object->mh_filetype != MH_OBJECT){
4502 /* this remains a global defined symbol */
4503 if(warned_about_global_coalesced_symbols == FALSE){
4504 warning_arch(arch, member, "can't make global "
4505 "coalesced symbols (like %s) into static "
4506 "symbols (use ld(1)'s "
4507 "-exported_symbols_list option) in a final "
4508 "linked image: ", strings + n_strx);
4509 warned_about_global_coalesced_symbols = TRUE;
4511 new_nextdefsym++;
4512 new_ext_strsize += len;
4513 new_strsize += len;
4514 sp = bsearch(strings + n_strx,
4515 remove_symbols, nremove_symbols,
4516 sizeof(struct symbol_list),
4517 (int (*)(const void *, const void *))
4518 symbol_list_bsearch);
4519 if(sp != NULL){
4520 if(sp->sym != NULL){
4521 error_arch(arch, member, "more than one "
4522 "symbol for: %s found in: ", sp->name);
4523 return(FALSE);
4525 else{
4526 if(object->mh != NULL)
4527 sp->sym = &(symbols[i]);
4528 else
4529 sp->sym = &(symbols64[i]);
4530 sp->seen = TRUE;
4531 warning_arch(arch, member, "can't make "
4532 "global coalesced symbol: %s into a "
4533 "static symbol in: ", sp->name);
4537 * In case the user has listed this coalesced
4538 * symbol in the save list look for it and mark it
4539 * as seen so we don't complain about not seeing it.
4541 sp = bsearch(strings + n_strx,
4542 save_symbols, nsave_symbols,
4543 sizeof(struct symbol_list),
4544 (int (*)(const void *, const void *))
4545 symbol_list_bsearch);
4546 if(sp != NULL){
4547 if(sp->sym != NULL){
4548 error_arch(arch, member, "more than one "
4549 "symbol for: %s found in: ", sp->name);
4550 return(FALSE);
4552 else{
4553 if(object->mh != NULL)
4554 sp->sym = &(symbols[i]);
4555 else
4556 sp->sym = &(symbols64[i]);
4557 sp->seen = TRUE;
4560 continue; /* leave this symbol unchanged */
4563 sp = bsearch(strings + n_strx,
4564 remove_symbols, nremove_symbols,
4565 sizeof(struct symbol_list),
4566 (int (*)(const void *, const void *))
4567 symbol_list_bsearch);
4568 if(sp != NULL){
4569 if(sp->sym != NULL){
4570 error_arch(arch, member, "more than one symbol "
4571 "for: %s found in: ", sp->name);
4572 return(FALSE);
4574 else{
4575 if(object->mh != NULL)
4576 sp->sym = &(symbols[i]);
4577 else
4578 sp->sym = &(symbols64[i]);
4579 sp->seen = TRUE;
4580 goto change_symbol;
4583 else{
4585 * If there is no list of saved symbols, then all
4586 * symbols will be saved unless listed in the remove
4587 * list.
4589 if(sfile == NULL){
4591 * There is no save list, so if there is also no
4592 * remove list but the -p flag is specified or it is
4593 * a dynamic library then change all symbols.
4595 if((pflag || object->mh_filetype == MH_DYLIB)
4596 && nremove_symbols == 0)
4597 goto change_symbol;
4598 /* this remains a global defined symbol */
4599 new_nextdefsym++;
4600 new_ext_strsize += len;
4601 new_strsize += len;
4602 continue; /* leave this symbol unchanged */
4605 sp = bsearch(strings + n_strx,
4606 save_symbols, nsave_symbols,
4607 sizeof(struct symbol_list),
4608 (int (*)(const void *, const void *))
4609 symbol_list_bsearch);
4610 if(sp != NULL){
4611 if(sp->sym != NULL){
4612 error_arch(arch, member, "more than one symbol "
4613 "for: %s found in: ", sp->name);
4614 return(FALSE);
4616 else{
4617 if(object->mh != NULL)
4618 sp->sym = &(symbols[i]);
4619 else
4620 sp->sym = &(symbols64[i]);
4621 sp->seen = TRUE;
4622 /* this remains a global defined symbol */
4623 new_nextdefsym++;
4624 new_ext_strsize += len;
4625 new_strsize += len;
4628 else{
4629 if(Aflag && n_type == (N_EXT | N_ABS) &&
4630 (n_value != 0 ||
4631 (n_strx != 0 &&
4632 strncmp(strings + n_strx,
4633 ".objc_class_name_",
4634 sizeof(".objc_class_name_") - 1) == 0))){
4635 /* this remains a global defined symbol */
4636 new_nextdefsym++;
4637 new_ext_strsize += len;
4638 new_strsize += len;
4640 else{
4641 change_symbol:
4642 if((n_type & N_TYPE) != N_INDR){
4643 nmedits[i] = TRUE;
4644 if(object->mh != NULL)
4645 changed_globals[nchanged_globals++] =
4646 symbols + i;
4647 else
4648 changed_globals64[nchanged_globals++] =
4649 symbols64 + i;
4650 if(pflag){
4651 /* this remains a global defined symbol */
4652 new_nextdefsym++;
4653 new_ext_strsize += len;
4654 new_strsize += len;
4656 else{
4657 /* this will become a non-global symbol */
4658 new_nlocalsym++;
4659 new_strsize += len;
4662 else{
4663 /* this remains a global defined symbol */
4664 new_nextdefsym++;
4665 new_ext_strsize += len;
4666 new_strsize += len;
4671 else{
4672 /* this is an undefined symbol */
4673 new_nundefsym++;
4674 new_ext_strsize += len;
4675 new_strsize += len;
4678 else{
4679 /* this is a local symbol */
4680 new_nlocalsym++;
4681 new_strsize += len;
4686 * The module table's module names are placed with the external
4687 * strings. So size them and add this to the external string size.
4689 for(i = 0; i < nmodtab; i++){
4690 if(object->mh != NULL)
4691 module_name = mods[i].module_name;
4692 else
4693 module_name = mods64[i].module_name;
4694 if(module_name == 0 || module_name > strsize){
4695 error_arch(arch, member, "bad string index for module_name "
4696 "of module table entry %d in: ", i);
4697 return(FALSE);
4699 len = strlen(strings + module_name) + 1;
4700 new_strsize += len;
4701 new_ext_strsize += len;
4705 * Warn about symbols to be saved that were missing.
4707 if(member == NULL){
4708 missing_syms = 0;
4709 if(iflag == 0){
4710 for(i = 0; i < nsave_symbols; i++){
4711 if(save_symbols[i].sym == NULL){
4712 if(missing_syms == 0){
4713 error_arch(arch, member, "symbols names listed "
4714 "in: %s not in: ", sfile);
4715 missing_syms = 1;
4717 fprintf(stderr, "%s\n", save_symbols[i].name);
4720 for(i = 0; i < nremove_symbols; i++){
4721 if(remove_symbols[i].sym == NULL){
4722 if(missing_syms == 0){
4723 error_arch(arch, member, "symbols names listed "
4724 "in: %s not in: ", Rfile);
4725 missing_syms = 1;
4727 fprintf(stderr, "%s\n", remove_symbols[i].name);
4734 * Second pass: fix stabs for the globals symbols that got turned into
4735 * non-global symbols. This is a MAJOR guess. The specific changes
4736 * to do here were determined by compiling test cases with and without
4737 * the key word 'static' and looking at the difference between the STABS
4738 * the compiler generates and trying to match that here.
4740 global_strings = strings;
4741 if(object->mh != NULL)
4742 qsort(changed_globals, nchanged_globals, sizeof(struct nlist *),
4743 (int (*)(const void *, const void *))cmp_qsort_global);
4744 else
4745 qsort(changed_globals64, nchanged_globals,sizeof(struct nlist_64 *),
4746 (int (*)(const void *, const void *))cmp_qsort_global_64);
4747 dwarf_debug_map = FALSE;
4748 for(i = 0; i < nsyms; i++){
4749 uint16_t n_desc;
4750 if(object->mh != NULL){
4751 n_strx = symbols[i].n_un.n_strx;
4752 n_type = symbols[i].n_type;
4753 n_desc = symbols[i].n_desc;
4755 else{
4756 n_strx = symbols64[i].n_un.n_strx;
4757 n_type = symbols64[i].n_type;
4758 n_desc = symbols64[i].n_desc;
4760 if(n_type == N_SO)
4761 dwarf_debug_map = FALSE;
4762 else if (n_type == N_OSO)
4763 dwarf_debug_map = n_desc != 0;
4764 else if (dwarf_debug_map && n_type == N_GSYM){
4765 global_name = strings + n_strx;
4766 if(object->mh != NULL){
4767 global_symbol = bsearch(global_name, changed_globals,
4768 nchanged_globals,sizeof(struct nlist *),
4769 (int (*)(const void *, const void *))
4770 cmp_bsearch_global);
4771 if(global_symbol != NULL){
4772 symbols[i].n_type = N_STSYM;
4773 symbols[i].n_sect = (*global_symbol)->n_sect;
4774 symbols[i].n_value = (*global_symbol)->n_value;
4777 else{
4778 global_symbol64 = bsearch(global_name, changed_globals64,
4779 nchanged_globals,
4780 sizeof(struct nlist_64 *),
4781 (int (*)(const void *, const void *))
4782 cmp_bsearch_global_64);
4783 if(global_symbol64 != NULL){
4784 symbols64[i].n_type = N_STSYM;
4785 symbols64[i].n_sect = (*global_symbol64)->n_sect;
4786 symbols64[i].n_value = (*global_symbol64)->n_value;
4790 else if(! dwarf_debug_map &&
4791 (n_type == N_GSYM || n_type == N_FUN) &&
4792 (n_strx != 0 && strings[n_strx] != '\0')){
4793 global_name = strings + n_strx;
4794 if((global_name[0] == '+' || global_name[0] == '-') &&
4795 global_name[1] == '['){
4796 j = 2;
4797 while(j + n_strx < strsize && global_name[j] != ']')
4798 j++;
4799 if(j + n_strx < strsize && global_name[j] == ']')
4800 j++;
4802 else
4803 j = 0;
4804 while(j + n_strx < strsize && global_name[j] != ':')
4805 j++;
4806 if(j + n_strx >= strsize){
4807 error_arch(arch, member, "bad N_STAB symbol name for entry "
4808 "%u (does not contain ':' separating name from type) "
4809 "in: ", i);
4810 return(FALSE);
4812 save_char = global_name[j];
4813 global_name[j] = '\0';
4815 global_symbol_found = FALSE;
4816 global_symbol_n_sect = 0;
4817 if(object->mh != NULL){
4818 global_symbol = bsearch(global_name, changed_globals,
4819 nchanged_globals,sizeof(struct nlist *),
4820 (int (*)(const void *, const void *))
4821 cmp_bsearch_global_stab);
4822 global_symbol64 = NULL;
4823 if(global_symbol != NULL){
4824 global_symbol_found = TRUE;
4825 global_symbol_n_sect = (*global_symbol)->n_sect;
4828 else{
4829 global_symbol64 = bsearch(global_name, changed_globals64,
4830 nchanged_globals,
4831 sizeof(struct nlist_64 *),
4832 (int (*)(const void *, const void *))
4833 cmp_bsearch_global_stab_64);
4834 global_symbol = NULL;
4835 if(global_symbol64 != NULL){
4836 global_symbol_found = TRUE;
4837 global_symbol_n_sect = (*global_symbol64)->n_sect;
4840 global_name[j] = save_char;
4841 if(global_symbol_found == TRUE){
4842 if(n_type == N_GSYM){
4843 if(global_symbol_n_sect == data_n_sect){
4844 if(object->mh != NULL)
4845 symbols[i].n_type = N_STSYM;
4846 else
4847 symbols64[i].n_type = N_STSYM;
4849 else{
4850 if(object->mh != NULL)
4851 symbols[i].n_type = N_FUN;
4852 else
4853 symbols64[i].n_type = N_FUN;
4855 if(object->mh != NULL){
4856 symbols[i].n_sect = (*global_symbol)->n_sect;
4857 symbols[i].n_value = (*global_symbol)->n_value;
4858 symbols[i].n_desc = (*global_symbol)->n_desc;
4860 else{
4861 symbols64[i].n_sect = (*global_symbol64)->n_sect;
4862 symbols64[i].n_value = (*global_symbol64)->n_value;
4863 symbols64[i].n_desc = (*global_symbol64)->n_desc;
4865 if(j + 1 + n_strx >= strsize ||
4866 global_name[j+1] != 'G'){
4867 error_arch(arch, member, "bad N_GSYM symbol name "
4868 "for entry %u (does not have type 'G' after "
4869 "':' in name) in: ", i);
4870 return(FALSE);
4872 global_name[j+1] = 'S';
4874 else{ /* n_type == N_FUN */
4875 if(j + 1 + n_strx >= strsize ||
4876 global_name[j+1] == 'F'){
4877 global_name[j+1] = 'f';
4883 global_strings = NULL;
4886 * Now what needs to be done is to create the new symbol table moving
4887 * those global symbols being changed into non-globals into the areas
4888 * in the symbol table for local symbols. The symbol table and string
4889 * table must be in this order:
4891 * symbol table
4892 * local symbols
4893 * external defined symbols
4894 * undefined symbols
4895 * string table
4896 * external strings
4897 * local strings
4899 if(saves != NULL)
4900 free(saves);
4901 saves = (int32_t *)allocate(nsyms * sizeof(int32_t));
4902 bzero(saves, nsyms * sizeof(int32_t));
4904 if(object->mh != NULL){
4905 new_symbols = (struct nlist *)
4906 allocate(new_nsyms * sizeof(struct nlist));
4907 new_symbols64 = NULL;
4909 else{
4910 new_symbols = NULL;
4911 new_symbols64 = (struct nlist_64 *)
4912 allocate(new_nsyms * sizeof(struct nlist_64));
4914 new_strsize = round(new_strsize, sizeof(int32_t));
4915 new_strings = (char *)allocate(new_strsize);
4916 new_strings[new_strsize - 3] = '\0';
4917 new_strings[new_strsize - 2] = '\0';
4918 new_strings[new_strsize - 1] = '\0';
4920 memset(new_strings, '\0', sizeof(int32_t));
4921 p = new_strings + sizeof(int32_t);
4922 q = p + new_ext_strsize;
4925 * If this is a dynamic library the movement of the symbols has to be
4926 * done with respect to the modules. As the local symbols, and external
4927 * defined symbols are grouped together for each module. Then a new
4928 * module table needs to be created with the new indexes into the symbol
4929 * table for each module.
4931 new_nmodtab = nmodtab;
4932 new_ntoc = ntoc;
4933 new_nextrefsyms = nextrefsyms;
4934 if(object->mh_filetype == MH_DYLIB && nmodtab != 0){
4935 if(object->mh != NULL){
4936 new_mods = allocate(nmodtab * sizeof(struct dylib_module));
4937 new_mods64 = NULL;
4939 else{
4940 new_mods = NULL;
4941 new_mods64 = allocate(nmodtab * sizeof(struct dylib_module_64));
4944 inew_syms = 0;
4946 * This first loop through the module table sets the index and
4947 * counts of the local symbols for each module.
4949 for(i = 0; i < nmodtab; i++){
4951 * First put the existing local symbols into the new symbol
4952 * table.
4954 if(object->mh != NULL){
4955 new_mods[i].ilocalsym = inew_syms;
4956 new_mods[i].nlocalsym = 0;
4957 ilocalsym = mods[i].ilocalsym;
4958 nlocalsym = mods[i].nlocalsym;
4960 else{
4961 new_mods64[i].ilocalsym = inew_syms;
4962 new_mods64[i].nlocalsym = 0;
4963 ilocalsym = mods64[i].ilocalsym;
4964 nlocalsym = mods64[i].nlocalsym;
4966 for(j = ilocalsym; j < ilocalsym + nlocalsym; j++){
4967 if(object->mh != NULL){
4968 n_strx = symbols[j].n_un.n_strx;
4969 n_type = symbols[j].n_type;
4971 else{
4972 n_strx = symbols64[j].n_un.n_strx;
4973 n_type = symbols64[j].n_type;
4975 if((n_type & N_EXT) == 0){
4976 if(object->mh != NULL)
4977 new_symbols[inew_syms] = symbols[j];
4978 else
4979 new_symbols64[inew_syms] = symbols64[j];
4980 if(n_strx != 0){
4981 strcpy(q, strings + n_strx);
4982 if(object->mh != NULL)
4983 new_symbols[inew_syms].n_un.n_strx =
4984 q - new_strings;
4985 else
4986 new_symbols64[inew_syms].n_un.n_strx =
4987 q - new_strings;
4988 q += strlen(q) + 1;
4990 inew_syms++;
4991 saves[j] = inew_syms;
4992 if(object->mh != NULL)
4993 new_mods[i].nlocalsym++;
4994 else
4995 new_mods64[i].nlocalsym++;
4999 * Next put the global symbols that were changed into
5000 * non-global symbols into the new symbol table and moved their
5001 * counts to the local symbol counts.
5003 if(object->mh != NULL){
5004 iextdefsym = mods[i].iextdefsym;
5005 nextdefsym = mods[i].nextdefsym;
5007 else{
5008 iextdefsym = mods64[i].iextdefsym;
5009 nextdefsym = mods64[i].nextdefsym;
5011 for(j = iextdefsym; j < iextdefsym + nextdefsym; j++){
5012 if(object->mh != NULL){
5013 n_strx = symbols[j].n_un.n_strx;
5014 n_type = symbols[j].n_type;
5016 else{
5017 n_strx = symbols64[j].n_un.n_strx;
5018 n_type = symbols64[j].n_type;
5020 if((n_type & N_EXT) != 0){
5021 if(nmedits[j] == TRUE){
5023 * Change the new symbol to a private extern symbol
5024 * with the extern bit off.
5026 if(object->mh != NULL){
5027 new_symbols[inew_syms] = symbols[j];
5028 new_symbols[inew_syms].n_type |= N_PEXT;
5029 new_symbols[inew_syms].n_type &= ~N_EXT;
5031 else{
5032 new_symbols64[inew_syms] = symbols64[j];
5033 new_symbols64[inew_syms].n_type |= N_PEXT;
5034 new_symbols64[inew_syms].n_type &= ~N_EXT;
5036 if(n_strx != 0){
5037 strcpy(q, strings + n_strx);
5038 if(object->mh != NULL)
5039 new_symbols[inew_syms].n_un.n_strx =
5040 q - new_strings;
5041 else
5042 new_symbols64[inew_syms].n_un.n_strx =
5043 q - new_strings;
5044 q += strlen(q) + 1;
5046 inew_syms++;
5047 saves[j] = inew_syms;
5048 if(object->mh != NULL)
5049 new_mods[i].nlocalsym++;
5050 else
5051 new_mods64[i].nlocalsym++;
5057 * Next put the unchanged defined global symbols into the new
5058 * symbol table.
5060 for(i = 0; i < nmodtab; i++){
5061 if(object->mh != NULL){
5062 new_mods[i].iextdefsym = inew_syms;
5063 new_mods[i].nextdefsym = 0;
5064 iextdefsym = mods[i].iextdefsym;
5065 nextdefsym = mods[i].nextdefsym;
5067 else{
5068 new_mods64[i].iextdefsym = inew_syms;
5069 new_mods64[i].nextdefsym = 0;
5070 iextdefsym = mods64[i].iextdefsym;
5071 nextdefsym = mods64[i].nextdefsym;
5073 for(j = iextdefsym; j < iextdefsym + nextdefsym; j++){
5074 if(object->mh != NULL){
5075 n_strx = symbols[j].n_un.n_strx;
5076 n_type = symbols[j].n_type;
5078 else{
5079 n_strx = symbols64[j].n_un.n_strx;
5080 n_type = symbols64[j].n_type;
5082 if((n_type & N_EXT) != 0){
5083 if(nmedits[j] == FALSE){
5084 if(object->mh != NULL)
5085 new_symbols[inew_syms] = symbols[j];
5086 else
5087 new_symbols64[inew_syms] = symbols64[j];
5088 if(n_strx != 0){
5089 strcpy(p, strings + n_strx);
5090 if(object->mh != NULL)
5091 new_symbols[inew_syms].n_un.n_strx =
5092 p - new_strings;
5093 else
5094 new_symbols64[inew_syms].n_un.n_strx =
5095 p - new_strings;
5096 p += strlen(p) + 1;
5098 inew_syms++;
5099 saves[j] = inew_syms;
5100 if(object->mh != NULL)
5101 new_mods[i].nextdefsym++;
5102 else
5103 new_mods64[i].nextdefsym++;
5109 * Last put the undefined symbols into the new symbol table.
5111 for(i = 0; i < nsyms; i++){
5112 if(object->mh != NULL){
5113 n_strx = symbols[i].n_un.n_strx;
5114 n_type = symbols[i].n_type;
5116 else{
5117 n_strx = symbols64[i].n_un.n_strx;
5118 n_type = symbols64[i].n_type;
5120 if((n_type & N_EXT) != 0 &&
5121 ((n_type & N_TYPE) == N_UNDF ||
5122 (n_type & N_TYPE) == N_PBUD)){
5123 if(object->mh != NULL)
5124 new_symbols[inew_syms] = symbols[i];
5125 else
5126 new_symbols64[inew_syms] = symbols64[i];
5127 if(n_strx != 0){
5128 strcpy(p, strings + n_strx);
5129 if(object->mh != NULL)
5130 new_symbols[inew_syms].n_un.n_strx =
5131 p - new_strings;
5132 else
5133 new_symbols64[inew_syms].n_un.n_strx =
5134 p - new_strings;
5135 p += strlen(p) + 1;
5137 inew_syms++;
5138 saves[i] = inew_syms;
5143 * Place the module table's module names with the external strings
5144 * and set the names in the new module table. And then copy the
5145 * other unchanged fields.
5147 for(i = 0; i < nmodtab; i++){
5148 if(object->mh != NULL){
5149 strcpy(p, strings + mods[i].module_name);
5150 new_mods[i].module_name = p - new_strings;
5151 p += strlen(p) + 1;
5153 new_mods[i].irefsym = mods[i].irefsym;
5154 new_mods[i].nrefsym = mods[i].nrefsym;
5155 new_mods[i].iextrel = mods[i].iextrel;
5156 new_mods[i].nextrel = mods[i].nextrel;
5157 new_mods[i].iinit_iterm = mods[i].iinit_iterm;
5158 new_mods[i].ninit_nterm = mods[i].ninit_nterm;
5159 new_mods[i].objc_module_info_addr =
5160 mods[i].objc_module_info_addr;
5161 new_mods[i].objc_module_info_size =
5162 mods[i].objc_module_info_size;
5164 else{
5165 strcpy(p, strings + mods64[i].module_name);
5166 new_mods64[i].module_name = p - new_strings;
5167 p += strlen(p) + 1;
5169 new_mods64[i].irefsym = mods64[i].irefsym;
5170 new_mods64[i].nrefsym = mods64[i].nrefsym;
5171 new_mods64[i].iextrel = mods64[i].iextrel;
5172 new_mods64[i].nextrel = mods64[i].nextrel;
5173 new_mods64[i].iinit_iterm = mods64[i].iinit_iterm;
5174 new_mods64[i].ninit_nterm = mods64[i].ninit_nterm;
5175 new_mods64[i].objc_module_info_addr =
5176 mods64[i].objc_module_info_addr;
5177 new_mods64[i].objc_module_info_size =
5178 mods64[i].objc_module_info_size;
5183 * Update the reference table with the new symbol indexes for all
5184 * entries and change type of reference (the flags field) for those
5185 * symbols that got changed from globals to non-globals.
5187 new_nextrefsyms = nextrefsyms;
5188 new_refs = allocate(new_nextrefsyms *
5189 sizeof(struct dylib_reference));
5190 j = 0;
5191 for(i = 0; i < nextrefsyms; i++){
5192 if(nmedits[refs[i].isym] == TRUE){
5193 if(refs[i].flags == REFERENCE_FLAG_DEFINED)
5194 new_refs[i].flags =
5195 REFERENCE_FLAG_PRIVATE_DEFINED;
5196 else if(refs[i].flags == REFERENCE_FLAG_UNDEFINED_NON_LAZY)
5197 new_refs[i].flags =
5198 REFERENCE_FLAG_PRIVATE_UNDEFINED_NON_LAZY;
5199 else if(refs[i].flags == REFERENCE_FLAG_UNDEFINED_LAZY)
5200 new_refs[i].flags =
5201 REFERENCE_FLAG_PRIVATE_UNDEFINED_LAZY;
5202 else
5203 new_refs[i].flags = refs[i].flags;
5205 else{
5206 new_refs[i].flags = refs[i].flags;
5208 new_refs[i].isym = saves[refs[i].isym] - 1;
5212 * Create a new dylib table of contents without the global symbols
5213 * that got turned into non-globals.
5215 new_ntoc = ntoc - nchanged_globals;
5216 new_tocs = allocate(new_ntoc *
5217 sizeof(struct dylib_table_of_contents));
5218 k = 0;
5219 for(i = 0; i < ntoc; i++){
5220 if(tocs[i].symbol_index >= nsyms){
5221 error_arch(arch, member, "bad symbol index for table of "
5222 "contents table entry %d in: ", i);
5223 return(FALSE);
5225 if(nmedits[tocs[i].symbol_index] == FALSE){
5226 new_tocs[k].symbol_index = saves[tocs[i].symbol_index] - 1;
5227 new_tocs[k].module_index = tocs[i].module_index;
5228 k++;
5233 * If is not a dynamic library so all global symbols changed into
5234 * statics can be moved to the end of the local symbols. If the pflag
5235 * is set then the changed symbols remain global and just get the
5236 * private extern bit set.
5238 else{
5240 * First put the existing local symbols into the new symbol table.
5242 inew_syms = 0;
5243 for(i = 0; i < nsyms; i++){
5244 if(object->mh != NULL){
5245 n_strx = symbols[i].n_un.n_strx;
5246 n_type = symbols[i].n_type;
5248 else{
5249 n_strx = symbols64[i].n_un.n_strx;
5250 n_type = symbols64[i].n_type;
5252 if((n_type & N_EXT) == 0){
5253 if(object->mh != NULL)
5254 new_symbols[inew_syms] = symbols[i];
5255 else
5256 new_symbols64[inew_syms] = symbols64[i];
5257 if(n_strx != 0){
5258 strcpy(q, strings + n_strx);
5259 if(object->mh != NULL)
5260 new_symbols[inew_syms].n_un.n_strx =
5261 q - new_strings;
5262 else
5263 new_symbols64[inew_syms].n_un.n_strx =
5264 q - new_strings;
5265 q += strlen(q) + 1;
5267 inew_syms++;
5268 saves[i] = inew_syms;
5272 * Next put the global symbols that were changed into statics
5273 * symbols into the new symbol table.
5275 if(pflag == FALSE){
5276 for(i = 0; i < nsyms; i++){
5277 if(object->mh != NULL){
5278 n_strx = symbols[i].n_un.n_strx;
5279 n_type = symbols[i].n_type;
5281 else{
5282 n_strx = symbols64[i].n_un.n_strx;
5283 n_type = symbols64[i].n_type;
5285 if((n_type & N_EXT) != 0){
5286 if(nmedits[i] == TRUE){
5288 * Change the new symbol to not be an extern symbol
5289 * by turning off the extern bit.
5291 if(object->mh != NULL){
5292 new_symbols[inew_syms] = symbols[i];
5293 new_symbols[inew_syms].n_type &= ~N_EXT;
5294 new_symbols[inew_syms].n_desc &= ~N_WEAK_DEF;
5296 else{
5297 new_symbols64[inew_syms] = symbols64[i];
5298 new_symbols64[inew_syms].n_type &= ~N_EXT;
5299 new_symbols64[inew_syms].n_desc &= ~N_WEAK_DEF;
5301 if(n_strx != 0){
5302 strcpy(q, strings + n_strx);
5303 if(object->mh != NULL)
5304 new_symbols[inew_syms].n_un.n_strx =
5305 q - new_strings;
5306 else
5307 new_symbols64[inew_syms].n_un.n_strx =
5308 q - new_strings;
5309 q += strlen(q) + 1;
5311 inew_syms++;
5312 saves[i] = inew_syms;
5318 * Last put the unchanged global symbols into the new symbol table
5319 * and symbols changed into private externs.
5321 for(i = 0; i < nsyms; i++){
5322 if(object->mh != NULL){
5323 n_strx = symbols[i].n_un.n_strx;
5324 n_type = symbols[i].n_type;
5326 else{
5327 n_strx = symbols64[i].n_un.n_strx;
5328 n_type = symbols64[i].n_type;
5330 if((n_type & N_EXT) != 0){
5331 if(nmedits[i] == FALSE || pflag == TRUE){
5332 if(object->mh != NULL)
5333 new_symbols[inew_syms] = symbols[i];
5334 else
5335 new_symbols64[inew_syms] = symbols64[i];
5336 if(nmedits[i] == TRUE && pflag == TRUE){
5338 * Change the new symbol to be a private extern
5339 * symbol by turning on the private extern bit.
5341 if(object->mh != NULL)
5342 new_symbols[inew_syms].n_type |= N_PEXT;
5343 else
5344 new_symbols64[inew_syms].n_type |= N_PEXT;
5346 if(n_strx != 0){
5347 strcpy(p, strings + n_strx);
5348 if(object->mh != NULL)
5349 new_symbols[inew_syms].n_un.n_strx =
5350 p - new_strings;
5351 else
5352 new_symbols64[inew_syms].n_un.n_strx =
5353 p - new_strings;
5354 p += strlen(p) + 1;
5356 inew_syms++;
5357 saves[i] = inew_syms;
5363 if(sections != NULL)
5364 free(sections);
5365 if(sections64 != NULL)
5366 free(sections64);
5368 if(errors == 0)
5369 return(TRUE);
5370 else
5371 return(FALSE);
5375 * Function for qsort for comparing global symbol names.
5377 static
5379 cmp_qsort_global(
5380 const struct nlist **sym1,
5381 const struct nlist **sym2)
5383 return(strcmp(global_strings + (*sym1)->n_un.n_strx,
5384 global_strings + (*sym2)->n_un.n_strx));
5387 static
5389 cmp_qsort_global_64(
5390 const struct nlist_64 **sym1,
5391 const struct nlist_64 **sym2)
5393 return(strcmp(global_strings + (*sym1)->n_un.n_strx,
5394 global_strings + (*sym2)->n_un.n_strx));
5398 * Function for bsearch for finding a global symbol that matches a stab name.
5400 static
5402 cmp_bsearch_global_stab(
5403 const char *name,
5404 const struct nlist **sym)
5407 * The +1 is for the '_' on the global symbol that is not on the
5408 * stab string that is trying to be matched.
5410 return(strcmp(name, global_strings + (*sym)->n_un.n_strx + 1));
5413 static
5415 cmp_bsearch_global_stab_64(
5416 const char *name,
5417 const struct nlist_64 **sym)
5420 * The +1 is for the '_' on the global symbol that is not on the
5421 * stab string that is trying to be matched.
5423 return(strcmp(name, global_strings + (*sym)->n_un.n_strx + 1));
5427 * Function for bsearch for finding a global symbol that matches a stab name
5428 * in the debug map.
5430 static
5432 cmp_bsearch_global(
5433 const char *name,
5434 const struct nlist **sym)
5436 return(strcmp(name, global_strings + (*sym)->n_un.n_strx));
5439 static
5441 cmp_bsearch_global_64(
5442 const char *name,
5443 const struct nlist_64 **sym)
5445 return(strcmp(name, global_strings + (*sym)->n_un.n_strx));
5447 #endif /* defined(NMEDIT) */