2 * Copyright (c) 1999 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
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
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@
25 #include <mach/mach.h>
26 #include "stuff/openstep_mach.h"
31 #include "stuff/ofile.h"
32 #include "stuff/breakout.h"
33 #include "stuff/allocate.h"
34 #include "stuff/rnd.h"
35 #include "stuff/errors.h"
37 static void copy_new_symbol_info(
40 struct dysymtab_command
*dyst
,
41 struct dysymtab_command
*old_dyst
,
42 struct twolevel_hints_command
*hints_cmd
,
43 struct twolevel_hints_command
*old_hints_cmd
,
44 struct object
*object
);
46 static void make_table_of_contents(
51 enum bool commons_in_toc
,
52 enum bool library_warnings
);
54 static enum bool toc_symbol(
56 enum bool commons_in_toc
,
57 struct section
**sections
);
59 static enum bool toc_symbol_64(
60 struct nlist_64
*symbol64
,
61 enum bool commons_in_toc
,
62 struct section_64
**sections64
);
68 enum bool commons_in_toc
,
69 enum bool attr_no_toc
);
71 static int toc_entry_name_qsort(
72 const struct toc_entry
*toc1
,
73 const struct toc_entry
*toc2
);
75 static int toc_entry_index_qsort(
76 const struct toc_entry
*toc1
,
77 const struct toc_entry
*toc2
);
79 static enum bool check_sort_toc_entries(
82 enum bool library_warnings
);
84 static void warn_member(
86 struct member
*member
,
87 const char *format
, ...)
89 __attribute__ ((format (printf
, 3, 4)))
94 * writeout() creates an ofile from the data structure pointed to by
95 * archs (of narchs size) into the specified output file (output). The file is
96 * created with the mode, mode. If there are libraries in the data structures
97 * a new table of contents is created and is sorted if sort_toc is TRUE and
98 * commons symbols are included in the table of contents if commons_in_toc is
99 * TRUE. The normal use will have sort_toc == TRUE and commons_in_toc == FALSE.
100 * If warnings about unusual libraries are printed if library_warnings == TRUE.
110 enum bool commons_in_toc
,
111 enum bool library_warnings
,
117 struct utimbuf timep
;
121 mach_port_t my_mach_host_self
;
125 enum bool seen_archive
;
128 seen_archive
= FALSE
;
131 writeout_to_mem(archs
, narchs
, output
, (void **)&file
, &file_size
,
132 sort_toc
, commons_in_toc
, library_warnings
,
136 * Create the output file. The unlink() is done to handle the problem
137 * when the outputfile is not writable but the directory allows the
138 * file to be removed (since the file may not be there the return code
139 * of the unlink() is ignored).
141 (void)unlink(output
);
147 if((fd
= open(output
, O_WRONLY
|O_CREAT
|O_TRUNC
|fsync
, mode
)) == -1){
148 system_error("can't create output file: %s", output
);
152 /* tell filesystem to NOT cache the file when reading or writing */
153 (void)fcntl(fd
, F_NOCACHE
, 1);
160 if(throttle
!= NULL
){
161 #define WRITE_SIZE (32 * 1024)
162 struct timeval start
, end
;
164 uint32_t bytes_written
, bytes_per_second
, write_size
;
165 double time_used
, time_should_have_took
, usecs_to_kill
;
166 static struct host_sched_info info
= { 0 };
172 bytes_per_second
= 0;
173 count
= HOST_SCHED_INFO_COUNT
;
174 my_mach_host_self
= mach_host_self();
175 if((r
= host_info(my_mach_host_self
, HOST_SCHED_INFO
, (host_info_t
)
176 (&info
), &count
)) != KERN_SUCCESS
){
177 mach_port_deallocate(mach_task_self(), my_mach_host_self
);
178 my_mach_error(r
, "can't get host sched info");
180 mach_port_deallocate(mach_task_self(), my_mach_host_self
);
181 if(gettimeofday(&start
, &tz
) == -1)
183 #undef THROTTLE_DEBUG
185 if((file
+ file_size
) - p
< WRITE_SIZE
)
186 write_size
= (file
+ file_size
) - p
;
188 write_size
= WRITE_SIZE
;
189 if(write(fd
, p
, write_size
) != (int)write_size
){
190 system_error("can't write output file: %s", output
);
194 if(p
< file
+ file_size
|| *throttle
== UINT_MAX
){
195 bytes_written
+= write_size
;
196 (void)gettimeofday(&end
, &tz
);
197 #ifdef THROTTLE_DEBUG
198 printf("start sec = %u usec = %u\n", start
.tv_sec
,
200 printf("end sec = %u usec = %u\n", end
.tv_sec
,
203 time_used
= end
.tv_sec
- start
.tv_sec
;
204 if(end
.tv_usec
>= start
.tv_usec
)
206 ((double)(end
.tv_usec
- start
.tv_usec
)) / 1000000.0;
209 ((double)(1000000 + end
.tv_usec
- start
.tv_usec
) /
211 bytes_per_second
= ((double)bytes_written
/ time_used
);
212 #ifdef THROTTLE_DEBUG
213 printf("time_used = %f bytes_written = %lu bytes_per_second"
214 " = %lu throttle = %lu\n", time_used
, bytes_written
,
215 bytes_per_second
, *throttle
);
217 if(bytes_per_second
> *throttle
){
218 time_should_have_took
=
219 (double)bytes_written
* (1.0/(double)(*throttle
));
221 (time_should_have_took
- time_used
) * 1000000.0;
222 #ifdef THROTTLE_DEBUG
223 printf("time should have taken = %f usecs to kill %f\n",
224 time_should_have_took
, usecs_to_kill
);
226 usleep((u_int
)usecs_to_kill
);
228 bytes_per_second
= 0;
229 (void)gettimeofday(&start
, &tz
);
232 } while(p
< file
+ file_size
);
233 if(*throttle
== UINT_MAX
)
234 *throttle
= bytes_per_second
;
238 if(write(fd
, file
, file_size
) != (int)file_size
){
239 system_error("can't write output file: %s", output
);
243 if(output
!= NULL
&& close(fd
) == -1){
244 system_fatal("can't close output file: %s", output
);
247 if(seen_archive
== TRUE
){
249 timep
.actime
= toc_time
- 5;
250 timep
.modtime
= toc_time
- 5;
251 if(utime(output
, &timep
) == -1)
253 timep
[0] = toc_time
- 5;
254 timep
[1] = toc_time
- 5;
255 if(utime(output
, timep
) == -1)
258 system_fatal("can't set the modifiy times in output file: %s",
264 if((r
= vm_deallocate(mach_task_self(), (vm_address_t
)file
,
265 file_size
)) != KERN_SUCCESS
){
266 my_mach_error(r
, "can't vm_deallocate() buffer for output file");
273 * writeout_to_mem() creates an ofile in memory from the data structure pointed
274 * to by archs (of narchs size). Upon successful return, *outputbuf will point
275 * to a vm_allocate'd buffer representing the ofile which should be
276 * vm_deallocated when it is no longer needed. length will point to the length
277 * of the outputbuf buffer. The filename parameter is used for error reporting
278 * - if filename is NULL, a dummy file name is used. If there are libraries in
279 * the data structures a new table of contents is created and is sorted if
280 * sort_toc is TRUE and commons symbols are included in the table of contents
281 * if commons_in_toc is TRUE. The normal use will have sort_toc == TRUE and
282 * commons_in_toc == FALSE. If warnings about unusual libraries are printed if
283 * library_warnings == TRUE.
294 enum bool commons_in_toc
,
295 enum bool library_warnings
,
296 enum bool *seen_archive
)
298 uint32_t i
, j
, k
, file_size
, offset
, pad
, size
;
300 enum byte_sex target_byte_sex
, host_byte_sex
;
303 struct fat_header
*fat_header
;
304 struct fat_arch
*fat_arch
;
305 struct dysymtab_command dyst
;
306 struct twolevel_hints_command hints_cmd
;
307 struct load_command lc
, *lcp
;
308 struct dylib_command dl
, *dlp
;
310 int32_t timestamp
, index
;
315 * If filename is NULL, we use a dummy file name.
318 filename
= "(file written out to memory)";
321 * The time the table of contents' are set to and the time to base the
322 * modification time of the output file to be set to.
324 *seen_archive
= FALSE
;
327 fat_arch
= NULL
; /* here to quite compiler maybe warning message */
331 error("no contents for file: %s (not created)", filename
);
335 host_byte_sex
= get_host_byte_sex();
338 * Calculate the total size of the file and the final size of each
341 if(narchs
> 1 || archs
[0].fat_arch
!= NULL
)
342 file_size
= sizeof(struct fat_header
) +
343 sizeof(struct fat_arch
) * narchs
;
346 for(i
= 0; i
< narchs
; i
++){
348 * For each arch that is an archive recreate the table of contents.
350 if(archs
[i
].type
== OFILE_ARCHIVE
){
351 *seen_archive
= TRUE
;
352 make_table_of_contents(archs
+ i
, filename
, toc_time
, sort_toc
,
353 commons_in_toc
, library_warnings
);
354 archs
[i
].library_size
+= SARMAG
+ archs
[i
].toc_size
;
355 if(archs
[i
].fat_arch
!= NULL
)
356 file_size
= rnd(file_size
, 1 << archs
[i
].fat_arch
->align
);
357 file_size
+= archs
[i
].library_size
;
358 if(archs
[i
].fat_arch
!= NULL
)
359 archs
[i
].fat_arch
->size
= archs
[i
].library_size
;
361 else if(archs
[i
].type
== OFILE_Mach_O
){
362 size
= archs
[i
].object
->object_size
363 - archs
[i
].object
->input_sym_info_size
364 + archs
[i
].object
->output_new_content_size
365 + archs
[i
].object
->output_sym_info_size
;
366 if(archs
[i
].fat_arch
!= NULL
)
367 file_size
= rnd(file_size
, 1 << archs
[i
].fat_arch
->align
);
369 if(archs
[i
].fat_arch
!= NULL
)
370 archs
[i
].fat_arch
->size
= size
;
372 else{ /* archs[i].type == OFILE_UNKNOWN */
373 if(archs
[i
].fat_arch
!= NULL
)
374 file_size
= rnd(file_size
, 1 << archs
[i
].fat_arch
->align
);
375 file_size
+= archs
[i
].unknown_size
;
376 if(archs
[i
].fat_arch
!= NULL
)
377 archs
[i
].fat_arch
->size
= archs
[i
].unknown_size
;
382 * This buffer is vm_allocate'ed to make sure all holes are filled with
385 if((r
= vm_allocate(mach_task_self(), (vm_address_t
*)&file
,
386 file_size
, TRUE
)) != KERN_SUCCESS
)
387 mach_fatal(r
, "can't vm_allocate() buffer for output file: %s of "
388 "size %u", filename
, file_size
);
391 * If there is more than one architecture then fill in the fat file
392 * header and the fat_arch structures in the buffer.
394 if(narchs
> 1 || archs
[0].fat_arch
!= NULL
){
395 fat_header
= (struct fat_header
*)file
;
396 fat_header
->magic
= FAT_MAGIC
;
397 fat_header
->nfat_arch
= narchs
;
398 offset
= sizeof(struct fat_header
) +
399 sizeof(struct fat_arch
) * narchs
;
400 fat_arch
= (struct fat_arch
*)(file
+ sizeof(struct fat_header
));
401 for(i
= 0; i
< narchs
; i
++){
402 fat_arch
[i
].cputype
= archs
[i
].fat_arch
->cputype
;
403 fat_arch
[i
].cpusubtype
= archs
[i
].fat_arch
->cpusubtype
;
404 offset
= rnd(offset
, 1 << archs
[i
].fat_arch
->align
);
405 fat_arch
[i
].offset
= offset
;
406 fat_arch
[i
].size
= archs
[i
].fat_arch
->size
;
407 fat_arch
[i
].align
= archs
[i
].fat_arch
->align
;
408 offset
+= archs
[i
].fat_arch
->size
;
413 * Now put each arch in the buffer.
415 for(i
= 0; i
< narchs
; i
++){
416 if(archs
[i
].fat_arch
!= NULL
)
417 p
= file
+ fat_arch
[i
].offset
;
421 if(archs
[i
].type
== OFILE_ARCHIVE
){
422 *seen_archive
= TRUE
;
424 * If the input files only contains non-object files then the
425 * byte sex of the output can't be determined which is needed
426 * for the two binary long's of the table of contents. But
427 * since these will be zero (the same in both byte sexes)
428 * because there are no symbols in the table of contents if
429 * there are no object files.
432 /* put in the archive magic string */
433 memcpy(p
, ARMAG
, SARMAG
);
437 * Warn for what really is a bad library that has an empty
438 * table of contents but this is allowed in the original
439 * bsd4.3 ranlib(1) implementation.
441 if(library_warnings
== TRUE
&& archs
[i
].ntocs
== 0){
442 if(narchs
> 1 || archs
[i
].fat_arch
!= NULL
)
443 warning("warning library: %s for architecture: %s the "
444 "table of contents is empty (no object file "
445 "members in the library)", filename
,
446 archs
[i
].fat_arch_name
);
448 warning("warning for library: %s the table of contents "
449 "is empty (no object file members in the "
450 "library)", filename
);
454 * Pick the byte sex to write the table of contents in.
456 target_byte_sex
= UNKNOWN_BYTE_SEX
;
458 j
< archs
[i
].nmembers
&& target_byte_sex
==UNKNOWN_BYTE_SEX
;
460 if(archs
[i
].members
[j
].type
== OFILE_Mach_O
)
462 archs
[i
].members
[j
].object
->object_byte_sex
;
464 if(target_byte_sex
== UNKNOWN_BYTE_SEX
)
465 target_byte_sex
= host_byte_sex
;
468 * Put in the table of contents member:
470 * a 32-bit for the number of bytes of the ranlib structs
472 * a 32-bit for the number of bytes of the ranlib strings
473 * the strings for the ranlib structs
475 memcpy(p
, (char *)(&archs
[i
].toc_ar_hdr
),sizeof(struct ar_hdr
));
476 p
+= sizeof(struct ar_hdr
);
478 if(archs
[i
].toc_long_name
== TRUE
){
479 memcpy(p
, archs
[i
].toc_name
, archs
[i
].toc_name_size
);
480 p
+= archs
[i
].toc_name_size
+
481 (rnd(sizeof(struct ar_hdr
), 8) -
482 sizeof(struct ar_hdr
));
485 i32
= archs
[i
].ntocs
* sizeof(struct ranlib
);
486 if(target_byte_sex
!= host_byte_sex
)
488 memcpy(p
, (char *)&i32
, sizeof(uint32_t));
489 p
+= sizeof(uint32_t);
491 if(target_byte_sex
!= host_byte_sex
)
492 swap_ranlib(archs
[i
].toc_ranlibs
, archs
[i
].ntocs
,
494 memcpy(p
, (char *)archs
[i
].toc_ranlibs
,
495 archs
[i
].ntocs
* sizeof(struct ranlib
));
496 p
+= archs
[i
].ntocs
* sizeof(struct ranlib
);
498 i32
= archs
[i
].toc_strsize
;
499 if(target_byte_sex
!= host_byte_sex
)
501 memcpy(p
, (char *)&i32
, sizeof(uint32_t));
502 p
+= sizeof(uint32_t);
504 memcpy(p
, (char *)archs
[i
].toc_strings
, archs
[i
].toc_strsize
);
505 p
+= archs
[i
].toc_strsize
;
508 * Put in the archive header and member contents for each
509 * member in the buffer.
511 for(j
= 0; j
< archs
[i
].nmembers
; j
++){
512 memcpy(p
, (char *)(archs
[i
].members
[j
].ar_hdr
),
513 sizeof(struct ar_hdr
));
514 p
+= sizeof(struct ar_hdr
);
516 if(archs
[i
].members
[j
].member_long_name
== TRUE
){
517 memcpy(p
, archs
[i
].members
[j
].member_name
,
518 archs
[i
].members
[j
].member_name_size
);
519 p
+= rnd(archs
[i
].members
[j
].member_name_size
, 8) +
520 (rnd(sizeof(struct ar_hdr
), 8) -
521 sizeof(struct ar_hdr
));
524 if(archs
[i
].members
[j
].type
== OFILE_Mach_O
){
526 * ofile_map swaps the headers to the host_byte_sex if
527 * the object's byte sex is not the same as the host
528 * byte sex so if this is the case swap them back
529 * before writing them out.
531 memset(&dyst
, '\0', sizeof(struct dysymtab_command
));
532 if(archs
[i
].members
[j
].object
->dyst
!= NULL
)
533 dyst
= *(archs
[i
].members
[j
].object
->dyst
);
534 if(archs
[i
].members
[j
].object
->hints_cmd
!= NULL
)
535 hints_cmd
= *(archs
[i
].members
[j
].object
->hints_cmd
);
536 if(archs
[i
].members
[j
].object
->object_byte_sex
!=
538 if(archs
[i
].members
[j
].object
->mh
!= NULL
){
539 if(swap_object_headers(
540 archs
[i
].members
[j
].object
->mh
,
541 archs
[i
].members
[j
].object
->load_commands
)
543 fatal("internal error: "
544 "swap_object_headers() failed");
545 if(archs
[i
].members
[j
].object
->output_nsymbols
548 archs
[i
].members
[j
].object
->
550 archs
[i
].members
[j
].object
->
552 archs
[i
].members
[j
].object
->
556 if(swap_object_headers(
557 archs
[i
].members
[j
].object
->mh64
,
558 archs
[i
].members
[j
].object
->load_commands
)
560 fatal("internal error: "
561 "swap_object_headers() failed");
562 if(archs
[i
].members
[j
].object
->output_nsymbols
565 archs
[i
].members
[j
].object
->
567 archs
[i
].members
[j
].object
->
569 archs
[i
].members
[j
].object
->
573 if(archs
[i
].members
[j
].object
->
574 output_sym_info_size
== 0 &&
575 archs
[i
].members
[j
].object
->
576 input_sym_info_size
== 0){
577 size
= archs
[i
].members
[j
].object
->object_size
;
578 memcpy(p
, archs
[i
].members
[j
].object
->object_addr
,
582 size
= archs
[i
].members
[j
].object
->object_size
583 - archs
[i
].members
[j
].object
->
585 memcpy(p
, archs
[i
].members
[j
].object
->object_addr
,
587 copy_new_symbol_info(p
, &size
, &dyst
,
588 archs
[i
].members
[j
].object
->dyst
, &hints_cmd
,
589 archs
[i
].members
[j
].object
->hints_cmd
,
590 archs
[i
].members
[j
].object
);
593 pad
= rnd(size
, 8) - size
;
596 memcpy(p
, archs
[i
].members
[j
].unknown_addr
,
597 archs
[i
].members
[j
].unknown_size
);
598 p
+= archs
[i
].members
[j
].unknown_size
;
599 pad
= rnd(archs
[i
].members
[j
].unknown_size
, 8) -
600 archs
[i
].members
[j
].unknown_size
;
602 /* as with the UNIX ar(1) program pad with '\n' chars */
603 for(k
= 0; k
< pad
; k
++)
607 else if(archs
[i
].type
== OFILE_Mach_O
){
608 memset(&dyst
, '\0', sizeof(struct dysymtab_command
));
609 if(archs
[i
].object
->dyst
!= NULL
)
610 dyst
= *(archs
[i
].object
->dyst
);
611 if(archs
[i
].object
->hints_cmd
!= NULL
)
612 hints_cmd
= *(archs
[i
].object
->hints_cmd
);
613 if(archs
[i
].object
->mh_filetype
== MH_DYLIB
){
615 * To avoid problems with prebinding and multiple
616 * cpusubtypes we stager the time stamps of fat dylibs
617 * that have more than one cpusubtype.
620 for(index
= i
- 1; timestamp
== 0 && index
>= 0; index
--){
621 if(archs
[index
].type
== OFILE_Mach_O
&&
622 archs
[index
].object
->mh_filetype
== MH_DYLIB
&&
623 archs
[index
].object
->mh_cputype
==
624 archs
[i
].object
->mh_cputype
){
625 if(archs
[index
].object
->mh
!= NULL
)
626 ncmds
= archs
[index
].object
->mh
->ncmds
;
628 ncmds
= archs
[index
].object
->mh64
->ncmds
;
629 lcp
= archs
[index
].object
->load_commands
;
630 swapped
= archs
[index
].object
->object_byte_sex
!=
633 ncmds
= SWAP_INT(ncmds
);
634 for(j
= 0; j
< ncmds
; j
++){
637 swap_load_command(&lc
, host_byte_sex
);
638 if(lc
.cmd
== LC_ID_DYLIB
){
639 dlp
= (struct dylib_command
*)lcp
;
642 swap_dylib_command(&dl
, host_byte_sex
);
643 timestamp
= dl
.dylib
.timestamp
- 1;
646 lcp
= (struct load_command
*)
647 ((char *)lcp
+ lc
.cmdsize
);
652 timestamp
= toc_time
;
653 lcp
= archs
[i
].object
->load_commands
;
654 if(archs
[i
].object
->mh
!= NULL
)
655 ncmds
= archs
[i
].object
->mh
->ncmds
;
657 ncmds
= archs
[i
].object
->mh64
->ncmds
;
658 for(j
= 0; j
< ncmds
; j
++){
659 if(lcp
->cmd
== LC_ID_DYLIB
){
660 dlp
= (struct dylib_command
*)lcp
;
661 if(archs
[i
].dont_update_LC_ID_DYLIB_timestamp
==
663 dlp
->dylib
.timestamp
= timestamp
;
666 lcp
= (struct load_command
*)((char *)lcp
+
670 if(archs
[i
].object
->object_byte_sex
!= host_byte_sex
){
671 if(archs
[i
].object
->mh
!= NULL
){
672 if(swap_object_headers(archs
[i
].object
->mh
,
673 archs
[i
].object
->load_commands
) == FALSE
)
674 fatal("internal error: swap_object_headers() "
676 if(archs
[i
].object
->output_nsymbols
!= 0)
677 swap_nlist(archs
[i
].object
->output_symbols
,
678 archs
[i
].object
->output_nsymbols
,
679 archs
[i
].object
->object_byte_sex
);
682 if(swap_object_headers(archs
[i
].object
->mh64
,
683 archs
[i
].object
->load_commands
) == FALSE
)
684 fatal("internal error: swap_object_headers() "
686 if(archs
[i
].object
->output_nsymbols
!= 0)
687 swap_nlist_64(archs
[i
].object
->output_symbols64
,
688 archs
[i
].object
->output_nsymbols
,
689 archs
[i
].object
->object_byte_sex
);
692 if(archs
[i
].object
->output_sym_info_size
== 0 &&
693 archs
[i
].object
->input_sym_info_size
== 0){
694 size
= archs
[i
].object
->object_size
;
695 memcpy(p
, archs
[i
].object
->object_addr
, size
);
698 size
= archs
[i
].object
->object_size
699 - archs
[i
].object
->input_sym_info_size
;
700 memcpy(p
, archs
[i
].object
->object_addr
, size
);
701 if(archs
[i
].object
->output_new_content_size
!= 0){
702 memcpy(p
+ size
, archs
[i
].object
->output_new_content
,
703 archs
[i
].object
->output_new_content_size
);
704 size
+= archs
[i
].object
->output_new_content_size
;
706 copy_new_symbol_info(p
, &size
, &dyst
,
707 archs
[i
].object
->dyst
, &hints_cmd
,
708 archs
[i
].object
->hints_cmd
,
712 else{ /* archs[i].type == OFILE_UNKNOWN */
713 memcpy(p
, archs
[i
].unknown_addr
, archs
[i
].unknown_size
);
716 #ifdef __LITTLE_ENDIAN__
717 if(narchs
> 1 || archs
[0].fat_arch
!= NULL
){
718 swap_fat_header(fat_header
, BIG_ENDIAN_BYTE_SEX
);
719 swap_fat_arch(fat_arch
, narchs
, BIG_ENDIAN_BYTE_SEX
);
721 #endif /* __LITTLE_ENDIAN__ */
727 * copy_new_symbol_info() copies the new and updated symbolic information into
728 * the buffer for the object.
732 copy_new_symbol_info(
735 struct dysymtab_command
*dyst
,
736 struct dysymtab_command
*old_dyst
,
737 struct twolevel_hints_command
*hints_cmd
,
738 struct twolevel_hints_command
*old_hints_cmd
,
739 struct object
*object
)
741 if(old_dyst
!= NULL
){
742 if(object
->output_dyld_info_size
!= 0){
743 if(object
->output_dyld_info
!= NULL
)
744 memcpy(p
+ *size
, object
->output_dyld_info
,
745 object
->output_dyld_info_size
);
746 *size
+= object
->output_dyld_info_size
;
748 memcpy(p
+ *size
, object
->output_loc_relocs
,
749 dyst
->nlocrel
* sizeof(struct relocation_info
));
750 *size
+= dyst
->nlocrel
*
751 sizeof(struct relocation_info
);
752 if(object
->output_split_info_data_size
!= 0){
753 if(object
->output_split_info_data
!= NULL
)
754 memcpy(p
+ *size
, object
->output_split_info_data
,
755 object
->output_split_info_data_size
);
756 *size
+= object
->output_split_info_data_size
;
758 if(object
->output_func_start_info_data_size
!= 0){
759 if(object
->output_func_start_info_data
!= NULL
)
760 memcpy(p
+ *size
, object
->output_func_start_info_data
,
761 object
->output_func_start_info_data_size
);
762 *size
+= object
->output_func_start_info_data_size
;
764 if(object
->output_data_in_code_info_data_size
!= 0){
765 if(object
->output_data_in_code_info_data
!= NULL
)
766 memcpy(p
+ *size
, object
->output_data_in_code_info_data
,
767 object
->output_data_in_code_info_data_size
);
768 *size
+= object
->output_data_in_code_info_data_size
;
770 if(object
->output_code_sign_drs_info_data_size
!= 0){
771 if(object
->output_code_sign_drs_info_data
!= NULL
)
772 memcpy(p
+ *size
, object
->output_code_sign_drs_info_data
,
773 object
->output_code_sign_drs_info_data_size
);
774 *size
+= object
->output_code_sign_drs_info_data_size
;
776 if(object
->mh
!= NULL
){
777 memcpy(p
+ *size
, object
->output_symbols
,
778 object
->output_nsymbols
* sizeof(struct nlist
));
779 *size
+= object
->output_nsymbols
*
780 sizeof(struct nlist
);
783 memcpy(p
+ *size
, object
->output_symbols64
,
784 object
->output_nsymbols
* sizeof(struct nlist_64
));
785 *size
+= object
->output_nsymbols
*
786 sizeof(struct nlist_64
);
788 if(old_hints_cmd
!= NULL
){
789 memcpy(p
+ *size
, object
->output_hints
,
790 hints_cmd
->nhints
* sizeof(struct twolevel_hint
));
791 *size
+= hints_cmd
->nhints
*
792 sizeof(struct twolevel_hint
);
794 memcpy(p
+ *size
, object
->output_ext_relocs
,
795 dyst
->nextrel
* sizeof(struct relocation_info
));
796 *size
+= dyst
->nextrel
*
797 sizeof(struct relocation_info
);
798 memcpy(p
+ *size
, object
->output_indirect_symtab
,
799 dyst
->nindirectsyms
* sizeof(uint32_t));
800 *size
+= dyst
->nindirectsyms
* sizeof(uint32_t) +
801 object
->input_indirectsym_pad
;
802 memcpy(p
+ *size
, object
->output_tocs
,
803 object
->output_ntoc
*sizeof(struct dylib_table_of_contents
));
804 *size
+= object
->output_ntoc
*
805 sizeof(struct dylib_table_of_contents
);
806 if(object
->mh
!= NULL
){
807 memcpy(p
+ *size
, object
->output_mods
,
808 object
->output_nmodtab
* sizeof(struct dylib_module
));
809 *size
+= object
->output_nmodtab
*
810 sizeof(struct dylib_module
);
813 memcpy(p
+ *size
, object
->output_mods64
,
814 object
->output_nmodtab
* sizeof(struct dylib_module_64
));
815 *size
+= object
->output_nmodtab
*
816 sizeof(struct dylib_module_64
);
818 memcpy(p
+ *size
, object
->output_refs
,
819 object
->output_nextrefsyms
* sizeof(struct dylib_reference
));
820 *size
+= object
->output_nextrefsyms
*
821 sizeof(struct dylib_reference
);
822 memcpy(p
+ *size
, object
->output_strings
,
823 object
->output_strings_size
);
824 *size
+= object
->output_strings_size
;
825 if(object
->output_code_sig_data_size
!= 0){
826 *size
= rnd(*size
, 16);
827 if(object
->output_code_sig_data
!= NULL
)
828 memcpy(p
+ *size
, object
->output_code_sig_data
,
829 object
->output_code_sig_data_size
);
830 *size
+= object
->output_code_sig_data_size
;
834 if(object
->output_func_start_info_data_size
!= 0){
835 if(object
->output_func_start_info_data
!= NULL
)
836 memcpy(p
+ *size
, object
->output_func_start_info_data
,
837 object
->output_func_start_info_data_size
);
838 *size
+= object
->output_func_start_info_data_size
;
840 if(object
->output_data_in_code_info_data_size
!= 0){
841 if(object
->output_data_in_code_info_data
!= NULL
)
842 memcpy(p
+ *size
, object
->output_data_in_code_info_data
,
843 object
->output_data_in_code_info_data_size
);
844 *size
+= object
->output_data_in_code_info_data_size
;
846 if(object
->mh
!= NULL
){
847 memcpy(p
+ *size
, object
->output_symbols
,
848 object
->output_nsymbols
* sizeof(struct nlist
));
849 *size
+= object
->output_nsymbols
*
850 sizeof(struct nlist
);
853 memcpy(p
+ *size
, object
->output_symbols64
,
854 object
->output_nsymbols
* sizeof(struct nlist_64
));
855 *size
+= object
->output_nsymbols
*
856 sizeof(struct nlist_64
);
858 memcpy(p
+ *size
, object
->output_strings
,
859 object
->output_strings_size
);
860 *size
+= object
->output_strings_size
;
861 if(object
->output_code_sig_data_size
!= 0){
862 *size
= rnd(*size
, 16);
863 if(object
->output_code_sig_data
!= NULL
)
864 memcpy(p
+ *size
, object
->output_code_sig_data
,
865 object
->output_code_sig_data_size
);
866 *size
+= object
->output_code_sig_data_size
;
872 * make_table_of_contents() make the table of contents for the specified arch
873 * and fills in the toc_* fields in the arch. Output is the name of the output
874 * file for error messages.
878 make_table_of_contents(
883 enum bool commons_in_toc
,
884 enum bool library_warnings
)
886 uint32_t i
, j
, k
, r
, s
, nsects
;
887 struct member
*member
;
888 struct object
*object
;
889 struct load_command
*lc
;
890 struct segment_command
*sg
;
891 struct segment_command_64
*sg64
;
892 struct nlist
*symbols
;
893 struct nlist_64
*symbols64
;
896 uint32_t strings_size
;
898 unsigned short toc_mode
;
901 struct section
*section
;
902 struct section_64
*section64
;
905 symbols
= NULL
; /* here to quite compiler maybe warning message */
907 strings
= NULL
; /* here to quite compiler maybe warning message */
910 * First pass over the members to count how many ranlib structs are
911 * needed and the size of the strings in the toc that are needed.
913 for(i
= 0; i
< arch
->nmembers
; i
++){
914 member
= arch
->members
+ i
;
915 if(member
->type
== OFILE_Mach_O
){
916 object
= member
->object
;
919 lc
= object
->load_commands
;
920 if(object
->mh
!= NULL
)
921 ncmds
= object
->mh
->ncmds
;
923 ncmds
= object
->mh64
->ncmds
;
924 for(j
= 0; j
< ncmds
; j
++){
925 if(lc
->cmd
== LC_SEGMENT
){
926 sg
= (struct segment_command
*)lc
;
927 nsects
+= sg
->nsects
;
929 else if(lc
->cmd
== LC_SEGMENT_64
){
930 sg64
= (struct segment_command_64
*)lc
;
931 nsects
+= sg64
->nsects
;
933 lc
= (struct load_command
*)((char *)lc
+ lc
->cmdsize
);
935 if(object
->mh
!= NULL
){
936 object
->sections
= allocate(nsects
*
937 sizeof(struct section
*));
938 object
->sections64
= NULL
;
941 object
->sections
= NULL
;
942 object
->sections64
= allocate(nsects
*
943 sizeof(struct section_64
*));
946 lc
= object
->load_commands
;
947 for(j
= 0; j
< ncmds
; j
++){
948 if(lc
->cmd
== LC_SEGMENT
){
949 sg
= (struct segment_command
*)lc
;
950 section
= (struct section
*)
951 ((char *)sg
+ sizeof(struct segment_command
));
952 for(k
= 0; k
< sg
->nsects
; k
++){
953 object
->sections
[nsects
++] = section
++;
956 else if(lc
->cmd
== LC_SEGMENT_64
){
957 sg64
= (struct segment_command_64
*)lc
;
958 section64
= (struct section_64
*)
959 ((char *)sg64
+ sizeof(struct segment_command_64
));
960 for(k
= 0; k
< sg64
->nsects
; k
++){
961 object
->sections64
[nsects
++] = section64
++;
964 lc
= (struct load_command
*)((char *)lc
+ lc
->cmdsize
);
966 if(object
->output_sym_info_size
== 0){
967 lc
= object
->load_commands
;
968 for(j
= 0; j
< ncmds
; j
++){
969 if(lc
->cmd
== LC_SYMTAB
){
970 object
->st
= (struct symtab_command
*)lc
;
973 lc
= (struct load_command
*)((char *)lc
+ lc
->cmdsize
);
975 if(object
->st
!= NULL
&& object
->st
->nsyms
!= 0){
976 if(object
->mh
!= NULL
){
977 symbols
= (struct nlist
*)(object
->object_addr
+
979 if(object
->object_byte_sex
!= get_host_byte_sex())
980 swap_nlist(symbols
, object
->st
->nsyms
,
981 get_host_byte_sex());
984 symbols64
= (struct nlist_64
*)
985 (object
->object_addr
+ object
->st
->symoff
);
986 if(object
->object_byte_sex
!= get_host_byte_sex())
987 swap_nlist_64(symbols64
, object
->st
->nsyms
,
988 get_host_byte_sex());
990 nsymbols
= object
->st
->nsyms
;
991 strings
= object
->object_addr
+ object
->st
->stroff
;
992 strings_size
= object
->st
->strsize
;
995 else /* object->output_sym_info_size != 0 */ {
996 if(object
->mh
!= NULL
)
997 symbols
= object
->output_symbols
;
999 symbols64
= object
->output_symbols64
;
1000 nsymbols
= object
->output_nsymbols
;
1001 strings
= object
->output_strings
;
1002 strings_size
= object
->output_strings_size
;
1004 for(j
= 0; j
< nsymbols
; j
++){
1005 if(object
->mh
!= NULL
){
1006 if(toc_symbol(symbols
+ j
, commons_in_toc
,
1007 object
->sections
) == TRUE
){
1009 arch
->toc_strsize
+=
1010 strlen(strings
+ symbols
[j
].n_un
.n_strx
) + 1;
1014 if(toc_symbol_64(symbols64
+ j
, commons_in_toc
,
1015 object
->sections64
) == TRUE
){
1017 arch
->toc_strsize
+=
1018 strlen(strings
+ symbols64
[j
].n_un
.n_strx
) + 1;
1026 * Allocate the space for the table of content entries, the ranlib
1027 * structs and strings for the table of contents.
1029 arch
->toc_entries
= allocate(sizeof(struct toc_entry
) * arch
->ntocs
);
1030 arch
->toc_ranlibs
= allocate(sizeof(struct ranlib
) * arch
->ntocs
);
1031 arch
->toc_strsize
= rnd(arch
->toc_strsize
, 8);
1032 arch
->toc_strings
= allocate(arch
->toc_strsize
);
1035 * Second pass over the members to fill in the toc_entry structs and
1036 * the strings for the table of contents. The symbol_name field is
1037 * filled in with a pointer to a string contained in arch->toc_strings
1038 * for easy sorting and conversion to an index. The member_index field
1039 * is filled in with the member index plus one to allow marking with
1040 * its negative value by check_sort_toc_entries() and easy conversion to
1045 for(i
= 0; i
< arch
->nmembers
; i
++){
1046 member
= arch
->members
+ i
;
1047 if(member
->type
== OFILE_Mach_O
){
1048 object
= member
->object
;
1050 if(object
->output_sym_info_size
== 0){
1051 if(object
->st
!= NULL
){
1052 if(object
->mh
!= NULL
)
1053 symbols
= (struct nlist
*)
1054 (object
->object_addr
+ object
->st
->symoff
);
1056 symbols64
= (struct nlist_64
*)
1057 (object
->object_addr
+ object
->st
->symoff
);
1058 nsymbols
= object
->st
->nsyms
;
1059 strings
= object
->object_addr
+ object
->st
->stroff
;
1060 strings_size
= object
->st
->strsize
;
1070 if(object
->mh
!= NULL
)
1071 symbols
= object
->output_symbols
;
1073 symbols64
= object
->output_symbols64
;
1074 nsymbols
= object
->output_nsymbols
;
1075 strings
= object
->output_strings
;
1076 strings_size
= object
->output_strings_size
;
1078 for(j
= 0; j
< nsymbols
; j
++){
1079 if(object
->mh
!= NULL
){
1080 if((uint32_t)symbols
[j
].n_un
.n_strx
> strings_size
)
1082 if(toc_symbol(symbols
+ j
, commons_in_toc
,
1083 object
->sections
) == TRUE
){
1084 strcpy(arch
->toc_strings
+ s
,
1085 strings
+ symbols
[j
].n_un
.n_strx
);
1086 arch
->toc_entries
[r
].symbol_name
=
1087 arch
->toc_strings
+ s
;
1088 arch
->toc_entries
[r
].member_index
= i
+ 1;
1090 s
+= strlen(strings
+ symbols
[j
].n_un
.n_strx
) + 1;
1094 if((uint32_t)symbols64
[j
].n_un
.n_strx
>
1097 if(toc_symbol_64(symbols64
+ j
, commons_in_toc
,
1098 object
->sections64
) == TRUE
){
1099 strcpy(arch
->toc_strings
+ s
,
1100 strings
+ symbols64
[j
].n_un
.n_strx
);
1101 arch
->toc_entries
[r
].symbol_name
=
1102 arch
->toc_strings
+ s
;
1103 arch
->toc_entries
[r
].member_index
= i
+ 1;
1105 s
+= strlen(strings
+ symbols64
[j
].n_un
.n_strx
) + 1;
1109 if(object
->output_sym_info_size
== 0){
1110 if(object
->object_byte_sex
!= get_host_byte_sex()){
1111 if(object
->mh
!= NULL
)
1112 swap_nlist(symbols
, nsymbols
,
1113 object
->object_byte_sex
);
1115 swap_nlist_64(symbols64
, nsymbols
,
1116 object
->object_byte_sex
);
1123 * If the table of contents is to be sorted by symbol name then try to
1124 * sort it and leave it sorted if no duplicates.
1126 if(sort_toc
== TRUE
){
1127 qsort(arch
->toc_entries
, arch
->ntocs
, sizeof(struct toc_entry
),
1128 (int (*)(const void *, const void *))toc_entry_name_qsort
);
1129 sorted
= check_sort_toc_entries(arch
, output
, library_warnings
);
1130 if(sorted
== FALSE
){
1131 qsort(arch
->toc_entries
, arch
->ntocs
, sizeof(struct toc_entry
),
1132 (int (*)(const void *, const void *))
1133 toc_entry_index_qsort
);
1141 * Now set the ran_off and ran_un.ran_strx fields of the ranlib structs.
1142 * To do this the size of the toc member must be know because it comes
1143 * first in the library. The size of the toc member is made up of the
1144 * sizeof an archive header struct, plus the sizeof the name if we are
1145 * using extended format #1 for the long name, then the toc which is
1146 * (as defined in ranlib.h):
1147 * a 32-bit int for the number of bytes of the ranlib structs
1148 * the ranlib structures
1149 * a 32-bit int for the number of bytes of the strings
1153 * We use a long name for the table of contents for both the sorted
1154 * and non-sorted case because it is needed to get the 8 byte alignment
1155 * of the first archive member by padding the long name since
1156 * sizeof(struct ar_hdr) is not a mutiple of 8.
1158 if(arch
->toc_long_name
== FALSE
)
1159 fatal("internal error: make_table_of_contents() called with "
1160 "arch->toc_long_name == FALSE");
1164 * This assumes that "__.SYMDEF SORTED" is 16 bytes and
1165 * (rnd(sizeof(struct ar_hdr), 8) - sizeof(struct ar_hdr)
1168 ar_name
= AR_EFMT1
"20";
1169 arch
->toc_name_size
= sizeof(SYMDEF_SORTED
) - 1;
1170 arch
->toc_name
= SYMDEF_SORTED
;
1174 * This assumes that "__.SYMDEF\0\0\0\0\0\0\0" is 16 bytes and
1175 * (rnd(sizeof(struct ar_hdr), 8) - sizeof(struct ar_hdr)
1178 ar_name
= AR_EFMT1
"20";
1179 arch
->toc_name_size
= 16;
1180 arch
->toc_name
= SYMDEF
"\0\0\0\0\0\0\0";
1182 arch
->toc_size
= sizeof(struct ar_hdr
) +
1184 arch
->ntocs
* sizeof(struct ranlib
) +
1187 if(arch
->toc_long_name
== TRUE
)
1188 arch
->toc_size
+= arch
->toc_name_size
+
1189 (rnd(sizeof(struct ar_hdr
), 8) -
1190 sizeof(struct ar_hdr
));
1191 for(i
= 0; i
< arch
->nmembers
; i
++)
1192 arch
->members
[i
].offset
+= SARMAG
+ arch
->toc_size
;
1193 for(i
= 0; i
< arch
->ntocs
; i
++){
1194 arch
->toc_ranlibs
[i
].ran_un
.ran_strx
=
1195 arch
->toc_entries
[i
].symbol_name
- arch
->toc_strings
;
1196 arch
->toc_ranlibs
[i
].ran_off
=
1197 arch
->members
[arch
->toc_entries
[i
].member_index
- 1].offset
;
1201 oumask
= umask(numask
);
1202 toc_mode
= S_IFREG
| (0666 & ~oumask
);
1203 (void)umask(oumask
);
1205 sprintf((char *)(&arch
->toc_ar_hdr
), "%-*s%-*ld%-*u%-*u%-*o%-*ld",
1206 (int)sizeof(arch
->toc_ar_hdr
.ar_name
),
1208 (int)sizeof(arch
->toc_ar_hdr
.ar_date
),
1210 (int)sizeof(arch
->toc_ar_hdr
.ar_uid
),
1211 (unsigned short)getuid(),
1212 (int)sizeof(arch
->toc_ar_hdr
.ar_gid
),
1213 (unsigned short)getgid(),
1214 (int)sizeof(arch
->toc_ar_hdr
.ar_mode
),
1215 (unsigned int)toc_mode
,
1216 (int)sizeof(arch
->toc_ar_hdr
.ar_size
),
1217 (long)(arch
->toc_size
- sizeof(struct ar_hdr
)));
1219 * This has to be done by hand because sprintf puts a null
1220 * at the end of the buffer.
1222 memcpy(arch
->toc_ar_hdr
.ar_fmag
, ARFMAG
,
1223 (int)sizeof(arch
->toc_ar_hdr
.ar_fmag
));
1227 * toc_symbol() returns TRUE if the symbol is to be included in the table of
1228 * contents otherwise it returns FALSE.
1233 struct nlist
*symbol
,
1234 enum bool commons_in_toc
,
1235 struct section
**sections
)
1237 return(toc(symbol
->n_un
.n_strx
,
1241 (symbol
->n_type
& N_TYPE
) == N_SECT
&&
1242 sections
[symbol
->n_sect
- 1]->flags
& S_ATTR_NO_TOC
));
1248 struct nlist_64
*symbol64
,
1249 enum bool commons_in_toc
,
1250 struct section_64
**sections64
)
1252 return(toc(symbol64
->n_un
.n_strx
,
1256 (symbol64
->n_type
& N_TYPE
) == N_SECT
&&
1257 sections64
[symbol64
->n_sect
-1]->flags
& S_ATTR_NO_TOC
));
1266 enum bool commons_in_toc
,
1267 enum bool attr_no_toc
)
1269 /* if the name is NULL then it won't be in the table of contents */
1272 /* if symbol is not external then it won't be in the toc */
1273 if((n_type
& N_EXT
) == 0)
1275 /* if symbol is undefined then it won't be in the toc */
1276 if((n_type
& N_TYPE
) == N_UNDF
&& n_value
== 0)
1278 /* if symbol is common and the commons are not to be in the toc */
1279 if((n_type
& N_TYPE
) == N_UNDF
&& n_value
!= 0 &&
1280 commons_in_toc
== FALSE
)
1282 /* if the symbols is in a section marked NO_TOC then ... */
1283 if(attr_no_toc
!= 0)
1290 * Function for qsort() for comparing toc_entry structures by name.
1294 toc_entry_name_qsort(
1295 const struct toc_entry
*toc1
,
1296 const struct toc_entry
*toc2
)
1298 return(strcmp(toc1
->symbol_name
, toc2
->symbol_name
));
1302 * Function for qsort() for comparing toc_entry structures by index.
1306 toc_entry_index_qsort(
1307 const struct toc_entry
*toc1
,
1308 const struct toc_entry
*toc2
)
1310 if(toc1
->member_index
< toc2
->member_index
)
1312 if(toc1
->member_index
> toc2
->member_index
)
1314 /* toc1->member_index == toc2->member_index */
1319 * check_sort_toc_entries() checks the table of contents for the specified arch
1320 * which is sorted by name for more then one object defining the same symbol.
1321 * If this is the case it prints each symbol that is defined in more than one
1322 * object along with the object it is defined in. It returns TRUE if there are
1323 * no multiple definitions and FALSE otherwise.
1327 check_sort_toc_entries(
1330 enum bool library_warnings
)
1333 enum bool multiple_defs
;
1334 struct member
*member
;
1336 if(arch
->ntocs
== 0 || arch
->ntocs
== 1)
1340 * Since the symbol table is sorted by name look to any two adjcent
1341 * entries with the same name. If such entries are found print them
1342 * only once (marked by changing the sign of their member_index).
1344 multiple_defs
= FALSE
;
1345 for(i
= 0; i
< arch
->ntocs
- 1; i
++){
1346 if(strcmp(arch
->toc_entries
[i
].symbol_name
,
1347 arch
->toc_entries
[i
+1].symbol_name
) == 0){
1348 if(multiple_defs
== FALSE
){
1349 if(library_warnings
== FALSE
)
1351 fprintf(stderr
, "%s: same symbol defined in more than one "
1352 "member ", progname
);
1353 if(arch
->fat_arch
!= NULL
)
1354 fprintf(stderr
, "for architecture: %s ",
1355 arch
->fat_arch_name
);
1356 fprintf(stderr
, "in: %s (table of contents will not be "
1357 "sorted)\n", output
);
1358 multiple_defs
= TRUE
;
1360 if(arch
->toc_entries
[i
].member_index
> 0){
1361 member
= arch
->members
+
1362 arch
->toc_entries
[i
].member_index
- 1;
1363 warn_member(arch
, member
, "defines symbol: %s",
1364 arch
->toc_entries
[i
].symbol_name
);
1365 arch
->toc_entries
[i
].member_index
=
1366 -(arch
->toc_entries
[i
].member_index
);
1368 if(arch
->toc_entries
[i
+1].member_index
> 0){
1369 member
= arch
->members
+
1370 arch
->toc_entries
[i
+1].member_index
- 1;
1371 warn_member(arch
, member
, "defines symbol: %s",
1372 arch
->toc_entries
[i
+1].symbol_name
);
1373 arch
->toc_entries
[i
+1].member_index
=
1374 -(arch
->toc_entries
[i
+1].member_index
);
1379 if(multiple_defs
== FALSE
)
1382 for(i
= 0; i
< arch
->ntocs
; i
++)
1383 if(arch
->toc_entries
[i
].member_index
< 0)
1384 arch
->toc_entries
[i
].member_index
=
1385 -(arch
->toc_entries
[i
].member_index
);
1391 * warn_member() is like the error routines it prints the program name the
1392 * member name specified and message specified.
1398 struct member
*member
,
1399 const char *format
, ...)
1403 fprintf(stderr
, "%s: ", progname
);
1404 if(arch
->fat_arch
!= NULL
)
1405 fprintf(stderr
, "for architecture: %s ", arch
->fat_arch_name
);
1407 if(member
->input_ar_hdr
!= NULL
){
1408 fprintf(stderr
, "file: %s(%.*s) ", member
->input_file_name
,
1409 (int)member
->member_name_size
, member
->member_name
);
1412 fprintf(stderr
, "file: %s ", member
->input_file_name
);
1414 va_start(ap
, format
);
1415 vfprintf(stderr
, format
, ap
);
1416 fprintf(stderr
, "\n");
1419 #endif /* !defined(RLD) */