Remove the <>'s from the version string so what does not get upset
[striptease.git] / install_name_tool.c
blobd576e62bb1f55d2bd189083240d7446623d6c4a4
1 /*
2 * Copyright (c) 2001 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@
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <string.h>
26 #include <limits.h>
27 #include <unistd.h>
28 #include <fcntl.h>
29 #include "stuff/errors.h"
30 #include "stuff/breakout.h"
31 #include "stuff/rnd.h"
32 #include "stuff/allocate.h"
34 /* used by error routines as the name of the program */
35 char *progname = NULL;
37 static void usage(
38 void);
40 static void process(
41 struct arch *archs,
42 uint32_t narchs);
44 static void write_on_input(
45 struct arch *archs,
46 uint32_t narchs,
47 char *input);
49 static void setup_object_symbolic_info(
50 struct object *object);
52 static void update_load_commands(
53 struct arch *arch,
54 uint32_t *header_size);
56 /* the argument to the -id option */
57 static char *id = NULL;
59 /* the arguments to the -change options */
60 struct changes {
61 char *old;
62 char *new;
64 static struct changes *changes = NULL;
65 static uint32_t nchanges = 0;
67 /* the arguments to the -rpath options */
68 struct rpaths {
69 char *old;
70 char *new;
71 enum bool found;
73 static struct rpaths *rpaths = NULL;
74 static uint32_t nrpaths = 0;
76 /* the arguments to the -add_rpath options */
77 struct add_rpaths {
78 char *new;
80 static struct add_rpaths *add_rpaths = NULL;
81 static uint32_t nadd_rpaths = 0;
83 /* the arguments to the -delete_rpath options */
84 struct delete_rpaths {
85 char *old;
86 enum bool found;
88 static struct delete_rpaths *delete_rpaths = NULL;
89 static uint32_t ndelete_rpaths = 0;
92 * This is a pointer to an array of the original header sizes (mach header and
93 * load commands) for each architecture which is used when we are writing on the
94 * input file.
96 static uint32_t *arch_header_sizes = NULL;
99 * The -o output option is not enabled as it is not needed and has the
100 * unintended side effect of changing the time stamps in LC_ID_DYLIB commands
101 * which is not the desired functionality of this command.
103 #undef OUTPUT_OPTION
105 /* apple_version is created by the libstuff/Makefile */
106 extern char apple_version[];
107 char *version = apple_version;
110 * The install_name_tool allow the dynamic shared library install names of a
111 * Mach-O binary to be changed. For this tool to work when the install names
112 * are larger the binary should be built with the ld(1)
113 * -headerpad_max_install_names option.
115 * Usage: install_name_tool [-change old new] ... [-rpath old new] ...
116 * [-add_rpath new] ... [-delete_rpath old] ... [-id name] input
118 * The "-change old new" option changes the "old" install name to the "new"
119 * install name if found in the binary.
121 * The "-rpath old new" option changes the "old" path name in the rpath to
122 * the "new" path name in an LC_RPATH load command in the binary.
124 * The "-add_rpath new" option adds an LC_RPATH load command.
126 * The "-delete_rpath old" option deletes the LC_RPATH load command with the
127 * "old" path name in the binary.
129 * The "-id name" option changes the install name in the LC_ID_DYLIB load
130 * command for a dynamic shared library.
133 main(
134 int argc,
135 char **argv,
136 char **envp)
138 int i, j;
139 struct arch *archs;
140 uint32_t narchs;
141 char *input;
142 char *output;
144 output = NULL;
145 progname = argv[0];
146 input = NULL;
147 archs = NULL;
148 narchs = 0;
149 for(i = 1; i < argc; i++){
150 #ifdef OUTPUT_OPTION
151 if(strcmp(argv[i], "-o") == 0){
152 if(i + 1 == argc){
153 error("missing argument to: %s option", argv[i]);
154 usage();
156 if(output != NULL){
157 error("more than one: %s option specified", argv[i]);
158 usage();
160 output = argv[i+1];
161 i++;
163 else
164 #endif /* OUTPUT_OPTION */
165 if(strcmp(argv[i], "-id") == 0){
166 if(i + 1 == argc){
167 error("missing argument to: %s option", argv[i]);
168 usage();
170 if(id != NULL){
171 error("more than one: %s option specified", argv[i]);
172 usage();
174 id = argv[i+1];
175 i++;
177 else if(strcmp(argv[i], "-change") == 0){
178 if(i + 2 >= argc){
179 error("missing argument(s) to: %s option", argv[i]);
180 usage();
182 changes = reallocate(changes,
183 sizeof(struct changes) * (nchanges + 1));
184 changes[nchanges].old = argv[i+1];
185 changes[nchanges].new = argv[i+2];
186 nchanges += 1;
187 i += 2;
189 else if(strcmp(argv[i], "-rpath") == 0){
190 if(i + 2 >= argc){
191 error("missing argument(s) to: %s option", argv[i]);
192 usage();
194 for(j = 0; j < nrpaths; j++){
195 if(strcmp(rpaths[j].old, argv[i+1]) == 0){
196 if(strcmp(rpaths[j].new, argv[i+2]) == 0){
197 error("\"-rpath %s %s\" specified more than once",
198 argv[i+1], argv[i+2]);
199 usage();
201 error("can't specify both \"-rpath %s %s\" and "
202 "\"-rpath %s %s\"", rpaths[j].old, rpaths[j].new,
203 argv[i+1], argv[i+2]);
204 usage();
206 if(strcmp(rpaths[j].new, argv[i+1]) == 0 ||
207 strcmp(rpaths[j].old, argv[i+2]) == 0 ||
208 strcmp(rpaths[j].new, argv[i+2]) == 0){
209 error("can't specify both \"-rpath %s %s\" and "
210 "\"-rpath %s %s\"", rpaths[j].old, rpaths[j].new,
211 argv[i+1], argv[i+2]);
212 usage();
215 for(j = 0; j < nadd_rpaths; j++){
216 if(strcmp(add_rpaths[j].new, argv[i+1]) == 0 ||
217 strcmp(add_rpaths[j].new, argv[i+2]) == 0){
218 error("can't specify both \"-add_rpath %s\" "
219 "and \"-rpath %s %s\"", add_rpaths[j].new,
220 argv[i+1], argv[i+2]);
221 usage();
224 for(j = 0; j < ndelete_rpaths; j++){
225 if(strcmp(delete_rpaths[j].old, argv[i+1]) == 0 ||
226 strcmp(delete_rpaths[j].old, argv[i+2]) == 0){
227 error("can't specify both \"-delete_rpath %s\" "
228 "and \"-rpath %s %s\"", delete_rpaths[j].old,
229 argv[i+1], argv[i+2]);
230 usage();
233 rpaths = reallocate(rpaths,
234 sizeof(struct rpaths) * (nrpaths + 1));
235 rpaths[nrpaths].old = argv[i+1];
236 rpaths[nrpaths].new = argv[i+2];
237 rpaths[nrpaths].found = FALSE;
238 nrpaths += 1;
239 i += 2;
241 else if(strcmp(argv[i], "-add_rpath") == 0){
242 if(i + 1 == argc){
243 error("missing argument(s) to: %s option", argv[i]);
244 usage();
246 for(j = 0; j < nadd_rpaths; j++){
247 if(strcmp(add_rpaths[j].new, argv[i+1]) == 0){
248 error("\"-add_rpath %s\" specified more than once",
249 add_rpaths[j].new);
250 usage();
253 for(j = 0; j < nrpaths; j++){
254 if(strcmp(rpaths[j].old, argv[i+1]) == 0 ||
255 strcmp(rpaths[j].new, argv[i+1]) == 0){
256 error("can't specify both \"-rpath %s %s\" and "
257 "\"-add_rpath %s\"", rpaths[j].old, rpaths[j].new,
258 argv[i+1]);
259 usage();
262 for(j = 0; j < ndelete_rpaths; j++){
263 if(strcmp(delete_rpaths[j].old, argv[i+1]) == 0){
264 error("can't specify both \"-delete_rpath %s\" "
265 "and \"-add_rpath %s\"", delete_rpaths[j].old,
266 argv[i+1]);
267 usage();
270 add_rpaths = reallocate(add_rpaths,
271 sizeof(struct add_rpaths) * (nadd_rpaths + 1));
272 add_rpaths[nadd_rpaths].new = argv[i+1];
273 nadd_rpaths += 1;
274 i += 1;
276 else if(strcmp(argv[i], "-delete_rpath") == 0){
277 if(i + 1 == argc){
278 error("missing argument(s) to: %s option", argv[i]);
279 usage();
281 for(j = 0; j < ndelete_rpaths; j++){
282 if(strcmp(delete_rpaths[j].old, argv[i+1]) == 0){
283 error("\"-delete_rpath %s\" specified more than once",
284 delete_rpaths[j].old);
285 usage();
288 for(j = 0; j < nrpaths; j++){
289 if(strcmp(rpaths[j].old, argv[i+1]) == 0 ||
290 strcmp(rpaths[j].new, argv[i+1]) == 0){
291 error("can't specify both \"-rpath %s %s\" and "
292 "\"-delete_rpath %s\"", rpaths[j].old,
293 rpaths[j].new, argv[i+1]);
294 usage();
297 for(j = 0; j < nadd_rpaths; j++){
298 if(strcmp(add_rpaths[j].new, argv[i+1]) == 0){
299 error("can't specify both \"-add_rpath %s\" "
300 "and \"-delete_rpath %s\"", add_rpaths[j].new,
301 argv[i+1]);
302 usage();
305 delete_rpaths = reallocate(delete_rpaths,
306 sizeof(struct delete_rpaths) *
307 (ndelete_rpaths + 1));
308 delete_rpaths[ndelete_rpaths].old = argv[i+1];
309 delete_rpaths[ndelete_rpaths].found = FALSE;
310 ndelete_rpaths += 1;
311 i += 1;
313 else{
314 if(input != NULL){
315 error("more than one input file specified (%s and %s)",
316 argv[i], input);
317 usage();
319 input = argv[i];
322 if(input == NULL || (id == NULL && nchanges == 0 && nrpaths == 0 &&
323 nadd_rpaths == 0 && ndelete_rpaths == 0))
324 usage();
326 breakout(input, &archs, &narchs, FALSE);
327 if(errors)
328 exit(EXIT_FAILURE);
330 checkout(archs, narchs);
331 if(errors)
332 exit(EXIT_FAILURE);
334 arch_header_sizes = allocate(narchs * sizeof(uint32_t));
335 process(archs, narchs);
336 if(errors)
337 exit(EXIT_FAILURE);
339 if(output != NULL)
340 writeout(archs, narchs, output, 0777, TRUE, FALSE, FALSE, NULL);
341 else
342 write_on_input(archs, narchs, input);
344 if(errors)
345 return(EXIT_FAILURE);
346 else
347 return(EXIT_SUCCESS);
351 * usage() prints the current usage message and exits indicating failure.
353 static
354 void
355 usage(
356 void)
358 fprintf(stderr, "Usage: %s [-change old new] ... [-rpath old new] ... "
359 "[-add_rpath new] ... [-delete_rpath old] ... "
360 "[-id name] input"
361 #ifdef OUTPUT_OPTION
362 " [-o output]"
363 #endif /* OUTPUT_OPTION */
364 "\n", progname);
365 exit(EXIT_FAILURE);
368 static
369 void
370 process(
371 struct arch *archs,
372 uint32_t narchs)
374 uint32_t i;
375 struct object *object;
377 for(i = 0; i < narchs; i++){
378 if(archs[i].type == OFILE_Mach_O){
379 object = archs[i].object;
380 if(object->mh_filetype == MH_DYLIB_STUB)
381 fatal("input file: %s is Mach-O dynamic shared library stub"
382 " file and can't be changed", archs[i].file_name);
383 setup_object_symbolic_info(object);
384 update_load_commands(archs + i, arch_header_sizes + i);
386 else{
387 error("input file: %s is not a Mach-O file",archs[i].file_name);
388 return;
394 * write_on_input() takes the modified archs and writes the load commands
395 * directly into the input file.
397 static
398 void
399 write_on_input(
400 struct arch *archs,
401 uint32_t narchs,
402 char *input)
404 int fd;
405 uint32_t i, offset, size, headers_size;
406 char *headers;
407 struct mach_header *mh;
408 struct mach_header_64 *mh64;
409 struct load_command *lc;
410 enum byte_sex host_byte_sex;
412 host_byte_sex = get_host_byte_sex();
414 fd = open(input, O_WRONLY, 0);
415 if(fd == -1)
416 system_error("can't open input file: %s for writing", input);
418 for(i = 0; i < narchs; i++){
419 if(archs[i].fat_arch != NULL)
420 offset = archs[i].fat_arch->offset;
421 else
422 offset = 0;
423 if(lseek(fd, offset, SEEK_SET) == -1)
424 system_error("can't lseek to offset: %u in file: %s for "
425 "writing", offset, input);
427 * Since the new headers may be smaller than the old headers and
428 * we want to make sure any old unused bytes are zero in the file
429 * we allocate the size of the original headers into a buffer and
430 * zero it out. Then copy the new headers into the buffer and write
431 * out the size of the original headers to the file.
433 if(archs[i].object->mh != NULL){
434 headers_size = sizeof(struct mach_header) +
435 archs[i].object->mh->sizeofcmds;
437 else{
438 headers_size = sizeof(struct mach_header_64) +
439 archs[i].object->mh64->sizeofcmds;
441 if(arch_header_sizes[i] > headers_size)
442 size = arch_header_sizes[i];
443 else
444 size = headers_size;
445 headers = allocate(size);
446 memset(headers, '\0', size);
448 if(archs[i].object->mh != NULL){
449 mh = (struct mach_header *)headers;
450 lc = (struct load_command *)(headers +
451 sizeof(struct mach_header));
452 *mh = *(archs[i].object->mh);
453 memcpy(lc, archs[i].object->load_commands, mh->sizeofcmds);
454 if(archs[i].object->object_byte_sex != host_byte_sex)
455 if(swap_object_headers(mh, lc) == FALSE)
456 fatal("internal error: swap_object_headers() failed");
458 else{
459 mh64 = (struct mach_header_64 *)headers;
460 lc = (struct load_command *)(headers +
461 sizeof(struct mach_header_64));
462 *mh64 = *(archs[i].object->mh64);
463 memcpy(lc, archs[i].object->load_commands, mh64->sizeofcmds);
464 if(archs[i].object->object_byte_sex != host_byte_sex)
465 if(swap_object_headers(mh64, lc) == FALSE)
466 fatal("internal error: swap_object_headers() failed");
469 if(write(fd, headers, size) != (int)size)
470 system_error("can't write new headers in file: %s", input);
472 free(headers);
474 if(close(fd) == -1)
475 system_error("can't close written on input file: %s", input);
478 static
479 void
480 setup_object_symbolic_info(
481 struct object *object)
483 #ifdef OUTPUT_OPTION
484 if(object->st != NULL && object->st->nsyms != 0){
485 object->output_symbols = (struct nlist *)
486 (object->object_addr + object->st->symoff);
487 if(object->object_byte_sex != get_host_byte_sex())
488 swap_nlist(object->output_symbols,
489 object->st->nsyms,
490 get_host_byte_sex());
491 object->output_nsymbols = object->st->nsyms;
492 object->output_strings =
493 object->object_addr + object->st->stroff;
494 object->output_strings_size = object->st->strsize;
495 object->input_sym_info_size =
496 object->st->nsyms * sizeof(struct nlist) +
497 object->st->strsize;
498 object->output_sym_info_size =
499 object->input_sym_info_size;
501 if(object->dyst != NULL){
502 object->output_ilocalsym = object->dyst->ilocalsym;
503 object->output_nlocalsym = object->dyst->nlocalsym;
504 object->output_iextdefsym = object->dyst->iextdefsym;
505 object->output_nextdefsym = object->dyst->nextdefsym;
506 object->output_iundefsym = object->dyst->iundefsym;
507 object->output_nundefsym = object->dyst->nundefsym;
509 object->output_loc_relocs = (struct relocation_info *)
510 (object->object_addr + object->dyst->locreloff);
511 object->output_ext_relocs = (struct relocation_info *)
512 (object->object_addr + object->dyst->extreloff);
513 object->output_indirect_symtab = (uint32_t *)
514 (object->object_addr + object->dyst->indirectsymoff);
515 object->output_tocs =
516 (struct dylib_table_of_contents *)
517 (object->object_addr + object->dyst->tocoff);
518 object->output_ntoc = object->dyst->ntoc;
519 object->output_mods = (struct dylib_module *)
520 (object->object_addr + object->dyst->modtaboff);
521 object->output_nmodtab = object->dyst->nmodtab;
522 object->output_refs = (struct dylib_reference *)
523 (object->object_addr + object->dyst->extrefsymoff);
524 object->output_nextrefsyms = object->dyst->nextrefsyms;
525 if(object->dyld_info != NULL){
526 object->input_sym_info_size += object->dyld_info->rebase_size
527 + object->dyld_info->bind_size
528 + object->dyld_info->weak_bind_size
529 + object->dyld_info->lazy_bind_size
530 + object->dyld_info->export_size;
532 object->input_sym_info_size +=
533 object->dyst->nlocrel *
534 sizeof(struct relocation_info) +
535 object->dyst->nextrel *
536 sizeof(struct relocation_info) +
537 object->dyst->nindirectsyms *
538 sizeof(uint32_t) +
539 object->dyst->ntoc *
540 sizeof(struct dylib_table_of_contents)+
541 object->dyst->nmodtab *
542 sizeof(struct dylib_module) +
543 object->dyst->nextrefsyms *
544 sizeof(struct dylib_reference);
545 object->output_sym_info_size +=
546 object->dyst->nlocrel *
547 sizeof(struct relocation_info) +
548 object->dyst->nextrel *
549 sizeof(struct relocation_info) +
550 object->dyst->nindirectsyms *
551 sizeof(uint32_t) +
552 object->dyst->ntoc *
553 sizeof(struct dylib_table_of_contents)+
554 object->dyst->nmodtab *
555 sizeof(struct dylib_module) +
556 object->dyst->nextrefsyms *
557 sizeof(struct dylib_reference);
558 if(object->split_info_cmd != NULL){
559 object->output_split_info_data =
560 (object->object_addr + object->split_info_cmd->dataoff);
561 object->output_split_info_data_size =
562 object->split_info_cmd->datasize;
563 object->input_sym_info_size +=
564 object->split_info_cmd->datasize;
565 object->output_sym_info_size +=
566 object->split_info_cmd->datasize;
568 if(object->func_starts_info_cmd != NULL){
569 object->output_func_start_info_data =
570 (object->object_addr + object->func_starts_info_cmd->dataoff);
571 object->output_func_start_info_data_size =
572 object->func_starts_info_cmd->datasize;
573 object->input_sym_info_size +=
574 object->func_starts_info_cmd->datasize;
575 object->output_sym_info_size +=
576 object->func_starts_info_cmd->datasize;
578 if(object->data_in_code_cmd != NULL){
579 object->output_data_in_code_info_data =
580 (object->object_addr + object->data_in_code_cmd->dataoff);
581 object->output_data_in_code_info_data_size =
582 object->data_in_code_cmd->datasize;
583 object->input_sym_info_size +=
584 object->data_in_code_cmd->datasize;
585 object->output_sym_info_size +=
586 object->data_in_code_cmd->datasize;
588 if(object->code_sign_drs_cmd != NULL){
589 object->output_code_sign_drs_info_data =
590 (object->object_addr + object->code_sign_drs_cmd->dataoff);
591 object->output_code_sign_drs_info_data_size =
592 object->code_sign_drs_cmd->datasize;
593 object->input_sym_info_size +=
594 object->code_sign_drs_cmd->datasize;
595 object->output_sym_info_size +=
596 object->code_sign_drs_cmd->datasize;
598 if(object->hints_cmd != NULL){
599 object->output_hints = (struct twolevel_hint *)
600 (object->object_addr +
601 object->hints_cmd->offset);
602 object->input_sym_info_size +=
603 object->hints_cmd->nhints *
604 sizeof(struct twolevel_hint);
605 object->output_sym_info_size +=
606 object->hints_cmd->nhints *
607 sizeof(struct twolevel_hint);
609 if(object->code_sig_cmd != NULL){
610 object->output_code_sig_data = object->object_addr +
611 object->code_sig_cmd->dataoff;
612 object->output_code_sig_data_size =
613 object->code_sig_cmd->datasize;
614 object->input_sym_info_size =
615 rnd(object->input_sym_info_size, 16);
616 object->input_sym_info_size +=
617 object->code_sig_cmd->datasize;
618 object->output_sym_info_size =
619 rnd(object->output_sym_info_size, 16);
620 object->output_sym_info_size +=
621 object->code_sig_cmd->datasize;
624 #endif /* OUTPUT_OPTION */
628 * update_load_commands() changes the install names the LC_LOAD_DYLIB,
629 * LC_LOAD_WEAK_DYLIB, LC_REEXPORT_DYLIB, LC_LOAD_UPWARD_DYLIB and
630 * LC_PREBOUND_DYLIB commands for the specified arch.
632 static
633 void
634 update_load_commands(
635 struct arch *arch,
636 uint32_t *header_size)
638 uint32_t i, j, new_sizeofcmds, new_size, linked_modules_size, ncmds,
639 sizeof_mach_header, cmd_round;
640 uint64_t low_fileoff;
641 struct load_command *lc1, *lc2, *new_load_commands;
642 struct dylib_command *dl_load1, *dl_load2, *dl_id1, *dl_id2;
643 struct prebound_dylib_command *pbdylib1, *pbdylib2;
644 char *dylib_name1, *dylib_name2, *arch_name, *linked_modules1,
645 *linked_modules2, *path1, *path2;
646 struct segment_command *sg;
647 struct segment_command_64 *sg64;
648 struct section *s;
649 struct section_64 *s64;
650 struct arch_flag arch_flag;
651 struct rpath_command *rpath1, *rpath2;
652 enum bool delete;
655 * Make a pass through the load commands and figure out what the new
656 * size of the the commands needs to be and how much room there is for
657 * them.
659 if(arch->object->mh != NULL){
660 new_sizeofcmds = arch->object->mh->sizeofcmds;
661 ncmds = arch->object->mh->ncmds;
662 sizeof_mach_header = sizeof(struct mach_header);
663 cmd_round = 4;
664 arch_flag.cputype = arch->object->mh->cputype;
665 arch_flag.cpusubtype = arch->object->mh->cpusubtype;
667 else{
668 new_sizeofcmds = arch->object->mh64->sizeofcmds;
669 ncmds = arch->object->mh64->ncmds;
670 sizeof_mach_header = sizeof(struct mach_header_64);
671 cmd_round = 8;
672 arch_flag.cputype = arch->object->mh64->cputype;
673 arch_flag.cpusubtype = arch->object->mh64->cpusubtype;
675 set_arch_flag_name(&arch_flag);
676 arch_name = arch_flag.name;
678 low_fileoff = ULLONG_MAX;
679 lc1 = arch->object->load_commands;
680 for(i = 0; i < ncmds; i++){
681 switch(lc1->cmd){
682 case LC_ID_DYLIB:
683 dl_id1 = (struct dylib_command *)lc1;
684 dylib_name1 = (char *)dl_id1 + dl_id1->dylib.name.offset;
685 if(id != NULL){
686 new_size = sizeof(struct dylib_command) +
687 rnd(strlen(id) + 1, cmd_round);
688 new_sizeofcmds += (new_size - dl_id1->cmdsize);
690 break;
692 case LC_LOAD_DYLIB:
693 case LC_LOAD_WEAK_DYLIB:
694 case LC_REEXPORT_DYLIB:
695 case LC_LOAD_UPWARD_DYLIB:
696 case LC_LAZY_LOAD_DYLIB:
697 dl_load1 = (struct dylib_command *)lc1;
698 dylib_name1 = (char *)dl_load1 + dl_load1->dylib.name.offset;
699 for(j = 0; j < nchanges; j++){
700 if(strcmp(changes[j].old, dylib_name1) == 0){
701 new_size = sizeof(struct dylib_command) +
702 rnd(strlen(changes[j].new) + 1,
703 cmd_round);
704 new_sizeofcmds += (new_size - dl_load1->cmdsize);
705 break;
708 break;
710 case LC_PREBOUND_DYLIB:
711 pbdylib1 = (struct prebound_dylib_command *)lc1;
712 dylib_name1 = (char *)pbdylib1 + pbdylib1->name.offset;
713 for(j = 0; j < nchanges; j++){
714 if(strcmp(changes[j].old, dylib_name1) == 0){
715 linked_modules_size = pbdylib1->cmdsize - (
716 sizeof(struct prebound_dylib_command) +
717 rnd(strlen(dylib_name1) + 1, cmd_round));
718 new_size = sizeof(struct prebound_dylib_command) +
719 rnd(strlen(changes[j].new) + 1,
720 cmd_round) +
721 linked_modules_size;
722 new_sizeofcmds += (new_size - pbdylib1->cmdsize);
723 break;
726 break;
728 case LC_SEGMENT:
729 sg = (struct segment_command *)lc1;
730 s = (struct section *)
731 ((char *)sg + sizeof(struct segment_command));
732 if(sg->nsects != 0){
733 for(j = 0; j < sg->nsects; j++){
734 if(s->size != 0 &&
735 (s->flags & S_ZEROFILL) != S_ZEROFILL &&
736 (s->flags & S_THREAD_LOCAL_ZEROFILL) !=
737 S_THREAD_LOCAL_ZEROFILL &&
738 s->offset < low_fileoff)
739 low_fileoff = s->offset;
740 s++;
743 else{
744 if(sg->filesize != 0 && sg->fileoff < low_fileoff)
745 low_fileoff = sg->fileoff;
747 break;
749 case LC_SEGMENT_64:
750 sg64 = (struct segment_command_64 *)lc1;
751 s64 = (struct section_64 *)
752 ((char *)sg64 + sizeof(struct segment_command_64));
753 if(sg64->nsects != 0){
754 for(j = 0; j < sg64->nsects; j++){
755 if(s64->size != 0 &&
756 (s64->flags & S_ZEROFILL) != S_ZEROFILL &&
757 (s64->flags & S_THREAD_LOCAL_ZEROFILL) !=
758 S_THREAD_LOCAL_ZEROFILL &&
759 s64->offset < low_fileoff)
760 low_fileoff = s64->offset;
761 s64++;
764 else{
765 if(sg64->filesize != 0 && sg64->fileoff < low_fileoff)
766 low_fileoff = sg64->fileoff;
768 break;
770 case LC_RPATH:
771 rpath1 = (struct rpath_command *)lc1;
772 path1 = (char *)rpath1 + rpath1->path.offset;
773 for(j = 0; j < nadd_rpaths; j++){
774 if(strcmp(add_rpaths[j].new, path1) == 0){
775 error("for: %s (for architecture %s) option "
776 "\"-add_rpath %s\" would duplicate path, file "
777 "already has LC_RPATH for: %s", arch->file_name,
778 arch_name, add_rpaths[j].new, path1);
781 for(j = 0; j < nrpaths; j++){
782 if(strcmp(rpaths[j].old, path1) == 0){
783 rpaths[j].found = TRUE;
784 new_size = rnd(sizeof(struct rpath_command) +
785 strlen(rpaths[j].new) + 1,
786 cmd_round);
787 new_sizeofcmds += (new_size - rpath1->cmdsize);
788 break;
791 for(j = 0; j < ndelete_rpaths; j++){
792 if(strcmp(delete_rpaths[j].old, path1) == 0){
793 delete_rpaths[j].found = TRUE;
794 new_sizeofcmds -= rpath1->cmdsize;
795 break;
798 break;
800 lc1 = (struct load_command *)((char *)lc1 + lc1->cmdsize);
803 for(i = 0; i < ndelete_rpaths; i++){
804 if(delete_rpaths[i].found == FALSE){
805 error("no LC_RPATH load command with path: %s found in: "
806 "%s (for architecture %s), required for specified option "
807 "\"-delete_rpath %s\"", delete_rpaths[i].old,
808 arch->file_name, arch_name, delete_rpaths[i].old);
811 for(i = 0; i < nrpaths; i++){
812 if(rpaths[i].found == FALSE){
813 error("no LC_RPATH load command with path: %s found in: "
814 "%s (for architecture %s), required for specified option "
815 "\"-rpath %s %s\"", rpaths[i].old, arch->file_name,
816 arch_name, rpaths[i].old, rpaths[i].new);
820 for(i = 0; i < nadd_rpaths; i++){
821 new_size = rnd(sizeof(struct rpath_command) +
822 strlen(add_rpaths[i].new) + 1, cmd_round);
823 new_sizeofcmds += new_size;
826 if(new_sizeofcmds + sizeof_mach_header > low_fileoff){
827 error("changing install names or rpaths can't be redone for: %s "
828 "(for architecture %s) because larger updated load commands "
829 "do not fit (the program must be relinked, and you may need "
830 "to use -headerpad or -headerpad_max_install_names)",
831 arch->file_name, arch_name);
832 return;
836 * Allocate space for the new load commands and zero it out so any holes
837 * will be zero bytes. Note this may be smaller than the original size
838 * of the load commands.
840 new_load_commands = allocate(new_sizeofcmds);
841 memset(new_load_commands, '\0', new_sizeofcmds);
844 * Fill in the new load commands by copying in the non-modified
845 * commands and updating ones with install name changes.
847 lc1 = arch->object->load_commands;
848 lc2 = new_load_commands;
849 for(i = 0; i < ncmds; i++){
850 delete = FALSE;
851 switch(lc1->cmd){
852 case LC_ID_DYLIB:
853 if(id != NULL){
854 memcpy(lc2, lc1, sizeof(struct dylib_command));
855 dl_id2 = (struct dylib_command *)lc2;
856 dl_id2->cmdsize = sizeof(struct dylib_command) +
857 rnd(strlen(id) + 1, cmd_round);
858 dl_id2->dylib.name.offset = sizeof(struct dylib_command);
859 dylib_name2 = (char *)dl_id2 + dl_id2->dylib.name.offset;
860 strcpy(dylib_name2, id);
862 else{
863 memcpy(lc2, lc1, lc1->cmdsize);
865 break;
867 case LC_LOAD_DYLIB:
868 case LC_LOAD_WEAK_DYLIB:
869 case LC_REEXPORT_DYLIB:
870 case LC_LOAD_UPWARD_DYLIB:
871 case LC_LAZY_LOAD_DYLIB:
872 dl_load1 = (struct dylib_command *)lc1;
873 dylib_name1 = (char *)dl_load1 + dl_load1->dylib.name.offset;
874 for(j = 0; j < nchanges; j++){
875 if(strcmp(changes[j].old, dylib_name1) == 0){
876 memcpy(lc2, lc1, sizeof(struct dylib_command));
877 dl_load2 = (struct dylib_command *)lc2;
878 dl_load2->cmdsize = sizeof(struct dylib_command) +
879 rnd(strlen(changes[j].new) + 1,
880 cmd_round);
881 dl_load2->dylib.name.offset =
882 sizeof(struct dylib_command);
883 dylib_name2 = (char *)dl_load2 +
884 dl_load2->dylib.name.offset;
885 strcpy(dylib_name2, changes[j].new);
886 break;
889 if(j >= nchanges){
890 memcpy(lc2, lc1, lc1->cmdsize);
892 break;
894 case LC_PREBOUND_DYLIB:
895 pbdylib1 = (struct prebound_dylib_command *)lc1;
896 dylib_name1 = (char *)pbdylib1 + pbdylib1->name.offset;
897 for(j = 0; j < nchanges; j++){
898 if(strcmp(changes[j].old, dylib_name1) == 0){
899 memcpy(lc2, lc1, sizeof(struct prebound_dylib_command));
900 pbdylib2 = (struct prebound_dylib_command *)lc2;
901 linked_modules_size = pbdylib1->cmdsize - (
902 sizeof(struct prebound_dylib_command) +
903 rnd(strlen(dylib_name1) + 1, cmd_round));
904 pbdylib2->cmdsize =
905 sizeof(struct prebound_dylib_command) +
906 rnd(strlen(changes[j].new) + 1, cmd_round) +
907 linked_modules_size;
909 pbdylib2->name.offset =
910 sizeof(struct prebound_dylib_command);
911 dylib_name2 = (char *)pbdylib2 +
912 pbdylib2->name.offset;
913 strcpy(dylib_name2, changes[j].new);
915 pbdylib2->linked_modules.offset =
916 sizeof(struct prebound_dylib_command) +
917 rnd(strlen(changes[j].new) + 1, cmd_round);
918 linked_modules1 = (char *)pbdylib1 +
919 pbdylib1->linked_modules.offset;
920 linked_modules2 = (char *)pbdylib2 +
921 pbdylib2->linked_modules.offset;
922 memcpy(linked_modules2, linked_modules1,
923 linked_modules_size);
924 break;
927 if(j >= nchanges){
928 memcpy(lc2, lc1, lc1->cmdsize);
930 break;
932 case LC_RPATH:
933 rpath1 = (struct rpath_command *)lc1;
934 path1 = (char *)rpath1 + rpath1->path.offset;
935 for(j = 0; j < ndelete_rpaths; j++){
936 if(strcmp(delete_rpaths[j].old, path1) == 0){
937 delete = TRUE;
938 break;
941 if(delete == TRUE)
942 break;
943 for(j = 0; j < nrpaths; j++){
944 if(strcmp(rpaths[j].old, path1) == 0){
945 memcpy(lc2, lc1, sizeof(struct rpath_command));
946 rpath2 = (struct rpath_command *)lc2;
947 rpath2->cmdsize = rnd(sizeof(struct rpath_command) +
948 strlen(rpaths[j].new) + 1,
949 cmd_round);
950 rpath2->path.offset = sizeof(struct rpath_command);
951 path2 = (char *)rpath2 + rpath2->path.offset;
952 strcpy(path2, rpaths[j].new);
953 break;
956 if(j >= nrpaths){
957 memcpy(lc2, lc1, lc1->cmdsize);
959 break;
961 default:
962 memcpy(lc2, lc1, lc1->cmdsize);
963 break;
965 lc1 = (struct load_command *)((char *)lc1 + lc1->cmdsize);
966 if(delete == FALSE)
967 lc2 = (struct load_command *)((char *)lc2 + lc2->cmdsize);
970 * Add the new rpath load commands.
972 for(i = 0; i < nadd_rpaths; i++){
973 rpath2 = (struct rpath_command *)lc2;
974 rpath2->cmd = LC_RPATH;
975 rpath2->cmdsize = rnd(sizeof(struct rpath_command) +
976 strlen(add_rpaths[i].new) + 1,
977 cmd_round);
978 rpath2->path.offset = sizeof(struct rpath_command);
979 path2 = (char *)rpath2 + rpath2->path.offset;
980 strcpy(path2, add_rpaths[i].new);
982 ncmds += nadd_rpaths;
983 ncmds -= ndelete_rpaths;
986 * Finally copy the updated load commands over the existing load
987 * commands. Since the headers could be smaller we save away the old
988 * header_size (for use when writing on the input) and also put zero
989 * bytes on the part that is no longer used for headers.
991 if(arch->object->mh != NULL){
992 *header_size = sizeof(struct mach_header) +
993 arch->object->mh->sizeofcmds;
994 if(new_sizeofcmds < arch->object->mh->sizeofcmds){
995 memset(((char *)arch->object->load_commands) + new_sizeofcmds,
996 '\0', arch->object->mh->sizeofcmds - new_sizeofcmds);
998 memcpy(arch->object->load_commands, new_load_commands,
999 new_sizeofcmds);
1000 arch->object->mh->sizeofcmds = new_sizeofcmds;
1001 arch->object->mh->ncmds = ncmds;
1003 else{
1004 *header_size = sizeof(struct mach_header_64) +
1005 arch->object->mh64->sizeofcmds;
1006 if(new_sizeofcmds < arch->object->mh64->sizeofcmds){
1007 memset(((char *)arch->object->load_commands) + new_sizeofcmds,
1008 '\0', arch->object->mh64->sizeofcmds - new_sizeofcmds);
1010 memcpy(arch->object->load_commands, new_load_commands,
1011 new_sizeofcmds);
1012 arch->object->mh64->sizeofcmds = new_sizeofcmds;
1013 arch->object->mh64->ncmds = ncmds;
1016 free(new_load_commands);
1018 /* reset the pointers into the load commands */
1019 lc1 = arch->object->load_commands;
1020 for(i = 0; i < ncmds; i++){
1021 switch(lc1->cmd){
1022 case LC_SYMTAB:
1023 arch->object->st = (struct symtab_command *)lc1;
1024 break;
1025 case LC_DYSYMTAB:
1026 arch->object->dyst = (struct dysymtab_command *)lc1;
1027 break;
1028 case LC_TWOLEVEL_HINTS:
1029 arch->object->hints_cmd = (struct twolevel_hints_command *)lc1;
1030 break;
1031 case LC_PREBIND_CKSUM:
1032 arch->object->cs = (struct prebind_cksum_command *)lc1;
1033 break;
1034 case LC_SEGMENT:
1035 sg = (struct segment_command *)lc1;
1036 if(strcmp(sg->segname, SEG_LINKEDIT) == 0)
1037 arch->object->seg_linkedit = sg;
1038 break;
1039 case LC_SEGMENT_64:
1040 sg64 = (struct segment_command_64 *)lc1;
1041 if(strcmp(sg64->segname, SEG_LINKEDIT) == 0)
1042 arch->object->seg_linkedit64 = sg64;
1043 break;
1044 case LC_CODE_SIGNATURE:
1045 arch->object->code_sig_cmd =
1046 (struct linkedit_data_command *)lc1;
1047 break;
1048 case LC_SEGMENT_SPLIT_INFO:
1049 arch->object->split_info_cmd =
1050 (struct linkedit_data_command *)lc1;
1051 break;
1052 case LC_FUNCTION_STARTS:
1053 arch->object->func_starts_info_cmd =
1054 (struct linkedit_data_command *)lc1;
1055 break;
1056 case LC_DATA_IN_CODE:
1057 arch->object->data_in_code_cmd =
1058 (struct linkedit_data_command *)lc1;
1059 break;
1060 case LC_DYLIB_CODE_SIGN_DRS:
1061 arch->object->code_sign_drs_cmd =
1062 (struct linkedit_data_command *)lc1;
1063 break;
1065 lc1 = (struct load_command *)((char *)lc1 + lc1->cmdsize);