Move the cctools source version number into version.mak
[striptease.git] / strip.c
blobc32f5c8dc32eb5ecb8b05b3c952426e17fa56f30
1 /*
2 * Copyright (c) 1999 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
11 * file.
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
21 * @APPLE_LICENSE_HEADER_END@
24 * The strip(1) and nmedit(l) program. This understands only Mach-O format
25 * files (with the restriction the symbol table is at the end of the file) and
26 * fat files with Mach-O files in them.
28 #include <stdio.h>
29 #include <stdlib.h>
30 #include <string.h>
31 #include <limits.h>
32 #include <ctype.h>
33 #include <libc.h>
34 #include <sys/types.h>
35 #include <sys/stat.h>
36 #include <mach-o/loader.h>
37 #include <mach-o/reloc.h>
38 #include <mach-o/nlist.h>
39 #include <mach-o/stab.h>
40 #include "stuff/breakout.h"
41 #include "stuff/allocate.h"
42 #include "stuff/errors.h"
43 #include "stuff/rnd.h"
44 #include "stuff/reloc.h"
45 #include "stuff/reloc.h"
46 #include "stuff/symbol_list.h"
47 #include "stuff/unix_standard_mode.h"
48 #include "stuff/execute.h"
49 #ifdef TRIE_SUPPORT
50 #include <mach-o/prune_trie.h>
51 #endif /* TRIE_SUPPORT */
53 /* These are set from the command line arguments */
54 __private_extern__
55 char *progname = NULL; /* name of the program for error messages (argv[0]) */
56 static char *output_file;/* name of the output file */
57 static char *sfile; /* filename of global symbol names to keep */
58 static char *Rfile; /* filename of global symbol names to remove */
59 static uint32_t Aflag; /* save only absolute symbols with non-zero value and
60 .objc_class_name_* symbols */
61 static uint32_t iflag; /* -i ignore symbols in -s file not in object */
62 #ifdef NMEDIT
63 static uint32_t pflag; /* make all defined global symbols private extern */
64 #else /* !defined(NMEDIT) */
65 static char *dfile; /* filename of filenames of debugger symbols to keep */
66 static uint32_t uflag; /* save undefined symbols */
67 static uint32_t rflag; /* save symbols referenced dynamically */
68 static uint32_t nflag; /* save N_SECT global symbols */
69 static uint32_t Sflag; /* -S strip only debugger symbols N_STAB */
70 static uint32_t xflag; /* -x strip non-globals */
71 static uint32_t Xflag; /* -X strip local symbols with 'L' names */
72 static uint32_t cflag; /* -c strip section contents from dynamic libraries
73 files to create stub libraries */
74 static uint32_t no_uuid;/* -no_uuid strip LC_UUID load commands */
75 static uint32_t vflag; /* -v for verbose debugging ld -r executions */
76 static uint32_t lflag; /* -l do ld -r executions even if it has bugs */
77 static uint32_t strip_all = 1;
79 * This is set on an object by object basis if the strip_all flag is still set
80 * and the object is an executable that is for use with the dynamic linker.
81 * This has the same effect as -r and -u.
83 static enum bool default_dyld_executable = FALSE;
84 #endif /* NMEDIT */
87 * Data structures to perform selective stripping of symbol table entries.
88 * save_symbols is the names of the symbols from the -s <file> argument.
89 * remove_symbols is the names of the symbols from the -R <file> argument.
91 static struct symbol_list *save_symbols = NULL;
92 static uint32_t nsave_symbols = 0;
93 static struct symbol_list *remove_symbols = NULL;
94 static uint32_t nremove_symbols = 0;
97 * saves points to an array of uint32_t's that is allocated. This array is a
98 * map of old symbol indexes to new symbol indexes. The new symbol indexes are
99 * plus 1 and zero value means that old symbol is not in the new symbol table.
100 * ref_saves is used in the same way but for the reference table.
101 * nmedits is an array and indexed by the symbol index the value indicates if
102 * the symbol was edited and turned into a non-global.
104 static int32_t *saves = NULL;
105 #ifndef NMEDIT
106 static int32_t *ref_saves = NULL;
107 #else
108 static enum bool *nmedits = NULL;
109 #endif
112 * These hold pointers to the symbol, string and indirect tables being worked on
113 * by strip_object and strip_symtab() from an input object file or possiblity
114 * changed to an ld -r (-S or -x) file by make_ld_r_object().
116 static struct nlist *symbols = NULL;
117 static struct nlist_64 *symbols64 = NULL;
118 static uint32_t nsyms = 0;
119 static char *strings = NULL;
120 static uint32_t strsize = 0;
121 static uint32_t *indirectsyms = NULL;
122 static uint32_t nindirectsyms = 0;
125 * These hold the new symbol and string table created by strip_symtab()
126 * and the new counts of local, defined external and undefined symbols.
128 static struct nlist *new_symbols = NULL;
129 static struct nlist_64 *new_symbols64 = NULL;
130 static uint32_t new_nsyms = 0;
131 static char *new_strings = NULL;
132 static uint32_t new_strsize = 0;
133 static uint32_t new_nlocalsym = 0;
134 static uint32_t new_nextdefsym = 0;
135 static uint32_t new_nundefsym = 0;
136 #if defined(TRIE_SUPPORT) && !defined(NMEDIT)
138 * The index into the new symbols where the defined external start.
140 static uint32_t inew_nextdefsym = 0;
141 #endif
144 * These hold the new table of contents, reference table and module table for
145 * dylibs.
147 static struct dylib_table_of_contents *new_tocs = NULL;
148 static uint32_t new_ntoc = 0;
149 static struct dylib_reference *new_refs = NULL;
150 static uint32_t new_nextrefsyms = 0;
151 #ifdef NMEDIT
152 static struct dylib_module *new_mods = NULL;
153 static struct dylib_module_64 *new_mods64 = NULL;
154 static uint32_t new_nmodtab = 0;
155 #endif
157 #ifndef NMEDIT
159 * The list of file names to save debugging symbols from.
161 static char **debug_filenames = NULL;
162 static uint32_t ndebug_filenames = 0;
163 struct undef_map {
164 uint32_t index;
165 struct nlist symbol;
167 struct undef_map64 {
168 uint32_t index;
169 struct nlist_64 symbol64;
171 static char *qsort_strings = NULL;
172 #endif /* !defined(NMEDIT) */
175 /* Internal routines */
176 static void usage(
177 void);
179 static void strip_file(
180 char *input_file,
181 struct arch_flag *arch_flags,
182 uint32_t narch_flags,
183 enum bool all_archs);
185 static void strip_arch(
186 struct arch *archs,
187 uint32_t narchs,
188 struct arch_flag *arch_flags,
189 uint32_t narch_flags,
190 enum bool all_archs);
192 static void strip_object(
193 struct arch *arch,
194 struct member *member,
195 struct object *object);
197 static uint32_t get_starting_syminfo_offset(
198 struct object *object);
200 static void check_object_relocs(
201 struct arch *arch,
202 struct member *member,
203 struct object *object,
204 char *segname,
205 char *sectname,
206 uint64_t sectsize,
207 char *contents,
208 struct relocation_info *relocs,
209 uint32_t nreloc,
210 struct nlist *symbols,
211 struct nlist_64 *symbols64,
212 uint32_t nsyms,
213 char *strings,
214 int32_t *missing_reloc_symbols,
215 enum byte_sex host_byte_sex);
217 static void check_indirect_symtab(
218 struct arch *arch,
219 struct member *member,
220 struct object *object,
221 uint32_t nitems,
222 uint32_t reserved1,
223 uint32_t section_type,
224 char *contents,
225 struct nlist *symbols,
226 struct nlist_64 *symbols64,
227 uint32_t nsyms,
228 char *strings,
229 int32_t *missing_reloc_symbols,
230 enum byte_sex host_byte_sex);
232 #ifndef NMEDIT
233 static enum bool strip_symtab(
234 struct arch *arch,
235 struct member *member,
236 struct object *object,
237 struct dylib_table_of_contents *tocs,
238 uint32_t ntoc,
239 struct dylib_module *mods,
240 struct dylib_module_64 *mods64,
241 uint32_t nmodtab,
242 struct dylib_reference *refs,
243 uint32_t nextrefsyms);
245 #ifdef TRIE_SUPPORT
246 static int prune(
247 const char *name);
248 #endif /* TRIE_SUPPORT */
250 static void make_ld_r_object(
251 struct arch *arch,
252 struct member *member,
253 struct object *object);
255 static void strip_LC_UUID_commands(
256 struct arch *arch,
257 struct member *member,
258 struct object *object);
260 #ifndef NMEDIT
261 static void strip_LC_CODE_SIGNATURE_commands(
262 struct arch *arch,
263 struct member *member,
264 struct object *object);
265 #endif /* !(NMEDIT) */
267 static enum bool private_extern_reference_by_module(
268 uint32_t symbol_index,
269 struct dylib_reference *refs,
270 uint32_t nextrefsyms);
272 static enum bool symbol_pointer_used(
273 uint32_t symbol_index,
274 uint32_t *indirectsyms,
275 uint32_t nindirectsyms);
277 static int cmp_qsort_undef_map(
278 const struct undef_map *sym1,
279 const struct undef_map *sym2);
281 static int cmp_qsort_undef_map_64(
282 const struct undef_map64 *sym1,
283 const struct undef_map64 *sym2);
284 #endif /* !defined(NMEDIT) */
286 #ifdef NMEDIT
287 static enum bool edit_symtab(
288 struct arch *arch,
289 struct member *member,
290 struct object *object,
291 struct nlist *symbols,
292 struct nlist_64 *symbols64,
293 uint32_t nsyms,
294 char *strings,
295 uint32_t strsize,
296 struct dylib_table_of_contents *tocs,
297 uint32_t ntoc,
298 struct dylib_module *mods,
299 struct dylib_module_64 *mods64,
300 uint32_t nmodtab,
301 struct dylib_reference *refs,
302 uint32_t nextrefsyms);
303 #endif /* NMEDIT */
305 #ifndef NMEDIT
306 static void setup_debug_filenames(
307 char *dfile);
309 static int cmp_qsort_filename(
310 const char **name1,
311 const char **name2);
313 static int cmp_bsearch_filename(
314 const char *name1,
315 const char **name2);
316 #endif /* NMEDIT */
318 #ifdef NMEDIT
320 * This variable and routines are used for nmedit(1) only.
322 static char *global_strings = NULL;
324 static int cmp_qsort_global(
325 const struct nlist **sym1,
326 const struct nlist **sym2);
328 static int cmp_qsort_global_64(
329 const struct nlist_64 **sym1,
330 const struct nlist_64 **sym2);
332 static int cmp_bsearch_global_stab(
333 const char *name,
334 const struct nlist **sym);
336 static int cmp_bsearch_global_stab_64(
337 const char *name,
338 const struct nlist_64 **sym);
340 static int cmp_bsearch_global(
341 const char *name,
342 const struct nlist **sym);
344 static int cmp_bsearch_global_64(
345 const char *name,
346 const struct nlist_64 **sym);
347 #endif /* NMEDIT */
349 /* apple_version is created by the libstuff/Makefile */
350 extern char apple_version[];
351 char *version = apple_version;
354 main(
355 int argc,
356 char *argv[],
357 char *envp[])
359 int i;
360 uint32_t j, args_left, files_specified;
361 struct arch_flag *arch_flags;
362 uint32_t narch_flags;
363 enum bool all_archs;
364 struct symbol_list *sp;
366 progname = argv[0];
368 arch_flags = NULL;
369 narch_flags = 0;
370 all_archs = FALSE;
372 files_specified = 0;
373 args_left = 1;
374 for (i = 1; i < argc; i++){
375 if(argv[i][0] == '-'){
376 if(argv[i][1] == '\0'){
377 args_left = 0;
378 break;
380 if(strcmp(argv[i], "-o") == 0){
381 if(i + 1 >= argc)
382 fatal("-o requires an argument");
383 if(output_file != NULL)
384 fatal("only one -o option allowed");
385 output_file = argv[i + 1];
386 i++;
388 else if(strcmp(argv[i], "-s") == 0){
389 if(i + 1 >= argc)
390 fatal("-s requires an argument");
391 if(sfile != NULL)
392 fatal("only one -s option allowed");
393 sfile = argv[i + 1];
394 i++;
396 else if(strcmp(argv[i], "-R") == 0){
397 if(i + 1 >= argc)
398 fatal("-R requires an argument");
399 if(Rfile != NULL)
400 fatal("only one -R option allowed");
401 Rfile = argv[i + 1];
402 i++;
404 #ifndef NMEDIT
405 else if(strcmp(argv[i], "-d") == 0){
406 if(i + 1 >= argc)
407 fatal("-d requires an argument");
408 if(dfile != NULL)
409 fatal("only one -d option allowed");
410 dfile = argv[i + 1];
411 i++;
413 else if(strcmp(argv[i], "-no_uuid") == 0){
414 no_uuid = 1;
416 #endif /* !defined(NMEDIT) */
417 else if(strcmp(argv[i], "-arch") == 0){
418 if(i + 1 == argc){
419 error("missing argument(s) to %s option", argv[i]);
420 usage();
422 if(strcmp("all", argv[i+1]) == 0){
423 all_archs = TRUE;
425 else{
426 arch_flags = reallocate(arch_flags,
427 (narch_flags + 1) * sizeof(struct arch_flag));
428 if(get_arch_from_flag(argv[i+1],
429 arch_flags + narch_flags) == 0){
430 error("unknown architecture specification flag: "
431 "%s %s", argv[i], argv[i+1]);
432 arch_usage();
433 usage();
435 for(j = 0; j < narch_flags; j++){
436 if(arch_flags[j].cputype ==
437 arch_flags[narch_flags].cputype &&
438 (arch_flags[j].cpusubtype & ~CPU_SUBTYPE_MASK) ==
439 (arch_flags[narch_flags].cpusubtype &
440 ~CPU_SUBTYPE_MASK) &&
441 strcmp(arch_flags[j].name,
442 arch_flags[narch_flags].name) == 0)
443 break;
445 if(j == narch_flags)
446 narch_flags++;
448 i++;
450 else{
451 for(j = 1; argv[i][j] != '\0'; j++){
452 switch(argv[i][j]){
453 #ifdef NMEDIT
454 case 'p':
455 pflag = 1;
456 break;
457 #else /* !defined(NMEDIT) */
458 case 'S':
459 Sflag = 1;
460 strip_all = 0;
461 break;
462 case 'X':
463 Xflag = 1;
464 strip_all = 0;
465 break;
466 case 'x':
467 xflag = 1;
468 strip_all = 0;
469 break;
470 case 'i':
471 iflag = 1;
472 break;
473 case 'u':
474 uflag = 1;
475 strip_all = 0;
476 break;
477 case 'r':
478 rflag = 1;
479 strip_all = 0;
480 break;
481 case 'n':
482 nflag = 1;
483 strip_all = 0;
484 break;
485 #endif /* !defined(NMEDIT) */
486 case 'A':
487 Aflag = 1;
488 #ifndef NMEDIT
489 strip_all = 0;
490 #endif /* !defined(NMEDIT) */
491 break;
492 #ifndef NMEDIT
493 case 'c':
494 cflag = 1;
495 strip_all = 0;
496 break;
497 case 'v':
498 vflag = 1;
499 break;
500 case 'l':
501 lflag = 1;
502 break;
503 #endif /* NMEDIT */
504 default:
505 error("unrecognized option: %s", argv[i]);
506 usage();
511 else
512 files_specified++;
514 if(args_left == 0)
515 files_specified += argc - (i + 1);
517 if(files_specified > 1 && output_file != NULL){
518 error("-o <filename> can only be used when one file is specified");
519 usage();
522 if(sfile){
523 setup_symbol_list(sfile, &save_symbols, &nsave_symbols);
525 #ifdef NMEDIT
526 else{
527 if(Rfile == NULL && pflag == 0){
528 error("-s <filename>, -R <filename> or -p argument required");
529 usage();
532 #endif /* NMEDIT */
534 if(Rfile){
535 setup_symbol_list(Rfile, &remove_symbols, &nremove_symbols);
536 if(sfile){
537 for(j = 0; j < nremove_symbols ; j++){
538 sp = bsearch(remove_symbols[j].name,
539 save_symbols, nsave_symbols,
540 sizeof(struct symbol_list),
541 (int (*)(const void *, const void *))
542 symbol_list_bsearch);
543 if(sp != NULL){
544 error("symbol name: %s is listed in both -s %s and -R "
545 "%s files (can't be both saved and removed)",
546 remove_symbols[j].name, sfile, Rfile);
549 if(errors)
550 exit(EXIT_FAILURE);
554 /* the default when no -arch flags is present is to strip all archs */
555 if(narch_flags == 0)
556 all_archs = TRUE;
558 #ifndef NMEDIT
559 if(dfile){
560 setup_debug_filenames(dfile);
562 #endif /* !defined(NMEDIT) */
564 files_specified = 0;
565 args_left = 1;
566 for (i = 1; i < argc; i++) {
567 if(args_left && argv[i][0] == '-'){
568 if(argv[i][1] == '\0')
569 args_left = 0;
570 else if(strcmp(argv[i], "-o") == 0 ||
571 strcmp(argv[i], "-s") == 0 ||
572 strcmp(argv[i], "-R") == 0 ||
573 #ifndef NMEDIT
574 strcmp(argv[i], "-d") == 0 ||
575 #endif /* !defined(NMEDIT) */
576 strcmp(argv[i], "-arch") == 0)
577 i++;
579 else{
580 char resolved_path[PATH_MAX + 1];
582 if(realpath(argv[i], resolved_path) == NULL)
583 strip_file(argv[i], arch_flags, narch_flags, all_archs);
584 else
585 strip_file(resolved_path, arch_flags,narch_flags,all_archs);
586 files_specified++;
589 if(files_specified == 0)
590 fatal("no files specified");
592 if(errors)
593 return(EXIT_FAILURE);
594 else
595 return(EXIT_SUCCESS);
598 static
599 void
600 usage(
601 void)
603 #ifndef NMEDIT
604 fprintf(stderr, "Usage: %s [-AnuSXx] [-] [-d filename] [-s filename] "
605 "[-R filename] [-o output] file [...] \n", progname);
606 #else /* defined(NMEDIT) */
607 fprintf(stderr, "Usage: %s -s filename [-R filename] [-p] [-A] [-] "
608 "[-o output] file [...] \n",
609 progname);
610 #endif /* NMEDIT */
611 exit(EXIT_FAILURE);
614 static
615 void
616 strip_file(
617 char *input_file,
618 struct arch_flag *arch_flags,
619 uint32_t narch_flags,
620 enum bool all_archs)
622 struct ofile *ofile;
623 struct arch *archs;
624 uint32_t narchs;
625 struct stat stat_buf;
626 uint32_t previous_errors;
627 enum bool unix_standard_mode;
628 int cwd_fd;
629 char *rename_file;
630 #ifndef NMEDIT
631 char *p;
632 #endif
634 archs = NULL;
635 narchs = 0;
636 previous_errors = errors;
637 errors = 0;
639 /* breakout the file for processing */
640 ofile = breakout(input_file, &archs, &narchs, FALSE);
641 if(errors)
642 return;
644 /* checkout the file for symbol table replacement processing */
645 checkout(archs, narchs);
647 /* process the symbols in the input file */
648 strip_arch(archs, narchs, arch_flags, narch_flags, all_archs);
649 if(errors){
650 free_archs(archs, narchs);
651 ofile_unmap(ofile);
652 return;
655 /* create the output file */
656 if(stat(input_file, &stat_buf) == -1)
657 system_error("can't stat input file: %s", input_file);
658 if(output_file != NULL){
659 writeout(archs, narchs, output_file, stat_buf.st_mode & 0777,
660 TRUE, FALSE, FALSE, NULL);
662 else{
663 unix_standard_mode = get_unix_standard_mode();
664 rename_file = NULL;
665 cwd_fd = -1;
666 #ifdef NMEDIT
667 output_file = makestr(input_file, ".nmedit", NULL);
668 #else /* !defined(NMEDIT) */
670 * In UNIX standard conformance mode we are not allowed to replace
671 * a file that is not writeable.
673 if(unix_standard_mode == TRUE &&
674 access(input_file, W_OK) == -1){
675 system_error("file: %s is not writable", input_file);
676 goto strip_file_return;
678 output_file = makestr(input_file, ".strip", NULL);
681 * The UNIX standard conformance test suite expects files of
682 * MAXPATHLEN to work.
684 if(strlen(output_file) >= MAXPATHLEN){
686 * If there is a directory path in the name try to change
687 * the current working directory to that path.
689 if((p = rindex(output_file, '/')) != NULL){
690 if((cwd_fd = open(".", O_RDONLY, 0)) == -1){
691 system_error("can't open current working directory");
692 goto strip_file_return;
694 *p = '\0';
695 if(chdir(output_file) == -1){
696 system_error("can't change current working directory "
697 "to: %s", output_file);
698 goto strip_file_return;
700 p = rindex(input_file, '/');
701 rename_file = makestr(p + 1, NULL);
704 * Create what might be a short enough name.
706 free(output_file);
707 output_file = makestr("strip.XXXXXX", NULL);
708 output_file = mktemp(output_file);
710 #endif /* NMEDIT */
711 writeout(archs, narchs, output_file, stat_buf.st_mode & 0777,
712 TRUE, FALSE, FALSE, NULL);
713 if(rename_file != NULL){
714 if(rename(output_file, rename_file) == -1)
715 system_error("can't move temporary file: %s to file: %s",
716 output_file, rename_file);
717 free(rename_file);
719 else{
720 if(rename(output_file, input_file) == -1)
721 system_error("can't move temporary file: %s to input "
722 "file: %s", output_file, input_file);
724 free(output_file);
725 output_file = NULL;
728 * If we changed the current working directory change back to
729 * the previous working directory.
731 if(cwd_fd != -1){
732 if(fchdir(cwd_fd) == -1)
733 system_error("can't change back to previous working "
734 "directory");
735 if(close(cwd_fd) == -1)
736 system_error("can't close previous working directory");
740 #ifndef NMEDIT
741 strip_file_return:
742 #endif /* !defined(NMEDIT) */
743 /* clean-up data structures */
744 free_archs(archs, narchs);
745 ofile_unmap(ofile);
747 errors += previous_errors;
750 static
751 void
752 strip_arch(
753 struct arch *archs,
754 uint32_t narchs,
755 struct arch_flag *arch_flags,
756 uint32_t narch_flags,
757 enum bool all_archs)
759 uint32_t i, j, k, offset, size, missing_syms;
760 cpu_type_t cputype;
761 cpu_subtype_t cpusubtype;
762 struct arch_flag host_arch_flag;
763 enum bool arch_process, any_processing, *arch_flag_processed, family;
764 const struct arch_flag *family_arch_flag;
767 * Using the specified arch_flags process specified objects for those
768 * architecures.
770 any_processing = FALSE;
771 arch_flag_processed = NULL;
772 if(narch_flags != 0)
773 arch_flag_processed = allocate(narch_flags * sizeof(enum bool));
774 memset(arch_flag_processed, '\0', narch_flags * sizeof(enum bool));
775 for(i = 0; i < narchs; i++){
777 * Determine the architecture (cputype and cpusubtype) of arch[i]
779 cputype = 0;
780 cpusubtype = 0;
781 if(archs[i].type == OFILE_ARCHIVE){
782 for(j = 0; j < archs[i].nmembers; j++){
783 if(archs[i].members[j].type == OFILE_Mach_O){
784 cputype = archs[i].members[j].object->mh_cputype;
785 cpusubtype = archs[i].members[j].object->mh_cpusubtype;
786 break;
790 else if(archs[i].type == OFILE_Mach_O){
791 cputype = archs[i].object->mh_cputype;
792 cpusubtype = archs[i].object->mh_cpusubtype;
794 else if(archs[i].fat_arch != NULL){
795 cputype = archs[i].fat_arch->cputype;
796 cpusubtype = archs[i].fat_arch->cpusubtype;
798 arch_process = FALSE;
799 if(all_archs == TRUE){
800 arch_process = TRUE;
802 else if(narch_flags != 0){
803 family = FALSE;
804 if(narch_flags == 1){
805 family_arch_flag =
806 get_arch_family_from_cputype(arch_flags[0].cputype);
807 if(family_arch_flag != NULL)
808 family = (enum bool)
809 ((family_arch_flag->cpusubtype & ~CPU_SUBTYPE_MASK) ==
810 (arch_flags[0].cpusubtype & ~CPU_SUBTYPE_MASK));
812 for(j = 0; j < narch_flags; j++){
813 if(arch_flags[j].cputype == cputype &&
814 ((arch_flags[j].cpusubtype & ~CPU_SUBTYPE_MASK) ==
815 (cpusubtype & ~CPU_SUBTYPE_MASK) ||
816 family == TRUE)){
817 arch_process = TRUE;
818 arch_flag_processed[j] = TRUE;
819 break;
823 else{
824 (void)get_arch_from_host(&host_arch_flag, NULL);
825 if(host_arch_flag.cputype == cputype &&
826 (host_arch_flag.cpusubtype & ~CPU_SUBTYPE_MASK) ==
827 (cpusubtype & ~CPU_SUBTYPE_MASK))
828 arch_process = TRUE;
830 if(narchs != 1 && arch_process == FALSE)
831 continue;
832 any_processing = TRUE;
835 * Now this arch[i] has been selected to be processed so process it
836 * according to its type.
838 if(archs[i].type == OFILE_ARCHIVE){
839 for(j = 0; j < archs[i].nmembers; j++){
840 if(archs[i].members[j].type == OFILE_Mach_O){
841 strip_object(archs + i, archs[i].members + j,
842 archs[i].members[j].object);
845 missing_syms = 0;
846 if(iflag == 0){
847 for(k = 0; k < nsave_symbols; k++){
848 if(save_symbols[k].seen == FALSE){
849 if(missing_syms == 0){
850 error_arch(archs + i, NULL, "symbols names "
851 "listed in: %s not in: ", sfile);
852 missing_syms = 1;
854 fprintf(stderr, "%s\n", save_symbols[k].name);
858 for(k = 0; k < nsave_symbols; k++){
859 save_symbols[k].seen = FALSE;
861 missing_syms = 0;
862 if(iflag == 0){
863 for(k = 0; k < nremove_symbols; k++){
864 if(remove_symbols[k].seen == FALSE){
865 if(missing_syms == 0){
866 error_arch(archs + i, NULL, "symbols names "
867 "listed in: %s not defined in: ",
868 Rfile);
869 missing_syms = 1;
871 fprintf(stderr, "%s\n", remove_symbols[k].name);
875 for(k = 0; k < nremove_symbols; k++){
876 remove_symbols[k].seen = FALSE;
879 * Reset the library offsets and size.
881 offset = 0;
882 for(j = 0; j < archs[i].nmembers; j++){
883 archs[i].members[j].offset = offset;
884 size = 0;
885 if(archs[i].members[j].member_long_name == TRUE){
886 size = rnd(archs[i].members[j].member_name_size, 8) +
887 (rnd(sizeof(struct ar_hdr), 8) -
888 sizeof(struct ar_hdr));
889 archs[i].toc_long_name = TRUE;
891 if(archs[i].members[j].object != NULL){
892 size +=
893 rnd(archs[i].members[j].object->object_size -
894 archs[i].members[j].object->input_sym_info_size +
895 archs[i].members[j].object->output_sym_info_size,
897 sprintf(archs[i].members[j].ar_hdr->ar_size, "%-*ld",
898 (int)sizeof(archs[i].members[j].ar_hdr->ar_size),
899 (long)(size));
901 * This has to be done by hand because sprintf puts a
902 * null at the end of the buffer.
904 memcpy(archs[i].members[j].ar_hdr->ar_fmag, ARFMAG,
905 (int)sizeof(archs[i].members[j].ar_hdr->ar_fmag));
907 else{
908 size += archs[i].members[j].unknown_size;
910 offset += sizeof(struct ar_hdr) + size;
912 archs[i].library_size = offset;
914 else if(archs[i].type == OFILE_Mach_O){
915 strip_object(archs + i, NULL, archs[i].object);
917 else {
918 warning_arch(archs + i, NULL, "can't process non-object and "
919 "non-archive file: ");
920 return;
923 if(all_archs == FALSE && narch_flags != 0){
924 for(i = 0; i < narch_flags; i++){
925 if(arch_flag_processed[i] == FALSE)
926 error("file: %s does not contain architecture: %s",
927 archs[0].file_name, arch_flags[i].name);
929 free(arch_flag_processed);
931 if(any_processing == FALSE)
932 fatal("no processing done on input file: %s (specify a -arch flag)",
933 archs[0].file_name);
936 static
937 void
938 strip_object(
939 struct arch *arch,
940 struct member *member,
941 struct object *object)
943 enum byte_sex host_byte_sex;
944 uint32_t offset;
945 struct dylib_table_of_contents *tocs;
946 uint32_t ntoc;
947 struct dylib_module *mods;
948 struct dylib_module_64 *mods64;
949 uint32_t nmodtab;
950 struct dylib_reference *refs;
951 uint32_t nextrefsyms;
952 uint32_t i, j;
953 struct load_command *lc;
954 struct segment_command *sg;
955 struct segment_command_64 *sg64;
956 struct section *s;
957 struct section_64 *s64;
958 struct relocation_info *relocs;
959 struct scattered_relocation_info *sreloc;
960 int32_t missing_reloc_symbols;
961 uint32_t stride, section_type, nitems;
962 char *contents;
963 uint32_t dyld_info_start;
964 uint32_t dyld_info_end;
965 #ifndef NMEDIT
966 uint32_t flags;
967 uint32_t k;
968 #endif
969 uint32_t ncmds;
971 host_byte_sex = get_host_byte_sex();
973 /* Don't do anything to stub dylibs which have no load commands. */
974 if(object->mh_filetype == MH_DYLIB_STUB){
975 if((object->mh != NULL && object->mh->ncmds == 0) ||
976 (object->mh64 != NULL && object->mh64->ncmds == 0)){
977 return;
980 if(object->mh_filetype == MH_DSYM)
981 fatal_arch(arch, member, "can't process dSYM companion file: ");
982 if(object->st == NULL || object->st->nsyms == 0){
983 warning_arch(arch, member, "input object file stripped: ");
984 return;
987 nsyms = object->st->nsyms;
988 if(object->mh != NULL){
989 symbols = (struct nlist *)
990 (object->object_addr + object->st->symoff);
991 if(object->object_byte_sex != host_byte_sex)
992 swap_nlist(symbols, nsyms, host_byte_sex);
993 symbols64 = NULL;
995 else{
996 symbols = NULL;
997 symbols64 = (struct nlist_64 *)
998 (object->object_addr + object->st->symoff);
999 if(object->object_byte_sex != host_byte_sex)
1000 swap_nlist_64(symbols64, nsyms, host_byte_sex);
1002 strings = object->object_addr + object->st->stroff;
1003 strsize = object->st->strsize;
1005 #ifndef NMEDIT
1006 if(object->mh != NULL)
1007 flags = object->mh->flags;
1008 else
1009 flags = object->mh64->flags;
1010 if(object->mh_filetype == MH_DYLIB &&
1011 (flags & MH_PREBOUND) != MH_PREBOUND){
1012 arch->dont_update_LC_ID_DYLIB_timestamp = TRUE;
1014 if(object->mh_filetype != MH_DYLIB && cflag)
1015 fatal_arch(arch, member, "-c can't be used on non-dynamic "
1016 "library: ");
1017 #endif /* !(NMEDIT) */
1018 if(object->mh_filetype == MH_DYLIB_STUB)
1019 fatal_arch(arch, member, "dynamic stub library can't be changed "
1020 "once created: ");
1022 if(object->mh_filetype == MH_DYLIB){
1023 tocs = (struct dylib_table_of_contents *)
1024 (object->object_addr + object->dyst->tocoff);
1025 ntoc = object->dyst->ntoc;
1026 nmodtab = object->dyst->nmodtab;
1027 if(object->mh != NULL){
1028 mods = (struct dylib_module *)
1029 (object->object_addr + object->dyst->modtaboff);
1030 if(object->object_byte_sex != host_byte_sex)
1031 swap_dylib_module(mods, nmodtab, host_byte_sex);
1032 mods64 = NULL;
1034 else{
1035 mods = NULL;
1036 mods64 = (struct dylib_module_64 *)
1037 (object->object_addr + object->dyst->modtaboff);
1038 if(object->object_byte_sex != host_byte_sex)
1039 swap_dylib_module_64(mods64, nmodtab, host_byte_sex);
1041 refs = (struct dylib_reference *)
1042 (object->object_addr + object->dyst->extrefsymoff);
1043 nextrefsyms = object->dyst->nextrefsyms;
1044 if(object->object_byte_sex != host_byte_sex){
1045 swap_dylib_table_of_contents(tocs, ntoc, host_byte_sex);
1046 swap_dylib_reference(refs, nextrefsyms, host_byte_sex);
1048 #ifndef NMEDIT
1050 * In the -c flag is specified then strip the section contents of
1051 * this dynamic library and change it into a stub library. When
1052 * creating a stub library the timestamp is not changed.
1054 if(cflag){
1055 arch->dont_update_LC_ID_DYLIB_timestamp = TRUE;
1057 lc = object->load_commands;
1058 if(object->mh != NULL){
1059 ncmds = object->mh->ncmds;
1060 object->mh_filetype = MH_DYLIB_STUB;
1061 object->mh->filetype = MH_DYLIB_STUB;
1063 else{
1064 ncmds = object->mh64->ncmds;
1065 object->mh_filetype = MH_DYLIB_STUB;
1066 object->mh64->filetype = MH_DYLIB_STUB;
1068 for(i = 0; i < ncmds; i++){
1069 if(lc->cmd == LC_SEGMENT){
1070 sg = (struct segment_command *)lc;
1071 if(strcmp(sg->segname, SEG_LINKEDIT) != 0){
1073 * Zero out the section offset, reloff, and size
1074 * fields as the section contents are being removed.
1076 s = (struct section *)
1077 ((char *)sg + sizeof(struct segment_command));
1078 for(j = 0; j < sg->nsects; j++){
1080 * For section types with indirect tables we
1081 * do not zero out the section size in a stub
1082 * library. As the section size is needed to
1083 * know now many indirect table entries the
1084 * section has. This is a bit odd but programs
1085 * dealing with MH_DYLIB_STUB filetypes special
1086 * case this.
1088 section_type = s[j].flags & SECTION_TYPE;
1089 if(section_type != S_SYMBOL_STUBS &&
1090 section_type != S_LAZY_SYMBOL_POINTERS &&
1091 section_type != S_LAZY_DYLIB_SYMBOL_POINTERS &&
1092 section_type != S_NON_LAZY_SYMBOL_POINTERS){
1093 s[j].size = 0;
1095 s[j].addr = 0;
1096 s[j].offset = 0;
1097 s[j].reloff = 0;
1099 /* zero out file offset and size in the segment */
1100 sg->fileoff = 0;
1101 sg->filesize = 0;
1104 else if(lc->cmd == LC_SEGMENT_64){
1105 sg64 = (struct segment_command_64 *)lc;
1106 if(strcmp(sg64->segname, SEG_LINKEDIT) != 0){
1108 * Zero out the section offset, reloff, and size
1109 * fields as the section contents are being removed.
1111 s64 = (struct section_64 *)
1112 ((char *)sg64 +
1113 sizeof(struct segment_command_64));
1114 for(j = 0; j < sg64->nsects; j++){
1116 * For section types with indirect tables we
1117 * do not zero out the section size in a stub
1118 * library. As the section size is needed to
1119 * know now many indirect table entries the
1120 * section has. This is a bit odd but programs
1121 * dealing with MH_DYLIB_STUB filetypes special
1122 * case this.
1124 section_type = s64[j].flags & SECTION_TYPE;
1125 if(section_type != S_SYMBOL_STUBS &&
1126 section_type != S_LAZY_SYMBOL_POINTERS &&
1127 section_type != S_LAZY_DYLIB_SYMBOL_POINTERS &&
1128 section_type != S_NON_LAZY_SYMBOL_POINTERS){
1129 s64[j].size = 0;
1131 s64[j].addr = 0;
1132 s64[j].offset = 0;
1133 s64[j].reloff = 0;
1135 /* zero out file offset and size in the segment */
1136 sg64->fileoff = 0;
1137 sg64->filesize = 0;
1140 lc = (struct load_command *)((char *)lc + lc->cmdsize);
1143 * To get the right amount of the file copied out by writeout()
1144 * for the case when we are stripping out the section contents
1145 * we reduce the object size by the size of the section contents
1146 * including the padding after the load commands. Then this
1147 * size minus the size of the input symbolic information is
1148 * copied out.
1150 if(object->mh != NULL){
1151 object->object_size -= (object->seg_linkedit->fileoff -
1152 (sizeof(struct mach_header) +
1153 object->mh->sizeofcmds));
1155 * Set the file offset to the link edit information to be
1156 * right after the load commands.
1158 object->seg_linkedit->fileoff =
1159 sizeof(struct mach_header) +
1160 object->mh->sizeofcmds;
1162 else{
1163 object->object_size -= (object->seg_linkedit64->fileoff -
1164 (sizeof(struct mach_header_64) +
1165 object->mh64->sizeofcmds));
1167 * Set the file offset to the link edit information to be
1168 * right after the load commands.
1170 object->seg_linkedit64->fileoff =
1171 sizeof(struct mach_header_64) +
1172 object->mh64->sizeofcmds;
1175 #endif /* !(NMEDIT) */
1177 else{
1178 tocs = NULL;
1179 ntoc = 0;
1180 mods = NULL;
1181 mods64 = NULL;
1182 nmodtab = 0;
1183 refs = NULL;
1184 nextrefsyms = 0;
1188 * coalesced symbols can be stripped only if they are not used via an
1189 * symbol pointer. So to know that strip_symtab() needs to be passed
1190 * the indirect symbol table.
1192 if(object->dyst != NULL && object->dyst->nindirectsyms != 0){
1193 nindirectsyms = object->dyst->nindirectsyms;
1194 indirectsyms = (uint32_t *)
1195 (object->object_addr + object->dyst->indirectsymoff);
1196 if(object->object_byte_sex != host_byte_sex)
1197 swap_indirect_symbols(indirectsyms, nindirectsyms,
1198 host_byte_sex);
1200 else{
1201 indirectsyms = NULL;
1202 nindirectsyms = 0;
1205 if(object->mh != NULL)
1206 object->input_sym_info_size =
1207 nsyms * sizeof(struct nlist) +
1208 strsize;
1209 else
1210 object->input_sym_info_size =
1211 nsyms * sizeof(struct nlist_64) +
1212 strsize;
1213 #ifndef NMEDIT
1214 if(object->mh != NULL)
1215 flags = object->mh->flags;
1216 else
1217 flags = object->mh64->flags;
1218 if(strip_all &&
1219 (flags & MH_DYLDLINK) == MH_DYLDLINK &&
1220 object->mh_filetype == MH_EXECUTE)
1221 default_dyld_executable = TRUE;
1222 else
1223 default_dyld_executable = FALSE;
1224 #endif /* !defined(NMEDIT) */
1226 #ifndef NMEDIT
1227 if(sfile != NULL || Rfile != NULL || dfile != NULL || Aflag || uflag ||
1228 Sflag || xflag || Xflag || nflag || rflag ||
1229 default_dyld_executable || object->mh_filetype == MH_DYLIB ||
1230 object->mh_filetype == MH_DYLINKER)
1231 #endif /* !defined(NMEDIT) */
1233 #ifdef NMEDIT
1234 if(edit_symtab(arch, member, object, symbols, symbols64, nsyms,
1235 strings, strsize, tocs, ntoc, mods, mods64, nmodtab, refs,
1236 nextrefsyms) == FALSE)
1237 return;
1238 #else /* !defined(NMEDIT) */
1239 if(strip_symtab(arch, member, object, tocs, ntoc, mods, mods64,
1240 nmodtab, refs, nextrefsyms) == FALSE)
1241 return;
1242 if(no_uuid == TRUE)
1243 strip_LC_UUID_commands(arch, member, object);
1244 #endif /* !defined(NMEDIT) */
1246 * The parts that make up output_sym_info_size must be added up in
1247 * the output order so that when the sizes of things are rounded up
1248 * before parts that must be aligned the final output_sym_info_size
1249 * is correct.
1251 * Also the parts that make up input_sym_info_size must be added up
1252 * in the same way. And must be done here as the input file may
1253 * have been changed to and "ld -r" file and may not be the
1254 * the original input file.
1256 object->output_sym_info_size = 0;
1257 object->input_sym_info_size = 0;
1258 if(object->dyld_info != NULL){
1259 /* there are five parts to the dyld info, but
1260 strip does not alter them, so copy as a block */
1261 dyld_info_start = 0;
1262 if (object->dyld_info->rebase_off != 0)
1263 dyld_info_start = object->dyld_info->rebase_off;
1264 else if (object->dyld_info->bind_off != 0)
1265 dyld_info_start = object->dyld_info->bind_off;
1266 else if (object->dyld_info->weak_bind_off != 0)
1267 dyld_info_start = object->dyld_info->weak_bind_off;
1268 else if (object->dyld_info->lazy_bind_off != 0)
1269 dyld_info_start = object->dyld_info->lazy_bind_off;
1270 else if (object->dyld_info->export_off != 0)
1271 dyld_info_start = object->dyld_info->export_off;
1272 dyld_info_end = 0;
1273 if (object->dyld_info->export_size != 0)
1274 dyld_info_end = object->dyld_info->export_off
1275 + object->dyld_info->export_size;
1276 else if (object->dyld_info->lazy_bind_size != 0)
1277 dyld_info_end = object->dyld_info->lazy_bind_off
1278 + object->dyld_info->lazy_bind_size;
1279 else if (object->dyld_info->weak_bind_size != 0)
1280 dyld_info_end = object->dyld_info->weak_bind_off
1281 + object->dyld_info->weak_bind_size;
1282 else if (object->dyld_info->bind_size != 0)
1283 dyld_info_end = object->dyld_info->bind_off
1284 + object->dyld_info->bind_size;
1285 else if (object->dyld_info->rebase_size != 0)
1286 dyld_info_end = object->dyld_info->rebase_off
1287 + object->dyld_info->rebase_size;
1288 object->output_dyld_info = object->object_addr +dyld_info_start;
1289 object->output_dyld_info_size = dyld_info_end - dyld_info_start;
1290 object->output_sym_info_size += object->output_dyld_info_size;
1292 * Warn about strip -s or -R on a final linked image with
1293 * dyld_info.
1295 if(nsave_symbols != 0){
1296 warning_arch(arch, NULL, "removing global symbols from a "
1297 "final linked no longer supported. Use "
1298 "-exported_symbols_list at link time when "
1299 "building: ");
1301 object->input_sym_info_size += object->dyld_info->rebase_size
1302 + object->dyld_info->bind_size
1303 + object->dyld_info->weak_bind_size
1304 + object->dyld_info->lazy_bind_size
1305 + object->dyld_info->export_size;
1308 if(object->dyst != NULL){
1309 #ifndef NMEDIT
1311 * When stripping out the section contents to create a
1312 * dynamic library stub the relocation info also gets
1313 * stripped.
1315 if(!cflag)
1316 #endif /* !(NMEDIT) */
1318 object->output_sym_info_size +=
1319 object->dyst->nlocrel * sizeof(struct relocation_info);
1321 object->input_sym_info_size +=
1322 object->dyst->nlocrel * sizeof(struct relocation_info);
1325 if(object->split_info_cmd != NULL){
1326 object->output_split_info_data = object->object_addr +
1327 object->split_info_cmd->dataoff;
1328 object->output_split_info_data_size =
1329 object->split_info_cmd->datasize;
1330 object->input_sym_info_size += object->split_info_cmd->datasize;
1331 object->output_sym_info_size +=
1332 object->split_info_cmd->datasize;
1335 if(object->func_starts_info_cmd != NULL){
1336 object->output_func_start_info_data = object->object_addr +
1337 object->func_starts_info_cmd->dataoff;
1338 object->output_func_start_info_data_size =
1339 object->func_starts_info_cmd->datasize;
1340 object->input_sym_info_size +=
1341 object->func_starts_info_cmd->datasize;
1342 object->output_sym_info_size +=
1343 object->func_starts_info_cmd->datasize;
1346 if(object->data_in_code_cmd != NULL){
1347 object->output_data_in_code_info_data = object->object_addr +
1348 object->data_in_code_cmd->dataoff;
1349 object->output_data_in_code_info_data_size =
1350 object->data_in_code_cmd->datasize;
1351 object->input_sym_info_size +=
1352 object->data_in_code_cmd->datasize;
1353 object->output_sym_info_size +=
1354 object->data_in_code_cmd->datasize;
1357 if(object->code_sign_drs_cmd != NULL){
1358 object->output_code_sign_drs_info_data = object->object_addr +
1359 object->code_sign_drs_cmd->dataoff;
1360 object->output_code_sign_drs_info_data_size =
1361 object->code_sign_drs_cmd->datasize;
1362 object->input_sym_info_size +=
1363 object->code_sign_drs_cmd->datasize;
1364 object->output_sym_info_size +=
1365 object->code_sign_drs_cmd->datasize;
1368 if(object->mh != NULL){
1369 object->input_sym_info_size += nsyms * sizeof(struct nlist);
1370 object->output_symbols = new_symbols;
1371 object->output_sym_info_size +=
1372 new_nsyms * sizeof(struct nlist);
1374 else{
1375 object->input_sym_info_size += nsyms * sizeof(struct nlist_64);
1376 object->output_symbols64 = new_symbols64;
1377 object->output_sym_info_size +=
1378 new_nsyms * sizeof(struct nlist_64);
1380 object->output_nsymbols = new_nsyms;
1381 object->st->nsyms = new_nsyms;
1383 if(object->hints_cmd != NULL){
1384 object->input_sym_info_size +=
1385 object->hints_cmd->nhints *
1386 sizeof(struct twolevel_hint);
1387 object->output_sym_info_size +=
1388 object->hints_cmd->nhints *
1389 sizeof(struct twolevel_hint);
1392 if(object->dyst != NULL){
1393 #ifndef NMEDIT
1395 * When stripping out the section contents to create a
1396 * dynamic library stub the relocation info also gets
1397 * stripped.
1399 if(!cflag)
1400 #endif /* !(NMEDIT) */
1402 object->output_sym_info_size +=
1403 object->dyst->nextrel * sizeof(struct relocation_info);
1405 object->input_sym_info_size +=
1406 object->dyst->nextrel * sizeof(struct relocation_info);
1409 if(object->dyst != NULL){
1410 object->output_sym_info_size +=
1411 object->dyst->nindirectsyms * sizeof(uint32_t) +
1412 object->input_indirectsym_pad;
1413 if(object->mh != NULL){
1414 object->input_sym_info_size +=
1415 object->dyst->nindirectsyms * sizeof(uint32_t);
1417 else{
1418 object->input_sym_info_size +=
1419 object->dyst->nindirectsyms * sizeof(uint32_t) +
1420 object->input_indirectsym_pad;
1424 if(object->dyst != NULL){
1425 object->output_sym_info_size +=
1426 new_ntoc * sizeof(struct dylib_table_of_contents);
1427 object->input_sym_info_size +=
1428 object->dyst->ntoc * sizeof(struct dylib_table_of_contents);
1431 if(object->dyst != NULL){
1432 if(object->mh != NULL){
1433 object->output_sym_info_size +=
1434 object->dyst->nmodtab * sizeof(struct dylib_module);
1435 object->input_sym_info_size +=
1436 object->dyst->nmodtab * sizeof(struct dylib_module);
1438 else{
1439 object->output_sym_info_size +=
1440 object->dyst->nmodtab * sizeof(struct dylib_module_64);
1441 object->input_sym_info_size +=
1442 object->dyst->nmodtab * sizeof(struct dylib_module_64);
1446 if(object->dyst != NULL){
1447 object->output_sym_info_size +=
1448 new_nextrefsyms * sizeof(struct dylib_reference);
1449 object->input_sym_info_size +=
1450 object->dyst->nextrefsyms * sizeof(struct dylib_reference);
1453 object->output_strings = new_strings;
1454 object->output_strings_size = new_strsize;
1455 object->output_sym_info_size += new_strsize;
1456 object->input_sym_info_size += strsize;
1457 object->st->strsize = new_strsize;
1459 if(object->code_sig_cmd != NULL){
1460 #ifndef NMEDIT
1461 if(!cflag)
1462 #endif /* !(NMEDIT) */
1464 object->output_code_sig_data = object->object_addr +
1465 object->code_sig_cmd->dataoff;
1466 object->output_code_sig_data_size =
1467 object->code_sig_cmd->datasize;
1469 object->input_sym_info_size =
1470 rnd(object->input_sym_info_size, 16);
1471 object->input_sym_info_size +=
1472 object->code_sig_cmd->datasize;
1473 #ifndef NMEDIT
1474 if(cflag){
1475 strip_LC_CODE_SIGNATURE_commands(arch, member, object);
1477 else
1478 #endif /* !(NMEDIT) */
1480 object->output_sym_info_size =
1481 rnd(object->output_sym_info_size, 16);
1482 object->output_sym_info_size +=
1483 object->code_sig_cmd->datasize;
1487 if(object->dyst != NULL){
1488 object->dyst->ilocalsym = 0;
1489 object->dyst->nlocalsym = new_nlocalsym;
1490 object->dyst->iextdefsym = new_nlocalsym;
1491 object->dyst->nextdefsym = new_nextdefsym;
1492 object->dyst->iundefsym = new_nlocalsym + new_nextdefsym;
1493 object->dyst->nundefsym = new_nundefsym;
1494 if(object->dyst->nindirectsyms != 0){
1495 object->output_indirect_symtab = indirectsyms;
1496 if(object->object_byte_sex != host_byte_sex)
1497 swap_indirect_symbols(indirectsyms, nindirectsyms,
1498 object->object_byte_sex);
1502 * If the -c option is specified the object's filetype will
1503 * have been changed from MH_DYLIB to MH_DYLIB_STUB above.
1505 if(object->mh_filetype == MH_DYLIB ||
1506 object->mh_filetype == MH_DYLIB_STUB){
1507 object->output_tocs = new_tocs;
1508 object->output_ntoc = new_ntoc;
1509 #ifdef NMEDIT
1510 if(object->mh != NULL)
1511 object->output_mods = new_mods;
1512 else
1513 object->output_mods64 = new_mods64;
1514 object->output_nmodtab = new_nmodtab;
1515 #else
1516 object->output_mods = mods;
1517 object->output_nmodtab = nmodtab;
1518 #endif
1519 object->output_refs = new_refs;
1520 object->output_nextrefsyms = new_nextrefsyms;
1521 if(object->object_byte_sex != host_byte_sex){
1522 swap_dylib_table_of_contents(new_tocs, new_ntoc,
1523 object->object_byte_sex);
1524 #ifdef NMEDIT
1525 if(object->mh != NULL)
1526 swap_dylib_module(new_mods, new_nmodtab,
1527 object->object_byte_sex);
1528 else
1529 swap_dylib_module_64(new_mods64, new_nmodtab,
1530 object->object_byte_sex);
1531 #else
1532 if(object->mh != NULL)
1533 swap_dylib_module(mods, nmodtab,
1534 object->object_byte_sex);
1535 else
1536 swap_dylib_module_64(mods64, nmodtab,
1537 object->object_byte_sex);
1538 #endif
1539 swap_dylib_reference(new_refs, new_nextrefsyms,
1540 object->object_byte_sex);
1543 object->dyst->ntoc = new_ntoc;
1544 object->dyst->nextrefsyms = new_nextrefsyms;
1546 offset = get_starting_syminfo_offset(object);
1548 if(object->dyld_info != 0){
1549 if (object->dyld_info->rebase_off != 0){
1550 object->dyld_info->rebase_off = offset;
1551 offset += object->dyld_info->rebase_size;
1553 if (object->dyld_info->bind_off != 0){
1554 object->dyld_info->bind_off = offset;
1555 offset += object->dyld_info->bind_size;
1557 if (object->dyld_info->weak_bind_off != 0){
1558 object->dyld_info->weak_bind_off = offset;
1559 offset += object->dyld_info->weak_bind_size;
1561 if (object->dyld_info->lazy_bind_off != 0){
1562 object->dyld_info->lazy_bind_off = offset;
1563 offset += object->dyld_info->lazy_bind_size;
1565 if (object->dyld_info->export_off != 0){
1566 object->dyld_info->export_off = offset;
1567 offset += object->dyld_info->export_size;
1571 if(object->dyst->nlocrel != 0){
1572 object->output_loc_relocs = (struct relocation_info *)
1573 (object->object_addr + object->dyst->locreloff);
1574 #ifndef NMEDIT
1576 * When stripping out the section contents to create a
1577 * dynamic library stub the relocation info also gets
1578 * stripped.
1580 if(cflag){
1581 object->dyst->nlocrel = 0;
1582 object->dyst->locreloff = 0;
1584 else
1585 #endif /* defined(NMEDIT) */
1587 object->dyst->locreloff = offset;
1588 offset += object->dyst->nlocrel *
1589 sizeof(struct relocation_info);
1592 else
1593 object->dyst->locreloff = 0;
1595 if(object->split_info_cmd != NULL){
1596 object->split_info_cmd->dataoff = offset;
1597 offset += object->split_info_cmd->datasize;
1600 if(object->func_starts_info_cmd != NULL){
1601 object->func_starts_info_cmd->dataoff = offset;
1602 offset += object->func_starts_info_cmd->datasize;
1605 if(object->data_in_code_cmd != NULL){
1606 object->data_in_code_cmd->dataoff = offset;
1607 offset += object->data_in_code_cmd->datasize;
1610 if(object->code_sign_drs_cmd != NULL){
1611 object->code_sign_drs_cmd->dataoff = offset;
1612 offset += object->code_sign_drs_cmd->datasize;
1615 if(object->st->nsyms != 0){
1616 object->st->symoff = offset;
1617 if(object->mh != NULL)
1618 offset += object->st->nsyms * sizeof(struct nlist);
1619 else
1620 offset += object->st->nsyms * sizeof(struct nlist_64);
1622 else
1623 object->st->symoff = 0;
1625 if(object->hints_cmd != NULL){
1626 if(object->hints_cmd->nhints != 0){
1627 object->output_hints = (struct twolevel_hint *)
1628 (object->object_addr + object->hints_cmd->offset);
1629 object->hints_cmd->offset = offset;
1630 offset += object->hints_cmd->nhints *
1631 sizeof(struct twolevel_hint);
1633 else
1634 object->hints_cmd->offset = 0;
1637 if(object->dyst->nextrel != 0){
1638 object->output_ext_relocs = (struct relocation_info *)
1639 (object->object_addr + object->dyst->extreloff);
1640 #ifndef NMEDIT
1642 * When stripping out the section contents to create a
1643 * dynamic library stub the relocation info also gets
1644 * stripped.
1646 if(cflag){
1647 object->dyst->nextrel = 0;
1648 object->dyst->extreloff = 0;
1650 else
1651 #endif /* defined(NMEDIT) */
1653 object->dyst->extreloff = offset;
1654 offset += object->dyst->nextrel *
1655 sizeof(struct relocation_info);
1658 else
1659 object->dyst->extreloff = 0;
1661 if(object->dyst->nindirectsyms != 0){
1662 object->dyst->indirectsymoff = offset;
1663 offset += object->dyst->nindirectsyms * sizeof(uint32_t) +
1664 object->input_indirectsym_pad;
1666 else
1667 object->dyst->indirectsymoff = 0;;
1669 if(object->dyst->ntoc != 0){
1670 object->dyst->tocoff = offset;
1671 offset += object->dyst->ntoc *
1672 sizeof(struct dylib_table_of_contents);
1674 else
1675 object->dyst->tocoff = 0;
1677 if(object->dyst->nmodtab != 0){
1678 #ifndef NMEDIT
1680 * When stripping out the section contents to create a
1681 * dynamic library stub zero out the fields in the module
1682 * table for the sections and relocation information and
1683 * clear Objective-C address and size from modules.
1685 if(cflag){
1686 if(object->mh != NULL){
1687 for(k = 0; k < object->dyst->nmodtab; k++){
1688 mods[k].iinit_iterm = 0;
1689 mods[k].ninit_nterm = 0;
1690 mods[k].iextrel = 0;
1691 mods[k].nextrel = 0;
1692 mods[k].objc_module_info_addr = 0;
1693 mods[k].objc_module_info_size = 0;
1696 else{
1697 for(k = 0; k < object->dyst->nmodtab; k++){
1698 mods64[k].iinit_iterm = 0;
1699 mods64[k].ninit_nterm = 0;
1700 mods64[k].iextrel = 0;
1701 mods64[k].nextrel = 0;
1702 mods64[k].objc_module_info_addr = 0;
1703 mods64[k].objc_module_info_size = 0;
1707 #endif /* !(NMEDIT) */
1708 object->dyst->modtaboff = offset;
1709 if(object->mh != NULL)
1710 offset += object->dyst->nmodtab *
1711 sizeof(struct dylib_module);
1712 else
1713 offset += object->dyst->nmodtab *
1714 sizeof(struct dylib_module_64);
1716 else
1717 object->dyst->modtaboff = 0;
1719 if(object->dyst->nextrefsyms != 0){
1720 object->dyst->extrefsymoff = offset;
1721 offset += object->dyst->nextrefsyms *
1722 sizeof(struct dylib_reference);
1724 else
1725 object->dyst->extrefsymoff = 0;
1727 if(object->st->strsize != 0){
1728 object->st->stroff = offset;
1729 offset += object->st->strsize;
1731 else
1732 object->st->stroff = 0;
1734 if(object->code_sig_cmd != NULL){
1735 offset = rnd(offset, 16);
1736 object->code_sig_cmd->dataoff = offset;
1737 offset += object->code_sig_cmd->datasize;
1740 else{
1741 if(new_strsize != 0){
1742 if(object->mh != NULL)
1743 object->st->stroff = object->st->symoff +
1744 new_nsyms * sizeof(struct nlist);
1745 else
1746 object->st->stroff = object->st->symoff +
1747 new_nsyms * sizeof(struct nlist_64);
1749 else
1750 object->st->stroff = 0;
1751 if(new_nsyms == 0)
1752 object->st->symoff = 0;
1755 #ifndef NMEDIT
1756 else{
1758 * Here we are doing a full symbol strip. In some cases it may
1759 * leave the local relocation entries as well as LOCAL indirect
1760 * symbol table entries.
1762 if(saves != NULL)
1763 free(saves);
1764 saves = (int32_t *)allocate(object->st->nsyms * sizeof(int32_t));
1765 bzero(saves, object->st->nsyms * sizeof(int32_t));
1768 * Account for the symbolic info in the input file.
1770 if(object->dyst != NULL){
1771 object->input_sym_info_size +=
1772 object->dyst->nlocrel * sizeof(struct relocation_info) +
1773 object->dyst->nextrel * sizeof(struct relocation_info) +
1774 object->dyst->ntoc * sizeof(struct dylib_table_of_contents)+
1775 object->dyst->nextrefsyms * sizeof(struct dylib_reference);
1776 if(object->mh != NULL){
1777 object->input_sym_info_size +=
1778 object->dyst->nmodtab * sizeof(struct dylib_module) +
1779 object->dyst->nindirectsyms * sizeof(uint32_t);
1781 else{
1782 object->input_sym_info_size +=
1783 object->dyst->nmodtab * sizeof(struct dylib_module_64) +
1784 object->dyst->nindirectsyms * sizeof(uint32_t) +
1785 object->input_indirectsym_pad;
1790 * Determine the offset where the remaining symbolic info will start
1791 * in the output file (if any).
1793 offset = get_starting_syminfo_offset(object);
1796 * For a full symbol strip all these values in the output file are
1797 * set to zero.
1799 object->st->symoff = 0;
1800 object->st->nsyms = 0;
1801 object->st->stroff = 0;
1802 object->st->strsize = 0;
1803 if(object->dyst != NULL){
1804 object->dyst->ilocalsym = 0;
1805 object->dyst->nlocalsym = 0;
1806 object->dyst->iextdefsym = 0;
1807 object->dyst->nextdefsym = 0;
1808 object->dyst->iundefsym = 0;
1809 object->dyst->nundefsym = 0;
1813 * This will accumulate any remaining symbolic info size in the
1814 * output file.
1816 object->output_sym_info_size = 0;
1819 * We set these so that checking can be done below to report the
1820 * symbols that can't be stripped because of relocation entries
1821 * or indirect symbol table entries. Normally if these table have a
1822 * non-zero number of entries it will be an error as we are trying
1823 * to strip everything. But it maybe that there are only LOCAL
1824 * indirect entries which is odd but will be OK.
1826 if(object->dyst != NULL){
1827 if(object->dyst->nextrel != 0){
1828 object->output_ext_relocs = (struct relocation_info *)
1829 (object->object_addr + object->dyst->extreloff);
1832 * Since this file has a dynamic symbol table and if this file
1833 * has local relocation entries on input make sure they are
1834 * there on output. This is a rare case that it will not have
1835 * external relocs or indirect symbols but can happen as is the
1836 * case with the dynamic linker itself.
1838 if(object->dyst->nlocrel != 0){
1839 object->output_loc_relocs = (struct relocation_info *)
1840 (object->object_addr + object->dyst->locreloff);
1841 object->output_sym_info_size +=
1842 object->dyst->nlocrel * sizeof(struct relocation_info);
1844 object->dyst->locreloff = offset;
1845 offset += object->dyst->nlocrel *
1846 sizeof(struct relocation_info);
1849 if(object->dyst->nindirectsyms != 0){
1850 object->output_indirect_symtab = (uint32_t *)
1851 (object->object_addr +
1852 object->dyst->indirectsymoff);
1853 if(object->object_byte_sex != host_byte_sex)
1854 swap_indirect_symbols(
1855 object->output_indirect_symtab,
1856 object->dyst->nindirectsyms,
1857 object->object_byte_sex);
1859 object->output_sym_info_size +=
1860 object->dyst->nindirectsyms * sizeof(uint32_t) +
1861 object->input_indirectsym_pad;
1863 object->dyst->indirectsymoff = offset;
1864 offset += object->dyst->nindirectsyms * sizeof(uint32_t) +
1865 object->input_indirectsym_pad;
1869 #endif /* !defined(NMEDIT) */
1872 * Always clear the prebind checksum if any when creating a new file.
1874 if(object->cs != NULL)
1875 object->cs->cksum = 0;
1877 if(object->seg_linkedit != NULL){
1878 object->seg_linkedit->filesize += object->output_sym_info_size -
1879 object->input_sym_info_size;
1880 object->seg_linkedit->vmsize = object->seg_linkedit->filesize;
1882 else if(object->seg_linkedit64 != NULL){
1883 /* Do this in two steps to avoid 32/64-bit casting problems. */
1884 object->seg_linkedit64->filesize -= object->input_sym_info_size;
1885 object->seg_linkedit64->filesize += object->output_sym_info_size;
1886 object->seg_linkedit64->vmsize = object->seg_linkedit64->filesize;
1890 * Check and update the external relocation entries to make sure
1891 * referenced symbols are not stripped and refer to the new symbol
1892 * table indexes.
1894 * The external relocation entries can be located in one of two places,
1895 * first off of the sections or second off of the dynamic symtab.
1897 missing_reloc_symbols = 0;
1898 lc = object->load_commands;
1899 if(object->mh != NULL)
1900 ncmds = object->mh->ncmds;
1901 else
1902 ncmds = object->mh64->ncmds;
1903 for(i = 0; i < ncmds; i++){
1904 if(lc->cmd == LC_SEGMENT &&
1905 object->seg_linkedit != (struct segment_command *)lc){
1906 sg = (struct segment_command *)lc;
1907 s = (struct section *)((char *)sg +
1908 sizeof(struct segment_command));
1909 for(j = 0; j < sg->nsects; j++){
1910 if(s->nreloc != 0){
1911 if(s->reloff + s->nreloc *
1912 sizeof(struct relocation_info) >
1913 object->object_size){
1914 fatal_arch(arch, member, "truncated or malformed "
1915 "object (relocation entries for section (%.16s,"
1916 "%.16s) extends past the end of the file)",
1917 s->segname, s->sectname);
1919 relocs = (struct relocation_info *)
1920 (object->object_addr + s->reloff);
1921 if(object->object_byte_sex != host_byte_sex)
1922 swap_relocation_info(relocs, s->nreloc,
1923 host_byte_sex);
1924 if(s->offset + s->size > object->object_size){
1925 fatal_arch(arch, member, "truncated or malformed "
1926 "object (contents of section (%.16s,"
1927 "%.16s) extends past the end of the file)",
1928 s->segname, s->sectname);
1930 contents = object->object_addr + s->offset;
1931 check_object_relocs(arch, member, object, s->segname,
1932 s->sectname, s->size, contents, relocs, s->nreloc,
1933 symbols, symbols64, nsyms, strings,
1934 &missing_reloc_symbols, host_byte_sex);
1935 if(object->object_byte_sex != host_byte_sex)
1936 swap_relocation_info(relocs, s->nreloc,
1937 object->object_byte_sex);
1939 s++;
1942 else if(lc->cmd == LC_SEGMENT_64 &&
1943 object->seg_linkedit64 != (struct segment_command_64 *)lc){
1944 sg64 = (struct segment_command_64 *)lc;
1945 s64 = (struct section_64 *)((char *)sg64 +
1946 sizeof(struct segment_command_64));
1947 for(j = 0; j < sg64->nsects; j++){
1948 if(s64->nreloc != 0){
1949 if(s64->reloff + s64->nreloc *
1950 sizeof(struct relocation_info) >
1951 object->object_size){
1952 fatal_arch(arch, member, "truncated or malformed "
1953 "object (relocation entries for section (%.16s,"
1954 "%.16s) extends past the end of the file)",
1955 s64->segname, s64->sectname);
1957 relocs = (struct relocation_info *)
1958 (object->object_addr + s64->reloff);
1959 if(object->object_byte_sex != host_byte_sex)
1960 swap_relocation_info(relocs, s64->nreloc,
1961 host_byte_sex);
1962 if(s64->offset + s64->size > object->object_size){
1963 fatal_arch(arch, member, "truncated or malformed "
1964 "object (contents of section (%.16s,"
1965 "%.16s) extends past the end of the file)",
1966 s64->segname, s64->sectname);
1968 contents = object->object_addr + s64->offset;
1969 check_object_relocs(arch, member, object, s64->segname,
1970 s64->sectname, s64->size, contents, relocs,
1971 s64->nreloc, symbols, symbols64, nsyms, strings,
1972 &missing_reloc_symbols, host_byte_sex);
1973 if(object->object_byte_sex != host_byte_sex)
1974 swap_relocation_info(relocs, s64->nreloc,
1975 object->object_byte_sex);
1977 s64++;
1980 lc = (struct load_command *)((char *)lc + lc->cmdsize);
1982 if(object->dyst != NULL && object->dyst->nextrel != 0){
1983 relocs = object->output_ext_relocs;
1984 if(object->object_byte_sex != host_byte_sex)
1985 swap_relocation_info(relocs, object->dyst->nextrel,
1986 host_byte_sex);
1988 for(i = 0; i < object->dyst->nextrel; i++){
1989 if((relocs[i].r_address & R_SCATTERED) == 0 &&
1990 relocs[i].r_extern == 1){
1991 if(relocs[i].r_symbolnum > nsyms){
1992 fatal_arch(arch, member, "bad r_symbolnum for external "
1993 "relocation entry %d in: ", i);
1995 if(saves[relocs[i].r_symbolnum] == 0){
1996 if(missing_reloc_symbols == 0){
1997 error_arch(arch, member, "symbols referenced by "
1998 "relocation entries that can't be stripped in: ");
1999 missing_reloc_symbols = 1;
2001 if(object->mh != NULL){
2002 fprintf(stderr, "%s\n", strings + symbols
2003 [relocs[i].r_symbolnum].n_un.n_strx);
2005 else {
2006 fprintf(stderr, "%s\n", strings + symbols64
2007 [relocs[i].r_symbolnum].n_un.n_strx);
2009 saves[relocs[i].r_symbolnum] = -1;
2011 if(saves[relocs[i].r_symbolnum] != -1){
2012 relocs[i].r_symbolnum =
2013 saves[relocs[i].r_symbolnum] - 1;
2016 else{
2017 fatal_arch(arch, member, "bad external relocation entry "
2018 "%d (not external) in: ", i);
2020 if((relocs[i].r_address & R_SCATTERED) == 0){
2021 if(reloc_has_pair(object->mh_cputype, relocs[i].r_type))
2022 i++;
2024 else{
2025 sreloc = (struct scattered_relocation_info *)relocs + i;
2026 if(reloc_has_pair(object->mh_cputype, sreloc->r_type))
2027 i++;
2030 if(object->object_byte_sex != host_byte_sex)
2031 swap_relocation_info(relocs, object->dyst->nextrel,
2032 object->object_byte_sex);
2036 * Check and update the indirect symbol table entries to make sure
2037 * referenced symbols are not stripped and refer to the new symbol
2038 * table indexes.
2040 if(object->dyst != NULL && object->dyst->nindirectsyms != 0){
2041 if(object->object_byte_sex != host_byte_sex)
2042 swap_indirect_symbols(object->output_indirect_symtab,
2043 object->dyst->nindirectsyms, host_byte_sex);
2045 lc = object->load_commands;
2046 if(object->mh != NULL)
2047 ncmds = object->mh->ncmds;
2048 else
2049 ncmds = object->mh64->ncmds;
2050 for(i = 0; i < ncmds; i++){
2051 if(lc->cmd == LC_SEGMENT &&
2052 object->seg_linkedit != (struct segment_command *)lc){
2053 sg = (struct segment_command *)lc;
2054 s = (struct section *)((char *)sg +
2055 sizeof(struct segment_command));
2056 for(j = 0; j < sg->nsects; j++){
2057 section_type = s->flags & SECTION_TYPE;
2058 if(section_type == S_LAZY_SYMBOL_POINTERS ||
2059 section_type == S_LAZY_DYLIB_SYMBOL_POINTERS ||
2060 section_type == S_NON_LAZY_SYMBOL_POINTERS)
2061 stride = 4;
2062 else if(section_type == S_SYMBOL_STUBS)
2063 stride = s->reserved2;
2064 else{
2065 s++;
2066 continue;
2068 nitems = s->size / stride;
2069 contents = object->object_addr + s->offset;
2070 check_indirect_symtab(arch, member, object, nitems,
2071 s->reserved1, section_type, contents, symbols,
2072 symbols64, nsyms, strings, &missing_reloc_symbols,
2073 host_byte_sex);
2074 s++;
2077 else if(lc->cmd == LC_SEGMENT_64 &&
2078 object->seg_linkedit64 != (struct segment_command_64 *)lc){
2079 sg64 = (struct segment_command_64 *)lc;
2080 s64 = (struct section_64 *)((char *)sg64 +
2081 sizeof(struct segment_command_64));
2082 for(j = 0; j < sg64->nsects; j++){
2083 section_type = s64->flags & SECTION_TYPE;
2084 if(section_type == S_LAZY_SYMBOL_POINTERS ||
2085 section_type == S_LAZY_DYLIB_SYMBOL_POINTERS ||
2086 section_type == S_NON_LAZY_SYMBOL_POINTERS)
2087 stride = 8;
2088 else if(section_type == S_SYMBOL_STUBS)
2089 stride = s64->reserved2;
2090 else{
2091 s64++;
2092 continue;
2094 nitems = s64->size / stride;
2095 contents = object->object_addr + s64->offset;
2096 check_indirect_symtab(arch, member, object, nitems,
2097 s64->reserved1, section_type, contents, symbols,
2098 symbols64, nsyms, strings, &missing_reloc_symbols,
2099 host_byte_sex);
2100 s64++;
2103 lc = (struct load_command *)((char *)lc + lc->cmdsize);
2106 if(object->object_byte_sex != host_byte_sex)
2107 swap_indirect_symbols(object->output_indirect_symtab,
2108 object->dyst->nindirectsyms, object->object_byte_sex);
2112 * Issue a warning if object file has a code signature that the
2113 * operation will invalidate it.
2115 if(object->code_sig_cmd != NULL)
2116 warning_arch(arch, member, "changes being made to the file will "
2117 "invalidate the code signature in: ");
2121 * get_starting_syminfo_offset() returns the starting offset of the symbolic
2122 * info in the object file.
2124 static
2125 uint32_t
2126 get_starting_syminfo_offset(
2127 struct object *object)
2129 uint32_t offset;
2131 if(object->seg_linkedit != NULL ||
2132 object->seg_linkedit64 != NULL){
2133 if(object->mh != NULL)
2134 offset = object->seg_linkedit->fileoff;
2135 else
2136 offset = object->seg_linkedit64->fileoff;
2138 else{
2139 offset = UINT_MAX;
2140 if(object->dyst != NULL &&
2141 object->dyst->nlocrel != 0 &&
2142 object->dyst->locreloff < offset)
2143 offset = object->dyst->locreloff;
2144 if(object->st->nsyms != 0 &&
2145 object->st->symoff < offset)
2146 offset = object->st->symoff;
2147 if(object->dyst != NULL &&
2148 object->dyst->nextrel != 0 &&
2149 object->dyst->extreloff < offset)
2150 offset = object->dyst->extreloff;
2151 if(object->dyst != NULL &&
2152 object->dyst->nindirectsyms != 0 &&
2153 object->dyst->indirectsymoff < offset)
2154 offset = object->dyst->indirectsymoff;
2155 if(object->dyst != NULL &&
2156 object->dyst->ntoc != 0 &&
2157 object->dyst->tocoff < offset)
2158 offset = object->dyst->tocoff;
2159 if(object->dyst != NULL &&
2160 object->dyst->nmodtab != 0 &&
2161 object->dyst->modtaboff < offset)
2162 offset = object->dyst->modtaboff;
2163 if(object->dyst != NULL &&
2164 object->dyst->nextrefsyms != 0 &&
2165 object->dyst->extrefsymoff < offset)
2166 offset = object->dyst->extrefsymoff;
2167 if(object->st->strsize != 0 &&
2168 object->st->stroff < offset)
2169 offset = object->st->stroff;
2171 return(offset);
2175 * check_object_relocs() is used to check and update the external relocation
2176 * entries from a section in an object file, to make sure referenced symbols
2177 * are not stripped and are changed to refer to the new symbol table indexes.
2179 static
2180 void
2181 check_object_relocs(
2182 struct arch *arch,
2183 struct member *member,
2184 struct object *object,
2185 char *segname,
2186 char *sectname,
2187 uint64_t sectsize,
2188 char *contents,
2189 struct relocation_info *relocs,
2190 uint32_t nreloc,
2191 struct nlist *symbols,
2192 struct nlist_64 *symbols64,
2193 uint32_t nsyms,
2194 char *strings,
2195 int32_t *missing_reloc_symbols,
2196 enum byte_sex host_byte_sex)
2198 uint32_t k, n_strx;
2199 uint64_t n_value;
2200 #ifdef NMEDIT
2201 uint32_t value, n_ext;
2202 uint64_t value64;
2203 #endif
2204 struct scattered_relocation_info *sreloc;
2206 for(k = 0; k < nreloc; k++){
2207 if((relocs[k].r_address & R_SCATTERED) == 0 &&
2208 relocs[k].r_extern == 1){
2209 if(relocs[k].r_symbolnum > nsyms){
2210 fatal_arch(arch, member, "bad r_symbolnum for relocation "
2211 "entry %d in section (%.16s,%.16s) in: ", k, segname,
2212 sectname);
2214 if(object->mh != NULL){
2215 n_strx = symbols[relocs[k].r_symbolnum].n_un.n_strx;
2216 n_value = symbols[relocs[k].r_symbolnum].n_value;
2218 else{
2219 n_strx = symbols64[relocs[k].r_symbolnum].n_un.n_strx;
2220 n_value = symbols64[relocs[k].r_symbolnum].n_value;
2222 #ifndef NMEDIT
2223 if(saves[relocs[k].r_symbolnum] == 0){
2224 if(*missing_reloc_symbols == 0){
2225 error_arch(arch, member, "symbols referenced by "
2226 "relocation entries that can't be stripped in: ");
2227 *missing_reloc_symbols = 1;
2229 fprintf(stderr, "%s\n", strings + n_strx);
2230 saves[relocs[k].r_symbolnum] = -1;
2232 #else /* defined(NMEDIT) */
2234 * We are letting nmedit change global coalesed symbols into
2235 * statics in MH_OBJECT file types only. Relocation entries to
2236 * global coalesced symbols are external relocs.
2238 if(object->mh != NULL)
2239 n_ext = new_symbols[saves[relocs[k].r_symbolnum] - 1].
2240 n_type & N_EXT;
2241 else
2242 n_ext = new_symbols64[saves[relocs[k].r_symbolnum] - 1].
2243 n_type & N_EXT;
2244 if(n_ext != N_EXT &&
2245 object->mh_cputype != CPU_TYPE_X86_64){
2247 * We need to do the relocation for this external relocation
2248 * entry so the item to be relocated is correct for a local
2249 * relocation entry. We don't need to do this for x86-64.
2251 if(relocs[k].r_address + sizeof(int32_t) > sectsize){
2252 fatal_arch(arch, member, "truncated or malformed "
2253 "object (r_address of relocation entry %u of "
2254 "section (%.16s,%.16s) extends past the end "
2255 "of the section)", k, segname, sectname);
2257 if(object->mh != NULL){
2258 value = *(uint32_t *)
2259 (contents + relocs[k].r_address);
2260 if(object->object_byte_sex != host_byte_sex)
2261 value = SWAP_INT(value);
2263 * We handle a very limited form here. Only VANILLA
2264 * (r_type == 0) long (r_length==2) absolute or pcrel
2265 * that won't need a scattered relocation entry.
2267 if(relocs[k].r_type != 0 ||
2268 relocs[k].r_length != 2){
2269 fatal_arch(arch, member, "don't have "
2270 "code to convert external relocation "
2271 "entry %d in section (%.16s,%.16s) "
2272 "for global coalesced symbol: %s "
2273 "in: ", k, segname, sectname,
2274 strings + n_strx);
2276 value += n_value;
2277 if(object->object_byte_sex != host_byte_sex)
2278 value = SWAP_INT(value);
2279 *(uint32_t *)(contents + relocs[k].r_address) =
2280 value;
2282 else{
2283 value64 = *(uint64_t *)(contents + relocs[k].r_address);
2284 if(object->object_byte_sex != host_byte_sex)
2285 value64 = SWAP_LONG_LONG(value64);
2287 * We handle a very limited form here. Only VANILLA
2288 * (r_type == 0) quad (r_length==3) absolute or pcrel
2289 * that won't need a scattered relocation entry.
2291 if(relocs[k].r_type != 0 ||
2292 relocs[k].r_length != 3){
2293 fatal_arch(arch, member, "don't have "
2294 "code to convert external relocation "
2295 "entry %d in section (%.16s,%.16s) "
2296 "for global coalesced symbol: %s "
2297 "in: ", k, segname, sectname,
2298 strings + n_strx);
2300 value64 += n_value;
2301 if(object->object_byte_sex != host_byte_sex)
2302 value64 = SWAP_LONG_LONG(value64);
2303 *(uint64_t *)(contents + relocs[k].r_address) = value64;
2306 * Turn the extern reloc into a local.
2308 if(object->mh != NULL)
2309 relocs[k].r_symbolnum =
2310 new_symbols[saves[relocs[k].r_symbolnum] - 1].n_sect;
2311 else
2312 relocs[k].r_symbolnum =
2313 new_symbols64[saves[relocs[k].r_symbolnum] - 1].n_sect;
2314 relocs[k].r_extern = 0;
2316 #endif /* NMEDIT */
2317 if(relocs[k].r_extern == 1 &&
2318 saves[relocs[k].r_symbolnum] != -1){
2319 relocs[k].r_symbolnum = saves[relocs[k].r_symbolnum] - 1;
2322 if((relocs[k].r_address & R_SCATTERED) == 0){
2323 if(reloc_has_pair(object->mh_cputype, relocs[k].r_type) == TRUE)
2324 k++;
2326 else{
2327 sreloc = (struct scattered_relocation_info *)relocs + k;
2328 if(reloc_has_pair(object->mh_cputype, sreloc->r_type) == TRUE)
2329 k++;
2335 * check_indirect_symtab() checks and updates the indirect symbol table entries
2336 * to make sure referenced symbols are not stripped and refer to the new symbol
2337 * table indexes.
2339 static
2340 void
2341 check_indirect_symtab(
2342 struct arch *arch,
2343 struct member *member,
2344 struct object *object,
2345 uint32_t nitems,
2346 uint32_t reserved1,
2347 uint32_t section_type,
2348 char *contents,
2349 struct nlist *symbols,
2350 struct nlist_64 *symbols64,
2351 uint32_t nsyms,
2352 char *strings,
2353 int32_t *missing_reloc_symbols,
2354 enum byte_sex host_byte_sex)
2356 uint32_t k, index;
2357 uint8_t n_type;
2358 uint32_t n_strx, value;
2359 uint64_t value64;
2360 enum bool made_local;
2362 for(k = 0; k < nitems; k++){
2363 made_local = FALSE;
2364 index = object->output_indirect_symtab[reserved1 + k];
2365 if(index == INDIRECT_SYMBOL_LOCAL ||
2366 index == INDIRECT_SYMBOL_ABS ||
2367 index == (INDIRECT_SYMBOL_LOCAL | INDIRECT_SYMBOL_ABS))
2368 continue;
2369 if(index > nsyms)
2370 fatal_arch(arch, member,"indirect symbol table entry %d (past " "the end of the symbol table) in: ", reserved1 + k);
2371 #ifdef NMEDIT
2372 if(pflag == 0 && nmedits[index] == TRUE && saves[index] != -1)
2373 #else
2374 if(saves[index] == 0)
2375 #endif
2378 * Indirect symbol table entries for defined symbols in a
2379 * non-lazy pointer section that are not saved are changed to
2380 * INDIRECT_SYMBOL_LOCAL which their values just have to be
2381 * slid if the are not absolute symbols.
2383 if(object->mh != NULL){
2384 n_type = symbols[index].n_type;
2385 n_strx = symbols[index].n_un.n_strx;
2387 else{
2388 n_type = symbols64[index].n_type;
2389 n_strx = symbols64[index].n_un.n_strx;
2391 if((n_type & N_TYPE) != N_UNDF &&
2392 (n_type & N_TYPE) != N_PBUD &&
2393 section_type == S_NON_LAZY_SYMBOL_POINTERS){
2394 object->output_indirect_symtab[reserved1 + k] =
2395 INDIRECT_SYMBOL_LOCAL;
2396 if((n_type & N_TYPE) == N_ABS)
2397 object->output_indirect_symtab[reserved1 + k] |=
2398 INDIRECT_SYMBOL_ABS;
2399 made_local = TRUE;
2401 * When creating a stub shared library the section contents
2402 * are not updated since they will be stripped.
2404 if(object->mh_filetype != MH_DYLIB_STUB){
2405 if(object->mh != NULL){
2406 value = symbols[index].n_value;
2407 if (symbols[index].n_desc & N_ARM_THUMB_DEF)
2408 value |= 1;
2409 if(object->object_byte_sex != host_byte_sex)
2410 value = SWAP_INT(value);
2411 *(uint32_t *)(contents + k * 4) = value;
2413 else{
2414 value64 = symbols64[index].n_value;
2415 if(object->object_byte_sex != host_byte_sex)
2416 value64 = SWAP_LONG_LONG(value64);
2417 *(uint64_t *)(contents + k * 8) = value64;
2421 #ifdef NMEDIT
2422 else {
2423 object->output_indirect_symtab[reserved1 + k] =
2424 saves[index] - 1;
2426 #else /* !defined(NMEDIT) */
2427 else{
2428 if(*missing_reloc_symbols == 0){
2429 error_arch(arch, member, "symbols referenced by "
2430 "indirect symbol table entries that can't be "
2431 "stripped in: ");
2432 *missing_reloc_symbols = 1;
2434 fprintf(stderr, "%s\n", strings + n_strx);
2435 saves[index] = -1;
2437 #endif /* !defined(NMEDIT) */
2439 #ifdef NMEDIT
2440 else
2441 #else /* !defined(NMEDIT) */
2442 if(made_local == FALSE && saves[index] != -1)
2443 #endif /* !defined(NMEDIT) */
2445 object->output_indirect_symtab[reserved1+k] = saves[index] - 1;
2450 #ifndef NMEDIT
2452 * This is called if there is a -d option specified. It reads the file with
2453 * the strings in it and places them in the array debug_filenames and sorts
2454 * them by name. The file that contains the file names must have names one
2455 * per line with no white space (except the newlines).
2457 static
2458 void
2459 setup_debug_filenames(
2460 char *dfile)
2462 int fd, i, strings_size;
2463 struct stat stat_buf;
2464 char *strings, *p;
2466 if((fd = open(dfile, O_RDONLY)) < 0){
2467 system_error("can't open: %s", dfile);
2468 return;
2470 if(fstat(fd, &stat_buf) == -1){
2471 system_error("can't stat: %s", dfile);
2472 close(fd);
2473 return;
2475 strings_size = stat_buf.st_size;
2476 strings = (char *)allocate(strings_size + 1);
2477 strings[strings_size] = '\0';
2478 if(read(fd, strings, strings_size) != strings_size){
2479 system_error("can't read: %s", dfile);
2480 close(fd);
2481 return;
2483 p = strings;
2484 for(i = 0; i < strings_size; i++){
2485 if(*p == '\n'){
2486 *p = '\0';
2487 ndebug_filenames++;
2489 p++;
2491 debug_filenames = (char **)allocate(ndebug_filenames * sizeof(char *));
2492 p = strings;
2493 for(i = 0; i < ndebug_filenames; i++){
2494 debug_filenames[i] = p;
2495 p += strlen(p) + 1;
2497 qsort(debug_filenames, ndebug_filenames, sizeof(char *),
2498 (int (*)(const void *, const void *))cmp_qsort_filename);
2500 #ifdef DEBUG
2501 printf("Debug filenames:\n");
2502 for(i = 0; i < ndebug_filenames; i++){
2503 printf("filename = %s\n", debug_filenames[i]);
2505 #endif /* DEBUG */
2509 * Strip the symbol table to the level specified by the command line arguments.
2510 * The new symbol table is built and new_symbols is left pointing to it. The
2511 * number of new symbols is left in new_nsyms, the new string table is built
2512 * and new_stings is left pointing to it and new_strsize is left containing it.
2513 * This routine returns zero if successfull and non-zero otherwise.
2515 static
2516 enum bool
2517 strip_symtab(
2518 struct arch *arch,
2519 struct member *member,
2520 struct object *object,
2521 struct dylib_table_of_contents *tocs,
2522 uint32_t ntoc,
2523 struct dylib_module *mods,
2524 struct dylib_module_64 *mods64,
2525 uint32_t nmodtab,
2526 struct dylib_reference *refs,
2527 uint32_t nextrefsyms)
2529 uint32_t i, j, k, n, inew_syms, save_debug, missing_syms;
2530 uint32_t missing_symbols;
2531 char *p, *q, **pp, *basename;
2532 struct symbol_list *sp;
2533 uint32_t new_ext_strsize, len, *changes, inew_undefsyms;
2534 unsigned char nsects;
2535 struct load_command *lc;
2536 struct segment_command *sg;
2537 struct segment_command_64 *sg64;
2538 struct section *s, **sections;
2539 struct section_64 *s64, **sections64;
2540 uint32_t ncmds, mh_flags, s_flags, n_strx;
2541 struct nlist *sym;
2542 struct undef_map *undef_map;
2543 struct undef_map64 *undef_map64;
2544 uint8_t n_type, n_sect;
2545 uint16_t n_desc;
2546 uint64_t n_value;
2547 uint32_t module_name, iextdefsym, nextdefsym, ilocalsym, nlocalsym;
2548 uint32_t irefsym, nrefsym;
2549 enum bool has_dwarf, hack_5614542;
2551 save_debug = 0;
2552 if(saves != NULL)
2553 free(saves);
2554 changes = NULL;
2555 for(i = 0; i < nsave_symbols; i++)
2556 save_symbols[i].sym = NULL;
2557 for(i = 0; i < nremove_symbols; i++)
2558 remove_symbols[i].sym = NULL;
2559 if(member == NULL){
2560 for(i = 0; i < nsave_symbols; i++)
2561 save_symbols[i].seen = FALSE;
2562 for(i = 0; i < nremove_symbols; i++)
2563 remove_symbols[i].seen = FALSE;
2566 new_nsyms = 0;
2567 if(object->mh != NULL)
2568 new_strsize = sizeof(int32_t);
2569 else
2570 new_strsize = sizeof(int64_t);
2571 new_nlocalsym = 0;
2572 new_nextdefsym = 0;
2573 new_nundefsym = 0;
2574 new_ext_strsize = 0;
2577 * If this an object file that has DWARF debugging sections to strip
2578 * then we have to run ld -r on it.
2580 if(object->mh_filetype == MH_OBJECT && (Sflag || xflag)){
2581 has_dwarf = FALSE;
2582 lc = object->load_commands;
2583 if(object->mh != NULL)
2584 ncmds = object->mh->ncmds;
2585 else
2586 ncmds = object->mh64->ncmds;
2587 for(i = 0; i < ncmds && has_dwarf == FALSE; i++){
2588 if(lc->cmd == LC_SEGMENT){
2589 sg = (struct segment_command *)lc;
2590 s = (struct section *)((char *)sg +
2591 sizeof(struct segment_command));
2592 for(j = 0; j < sg->nsects; j++){
2593 if(s->flags & S_ATTR_DEBUG){
2594 has_dwarf = TRUE;
2595 break;
2597 s++;
2600 else if(lc->cmd == LC_SEGMENT_64){
2601 sg64 = (struct segment_command_64 *)lc;
2602 s64 = (struct section_64 *)((char *)sg64 +
2603 sizeof(struct segment_command_64));
2604 for(j = 0; j < sg64->nsects; j++){
2605 if(s64->flags & S_ATTR_DEBUG){
2606 has_dwarf = TRUE;
2607 break;
2609 s64++;
2612 lc = (struct load_command *)((char *)lc + lc->cmdsize);
2614 if(has_dwarf == TRUE)
2615 make_ld_r_object(arch, member, object);
2618 * Because of the "design" of 64-bit object files and the lack of
2619 * local relocation entries it is not possible for strip(1) to do its
2620 * job without becoming a static link editor. The "design" does not
2621 * actually strip the symbols it simply renames them to things like
2622 * "l1000". And they become static symbols but still have external
2623 * relocation entries. Thus can never actually be stripped. Also some
2624 * symbols, *.eh, symbols are not even changed to these names if there
2625 * corresponding global symbol is not stripped. So strip(1) only
2626 * recourse is to use the unified linker to create an ld -r object then
2627 * save all resulting symbols (both static and global) and hope the user
2628 * does not notice the stripping is not what they asked for.
2630 if(object->mh_filetype == MH_OBJECT &&
2631 (object->mh64 != NULL && object->ld_r_ofile == NULL))
2632 make_ld_r_object(arch, member, object);
2635 * Since make_ld_r_object() may create an object with more symbols
2636 * this has to be done after make_ld_r_object() and nsyms is updated.
2638 saves = (int32_t *)allocate(nsyms * sizeof(int32_t));
2639 bzero(saves, nsyms * sizeof(int32_t));
2642 * Gather an array of section struct pointers so we can later determine
2643 * if we run into a global symbol in a coalesced section and not strip
2644 * those symbols.
2645 * statics.
2647 nsects = 0;
2648 lc = object->load_commands;
2649 if(object->mh != NULL)
2650 ncmds = object->mh->ncmds;
2651 else
2652 ncmds = object->mh64->ncmds;
2653 for(i = 0; i < ncmds; i++){
2654 if(lc->cmd == LC_SEGMENT){
2655 sg = (struct segment_command *)lc;
2656 nsects += sg->nsects;
2658 else if(lc->cmd == LC_SEGMENT_64){
2659 sg64 = (struct segment_command_64 *)lc;
2660 nsects += sg64->nsects;
2662 lc = (struct load_command *)((char *)lc + lc->cmdsize);
2664 if(object->mh != NULL){
2665 sections = allocate(nsects * sizeof(struct section *));
2666 sections64 = NULL;
2668 else{
2669 sections = NULL;
2670 sections64 = allocate(nsects * sizeof(struct section_64 *));
2672 nsects = 0;
2673 lc = object->load_commands;
2674 for(i = 0; i < ncmds; i++){
2675 if(lc->cmd == LC_SEGMENT){
2676 sg = (struct segment_command *)lc;
2677 s = (struct section *)((char *)sg +
2678 sizeof(struct segment_command));
2679 for(j = 0; j < sg->nsects; j++)
2680 sections[nsects++] = s++;
2682 else if(lc->cmd == LC_SEGMENT_64){
2683 sg64 = (struct segment_command_64 *)lc;
2684 s64 = (struct section_64 *)((char *)sg64 +
2685 sizeof(struct segment_command_64));
2686 for(j = 0; j < sg64->nsects; j++)
2687 sections64[nsects++] = s64++;
2689 lc = (struct load_command *)((char *)lc + lc->cmdsize);
2692 for(i = 0; i < nsyms; i++){
2693 s_flags = 0;
2694 if(object->mh != NULL){
2695 mh_flags = object->mh->flags;
2696 n_strx = symbols[i].n_un.n_strx;
2697 n_type = symbols[i].n_type;
2698 n_sect = symbols[i].n_sect;
2699 if((n_type & N_TYPE) == N_SECT){
2700 if(n_sect == 0 || n_sect > nsects){
2701 error_arch(arch, member, "bad n_sect for symbol "
2702 "table entry %d in: ", i);
2703 return(FALSE);
2705 s_flags = sections[n_sect - 1]->flags;
2707 n_desc = symbols[i].n_desc;
2708 n_value = symbols[i].n_value;
2710 else{
2711 mh_flags = object->mh64->flags;
2712 n_strx = symbols64[i].n_un.n_strx;
2713 n_type = symbols64[i].n_type;
2714 n_sect = symbols64[i].n_sect;
2715 if((n_type & N_TYPE) == N_SECT){
2716 if(n_sect == 0 || n_sect > nsects){
2717 error_arch(arch, member, "bad n_sect for symbol "
2718 "table entry %d in: ", i);
2719 return(FALSE);
2721 s_flags = sections64[n_sect - 1]->flags;
2723 n_desc = symbols64[i].n_desc;
2724 n_value = symbols64[i].n_value;
2726 if(n_strx != 0){
2727 if(n_strx > strsize){
2728 error_arch(arch, member, "bad string index for symbol "
2729 "table entry %d in: ", i);
2730 return(FALSE);
2733 if((n_type & N_TYPE) == N_INDR){
2734 if(n_value != 0){
2735 if(n_value > strsize){
2736 error_arch(arch, member, "bad string index for "
2737 "indirect symbol table entry %d in: ", i);
2738 return(FALSE);
2742 if((n_type & N_EXT) == 0){ /* local symbol */
2744 * For x86_64 .o files we have run ld -r on them and are stuck
2745 * keeping all resulting symbols.
2747 if(object->mh == NULL && (
2748 object->mh64->cputype == CPU_TYPE_X86_64) &&
2749 object->mh64->filetype == MH_OBJECT){
2750 if(n_strx != 0)
2751 new_strsize += strlen(strings + n_strx) + 1;
2752 new_nlocalsym++;
2753 new_nsyms++;
2754 saves[i] = new_nsyms;
2757 * The cases a local symbol might be saved is with -X -S or
2758 * with -d filename.
2760 else if((!strip_all && (Xflag || Sflag)) || dfile){
2761 if(n_type & N_STAB){ /* debug symbol */
2762 if(dfile && n_type == N_SO){
2763 if(n_strx != 0){
2764 basename = strrchr(strings + n_strx, '/');
2765 if(basename != NULL)
2766 basename++;
2767 else
2768 basename = strings + n_strx;
2769 pp = bsearch(basename, debug_filenames,
2770 ndebug_filenames, sizeof(char *),
2771 (int (*)(const void *, const void *)
2772 )cmp_bsearch_filename);
2774 * Save the bracketing N_SO. For each N_SO that
2775 * has a filename there is an N_SO that has a
2776 * name of "" which ends the stabs for that file
2778 if(*basename != '\0'){
2779 if(pp != NULL)
2780 save_debug = 1;
2781 else
2782 save_debug = 0;
2784 else{
2786 * This is a bracketing SO so if we are
2787 * currently saving debug symbols save this
2788 * last one and turn off saving debug syms.
2790 if(save_debug){
2791 if(n_strx != 0)
2792 new_strsize += strlen(strings +
2793 n_strx) + 1;
2794 new_nlocalsym++;
2795 new_nsyms++;
2796 saves[i] = new_nsyms;
2798 save_debug = 0;
2801 else{
2802 save_debug = 0;
2805 if(saves[i] == 0 && (!Sflag || save_debug)){
2806 if(n_strx != 0)
2807 new_strsize += strlen(strings + n_strx) + 1;
2808 new_nlocalsym++;
2809 new_nsyms++;
2810 saves[i] = new_nsyms;
2813 else{ /* non-debug local symbol */
2814 if(xflag == 0 && (Sflag || Xflag)){
2815 if(Xflag == 0 ||
2816 (n_strx != 0 &&
2817 strings[n_strx] != 'L')){
2819 * If this file is a for the dynamic linker and
2820 * this symbol is in a section marked so that
2821 * static symbols are stripped then don't
2822 * keep this symbol.
2824 if((mh_flags & MH_DYLDLINK) != MH_DYLDLINK ||
2825 (n_type & N_TYPE) != N_SECT ||
2826 (s_flags & S_ATTR_STRIP_STATIC_SYMS) !=
2827 S_ATTR_STRIP_STATIC_SYMS){
2828 new_strsize += strlen(strings + n_strx) + 1;
2829 new_nlocalsym++;
2830 new_nsyms++;
2831 saves[i] = new_nsyms;
2836 * Treat a local symbol that was a private extern as if
2837 * were global if it is referenced by a module and save
2838 * it.
2840 if((n_type & N_PEXT) == N_PEXT){
2841 if(saves[i] == 0 &&
2842 private_extern_reference_by_module(
2843 i, refs ,nextrefsyms) == TRUE){
2844 if(n_strx != 0)
2845 new_strsize += strlen(strings + n_strx) + 1;
2846 new_nlocalsym++;
2847 new_nsyms++;
2848 saves[i] = new_nsyms;
2851 * We need to save symbols that were private externs
2852 * that are used with indirect symbols.
2854 if(saves[i] == 0 &&
2855 symbol_pointer_used(i, indirectsyms,
2856 nindirectsyms) == TRUE){
2857 if(n_strx != 0){
2858 len = strlen(strings + n_strx) + 1;
2859 new_strsize += len;
2861 new_nlocalsym++;
2862 new_nsyms++;
2863 saves[i] = new_nsyms;
2869 * Treat a local symbol that was a private extern as if were
2870 * global if it is not referenced by a module.
2872 else if((n_type & N_PEXT) == N_PEXT){
2873 if(saves[i] == 0 && sfile){
2874 sp = bsearch(strings + n_strx,
2875 save_symbols, nsave_symbols,
2876 sizeof(struct symbol_list),
2877 (int (*)(const void *, const void *))
2878 symbol_list_bsearch);
2879 if(sp != NULL){
2880 if(sp->sym == NULL){
2881 if(object->mh != NULL)
2882 sp->sym = &(symbols[i]);
2883 else
2884 sp->sym = &(symbols64[i]);
2885 sp->seen = TRUE;
2887 if(n_strx != 0)
2888 new_strsize += strlen(strings + n_strx) + 1;
2889 new_nlocalsym++;
2890 new_nsyms++;
2891 saves[i] = new_nsyms;
2894 if(saves[i] == 0 &&
2895 private_extern_reference_by_module(
2896 i, refs ,nextrefsyms) == TRUE){
2897 if(n_strx != 0)
2898 new_strsize += strlen(strings + n_strx) + 1;
2899 new_nlocalsym++;
2900 new_nsyms++;
2901 saves[i] = new_nsyms;
2904 * We need to save symbols that were private externs that
2905 * are used with indirect symbols.
2907 if(saves[i] == 0 &&
2908 symbol_pointer_used(i, indirectsyms, nindirectsyms) ==
2909 TRUE){
2910 if(n_strx != 0){
2911 len = strlen(strings + n_strx) + 1;
2912 new_strsize += len;
2914 new_nlocalsym++;
2915 new_nsyms++;
2916 saves[i] = new_nsyms;
2920 else{ /* global symbol */
2922 * strip -R on an x86_64 .o file should do nothing.
2924 if(Rfile &&
2925 (object->mh != NULL ||
2926 object->mh64->cputype != CPU_TYPE_X86_64 ||
2927 object->mh64->filetype != MH_OBJECT)){
2928 sp = bsearch(strings + n_strx,
2929 remove_symbols, nremove_symbols,
2930 sizeof(struct symbol_list),
2931 (int (*)(const void *, const void *))
2932 symbol_list_bsearch);
2933 if(sp != NULL){
2934 if((n_type & N_TYPE) == N_UNDF ||
2935 (n_type & N_TYPE) == N_PBUD){
2936 error_arch(arch, member, "symbol: %s undefined"
2937 " and can't be stripped from: ",
2938 sp->name);
2940 else if(sp->sym != NULL){
2941 sym = (struct nlist *)sp->sym;
2942 if((sym->n_type & N_PEXT) != N_PEXT)
2943 error_arch(arch, member, "more than one symbol "
2944 "for: %s found in: ", sp->name);
2946 else{
2947 if(object->mh != NULL)
2948 sp->sym = &(symbols[i]);
2949 else
2950 sp->sym = &(symbols64[i]);
2951 sp->seen = TRUE;
2953 if(n_desc & REFERENCED_DYNAMICALLY){
2954 error_arch(arch, member, "symbol: %s is dynamically"
2955 " referenced and can't be stripped "
2956 "from: ", sp->name);
2958 if((n_type & N_TYPE) == N_SECT &&
2959 (s_flags & SECTION_TYPE) == S_COALESCED){
2960 error_arch(arch, member, "symbol: %s is a global "
2961 "coalesced symbol and can't be "
2962 "stripped from: ", sp->name);
2964 /* don't save this symbol */
2965 continue;
2968 if(Aflag && (n_type & N_TYPE) == N_ABS &&
2969 (n_value != 0 ||
2970 (n_strx != 0 &&
2971 strncmp(strings + n_strx,
2972 ".objc_class_name_",
2973 sizeof(".objc_class_name_") - 1) == 0))){
2974 len = strlen(strings + n_strx) + 1;
2975 new_strsize += len;
2976 new_ext_strsize += len;
2977 new_nextdefsym++;
2978 new_nsyms++;
2979 saves[i] = new_nsyms;
2981 if(saves[i] == 0 && (uflag || default_dyld_executable) &&
2982 ((((n_type & N_TYPE) == N_UNDF) &&
2983 n_value == 0) ||
2984 (n_type & N_TYPE) == N_PBUD)){
2985 if(n_strx != 0){
2986 len = strlen(strings + n_strx) + 1;
2987 new_strsize += len;
2988 new_ext_strsize += len;
2990 new_nundefsym++;
2991 new_nsyms++;
2992 saves[i] = new_nsyms;
2994 if(saves[i] == 0 && nflag &&
2995 (n_type & N_TYPE) == N_SECT){
2996 if(n_strx != 0){
2997 len = strlen(strings + n_strx) + 1;
2998 new_strsize += len;
2999 new_ext_strsize += len;
3001 new_nextdefsym++;
3002 new_nsyms++;
3003 saves[i] = new_nsyms;
3005 if(saves[i] == 0 && sfile){
3006 sp = bsearch(strings + n_strx,
3007 save_symbols, nsave_symbols,
3008 sizeof(struct symbol_list),
3009 (int (*)(const void *, const void *))
3010 symbol_list_bsearch);
3011 if(sp != NULL){
3012 if(sp->sym != NULL){
3013 sym = (struct nlist *)sp->sym;
3014 if((sym->n_type & N_PEXT) != N_PEXT)
3015 error_arch(arch, member, "more than one symbol "
3016 "for: %s found in: ", sp->name);
3018 else{
3019 if(object->mh != NULL)
3020 sp->sym = &(symbols[i]);
3021 else
3022 sp->sym = &(symbols64[i]);
3023 sp->seen = TRUE;
3024 len = strlen(strings + n_strx) + 1;
3025 new_strsize += len;
3026 new_ext_strsize += len;
3027 if((n_type & N_TYPE) == N_UNDF ||
3028 (n_type & N_TYPE) == N_PBUD)
3029 new_nundefsym++;
3030 else
3031 new_nextdefsym++;
3032 new_nsyms++;
3033 saves[i] = new_nsyms;
3038 * We only need to save coalesced symbols that are used as
3039 * indirect symbols in 32-bit applications.
3041 * In 64-bit applications, we only need to save coalesced
3042 * symbols that are used as weak definitions.
3044 if(object->mh != NULL &&
3045 saves[i] == 0 &&
3046 (n_type & N_TYPE) == N_SECT &&
3047 (s_flags & SECTION_TYPE) == S_COALESCED &&
3048 symbol_pointer_used(i, indirectsyms, nindirectsyms) == TRUE){
3049 if(n_strx != 0){
3050 len = strlen(strings + n_strx) + 1;
3051 new_strsize += len;
3052 new_ext_strsize += len;
3054 new_nextdefsym++;
3055 new_nsyms++;
3056 saves[i] = new_nsyms;
3058 if(saves[i] == 0 &&
3059 (n_type & N_TYPE) == N_SECT &&
3060 (n_desc & N_WEAK_DEF) != 0){
3061 if(n_strx != 0){
3062 len = strlen(strings + n_strx) + 1;
3063 new_strsize += len;
3064 new_ext_strsize += len;
3066 new_nextdefsym++;
3067 new_nsyms++;
3068 saves[i] = new_nsyms;
3070 if(saves[i] == 0 && ((Xflag || Sflag || xflag) ||
3071 ((rflag || default_dyld_executable) &&
3072 n_desc & REFERENCED_DYNAMICALLY))){
3073 len = strlen(strings + n_strx) + 1;
3074 new_strsize += len;
3075 new_ext_strsize += len;
3076 if((n_type & N_TYPE) == N_INDR){
3077 len = strlen(strings + n_value) + 1;
3078 new_strsize += len;
3079 new_ext_strsize += len;
3081 if((n_type & N_TYPE) == N_UNDF ||
3082 (n_type & N_TYPE) == N_PBUD)
3083 new_nundefsym++;
3084 else
3085 new_nextdefsym++;
3086 new_nsyms++;
3087 saves[i] = new_nsyms;
3090 * For x86_64 .o files we have run ld -r on them and are stuck
3091 * keeping all resulting symbols.
3093 if(saves[i] == 0 &&
3094 object->mh == NULL &&
3095 object->mh64->cputype == CPU_TYPE_X86_64 &&
3096 object->mh64->filetype == MH_OBJECT){
3097 len = strlen(strings + n_strx) + 1;
3098 new_strsize += len;
3099 new_ext_strsize += len;
3100 if((n_type & N_TYPE) == N_INDR){
3101 len = strlen(strings + n_value) + 1;
3102 new_strsize += len;
3103 new_ext_strsize += len;
3105 if((n_type & N_TYPE) == N_UNDF ||
3106 (n_type & N_TYPE) == N_PBUD)
3107 new_nundefsym++;
3108 else
3109 new_nextdefsym++;
3110 new_nsyms++;
3111 saves[i] = new_nsyms;
3116 * The module table's module names are placed with the external strings.
3117 * So size them and add this to the external string size.
3119 for(i = 0; i < nmodtab; i++){
3120 if(object->mh != NULL)
3121 module_name = mods[i].module_name;
3122 else
3123 module_name = mods64[i].module_name;
3124 if(module_name == 0 || module_name > strsize){
3125 error_arch(arch, member, "bad string index for module_name "
3126 "of module table entry %d in: ", i);
3127 return(FALSE);
3129 len = strlen(strings + module_name) + 1;
3130 new_strsize += len;
3131 new_ext_strsize += len;
3135 * Updating the reference table may require a symbol not yet listed as
3136 * as saved to be present in the output file. If a defined external
3137 * symbol is removed and there is a undefined reference to it in the
3138 * reference table an undefined symbol needs to be created for it in
3139 * the output file. If this happens the number of new symbols and size
3140 * of the new strings are adjusted. And the array changes[] is set to
3141 * map the old symbol index to the new symbol index for the symbol that
3142 * is changed to an undefined symbol.
3144 missing_symbols = 0;
3145 if(ref_saves != NULL)
3146 free(ref_saves);
3147 ref_saves = (int32_t *)allocate(nextrefsyms * sizeof(int32_t));
3148 bzero(ref_saves, nextrefsyms * sizeof(int32_t));
3149 changes = (uint32_t *)allocate(nsyms * sizeof(int32_t));
3150 bzero(changes, nsyms * sizeof(int32_t));
3151 new_nextrefsyms = 0;
3152 for(i = 0; i < nextrefsyms; i++){
3153 if(refs[i].isym > nsyms){
3154 error_arch(arch, member, "bad symbol table index for "
3155 "reference table entry %d in: ", i);
3156 return(FALSE);
3158 if(saves[refs[i].isym]){
3159 new_nextrefsyms++;
3160 ref_saves[i] = new_nextrefsyms;
3162 else{
3163 if(refs[i].flags == REFERENCE_FLAG_UNDEFINED_NON_LAZY ||
3164 refs[i].flags == REFERENCE_FLAG_UNDEFINED_LAZY){
3165 if(changes[refs[i].isym] == 0){
3166 if(object->mh != NULL)
3167 n_strx = symbols[refs[i].isym].n_un.n_strx;
3168 else
3169 n_strx = symbols64[refs[i].isym].n_un.n_strx;
3170 len = strlen(strings + n_strx) + 1;
3171 new_strsize += len;
3172 new_ext_strsize += len;
3173 new_nundefsym++;
3174 new_nsyms++;
3175 changes[refs[i].isym] = new_nsyms;
3176 new_nextrefsyms++;
3177 ref_saves[i] = new_nextrefsyms;
3180 else{
3181 if(refs[i].flags ==
3182 REFERENCE_FLAG_PRIVATE_UNDEFINED_NON_LAZY ||
3183 refs[i].flags == REFERENCE_FLAG_PRIVATE_UNDEFINED_LAZY){
3184 if(missing_symbols == 0){
3185 error_arch(arch, member, "private extern symbols "
3186 "referenced by modules can't be stripped in: ");
3187 missing_symbols = 1;
3189 if(object->mh != NULL)
3190 n_strx = symbols[refs[i].isym].n_un.n_strx;
3191 else
3192 n_strx = symbols64[refs[i].isym].n_un.n_strx;
3193 fprintf(stderr, "%s\n", strings + n_strx);
3194 saves[refs[i].isym] = -1;
3199 if(missing_symbols == 1)
3200 return(FALSE);
3202 if(member == NULL){
3203 missing_syms = 0;
3204 if(iflag == 0){
3205 for(i = 0; i < nsave_symbols; i++){
3206 if(save_symbols[i].sym == NULL){
3207 if(missing_syms == 0){
3208 error_arch(arch, member, "symbols names listed "
3209 "in: %s not in: ", sfile);
3210 missing_syms = 1;
3212 fprintf(stderr, "%s\n", save_symbols[i].name);
3216 missing_syms = 0;
3218 * strip -R on an x86_64 .o file should do nothing.
3220 if(iflag == 0 &&
3221 (object->mh != NULL ||
3222 object->mh64->cputype != CPU_TYPE_X86_64 ||
3223 object->mh64->filetype != MH_OBJECT)){
3224 for(i = 0; i < nremove_symbols; i++){
3225 if(remove_symbols[i].sym == NULL){
3226 if(missing_syms == 0){
3227 error_arch(arch, member, "symbols names listed "
3228 "in: %s not in: ", Rfile);
3229 missing_syms = 1;
3231 fprintf(stderr, "%s\n", remove_symbols[i].name);
3238 * If there is a chance that we could end up with an indirect symbol
3239 * with an index of zero we need to avoid that due to a work around
3240 * in the dynamic linker for a bug it is working around that was in
3241 * the old classic static linker. See radar bug 5614542 and the
3242 * related bugs 3685312 and 3534709.
3244 * A reasonable way to do this to know that local symbols are first in
3245 * the symbol table. So if we have any local symbols this won't happen
3246 * and if there are no indirect symbols it will also not happen. Past
3247 * that we'll just add a local symbol so it will end up at symbol index
3248 * zero and avoid any indirect symbol having that index.
3250 * If one really wanted they could build up the new symbol table then
3251 * look at all the indirect symbol table entries to see if any of them
3252 * have an index of zero then in that case throw that new symbol table
3253 * away and rebuild the symbol and string table once again after adding
3254 * a local symbol. This seems not all that resonable to save one symbol
3255 * table entry and a few bytes in the string table for the complexity it
3256 * would add and what it would save.
3258 if(new_nlocalsym == 0 && nindirectsyms != 0){
3259 len = strlen("radr://5614542") + 1;
3260 new_strsize += len;
3261 new_nlocalsym++;
3262 new_nsyms++;
3263 hack_5614542 = TRUE;
3265 else{
3266 hack_5614542 = FALSE;
3269 if(object->mh != NULL){
3270 new_symbols = (struct nlist *)
3271 allocate(new_nsyms * sizeof(struct nlist));
3272 new_symbols64 = NULL;
3274 else{
3275 new_symbols = NULL;
3276 new_symbols64 = (struct nlist_64 *)
3277 allocate(new_nsyms * sizeof(struct nlist_64));
3279 if(object->mh != NULL)
3280 new_strsize = rnd(new_strsize, sizeof(int32_t));
3281 else
3282 new_strsize = rnd(new_strsize, sizeof(int64_t));
3283 new_strings = (char *)allocate(new_strsize);
3284 if(object->mh != NULL){
3285 new_strings[new_strsize - 3] = '\0';
3286 new_strings[new_strsize - 2] = '\0';
3287 new_strings[new_strsize - 1] = '\0';
3289 else{
3290 new_strings[new_strsize - 7] = '\0';
3291 new_strings[new_strsize - 6] = '\0';
3292 new_strings[new_strsize - 5] = '\0';
3293 new_strings[new_strsize - 4] = '\0';
3294 new_strings[new_strsize - 3] = '\0';
3295 new_strings[new_strsize - 2] = '\0';
3296 new_strings[new_strsize - 1] = '\0';
3299 memset(new_strings, '\0', sizeof(int32_t));
3300 p = new_strings + sizeof(int32_t);
3301 q = p + new_ext_strsize;
3304 * If all strings were stripped set the size to zero but only for 32-bit
3305 * because the unified linker seems to set the filesize of empty .o
3306 * files to include the string table.
3308 if(object->mh != NULL && new_strsize == sizeof(int32_t))
3309 new_strsize = 0;
3312 * Now create a symbol table and string table in this order
3313 * symbol table
3314 * local symbols
3315 * external defined symbols
3316 * undefined symbols
3317 * string table
3318 * external strings
3319 * local strings
3321 inew_syms = 0;
3324 * If we are doing the hack for radar bug 5614542 (see above) add the
3325 * one local symbol and string.
3327 * We use an N_OPT stab which should be safe to use and not mess any
3328 * thing up. In Mac OS X, gcc(1) writes one N_OPT stab saying the file
3329 * is compiled with gcc(1). Then gdb(1) looks for that stab, but it
3330 * also looks at the name. If the name string is "gcc_compiled" or
3331 * "gcc2_compiled" gdb(1) sets its "compiled by gcc flag. If the N_OPT
3332 * is emitted INSIDE an N_SO section, then gdb(1) thinks that object
3333 * module was compiled by Sun's compiler, which apparently sticks one
3334 * outermost N_LBRAC/N_RBRAC pair, which gdb(1) strips off. But if the
3335 * N_OPT comes before any N_SO stabs, then gdb(1) will just ignore it.
3336 * Since this N_OPT is the first local symbol, it will always come
3337 * before any N_SO stabs that might be around and should be fine.
3339 if(hack_5614542 == TRUE){
3340 if(object->mh != NULL){
3341 new_symbols[inew_syms].n_type = N_OPT;
3342 new_symbols[inew_syms].n_sect = NO_SECT;
3343 new_symbols[inew_syms].n_desc = 0;
3344 new_symbols[inew_syms].n_value = 0x05614542;
3346 else{
3347 new_symbols64[inew_syms].n_type = N_OPT;
3348 new_symbols64[inew_syms].n_sect = NO_SECT;
3349 new_symbols64[inew_syms].n_desc = 0;
3350 new_symbols64[inew_syms].n_value = 0x05614542;
3352 strcpy(q, "radr://5614542");
3353 if(object->mh != NULL)
3354 new_symbols[inew_syms].n_un.n_strx =
3355 q - new_strings;
3356 else
3357 new_symbols64[inew_syms].n_un.n_strx =
3358 q - new_strings;
3359 q += strlen(q) + 1;
3360 inew_syms++;
3363 for(i = 0; i < nsyms; i++){
3364 if(saves[i]){
3365 if(object->mh != NULL){
3366 n_strx = symbols[i].n_un.n_strx;
3367 n_type = symbols[i].n_type;
3369 else{
3370 n_strx = symbols64[i].n_un.n_strx;
3371 n_type = symbols64[i].n_type;
3373 if((n_type & N_EXT) == 0){
3374 if(object->mh != NULL)
3375 new_symbols[inew_syms] = symbols[i];
3376 else
3377 new_symbols64[inew_syms] = symbols64[i];
3378 if(n_strx != 0){
3379 strcpy(q, strings + n_strx);
3380 if(object->mh != NULL)
3381 new_symbols[inew_syms].n_un.n_strx =
3382 q - new_strings;
3383 else
3384 new_symbols64[inew_syms].n_un.n_strx =
3385 q - new_strings;
3386 q += strlen(q) + 1;
3388 inew_syms++;
3389 saves[i] = inew_syms;
3393 #ifdef TRIE_SUPPORT
3394 inew_nextdefsym = inew_syms;
3395 #endif /* TRIE_SUPPORT */
3396 for(i = 0; i < nsyms; i++){
3397 if(saves[i]){
3398 if(object->mh != NULL){
3399 n_strx = symbols[i].n_un.n_strx;
3400 n_type = symbols[i].n_type;
3401 n_value = symbols[i].n_value;
3403 else{
3404 n_strx = symbols64[i].n_un.n_strx;
3405 n_type = symbols64[i].n_type;
3406 n_value = symbols64[i].n_value;
3408 if((n_type & N_EXT) == N_EXT &&
3409 ((n_type & N_TYPE) != N_UNDF &&
3410 (n_type & N_TYPE) != N_PBUD)){
3411 if(object->mh != NULL)
3412 new_symbols[inew_syms] = symbols[i];
3413 else
3414 new_symbols64[inew_syms] = symbols64[i];
3415 if(n_strx != 0){
3416 strcpy(p, strings + n_strx);
3417 if(object->mh != NULL)
3418 new_symbols[inew_syms].n_un.n_strx =
3419 p - new_strings;
3420 else
3421 new_symbols64[inew_syms].n_un.n_strx =
3422 p - new_strings;
3423 p += strlen(p) + 1;
3425 if((n_type & N_TYPE) == N_INDR){
3426 if(n_value != 0){
3427 strcpy(p, strings + n_value);
3428 if(object->mh != NULL)
3429 new_symbols[inew_syms].n_value =
3430 p - new_strings;
3431 else
3432 new_symbols64[inew_syms].n_value =
3433 p - new_strings;
3434 p += strlen(p) + 1;
3437 inew_syms++;
3438 saves[i] = inew_syms;
3443 * Build the new undefined symbols into a map and sort it.
3445 inew_undefsyms = 0;
3446 if(object->mh != NULL){
3447 undef_map = (struct undef_map *)allocate(new_nundefsym *
3448 sizeof(struct undef_map));
3449 undef_map64 = NULL;
3451 else{
3452 undef_map = NULL;
3453 undef_map64 = (struct undef_map64 *)allocate(new_nundefsym *
3454 sizeof(struct undef_map64));
3456 for(i = 0; i < nsyms; i++){
3457 if(saves[i]){
3458 if(object->mh != NULL){
3459 n_strx = symbols[i].n_un.n_strx;
3460 n_type = symbols[i].n_type;
3462 else{
3463 n_strx = symbols64[i].n_un.n_strx;
3464 n_type = symbols64[i].n_type;
3466 if((n_type & N_EXT) == N_EXT &&
3467 ((n_type & N_TYPE) == N_UNDF ||
3468 (n_type & N_TYPE) == N_PBUD)){
3469 if(object->mh != NULL)
3470 undef_map[inew_undefsyms].symbol = symbols[i];
3471 else
3472 undef_map64[inew_undefsyms].symbol64 = symbols64[i];
3473 if(n_strx != 0){
3474 strcpy(p, strings + n_strx);
3475 if(object->mh != NULL)
3476 undef_map[inew_undefsyms].symbol.n_un.n_strx =
3477 p - new_strings;
3478 else
3479 undef_map64[inew_undefsyms].symbol64.n_un.n_strx =
3480 p - new_strings;
3481 p += strlen(p) + 1;
3483 if(object->mh != NULL)
3484 undef_map[inew_undefsyms].index = i;
3485 else
3486 undef_map64[inew_undefsyms].index = i;
3487 inew_undefsyms++;
3491 for(i = 0; i < nsyms; i++){
3492 if(changes[i]){
3493 if(object->mh != NULL)
3494 n_strx = symbols[i].n_un.n_strx;
3495 else
3496 n_strx = symbols64[i].n_un.n_strx;
3497 if(n_strx != 0){
3498 strcpy(p, strings + n_strx);
3499 if(object->mh != NULL)
3500 undef_map[inew_undefsyms].symbol.n_un.n_strx =
3501 p - new_strings;
3502 else
3503 undef_map64[inew_undefsyms].symbol64.n_un.n_strx =
3504 p - new_strings;
3505 p += strlen(p) + 1;
3507 if(object->mh != NULL){
3508 undef_map[inew_undefsyms].symbol.n_type = N_UNDF | N_EXT;
3509 undef_map[inew_undefsyms].symbol.n_sect = NO_SECT;
3510 undef_map[inew_undefsyms].symbol.n_desc = 0;
3511 undef_map[inew_undefsyms].symbol.n_value = 0;
3512 undef_map[inew_undefsyms].index = i;
3514 else{
3515 undef_map64[inew_undefsyms].symbol64.n_type = N_UNDF |N_EXT;
3516 undef_map64[inew_undefsyms].symbol64.n_sect = NO_SECT;
3517 undef_map64[inew_undefsyms].symbol64.n_desc = 0;
3518 undef_map64[inew_undefsyms].symbol64.n_value = 0;
3519 undef_map64[inew_undefsyms].index = i;
3521 inew_undefsyms++;
3524 /* Sort the undefined symbols by name */
3525 qsort_strings = new_strings;
3526 if(object->mh != NULL)
3527 qsort(undef_map, new_nundefsym, sizeof(struct undef_map),
3528 (int (*)(const void *, const void *))cmp_qsort_undef_map);
3529 else
3530 qsort(undef_map64, new_nundefsym, sizeof(struct undef_map64),
3531 (int (*)(const void *, const void *))cmp_qsort_undef_map_64);
3532 /* Copy the symbols now in sorted order into new_symbols */
3533 for(i = 0; i < new_nundefsym; i++){
3534 if(object->mh != NULL){
3535 new_symbols[inew_syms] = undef_map[i].symbol;
3536 inew_syms++;
3537 saves[undef_map[i].index] = inew_syms;
3539 else{
3540 new_symbols64[inew_syms] = undef_map64[i].symbol64;
3541 inew_syms++;
3542 saves[undef_map64[i].index] = inew_syms;
3547 * Fixup the module table's module name strings adding them to the
3548 * string table. Also fix the indexes into the symbol table for
3549 * external and local symbols. And fix up the indexes into the
3550 * reference table.
3552 for(i = 0; i < nmodtab; i++){
3553 if(object->mh != NULL){
3554 strcpy(p, strings + mods[i].module_name);
3555 mods[i].module_name = p - new_strings;
3556 iextdefsym = mods[i].iextdefsym;
3557 nextdefsym = mods[i].nextdefsym;
3558 ilocalsym = mods[i].ilocalsym;
3559 nlocalsym = mods[i].nlocalsym;
3560 irefsym = mods[i].irefsym;
3561 nrefsym = mods[i].nrefsym;
3563 else{
3564 strcpy(p, strings + mods64[i].module_name);
3565 mods64[i].module_name = p - new_strings;
3566 iextdefsym = mods64[i].iextdefsym;
3567 nextdefsym = mods64[i].nextdefsym;
3568 ilocalsym = mods64[i].ilocalsym;
3569 nlocalsym = mods64[i].nlocalsym;
3570 irefsym = mods64[i].irefsym;
3571 nrefsym = mods64[i].nrefsym;
3573 p += strlen(p) + 1;
3575 if(iextdefsym > nsyms){
3576 error_arch(arch, member, "bad index into externally defined "
3577 "symbols of module table entry %d in: ", i);
3578 return(FALSE);
3580 if(iextdefsym + nextdefsym > nsyms){
3581 error_arch(arch, member, "bad number of externally defined "
3582 "symbols of module table entry %d in: ", i);
3583 return(FALSE);
3585 for(j = iextdefsym; j < iextdefsym + nextdefsym; j++){
3586 if(saves[j] != 0 && changes[j] == 0)
3587 break;
3589 n = 0;
3590 for(k = j; k < iextdefsym + nextdefsym; k++){
3591 if(saves[k] != 0 && changes[k] == 0)
3592 n++;
3594 if(n == 0){
3595 if(object->mh != NULL){
3596 mods[i].iextdefsym = 0;
3597 mods[i].nextdefsym = 0;
3599 else{
3600 mods64[i].iextdefsym = 0;
3601 mods64[i].nextdefsym = 0;
3604 else{
3605 if(object->mh != NULL){
3606 mods[i].iextdefsym = saves[j] - 1;
3607 mods[i].nextdefsym = n;
3609 else{
3610 mods64[i].iextdefsym = saves[j] - 1;
3611 mods64[i].nextdefsym = n;
3615 if(ilocalsym > nsyms){
3616 error_arch(arch, member, "bad index into symbols for local "
3617 "symbols of module table entry %d in: ", i);
3618 return(FALSE);
3620 if(ilocalsym + nlocalsym > nsyms){
3621 error_arch(arch, member, "bad number of local "
3622 "symbols of module table entry %d in: ", i);
3623 return(FALSE);
3625 for(j = ilocalsym; j < ilocalsym + nlocalsym; j++){
3626 if(saves[j] != 0)
3627 break;
3629 n = 0;
3630 for(k = j; k < ilocalsym + nlocalsym; k++){
3631 if(saves[k] != 0)
3632 n++;
3634 if(n == 0){
3635 if(object->mh != NULL){
3636 mods[i].ilocalsym = 0;
3637 mods[i].nlocalsym = 0;
3639 else{
3640 mods64[i].ilocalsym = 0;
3641 mods64[i].nlocalsym = 0;
3644 else{
3645 if(object->mh != NULL){
3646 mods[i].ilocalsym = saves[j] - 1;
3647 mods[i].nlocalsym = n;
3649 else{
3650 mods64[i].ilocalsym = saves[j] - 1;
3651 mods64[i].nlocalsym = n;
3655 if(irefsym > nextrefsyms){
3656 error_arch(arch, member, "bad index into reference table "
3657 "of module table entry %d in: ", i);
3658 return(FALSE);
3660 if(irefsym + nrefsym > nextrefsyms){
3661 error_arch(arch, member, "bad number of reference table "
3662 "entries of module table entry %d in: ", i);
3663 return(FALSE);
3665 for(j = irefsym; j < irefsym + nrefsym; j++){
3666 if(ref_saves[j] != 0)
3667 break;
3669 n = 0;
3670 for(k = j; k < irefsym + nrefsym; k++){
3671 if(ref_saves[k] != 0)
3672 n++;
3674 if(n == 0){
3675 if(object->mh != NULL){
3676 mods[i].irefsym = 0;
3677 mods[i].nrefsym = 0;
3679 else{
3680 mods64[i].irefsym = 0;
3681 mods64[i].nrefsym = 0;
3684 else{
3685 if(object->mh != NULL){
3686 mods[i].irefsym = ref_saves[j] - 1;
3687 mods[i].nrefsym = n;
3689 else{
3690 mods64[i].irefsym = ref_saves[j] - 1;
3691 mods64[i].nrefsym = n;
3697 * Create a new reference table.
3699 new_refs = allocate(new_nextrefsyms * sizeof(struct dylib_reference));
3700 j = 0;
3701 for(i = 0; i < nextrefsyms; i++){
3702 if(ref_saves[i]){
3703 if(saves[refs[i].isym]){
3704 new_refs[j].isym = saves[refs[i].isym] - 1;
3705 new_refs[j].flags = refs[i].flags;
3707 else{
3708 if(refs[i].flags == REFERENCE_FLAG_UNDEFINED_NON_LAZY ||
3709 refs[i].flags == REFERENCE_FLAG_UNDEFINED_LAZY){
3710 new_refs[j].isym = changes[refs[i].isym] - 1;
3711 new_refs[j].flags = refs[i].flags;
3714 j++;
3719 * Create a new dylib table of contents.
3721 new_ntoc = 0;
3722 for(i = 0; i < ntoc; i++){
3723 if(tocs[i].symbol_index >= nsyms){
3724 error_arch(arch, member, "bad symbol index for table of "
3725 "contents table entry %d in: ", i);
3726 return(FALSE);
3728 if(saves[tocs[i].symbol_index] != 0 &&
3729 changes[tocs[i].symbol_index] == 0)
3730 new_ntoc++;
3732 new_tocs = allocate(new_ntoc * sizeof(struct dylib_table_of_contents));
3733 j = 0;
3734 for(i = 0; i < ntoc; i++){
3735 if(saves[tocs[i].symbol_index] != 0 &&
3736 changes[tocs[i].symbol_index] == 0){
3737 new_tocs[j].symbol_index = saves[tocs[i].symbol_index] - 1;
3738 new_tocs[j].module_index = tocs[i].module_index;
3739 j++;
3742 #ifdef TRIE_SUPPORT
3744 * Update the export trie if it has one but only call the the
3745 * prune_trie() routine when we are removing global symbols as is
3746 * done with default stripping of a dyld executable or with the -s
3747 * or -R options.
3749 if(object->dyld_info != NULL &&
3750 object->dyld_info->export_size != 0 &&
3751 (default_dyld_executable || sfile != NULL || Rfile != NULL)){
3752 const char *error_string;
3753 uint32_t trie_new_size;
3755 error_string = prune_trie((uint8_t *)(object->object_addr +
3756 object->dyld_info->export_off),
3757 object->dyld_info->export_size,
3758 prune,
3759 &trie_new_size);
3760 if(error_string != NULL){
3761 error_arch(arch, member, "%s", error_string);
3762 return(FALSE);
3765 #endif /* TRIE_SUPPORT */
3767 if(undef_map != NULL)
3768 free(undef_map);
3769 if(undef_map64 != NULL)
3770 free(undef_map64);
3771 if(changes != NULL)
3772 free(changes);
3773 if(sections != NULL)
3774 free(sections);
3775 if(sections64 != NULL)
3776 free(sections64);
3778 if(errors == 0)
3779 return(TRUE);
3780 else
3781 return(FALSE);
3784 #ifdef TRIE_SUPPORT
3786 * prune() is called by prune_trie() and passed a name of an external symbol
3787 * in the trie. It returns 1 if the symbols is to be pruned out and 0 if the
3788 * symbol is to be kept.
3790 * Note that it may seem like a linear search of the new symbols would not be
3791 * the best approach but in 10.6 the only defined global symbol left in a
3792 * stripped executable is __mh_execute_header and new_nextdefsym is usually 1
3793 * so this never actually loops in practice.
3795 static
3797 prune(
3798 const char *name)
3800 uint32_t i;
3802 for(i = 0; i < new_nextdefsym; i++){
3803 if(new_symbols != NULL){
3804 if(strcmp(name, new_strings + new_symbols[inew_nextdefsym + i]
3805 .n_un.n_strx) == 0)
3806 return(0);
3808 else{
3809 if(strcmp(name, new_strings + new_symbols64[inew_nextdefsym + i]
3810 .n_un.n_strx) == 0)
3811 return(0);
3814 return(1);
3816 #endif /* TRIE_SUPPORT */
3819 * make_ld_r_object() takes the object file contents referenced by the passed
3820 * data structures, writes that to a temporary file, runs "ld -r" plus the
3821 * specified stripping option creating a second temporary file, reads that file
3822 * in and replaces the object file contents with that and resets the variables
3823 * pointing to the symbol, string and indirect tables.
3825 static
3826 void
3827 make_ld_r_object(
3828 struct arch *arch,
3829 struct member *member,
3830 struct object *object)
3832 enum byte_sex host_byte_sex;
3833 char *input_file, *output_file;
3834 int fd;
3835 struct ofile *ld_r_ofile;
3836 struct arch *ld_r_archs;
3837 uint32_t ld_r_narchs, save_errors;
3839 host_byte_sex = get_host_byte_sex();
3842 * Swap the object file back into its bytesex before writing it to the
3843 * temporary file if needed.
3845 if(object->object_byte_sex != host_byte_sex){
3846 if(object->mh != NULL){
3847 if(swap_object_headers(object->mh, object->load_commands) ==
3848 FALSE)
3849 fatal("internal error: swap_object_headers() failed");
3850 swap_nlist(symbols, nsyms, object->object_byte_sex);
3852 else{
3853 if(swap_object_headers(object->mh64, object->load_commands) ==
3854 FALSE)
3855 fatal("internal error: swap_object_headers() failed");
3856 swap_nlist_64(symbols64, nsyms, object->object_byte_sex);
3858 swap_indirect_symbols(indirectsyms, nindirectsyms,
3859 object->object_byte_sex);
3863 * Create an input object file for the ld -r command from the bytes
3864 * of this arch's object file.
3866 input_file = makestr("/tmp/strip.XXXXXX", NULL);
3867 input_file = mktemp(input_file);
3869 if((fd = open(input_file, O_WRONLY|O_CREAT, 0600)) < 0)
3870 system_fatal("can't open temporary file: %s", input_file);
3872 if(write(fd, object->object_addr, object->object_size) !=
3873 object->object_size)
3874 system_fatal("can't write temporary file: %s", input_file);
3876 if(close(fd) == -1)
3877 system_fatal("can't close temporary file: %s", input_file);
3880 * Create a temporary name for the output file of the ld -r
3882 output_file = makestr("/tmp/strip.XXXXXX", NULL);
3883 output_file = mktemp(output_file);
3886 * Create the ld -r command line and execute it.
3888 reset_execute_list();
3889 add_execute_list_with_prefix("ld");
3890 add_execute_list("-keep_private_externs");
3891 add_execute_list("-r");
3892 if(Sflag)
3893 add_execute_list("-S");
3894 if(xflag)
3895 add_execute_list("-x");
3896 add_execute_list(input_file);
3897 add_execute_list("-o");
3898 add_execute_list(output_file);
3899 if(sfile != NULL){
3900 add_execute_list("-x");
3901 add_execute_list("-exported_symbols_list");
3902 add_execute_list(sfile);
3904 if(Rfile != NULL){
3905 add_execute_list("-unexported_symbols_list");
3906 add_execute_list(Rfile);
3908 if(execute_list(vflag) == 0)
3909 fatal("internal link edit command failed");
3911 save_errors = errors;
3912 errors = 0;
3913 /* breakout the output file of the ld -f for processing */
3914 ld_r_ofile = breakout(output_file, &ld_r_archs, &ld_r_narchs, FALSE);
3915 if(errors)
3916 goto make_ld_r_object_cleanup;
3918 /* checkout the file for symbol table replacement processing */
3919 checkout(ld_r_archs, ld_r_narchs);
3922 * Make sure the output of the ld -r is an object file with one arch.
3924 if(ld_r_narchs != 1 ||
3925 ld_r_archs->type != OFILE_Mach_O ||
3926 ld_r_archs->object == NULL ||
3927 ld_r_archs->object->mh_filetype != MH_OBJECT)
3928 fatal("internal link edit command failed to produce a thin Mach-O "
3929 "object file");
3932 * Now reset all the data of the input object with the ld -r output
3933 * object file.
3935 nsyms = ld_r_archs->object->st->nsyms;
3936 if(ld_r_archs->object->mh != NULL){
3937 symbols = (struct nlist *)
3938 (ld_r_archs->object->object_addr +
3939 ld_r_archs->object->st->symoff);
3940 if(ld_r_archs->object->object_byte_sex != host_byte_sex)
3941 swap_nlist(symbols, nsyms, host_byte_sex);
3942 symbols64 = NULL;
3944 else{
3945 symbols = NULL;
3946 symbols64 = (struct nlist_64 *)
3947 (ld_r_archs->object->object_addr +
3948 ld_r_archs->object->st->symoff);
3949 if(ld_r_archs->object->object_byte_sex != host_byte_sex)
3950 swap_nlist_64(symbols64, nsyms, host_byte_sex);
3952 strings = ld_r_archs->object->object_addr +
3953 ld_r_archs->object->st->stroff;
3954 strsize = ld_r_archs->object->st->strsize;
3956 if(ld_r_archs->object->dyst != NULL &&
3957 ld_r_archs->object->dyst->nindirectsyms != 0){
3958 nindirectsyms = ld_r_archs->object->dyst->nindirectsyms;
3959 indirectsyms = (uint32_t *)
3960 (ld_r_archs->object->object_addr +
3961 ld_r_archs->object->dyst->indirectsymoff);
3962 if(ld_r_archs->object->object_byte_sex != host_byte_sex)
3963 swap_indirect_symbols(indirectsyms, nindirectsyms,
3964 host_byte_sex);
3966 else{
3967 indirectsyms = NULL;
3968 nindirectsyms = 0;
3971 if(ld_r_archs->object->mh != NULL)
3972 ld_r_archs->object->input_sym_info_size =
3973 nsyms * sizeof(struct nlist) +
3974 strsize;
3975 else
3976 ld_r_archs->object->input_sym_info_size =
3977 nsyms * sizeof(struct nlist_64) +
3978 strsize;
3981 * Copy over the object struct from the ld -r object file onto the
3982 * input object file.
3984 *object = *ld_r_archs->object;
3987 * Save the ofile struct for the ld -r output so it can be umapped when
3988 * we are done. And free up the ld_r_archs now that we are done with
3989 * them.
3991 object->ld_r_ofile = ld_r_ofile;
3992 free_archs(ld_r_archs, ld_r_narchs);
3994 make_ld_r_object_cleanup:
3995 errors += save_errors;
3997 * Remove the input and output files and clean up.
3999 if(unlink(input_file) == -1)
4000 system_fatal("can't remove temporary file: %s", input_file);
4001 if(unlink(output_file) == -1)
4002 system_fatal("can't remove temporary file: %s", output_file);
4003 free(input_file);
4004 free(output_file);
4008 * strip_LC_UUID_commands() is called when -no_uuid is specified to remove any
4009 * LC_UUID load commands from the object's load commands.
4011 static
4012 void
4013 strip_LC_UUID_commands(
4014 struct arch *arch,
4015 struct member *member,
4016 struct object *object)
4018 uint32_t i, ncmds, nuuids, mh_sizeofcmds, sizeofcmds;
4019 struct load_command *lc1, *lc2, *new_load_commands;
4020 struct segment_command *sg;
4023 * See if there are any LC_UUID load commands.
4025 nuuids = 0;
4026 lc1 = arch->object->load_commands;
4027 if(arch->object->mh != NULL){
4028 ncmds = arch->object->mh->ncmds;
4029 mh_sizeofcmds = arch->object->mh->sizeofcmds;
4031 else{
4032 ncmds = arch->object->mh64->ncmds;
4033 mh_sizeofcmds = arch->object->mh64->sizeofcmds;
4035 for(i = 0; i < ncmds; i++){
4036 if(lc1->cmd == LC_UUID){
4037 nuuids++;
4039 lc1 = (struct load_command *)((char *)lc1 + lc1->cmdsize);
4041 /* if no LC_UUID load commands just return */
4042 if(nuuids == 0)
4043 return;
4046 * Allocate space for the new load commands as zero it out so any holes
4047 * will be zero bytes.
4049 new_load_commands = allocate(mh_sizeofcmds);
4050 memset(new_load_commands, '\0', mh_sizeofcmds);
4053 * Copy all the load commands except the LC_UUID load commands into the
4054 * allocated space for the new load commands.
4056 lc1 = arch->object->load_commands;
4057 lc2 = new_load_commands;
4058 sizeofcmds = 0;
4059 for(i = 0; i < ncmds; i++){
4060 if(lc1->cmd != LC_UUID){
4061 memcpy(lc2, lc1, lc1->cmdsize);
4062 sizeofcmds += lc2->cmdsize;
4063 lc2 = (struct load_command *)((char *)lc2 + lc2->cmdsize);
4065 lc1 = (struct load_command *)((char *)lc1 + lc1->cmdsize);
4069 * Finally copy the updated load commands over the existing load
4070 * commands.
4072 memcpy(arch->object->load_commands, new_load_commands, sizeofcmds);
4073 if(mh_sizeofcmds > sizeofcmds){
4074 memset((char *)arch->object->load_commands + sizeofcmds, '\0',
4075 (mh_sizeofcmds - sizeofcmds));
4077 ncmds -= nuuids;
4078 if(arch->object->mh != NULL) {
4079 arch->object->mh->sizeofcmds = sizeofcmds;
4080 arch->object->mh->ncmds = ncmds;
4081 } else {
4082 arch->object->mh64->sizeofcmds = sizeofcmds;
4083 arch->object->mh64->ncmds = ncmds;
4085 free(new_load_commands);
4087 /* reset the pointers into the load commands */
4088 lc1 = arch->object->load_commands;
4089 for(i = 0; i < ncmds; i++){
4090 switch(lc1->cmd){
4091 case LC_SYMTAB:
4092 arch->object->st = (struct symtab_command *)lc1;
4093 break;
4094 case LC_DYSYMTAB:
4095 arch->object->dyst = (struct dysymtab_command *)lc1;
4096 break;
4097 case LC_TWOLEVEL_HINTS:
4098 arch->object->hints_cmd = (struct twolevel_hints_command *)lc1;
4099 break;
4100 case LC_PREBIND_CKSUM:
4101 arch->object->cs = (struct prebind_cksum_command *)lc1;
4102 break;
4103 case LC_SEGMENT:
4104 sg = (struct segment_command *)lc1;
4105 if(strcmp(sg->segname, SEG_LINKEDIT) == 0)
4106 arch->object->seg_linkedit = sg;
4107 break;
4108 case LC_SEGMENT_SPLIT_INFO:
4109 object->split_info_cmd = (struct linkedit_data_command *)lc1;
4110 break;
4111 case LC_FUNCTION_STARTS:
4112 object->func_starts_info_cmd =
4113 (struct linkedit_data_command *)lc1;
4114 break;
4115 case LC_DATA_IN_CODE:
4116 object->data_in_code_cmd =
4117 (struct linkedit_data_command *)lc1;
4118 break;
4119 case LC_DYLIB_CODE_SIGN_DRS:
4120 object->code_sign_drs_cmd =
4121 (struct linkedit_data_command *)lc1;
4122 break;
4123 case LC_CODE_SIGNATURE:
4124 object->code_sig_cmd = (struct linkedit_data_command *)lc1;
4125 break;
4126 case LC_DYLD_INFO_ONLY:
4127 case LC_DYLD_INFO:
4128 object->dyld_info = (struct dyld_info_command *)lc1;
4130 lc1 = (struct load_command *)((char *)lc1 + lc1->cmdsize);
4134 #ifndef NMEDIT
4136 * strip_LC_CODE_SIGNATURE_commands() is called when -c is specified to remove
4137 * any LC_CODE_SIGNATURE load commands from the object's load commands.
4139 static
4140 void
4141 strip_LC_CODE_SIGNATURE_commands(
4142 struct arch *arch,
4143 struct member *member,
4144 struct object *object)
4146 uint32_t i, ncmds, mh_sizeofcmds, sizeofcmds;
4147 struct load_command *lc1, *lc2, *new_load_commands;
4148 struct segment_command *sg;
4151 * See if there is an LC_CODE_SIGNATURE load command and if no command
4152 * just return.
4154 if(object->code_sig_cmd == NULL)
4155 return;
4158 * Allocate space for the new load commands and zero it out so any holes
4159 * will be zero bytes.
4161 if(arch->object->mh != NULL){
4162 ncmds = arch->object->mh->ncmds;
4163 mh_sizeofcmds = arch->object->mh->sizeofcmds;
4165 else{
4166 ncmds = arch->object->mh64->ncmds;
4167 mh_sizeofcmds = arch->object->mh64->sizeofcmds;
4169 new_load_commands = allocate(mh_sizeofcmds);
4170 memset(new_load_commands, '\0', mh_sizeofcmds);
4173 * Copy all the load commands except the LC_CODE_SIGNATURE load commands
4174 * into the allocated space for the new load commands.
4176 lc1 = arch->object->load_commands;
4177 lc2 = new_load_commands;
4178 sizeofcmds = 0;
4179 for(i = 0; i < ncmds; i++){
4180 if(lc1->cmd != LC_CODE_SIGNATURE){
4181 memcpy(lc2, lc1, lc1->cmdsize);
4182 sizeofcmds += lc2->cmdsize;
4183 lc2 = (struct load_command *)((char *)lc2 + lc2->cmdsize);
4185 lc1 = (struct load_command *)((char *)lc1 + lc1->cmdsize);
4189 * Finally copy the updated load commands over the existing load
4190 * commands.
4192 memcpy(arch->object->load_commands, new_load_commands, sizeofcmds);
4193 if(mh_sizeofcmds > sizeofcmds){
4194 memset((char *)arch->object->load_commands + sizeofcmds, '\0',
4195 (mh_sizeofcmds - sizeofcmds));
4197 ncmds -= 1;
4198 if(arch->object->mh != NULL) {
4199 arch->object->mh->sizeofcmds = sizeofcmds;
4200 arch->object->mh->ncmds = ncmds;
4201 } else {
4202 arch->object->mh64->sizeofcmds = sizeofcmds;
4203 arch->object->mh64->ncmds = ncmds;
4205 free(new_load_commands);
4207 /* reset the pointers into the load commands */
4208 object->code_sig_cmd = NULL;
4209 lc1 = arch->object->load_commands;
4210 for(i = 0; i < ncmds; i++){
4211 switch(lc1->cmd){
4212 case LC_SYMTAB:
4213 arch->object->st = (struct symtab_command *)lc1;
4214 break;
4215 case LC_DYSYMTAB:
4216 arch->object->dyst = (struct dysymtab_command *)lc1;
4217 break;
4218 case LC_TWOLEVEL_HINTS:
4219 arch->object->hints_cmd = (struct twolevel_hints_command *)lc1;
4220 break;
4221 case LC_PREBIND_CKSUM:
4222 arch->object->cs = (struct prebind_cksum_command *)lc1;
4223 break;
4224 case LC_SEGMENT:
4225 sg = (struct segment_command *)lc1;
4226 if(strcmp(sg->segname, SEG_LINKEDIT) == 0)
4227 arch->object->seg_linkedit = sg;
4228 break;
4229 case LC_SEGMENT_SPLIT_INFO:
4230 object->split_info_cmd = (struct linkedit_data_command *)lc1;
4231 break;
4232 case LC_FUNCTION_STARTS:
4233 object->func_starts_info_cmd =
4234 (struct linkedit_data_command *)lc1;
4235 break;
4236 case LC_DATA_IN_CODE:
4237 object->data_in_code_cmd =
4238 (struct linkedit_data_command *)lc1;
4239 break;
4240 case LC_DYLIB_CODE_SIGN_DRS:
4241 object->code_sign_drs_cmd =
4242 (struct linkedit_data_command *)lc1;
4243 break;
4245 lc1 = (struct load_command *)((char *)lc1 + lc1->cmdsize);
4249 * To get the right amount of the file copied out by writeout() for the
4250 * case when we are stripping out the section contents we already reduce
4251 * the object size by the size of the section contents including the
4252 * padding after the load commands. So here we need to further reduce
4253 * it by the load command for the LC_CODE_SIGNATURE (a struct
4254 * linkedit_data_command) we are removing.
4256 object->object_size -= sizeof(struct linkedit_data_command);
4258 * Then this size minus the size of the input symbolic information is
4259 * what is copied out from the file by writeout(). Which in this case
4260 * is just the new headers.
4264 * Finally for -c the file offset to the link edit information is to be
4265 * right after the load commands. So reset this for the updated size
4266 * of the load commands without the LC_CODE_SIGNATURE.
4268 if(object->mh != NULL)
4269 object->seg_linkedit->fileoff = sizeof(struct mach_header) +
4270 sizeofcmds;
4271 else
4272 object->seg_linkedit64->fileoff = sizeof(struct mach_header_64) +
4273 sizeofcmds;
4275 #endif /* !(NMEDIT) */
4278 * private_extern_reference_by_module() is passed a symbol_index of a private
4279 * extern symbol and the module table. If the symbol_index appears in the
4280 * module symbol table this returns TRUE else it returns FALSE.
4282 static
4283 enum bool
4284 private_extern_reference_by_module(
4285 uint32_t symbol_index,
4286 struct dylib_reference *refs,
4287 uint32_t nextrefsyms)
4289 uint32_t i;
4291 for(i = 0; i < nextrefsyms; i++){
4292 if(refs[i].isym == symbol_index){
4293 if(refs[i].flags == REFERENCE_FLAG_PRIVATE_UNDEFINED_NON_LAZY ||
4294 refs[i].flags == REFERENCE_FLAG_PRIVATE_UNDEFINED_LAZY){
4295 return(TRUE);
4299 return(FALSE);
4303 * symbol_pointer_used() is passed a symbol_index and the indirect table. If
4304 * the symbol_index appears in the indirect symbol table this returns TRUE else
4305 * it returns FALSE.
4307 static
4308 enum bool
4309 symbol_pointer_used(
4310 uint32_t symbol_index,
4311 uint32_t *indirectsyms,
4312 uint32_t nindirectsyms)
4314 uint32_t i;
4316 for(i = 0; i < nindirectsyms; i++){
4317 if(indirectsyms[i] == symbol_index)
4318 return(TRUE);
4320 return(FALSE);
4324 * Function for qsort for comparing undefined map entries.
4326 static
4328 cmp_qsort_undef_map(
4329 const struct undef_map *sym1,
4330 const struct undef_map *sym2)
4332 return(strcmp(qsort_strings + sym1->symbol.n_un.n_strx,
4333 qsort_strings + sym2->symbol.n_un.n_strx));
4336 static
4338 cmp_qsort_undef_map_64(
4339 const struct undef_map64 *sym1,
4340 const struct undef_map64 *sym2)
4342 return(strcmp(qsort_strings + sym1->symbol64.n_un.n_strx,
4343 qsort_strings + sym2->symbol64.n_un.n_strx));
4345 #endif /* !defined(NMEDIT) */
4347 #ifndef NMEDIT
4349 * Function for qsort for comparing object names.
4351 static
4353 cmp_qsort_filename(
4354 const char **name1,
4355 const char **name2)
4357 return(strcmp(*name1, *name2));
4361 * Function for bsearch for finding a object name.
4363 static
4365 cmp_bsearch_filename(
4366 const char *name1,
4367 const char **name2)
4369 return(strcmp(name1, *name2));
4371 #endif /* !defined(NMEDIT) */
4373 #ifdef NMEDIT
4374 static
4375 enum bool
4376 edit_symtab(
4377 struct arch *arch,
4378 struct member *member,
4379 struct object *object,
4380 struct nlist *symbols,
4381 struct nlist_64 *symbols64,
4382 uint32_t nsyms,
4383 char *strings,
4384 uint32_t strsize,
4385 struct dylib_table_of_contents *tocs,
4386 uint32_t ntoc,
4387 struct dylib_module *mods,
4388 struct dylib_module_64 *mods64,
4389 uint32_t nmodtab,
4390 struct dylib_reference *refs,
4391 uint32_t nextrefsyms)
4393 uint32_t i, j, k;
4394 unsigned char data_n_sect, nsects;
4395 struct load_command *lc;
4396 struct segment_command *sg;
4397 struct segment_command_64 *sg64;
4398 struct section *s, **sections;
4399 struct section_64 *s64, **sections64;
4401 uint32_t missing_syms;
4402 struct symbol_list *sp;
4403 struct nlist **global_symbol;
4404 struct nlist_64 **global_symbol64;
4405 enum bool global_symbol_found;
4406 char *global_name, save_char;
4407 enum bool dwarf_debug_map;
4408 enum byte_sex host_byte_sex;
4409 int32_t missing_reloc_symbols;
4410 enum bool edit_symtab_return;
4412 char *p, *q;
4413 uint32_t new_ext_strsize, len, inew_syms;
4415 struct nlist **changed_globals;
4416 struct nlist_64 **changed_globals64;
4417 uint32_t nchanged_globals;
4418 uint32_t ncmds, s_flags, n_strx, module_name, ilocalsym, nlocalsym;
4419 uint32_t iextdefsym, nextdefsym;
4420 uint8_t n_type, n_sect, global_symbol_n_sect;
4421 uint64_t n_value;
4422 enum bool warned_about_global_coalesced_symbols;
4424 edit_symtab_return = TRUE;
4425 host_byte_sex = get_host_byte_sex();
4426 missing_reloc_symbols = 0;
4427 warned_about_global_coalesced_symbols = FALSE;
4429 if(nmedits != NULL)
4430 free(nmedits);
4431 nmedits = allocate(nsyms * sizeof(enum bool));
4432 for(i = 0; i < nsyms; i++)
4433 nmedits[i] = FALSE;
4436 * If nmedit is operating on a dynamic library then symbols are turned
4437 * into private externs with the extern bit off not into static symbols.
4439 if(object->mh_filetype == MH_DYLIB && pflag == TRUE){
4440 error_arch(arch, member, "can't use -p with dynamic libraries");
4441 return(FALSE);
4445 * As part of the MAJOR guess for the second pass to fix stabs for the
4446 * globals symbols that get turned into non-global symbols. We need to
4447 * change the stabs. To do this we to know if a N_GSYM is for a data
4448 * symbol or not to know to turn it into an N_STSYM or a N_FUN.
4449 * This logic as determined by compiling test cases with and without
4450 * the key word 'static' and looking at the difference between the STABS
4451 * the compiler generates and trying to match that here.
4453 * We also use this loop and the next to gather an array of section
4454 * struct pointers so we can later determine if we run into a global
4455 * symbol in a coalesced section and not turn those symbols into
4456 * statics.
4458 j = 0;
4459 nsects = 0;
4460 n_sect = 1;
4461 data_n_sect = NO_SECT;
4462 lc = object->load_commands;
4463 if(object->mh != NULL)
4464 ncmds = object->mh->ncmds;
4465 else
4466 ncmds = object->mh64->ncmds;
4467 for(i = 0; i < ncmds; i++){
4468 if(lc->cmd == LC_SEGMENT){
4469 sg = (struct segment_command *)lc;
4470 s = (struct section *)((char *)sg +
4471 sizeof(struct segment_command));
4472 nsects += sg->nsects;
4473 for(j = 0; j < sg->nsects; j++){
4474 if(strcmp(s->segname, SEG_DATA) == 0 &&
4475 strcmp(s->sectname, SECT_DATA) == 0 &&
4476 data_n_sect == NO_SECT){
4477 data_n_sect = n_sect;
4478 break;
4480 n_sect++;
4481 s++;
4484 else if(lc->cmd == LC_SEGMENT_64){
4485 sg64 = (struct segment_command_64 *)lc;
4486 s64 = (struct section_64 *)((char *)sg64 +
4487 sizeof(struct segment_command_64));
4488 nsects += sg64->nsects;
4489 for(j = 0; j < sg64->nsects; j++){
4490 if(strcmp(s64->segname, SEG_DATA) == 0 &&
4491 strcmp(s64->sectname, SECT_DATA) == 0 &&
4492 data_n_sect == NO_SECT){
4493 data_n_sect = n_sect;
4494 break;
4496 n_sect++;
4497 s64++;
4500 lc = (struct load_command *)((char *)lc + lc->cmdsize);
4502 if(object->mh != NULL){
4503 sections = allocate(nsects * sizeof(struct section *));
4504 sections64 = NULL;
4506 else{
4507 sections = NULL;
4508 sections64 = allocate(nsects * sizeof(struct section_64 *));
4510 nsects = 0;
4511 lc = object->load_commands;
4512 for(i = 0; i < ncmds; i++){
4513 if(lc->cmd == LC_SEGMENT){
4514 sg = (struct segment_command *)lc;
4515 s = (struct section *)((char *)sg +
4516 sizeof(struct segment_command));
4517 for(j = 0; j < sg->nsects; j++){
4518 sections[nsects++] = s++;
4521 else if(lc->cmd == LC_SEGMENT_64){
4522 sg64 = (struct segment_command_64 *)lc;
4523 s64 = (struct section_64 *)((char *)sg64 +
4524 sizeof(struct segment_command_64));
4525 for(j = 0; j < sg64->nsects; j++){
4526 sections64[nsects++] = s64++;
4529 lc = (struct load_command *)((char *)lc + lc->cmdsize);
4533 * Zero out the saved symbols so they can be recorded for this file.
4535 for(i = 0; i < nsave_symbols; i++)
4536 save_symbols[i].sym = NULL;
4537 for(i = 0; i < nremove_symbols; i++)
4538 remove_symbols[i].sym = NULL;
4539 if(member == NULL){
4540 for(i = 0; i < nsave_symbols; i++)
4541 save_symbols[i].seen = FALSE;
4542 for(i = 0; i < nremove_symbols; i++)
4543 remove_symbols[i].seen = FALSE;
4546 nchanged_globals = 0;
4547 if(object->mh != NULL){
4548 changed_globals = allocate(nsyms * sizeof(struct nlist *));
4549 changed_globals64 = NULL;
4550 for(i = 0; i < nsyms; i++)
4551 changed_globals[i] = NULL;
4553 else{
4554 changed_globals = NULL;
4555 changed_globals64 = allocate(nsyms * sizeof(struct nlist_64 *));
4556 for(i = 0; i < nsyms; i++)
4557 changed_globals64[i] = NULL;
4561 * These are the variables for the new symbol table and new string
4562 * table. Since this routine only turns globals into non-globals the
4563 * number of symbols does not change. But the count of local, defined
4564 * external symbols does change.
4566 new_nsyms = nsyms;
4567 new_nlocalsym = 0;
4568 new_nextdefsym = 0;
4569 new_nundefsym = 0;
4571 new_strsize = sizeof(int32_t);
4572 new_ext_strsize = 0;
4575 * First pass: turn the globals symbols into non-global symbols.
4577 for(i = 0; i < nsyms; i++){
4578 len = 0;
4579 s_flags = 0;
4580 if(object->mh != NULL){
4581 n_strx = symbols[i].n_un.n_strx;
4582 n_type = symbols[i].n_type;
4583 n_sect = symbols[i].n_sect;
4584 if((n_type & N_TYPE) == N_SECT)
4585 s_flags = sections[n_sect - 1]->flags;
4586 n_value = symbols[i].n_value;
4588 else{
4589 n_strx = symbols64[i].n_un.n_strx;
4590 n_type = symbols64[i].n_type;
4591 n_sect = symbols64[i].n_sect;
4592 if((n_type & N_TYPE) == N_SECT)
4593 s_flags = sections64[n_sect - 1]->flags;
4594 n_value = symbols64[i].n_value;
4596 if(n_strx != 0){
4597 if(n_strx > strsize){
4598 error_arch(arch, member, "bad string index for symbol "
4599 "table entry %u in: ", i);
4600 return(FALSE);
4602 len = strlen(strings + n_strx) + 1;
4604 if(n_type & N_EXT){
4605 if((n_type & N_TYPE) != N_UNDF &&
4606 (n_type & N_TYPE) != N_PBUD){
4607 if((n_type & N_TYPE) == N_SECT){
4608 if(n_sect > nsects){
4609 error_arch(arch, member, "bad n_sect for symbol "
4610 "table entry %u in: ", i);
4611 return(FALSE);
4613 if(((s_flags & SECTION_TYPE) == S_COALESCED) &&
4614 pflag == FALSE &&
4615 object->mh_filetype != MH_OBJECT){
4616 /* this remains a global defined symbol */
4617 if(warned_about_global_coalesced_symbols == FALSE){
4618 warning_arch(arch, member, "can't make global "
4619 "coalesced symbols (like %s) into static "
4620 "symbols (use ld(1)'s "
4621 "-exported_symbols_list option) in a final "
4622 "linked image: ", strings + n_strx);
4623 warned_about_global_coalesced_symbols = TRUE;
4625 new_nextdefsym++;
4626 new_ext_strsize += len;
4627 new_strsize += len;
4628 sp = bsearch(strings + n_strx,
4629 remove_symbols, nremove_symbols,
4630 sizeof(struct symbol_list),
4631 (int (*)(const void *, const void *))
4632 symbol_list_bsearch);
4633 if(sp != NULL){
4634 if(sp->sym != NULL){
4635 error_arch(arch, member, "more than one "
4636 "symbol for: %s found in: ", sp->name);
4637 return(FALSE);
4639 else{
4640 if(object->mh != NULL)
4641 sp->sym = &(symbols[i]);
4642 else
4643 sp->sym = &(symbols64[i]);
4644 sp->seen = TRUE;
4645 warning_arch(arch, member, "can't make "
4646 "global coalesced symbol: %s into a "
4647 "static symbol in: ", sp->name);
4651 * In case the user has listed this coalesced
4652 * symbol in the save list look for it and mark it
4653 * as seen so we don't complain about not seeing it.
4655 sp = bsearch(strings + n_strx,
4656 save_symbols, nsave_symbols,
4657 sizeof(struct symbol_list),
4658 (int (*)(const void *, const void *))
4659 symbol_list_bsearch);
4660 if(sp != NULL){
4661 if(sp->sym != NULL){
4662 error_arch(arch, member, "more than one "
4663 "symbol for: %s found in: ", sp->name);
4664 return(FALSE);
4666 else{
4667 if(object->mh != NULL)
4668 sp->sym = &(symbols[i]);
4669 else
4670 sp->sym = &(symbols64[i]);
4671 sp->seen = TRUE;
4674 continue; /* leave this symbol unchanged */
4677 sp = bsearch(strings + n_strx,
4678 remove_symbols, nremove_symbols,
4679 sizeof(struct symbol_list),
4680 (int (*)(const void *, const void *))
4681 symbol_list_bsearch);
4682 if(sp != NULL){
4683 if(sp->sym != NULL){
4684 error_arch(arch, member, "more than one symbol "
4685 "for: %s found in: ", sp->name);
4686 return(FALSE);
4688 else{
4689 if(object->mh != NULL)
4690 sp->sym = &(symbols[i]);
4691 else
4692 sp->sym = &(symbols64[i]);
4693 sp->seen = TRUE;
4694 goto change_symbol;
4697 else{
4699 * If there is no list of saved symbols, then all
4700 * symbols will be saved unless listed in the remove
4701 * list.
4703 if(sfile == NULL){
4705 * There is no save list, so if there is also no
4706 * remove list but the -p flag is specified or it is
4707 * a dynamic library then change all symbols.
4709 if((pflag || object->mh_filetype == MH_DYLIB)
4710 && nremove_symbols == 0)
4711 goto change_symbol;
4712 /* this remains a global defined symbol */
4713 new_nextdefsym++;
4714 new_ext_strsize += len;
4715 new_strsize += len;
4716 continue; /* leave this symbol unchanged */
4719 sp = bsearch(strings + n_strx,
4720 save_symbols, nsave_symbols,
4721 sizeof(struct symbol_list),
4722 (int (*)(const void *, const void *))
4723 symbol_list_bsearch);
4724 if(sp != NULL){
4725 if(sp->sym != NULL){
4726 error_arch(arch, member, "more than one symbol "
4727 "for: %s found in: ", sp->name);
4728 return(FALSE);
4730 else{
4731 if(object->mh != NULL)
4732 sp->sym = &(symbols[i]);
4733 else
4734 sp->sym = &(symbols64[i]);
4735 sp->seen = TRUE;
4736 /* this remains a global defined symbol */
4737 new_nextdefsym++;
4738 new_ext_strsize += len;
4739 new_strsize += len;
4742 else{
4743 if(Aflag && n_type == (N_EXT | N_ABS) &&
4744 (n_value != 0 ||
4745 (n_strx != 0 &&
4746 strncmp(strings + n_strx,
4747 ".objc_class_name_",
4748 sizeof(".objc_class_name_") - 1) == 0))){
4749 /* this remains a global defined symbol */
4750 new_nextdefsym++;
4751 new_ext_strsize += len;
4752 new_strsize += len;
4754 else{
4755 change_symbol:
4756 if((n_type & N_TYPE) != N_INDR){
4757 nmedits[i] = TRUE;
4758 if(object->mh != NULL)
4759 changed_globals[nchanged_globals++] =
4760 symbols + i;
4761 else
4762 changed_globals64[nchanged_globals++] =
4763 symbols64 + i;
4764 if(pflag){
4765 /* this remains a global defined symbol */
4766 new_nextdefsym++;
4767 new_ext_strsize += len;
4768 new_strsize += len;
4770 else{
4771 /* this will become a non-global symbol */
4772 new_nlocalsym++;
4773 new_strsize += len;
4776 else{
4777 /* this remains a global defined symbol */
4778 new_nextdefsym++;
4779 new_ext_strsize += len;
4780 new_strsize += len;
4785 else{
4786 /* this is an undefined symbol */
4787 new_nundefsym++;
4788 new_ext_strsize += len;
4789 new_strsize += len;
4792 else{
4793 /* this is a local symbol */
4794 new_nlocalsym++;
4795 new_strsize += len;
4800 * The module table's module names are placed with the external
4801 * strings. So size them and add this to the external string size.
4803 for(i = 0; i < nmodtab; i++){
4804 if(object->mh != NULL)
4805 module_name = mods[i].module_name;
4806 else
4807 module_name = mods64[i].module_name;
4808 if(module_name == 0 || module_name > strsize){
4809 error_arch(arch, member, "bad string index for module_name "
4810 "of module table entry %d in: ", i);
4811 return(FALSE);
4813 len = strlen(strings + module_name) + 1;
4814 new_strsize += len;
4815 new_ext_strsize += len;
4819 * Warn about symbols to be saved that were missing.
4821 if(member == NULL){
4822 missing_syms = 0;
4823 if(iflag == 0){
4824 for(i = 0; i < nsave_symbols; i++){
4825 if(save_symbols[i].sym == NULL){
4826 if(missing_syms == 0){
4827 error_arch(arch, member, "symbols names listed "
4828 "in: %s not in: ", sfile);
4829 missing_syms = 1;
4831 fprintf(stderr, "%s\n", save_symbols[i].name);
4834 for(i = 0; i < nremove_symbols; i++){
4835 if(remove_symbols[i].sym == NULL){
4836 if(missing_syms == 0){
4837 error_arch(arch, member, "symbols names listed "
4838 "in: %s not in: ", Rfile);
4839 missing_syms = 1;
4841 fprintf(stderr, "%s\n", remove_symbols[i].name);
4848 * Second pass: fix stabs for the globals symbols that got turned into
4849 * non-global symbols. This is a MAJOR guess. The specific changes
4850 * to do here were determined by compiling test cases with and without
4851 * the key word 'static' and looking at the difference between the STABS
4852 * the compiler generates and trying to match that here.
4854 global_strings = strings;
4855 if(object->mh != NULL)
4856 qsort(changed_globals, nchanged_globals, sizeof(struct nlist *),
4857 (int (*)(const void *, const void *))cmp_qsort_global);
4858 else
4859 qsort(changed_globals64, nchanged_globals,sizeof(struct nlist_64 *),
4860 (int (*)(const void *, const void *))cmp_qsort_global_64);
4861 dwarf_debug_map = FALSE;
4862 for(i = 0; i < nsyms; i++){
4863 uint16_t n_desc;
4864 if(object->mh != NULL){
4865 n_strx = symbols[i].n_un.n_strx;
4866 n_type = symbols[i].n_type;
4867 n_desc = symbols[i].n_desc;
4869 else{
4870 n_strx = symbols64[i].n_un.n_strx;
4871 n_type = symbols64[i].n_type;
4872 n_desc = symbols64[i].n_desc;
4874 if(n_type == N_SO)
4875 dwarf_debug_map = FALSE;
4876 else if (n_type == N_OSO)
4877 dwarf_debug_map = n_desc != 0;
4878 else if (dwarf_debug_map && n_type == N_GSYM){
4879 global_name = strings + n_strx;
4880 if(object->mh != NULL){
4881 global_symbol = bsearch(global_name, changed_globals,
4882 nchanged_globals,sizeof(struct nlist *),
4883 (int (*)(const void *, const void *))
4884 cmp_bsearch_global);
4885 if(global_symbol != NULL){
4886 symbols[i].n_type = N_STSYM;
4887 symbols[i].n_sect = (*global_symbol)->n_sect;
4888 symbols[i].n_value = (*global_symbol)->n_value;
4891 else{
4892 global_symbol64 = bsearch(global_name, changed_globals64,
4893 nchanged_globals,
4894 sizeof(struct nlist_64 *),
4895 (int (*)(const void *, const void *))
4896 cmp_bsearch_global_64);
4897 if(global_symbol64 != NULL){
4898 symbols64[i].n_type = N_STSYM;
4899 symbols64[i].n_sect = (*global_symbol64)->n_sect;
4900 symbols64[i].n_value = (*global_symbol64)->n_value;
4904 else if(! dwarf_debug_map &&
4905 (n_type == N_GSYM || n_type == N_FUN) &&
4906 (n_strx != 0 && strings[n_strx] != '\0')){
4907 global_name = strings + n_strx;
4908 if((global_name[0] == '+' || global_name[0] == '-') &&
4909 global_name[1] == '['){
4910 j = 2;
4911 while(j + n_strx < strsize && global_name[j] != ']')
4912 j++;
4913 if(j + n_strx < strsize && global_name[j] == ']')
4914 j++;
4916 else
4917 j = 0;
4918 while(j + n_strx < strsize && global_name[j] != ':')
4919 j++;
4920 if(j + n_strx >= strsize){
4921 error_arch(arch, member, "bad N_STAB symbol name for entry "
4922 "%u (does not contain ':' separating name from type) "
4923 "in: ", i);
4924 return(FALSE);
4926 save_char = global_name[j];
4927 global_name[j] = '\0';
4929 global_symbol_found = FALSE;
4930 global_symbol_n_sect = 0;
4931 if(object->mh != NULL){
4932 global_symbol = bsearch(global_name, changed_globals,
4933 nchanged_globals,sizeof(struct nlist *),
4934 (int (*)(const void *, const void *))
4935 cmp_bsearch_global_stab);
4936 global_symbol64 = NULL;
4937 if(global_symbol != NULL){
4938 global_symbol_found = TRUE;
4939 global_symbol_n_sect = (*global_symbol)->n_sect;
4942 else{
4943 global_symbol64 = bsearch(global_name, changed_globals64,
4944 nchanged_globals,
4945 sizeof(struct nlist_64 *),
4946 (int (*)(const void *, const void *))
4947 cmp_bsearch_global_stab_64);
4948 global_symbol = NULL;
4949 if(global_symbol64 != NULL){
4950 global_symbol_found = TRUE;
4951 global_symbol_n_sect = (*global_symbol64)->n_sect;
4954 global_name[j] = save_char;
4955 if(global_symbol_found == TRUE){
4956 if(n_type == N_GSYM){
4957 if(global_symbol_n_sect == data_n_sect){
4958 if(object->mh != NULL)
4959 symbols[i].n_type = N_STSYM;
4960 else
4961 symbols64[i].n_type = N_STSYM;
4963 else{
4964 if(object->mh != NULL)
4965 symbols[i].n_type = N_FUN;
4966 else
4967 symbols64[i].n_type = N_FUN;
4969 if(object->mh != NULL){
4970 symbols[i].n_sect = (*global_symbol)->n_sect;
4971 symbols[i].n_value = (*global_symbol)->n_value;
4972 symbols[i].n_desc = (*global_symbol)->n_desc;
4974 else{
4975 symbols64[i].n_sect = (*global_symbol64)->n_sect;
4976 symbols64[i].n_value = (*global_symbol64)->n_value;
4977 symbols64[i].n_desc = (*global_symbol64)->n_desc;
4979 if(j + 1 + n_strx >= strsize ||
4980 global_name[j+1] != 'G'){
4981 error_arch(arch, member, "bad N_GSYM symbol name "
4982 "for entry %u (does not have type 'G' after "
4983 "':' in name) in: ", i);
4984 return(FALSE);
4986 global_name[j+1] = 'S';
4988 else{ /* n_type == N_FUN */
4989 if(j + 1 + n_strx >= strsize ||
4990 global_name[j+1] == 'F'){
4991 global_name[j+1] = 'f';
4997 global_strings = NULL;
5000 * Now what needs to be done is to create the new symbol table moving
5001 * those global symbols being changed into non-globals into the areas
5002 * in the symbol table for local symbols. The symbol table and string
5003 * table must be in this order:
5005 * symbol table
5006 * local symbols
5007 * external defined symbols
5008 * undefined symbols
5009 * string table
5010 * external strings
5011 * local strings
5013 if(saves != NULL)
5014 free(saves);
5015 saves = (int32_t *)allocate(nsyms * sizeof(int32_t));
5016 bzero(saves, nsyms * sizeof(int32_t));
5018 if(object->mh != NULL){
5019 new_symbols = (struct nlist *)
5020 allocate(new_nsyms * sizeof(struct nlist));
5021 new_symbols64 = NULL;
5023 else{
5024 new_symbols = NULL;
5025 new_symbols64 = (struct nlist_64 *)
5026 allocate(new_nsyms * sizeof(struct nlist_64));
5028 new_strsize = rnd(new_strsize, sizeof(int32_t));
5029 new_strings = (char *)allocate(new_strsize);
5030 new_strings[new_strsize - 3] = '\0';
5031 new_strings[new_strsize - 2] = '\0';
5032 new_strings[new_strsize - 1] = '\0';
5034 memset(new_strings, '\0', sizeof(int32_t));
5035 p = new_strings + sizeof(int32_t);
5036 q = p + new_ext_strsize;
5039 * If this is a dynamic library the movement of the symbols has to be
5040 * done with respect to the modules. As the local symbols, and external
5041 * defined symbols are grouped together for each module. Then a new
5042 * module table needs to be created with the new indexes into the symbol
5043 * table for each module.
5045 new_nmodtab = nmodtab;
5046 new_ntoc = ntoc;
5047 new_nextrefsyms = nextrefsyms;
5048 if(object->mh_filetype == MH_DYLIB && nmodtab != 0){
5049 if(object->mh != NULL){
5050 new_mods = allocate(nmodtab * sizeof(struct dylib_module));
5051 new_mods64 = NULL;
5053 else{
5054 new_mods = NULL;
5055 new_mods64 = allocate(nmodtab * sizeof(struct dylib_module_64));
5058 inew_syms = 0;
5060 * This first loop through the module table sets the index and
5061 * counts of the local symbols for each module.
5063 for(i = 0; i < nmodtab; i++){
5065 * First put the existing local symbols into the new symbol
5066 * table.
5068 if(object->mh != NULL){
5069 new_mods[i].ilocalsym = inew_syms;
5070 new_mods[i].nlocalsym = 0;
5071 ilocalsym = mods[i].ilocalsym;
5072 nlocalsym = mods[i].nlocalsym;
5074 else{
5075 new_mods64[i].ilocalsym = inew_syms;
5076 new_mods64[i].nlocalsym = 0;
5077 ilocalsym = mods64[i].ilocalsym;
5078 nlocalsym = mods64[i].nlocalsym;
5080 for(j = ilocalsym; j < ilocalsym + nlocalsym; j++){
5081 if(object->mh != NULL){
5082 n_strx = symbols[j].n_un.n_strx;
5083 n_type = symbols[j].n_type;
5085 else{
5086 n_strx = symbols64[j].n_un.n_strx;
5087 n_type = symbols64[j].n_type;
5089 if((n_type & N_EXT) == 0){
5090 if(object->mh != NULL)
5091 new_symbols[inew_syms] = symbols[j];
5092 else
5093 new_symbols64[inew_syms] = symbols64[j];
5094 if(n_strx != 0){
5095 strcpy(q, strings + n_strx);
5096 if(object->mh != NULL)
5097 new_symbols[inew_syms].n_un.n_strx =
5098 q - new_strings;
5099 else
5100 new_symbols64[inew_syms].n_un.n_strx =
5101 q - new_strings;
5102 q += strlen(q) + 1;
5104 inew_syms++;
5105 saves[j] = inew_syms;
5106 if(object->mh != NULL)
5107 new_mods[i].nlocalsym++;
5108 else
5109 new_mods64[i].nlocalsym++;
5113 * Next put the global symbols that were changed into
5114 * non-global symbols into the new symbol table and moved their
5115 * counts to the local symbol counts.
5117 if(object->mh != NULL){
5118 iextdefsym = mods[i].iextdefsym;
5119 nextdefsym = mods[i].nextdefsym;
5121 else{
5122 iextdefsym = mods64[i].iextdefsym;
5123 nextdefsym = mods64[i].nextdefsym;
5125 for(j = iextdefsym; j < iextdefsym + nextdefsym; j++){
5126 if(object->mh != NULL){
5127 n_strx = symbols[j].n_un.n_strx;
5128 n_type = symbols[j].n_type;
5130 else{
5131 n_strx = symbols64[j].n_un.n_strx;
5132 n_type = symbols64[j].n_type;
5134 if((n_type & N_EXT) != 0){
5135 if(nmedits[j] == TRUE){
5137 * Change the new symbol to a private extern symbol
5138 * with the extern bit off.
5140 if(object->mh != NULL){
5141 new_symbols[inew_syms] = symbols[j];
5142 new_symbols[inew_syms].n_type |= N_PEXT;
5143 new_symbols[inew_syms].n_type &= ~N_EXT;
5145 else{
5146 new_symbols64[inew_syms] = symbols64[j];
5147 new_symbols64[inew_syms].n_type |= N_PEXT;
5148 new_symbols64[inew_syms].n_type &= ~N_EXT;
5150 if(n_strx != 0){
5151 strcpy(q, strings + n_strx);
5152 if(object->mh != NULL)
5153 new_symbols[inew_syms].n_un.n_strx =
5154 q - new_strings;
5155 else
5156 new_symbols64[inew_syms].n_un.n_strx =
5157 q - new_strings;
5158 q += strlen(q) + 1;
5160 inew_syms++;
5161 saves[j] = inew_syms;
5162 if(object->mh != NULL)
5163 new_mods[i].nlocalsym++;
5164 else
5165 new_mods64[i].nlocalsym++;
5171 * Next put the unchanged defined global symbols into the new
5172 * symbol table.
5174 for(i = 0; i < nmodtab; i++){
5175 if(object->mh != NULL){
5176 new_mods[i].iextdefsym = inew_syms;
5177 new_mods[i].nextdefsym = 0;
5178 iextdefsym = mods[i].iextdefsym;
5179 nextdefsym = mods[i].nextdefsym;
5181 else{
5182 new_mods64[i].iextdefsym = inew_syms;
5183 new_mods64[i].nextdefsym = 0;
5184 iextdefsym = mods64[i].iextdefsym;
5185 nextdefsym = mods64[i].nextdefsym;
5187 for(j = iextdefsym; j < iextdefsym + nextdefsym; j++){
5188 if(object->mh != NULL){
5189 n_strx = symbols[j].n_un.n_strx;
5190 n_type = symbols[j].n_type;
5192 else{
5193 n_strx = symbols64[j].n_un.n_strx;
5194 n_type = symbols64[j].n_type;
5196 if((n_type & N_EXT) != 0){
5197 if(nmedits[j] == FALSE){
5198 if(object->mh != NULL)
5199 new_symbols[inew_syms] = symbols[j];
5200 else
5201 new_symbols64[inew_syms] = symbols64[j];
5202 if(n_strx != 0){
5203 strcpy(p, strings + n_strx);
5204 if(object->mh != NULL)
5205 new_symbols[inew_syms].n_un.n_strx =
5206 p - new_strings;
5207 else
5208 new_symbols64[inew_syms].n_un.n_strx =
5209 p - new_strings;
5210 p += strlen(p) + 1;
5212 inew_syms++;
5213 saves[j] = inew_syms;
5214 if(object->mh != NULL)
5215 new_mods[i].nextdefsym++;
5216 else
5217 new_mods64[i].nextdefsym++;
5223 * Last put the undefined symbols into the new symbol table.
5225 for(i = 0; i < nsyms; i++){
5226 if(object->mh != NULL){
5227 n_strx = symbols[i].n_un.n_strx;
5228 n_type = symbols[i].n_type;
5230 else{
5231 n_strx = symbols64[i].n_un.n_strx;
5232 n_type = symbols64[i].n_type;
5234 if((n_type & N_EXT) != 0 &&
5235 ((n_type & N_TYPE) == N_UNDF ||
5236 (n_type & N_TYPE) == N_PBUD)){
5237 if(object->mh != NULL)
5238 new_symbols[inew_syms] = symbols[i];
5239 else
5240 new_symbols64[inew_syms] = symbols64[i];
5241 if(n_strx != 0){
5242 strcpy(p, strings + n_strx);
5243 if(object->mh != NULL)
5244 new_symbols[inew_syms].n_un.n_strx =
5245 p - new_strings;
5246 else
5247 new_symbols64[inew_syms].n_un.n_strx =
5248 p - new_strings;
5249 p += strlen(p) + 1;
5251 inew_syms++;
5252 saves[i] = inew_syms;
5257 * Place the module table's module names with the external strings
5258 * and set the names in the new module table. And then copy the
5259 * other unchanged fields.
5261 for(i = 0; i < nmodtab; i++){
5262 if(object->mh != NULL){
5263 strcpy(p, strings + mods[i].module_name);
5264 new_mods[i].module_name = p - new_strings;
5265 p += strlen(p) + 1;
5267 new_mods[i].irefsym = mods[i].irefsym;
5268 new_mods[i].nrefsym = mods[i].nrefsym;
5269 new_mods[i].iextrel = mods[i].iextrel;
5270 new_mods[i].nextrel = mods[i].nextrel;
5271 new_mods[i].iinit_iterm = mods[i].iinit_iterm;
5272 new_mods[i].ninit_nterm = mods[i].ninit_nterm;
5273 new_mods[i].objc_module_info_addr =
5274 mods[i].objc_module_info_addr;
5275 new_mods[i].objc_module_info_size =
5276 mods[i].objc_module_info_size;
5278 else{
5279 strcpy(p, strings + mods64[i].module_name);
5280 new_mods64[i].module_name = p - new_strings;
5281 p += strlen(p) + 1;
5283 new_mods64[i].irefsym = mods64[i].irefsym;
5284 new_mods64[i].nrefsym = mods64[i].nrefsym;
5285 new_mods64[i].iextrel = mods64[i].iextrel;
5286 new_mods64[i].nextrel = mods64[i].nextrel;
5287 new_mods64[i].iinit_iterm = mods64[i].iinit_iterm;
5288 new_mods64[i].ninit_nterm = mods64[i].ninit_nterm;
5289 new_mods64[i].objc_module_info_addr =
5290 mods64[i].objc_module_info_addr;
5291 new_mods64[i].objc_module_info_size =
5292 mods64[i].objc_module_info_size;
5297 * Update the reference table with the new symbol indexes for all
5298 * entries and change type of reference (the flags field) for those
5299 * symbols that got changed from globals to non-globals.
5301 new_nextrefsyms = nextrefsyms;
5302 new_refs = allocate(new_nextrefsyms *
5303 sizeof(struct dylib_reference));
5304 j = 0;
5305 for(i = 0; i < nextrefsyms; i++){
5306 if(nmedits[refs[i].isym] == TRUE){
5307 if(refs[i].flags == REFERENCE_FLAG_DEFINED)
5308 new_refs[i].flags =
5309 REFERENCE_FLAG_PRIVATE_DEFINED;
5310 else if(refs[i].flags == REFERENCE_FLAG_UNDEFINED_NON_LAZY)
5311 new_refs[i].flags =
5312 REFERENCE_FLAG_PRIVATE_UNDEFINED_NON_LAZY;
5313 else if(refs[i].flags == REFERENCE_FLAG_UNDEFINED_LAZY)
5314 new_refs[i].flags =
5315 REFERENCE_FLAG_PRIVATE_UNDEFINED_LAZY;
5316 else
5317 new_refs[i].flags = refs[i].flags;
5319 else{
5320 new_refs[i].flags = refs[i].flags;
5322 new_refs[i].isym = saves[refs[i].isym] - 1;
5326 * Create a new dylib table of contents without the global symbols
5327 * that got turned into non-globals.
5329 new_ntoc = ntoc - nchanged_globals;
5330 new_tocs = allocate(new_ntoc *
5331 sizeof(struct dylib_table_of_contents));
5332 k = 0;
5333 for(i = 0; i < ntoc; i++){
5334 if(tocs[i].symbol_index >= nsyms){
5335 error_arch(arch, member, "bad symbol index for table of "
5336 "contents table entry %d in: ", i);
5337 return(FALSE);
5339 if(nmedits[tocs[i].symbol_index] == FALSE){
5340 new_tocs[k].symbol_index = saves[tocs[i].symbol_index] - 1;
5341 new_tocs[k].module_index = tocs[i].module_index;
5342 k++;
5347 * If is not a dynamic library so all global symbols changed into
5348 * statics can be moved to the end of the local symbols. If the pflag
5349 * is set then the changed symbols remain global and just get the
5350 * private extern bit set.
5352 else{
5354 * First put the existing local symbols into the new symbol table.
5356 inew_syms = 0;
5357 for(i = 0; i < nsyms; i++){
5358 if(object->mh != NULL){
5359 n_strx = symbols[i].n_un.n_strx;
5360 n_type = symbols[i].n_type;
5362 else{
5363 n_strx = symbols64[i].n_un.n_strx;
5364 n_type = symbols64[i].n_type;
5366 if((n_type & N_EXT) == 0){
5367 if(object->mh != NULL)
5368 new_symbols[inew_syms] = symbols[i];
5369 else
5370 new_symbols64[inew_syms] = symbols64[i];
5371 if(n_strx != 0){
5372 strcpy(q, strings + n_strx);
5373 if(object->mh != NULL)
5374 new_symbols[inew_syms].n_un.n_strx =
5375 q - new_strings;
5376 else
5377 new_symbols64[inew_syms].n_un.n_strx =
5378 q - new_strings;
5379 q += strlen(q) + 1;
5381 inew_syms++;
5382 saves[i] = inew_syms;
5386 * Next put the global symbols that were changed into statics
5387 * symbols into the new symbol table.
5389 if(pflag == FALSE){
5390 for(i = 0; i < nsyms; i++){
5391 if(object->mh != NULL){
5392 n_strx = symbols[i].n_un.n_strx;
5393 n_type = symbols[i].n_type;
5395 else{
5396 n_strx = symbols64[i].n_un.n_strx;
5397 n_type = symbols64[i].n_type;
5399 if((n_type & N_EXT) != 0){
5400 if(nmedits[i] == TRUE){
5402 * Change the new symbol to not be an extern symbol
5403 * by turning off the extern bit.
5405 if(object->mh != NULL){
5406 new_symbols[inew_syms] = symbols[i];
5407 new_symbols[inew_syms].n_type &= ~N_EXT;
5408 new_symbols[inew_syms].n_desc &= ~N_WEAK_DEF;
5410 else{
5411 new_symbols64[inew_syms] = symbols64[i];
5412 new_symbols64[inew_syms].n_type &= ~N_EXT;
5413 new_symbols64[inew_syms].n_desc &= ~N_WEAK_DEF;
5415 if(n_strx != 0){
5416 strcpy(q, strings + n_strx);
5417 if(object->mh != NULL)
5418 new_symbols[inew_syms].n_un.n_strx =
5419 q - new_strings;
5420 else
5421 new_symbols64[inew_syms].n_un.n_strx =
5422 q - new_strings;
5423 q += strlen(q) + 1;
5425 inew_syms++;
5426 saves[i] = inew_syms;
5432 * Last put the unchanged global symbols into the new symbol table
5433 * and symbols changed into private externs.
5435 for(i = 0; i < nsyms; i++){
5436 if(object->mh != NULL){
5437 n_strx = symbols[i].n_un.n_strx;
5438 n_type = symbols[i].n_type;
5440 else{
5441 n_strx = symbols64[i].n_un.n_strx;
5442 n_type = symbols64[i].n_type;
5444 if((n_type & N_EXT) != 0){
5445 if(nmedits[i] == FALSE || pflag == TRUE){
5446 if(object->mh != NULL)
5447 new_symbols[inew_syms] = symbols[i];
5448 else
5449 new_symbols64[inew_syms] = symbols64[i];
5450 if(nmedits[i] == TRUE && pflag == TRUE){
5452 * Change the new symbol to be a private extern
5453 * symbol by turning on the private extern bit.
5455 if(object->mh != NULL)
5456 new_symbols[inew_syms].n_type |= N_PEXT;
5457 else
5458 new_symbols64[inew_syms].n_type |= N_PEXT;
5460 if(n_strx != 0){
5461 strcpy(p, strings + n_strx);
5462 if(object->mh != NULL)
5463 new_symbols[inew_syms].n_un.n_strx =
5464 p - new_strings;
5465 else
5466 new_symbols64[inew_syms].n_un.n_strx =
5467 p - new_strings;
5468 p += strlen(p) + 1;
5470 inew_syms++;
5471 saves[i] = inew_syms;
5477 if(sections != NULL)
5478 free(sections);
5479 if(sections64 != NULL)
5480 free(sections64);
5482 if(errors == 0)
5483 return(TRUE);
5484 else
5485 return(FALSE);
5489 * Function for qsort for comparing global symbol names.
5491 static
5493 cmp_qsort_global(
5494 const struct nlist **sym1,
5495 const struct nlist **sym2)
5497 return(strcmp(global_strings + (*sym1)->n_un.n_strx,
5498 global_strings + (*sym2)->n_un.n_strx));
5501 static
5503 cmp_qsort_global_64(
5504 const struct nlist_64 **sym1,
5505 const struct nlist_64 **sym2)
5507 return(strcmp(global_strings + (*sym1)->n_un.n_strx,
5508 global_strings + (*sym2)->n_un.n_strx));
5512 * Function for bsearch for finding a global symbol that matches a stab name.
5514 static
5516 cmp_bsearch_global_stab(
5517 const char *name,
5518 const struct nlist **sym)
5521 * The +1 is for the '_' on the global symbol that is not on the
5522 * stab string that is trying to be matched.
5524 return(strcmp(name, global_strings + (*sym)->n_un.n_strx + 1));
5527 static
5529 cmp_bsearch_global_stab_64(
5530 const char *name,
5531 const struct nlist_64 **sym)
5534 * The +1 is for the '_' on the global symbol that is not on the
5535 * stab string that is trying to be matched.
5537 return(strcmp(name, global_strings + (*sym)->n_un.n_strx + 1));
5541 * Function for bsearch for finding a global symbol that matches a stab name
5542 * in the debug map.
5544 static
5546 cmp_bsearch_global(
5547 const char *name,
5548 const struct nlist **sym)
5550 return(strcmp(name, global_strings + (*sym)->n_un.n_strx));
5553 static
5555 cmp_bsearch_global_64(
5556 const char *name,
5557 const struct nlist_64 **sym)
5559 return(strcmp(name, global_strings + (*sym)->n_un.n_strx));
5561 #endif /* defined(NMEDIT) */