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@
27 #include "stuff/ofile.h"
28 #include "stuff/breakout.h"
29 #include "stuff/allocate.h"
30 #include "stuff/errors.h"
31 #include "stuff/rnd.h"
32 #include "stuff/crc32.h"
34 static void breakout_internal(
38 enum bool calculate_input_prebind_cksum
,
40 static void breakout_loop_through_archive(
44 static void cksum_object(
46 enum bool calculate_input_prebind_cksum
);
47 static struct arch
*new_arch(
50 static struct member
*new_member(
61 enum bool calculate_input_prebind_cksum
)
64 uint32_t previous_errors
;
68 ofile
= allocate(sizeof(struct ofile
));
71 * If the file_name is NULL, we will use a dummy file name so
72 * that error reporting, etc. works.
75 filename
= "(broken out from memory)";
78 * Rely on the ofile_*() routines to do all the checking and only
79 * return valid ofiles files broken out.
81 if(ofile_map_from_memory((char *)membuf
, length
, filename
, 0,NULL
, NULL
,
82 ofile
, FALSE
) == FALSE
){
87 previous_errors
= errors
;
88 breakout_internal(filename
, archs
, narchs
,
89 calculate_input_prebind_cksum
, ofile
);
90 errors
+= previous_errors
;
104 enum bool calculate_input_prebind_cksum
)
107 uint32_t previous_errors
;
111 ofile
= allocate(sizeof(struct ofile
));
113 * Rely on the ofile_*() routines to do all the checking and only
114 * return valid ofiles files broken out.
116 if(ofile_map(filename
, NULL
, NULL
, ofile
, FALSE
) == FALSE
){
121 previous_errors
= errors
;
122 breakout_internal(filename
, archs
, narchs
,
123 calculate_input_prebind_cksum
, ofile
);
124 errors
+= previous_errors
;
138 enum bool calculate_input_prebind_cksum
,
144 if(ofile
->file_type
== OFILE_FAT
&& errors
== 0){
145 /* loop through the fat architectures (can't have zero archs) */
146 (void)ofile_first_arch(ofile
);
150 arch
= new_arch(archs
, narchs
);
151 arch
->file_name
= savestr(filename
);
152 arch
->type
= ofile
->arch_type
;
153 arch
->fat_arch
= ofile
->fat_archs
+ ofile
->narch
;
154 arch
->fat_arch_name
= savestr(ofile
->arch_flag
.name
);
156 if(ofile
->arch_type
== OFILE_ARCHIVE
){
157 breakout_loop_through_archive(filename
, arch
, ofile
);
159 else if(ofile
->arch_type
== OFILE_Mach_O
){
160 arch
->object
= allocate(sizeof(struct object
));
161 memset(arch
->object
, '\0', sizeof(struct object
));
162 arch
->object
->object_addr
= ofile
->object_addr
;
163 arch
->object
->object_size
= ofile
->object_size
;
164 arch
->object
->object_byte_sex
= ofile
->object_byte_sex
;
165 arch
->object
->mh64
= ofile
->mh64
;
166 arch
->object
->mh
= ofile
->mh
;
167 arch
->object
->mh_filetype
= ofile
->mh_filetype
;
168 arch
->object
->mh_cputype
= ofile
->mh_cputype
;
169 arch
->object
->mh_cpusubtype
= ofile
->mh_cpusubtype
;
170 arch
->object
->load_commands
= ofile
->load_commands
;
171 cksum_object(arch
, calculate_input_prebind_cksum
);
173 else{ /* ofile->arch_type == OFILE_UNKNOWN */
174 arch
->unknown_addr
= ofile
->file_addr
+
175 arch
->fat_arch
->offset
;
176 arch
->unknown_size
= arch
->fat_arch
->size
;
178 }while(ofile_next_arch(ofile
) == TRUE
);
180 else if(ofile
->file_type
== OFILE_ARCHIVE
&& errors
== 0){
181 arch
= new_arch(archs
, narchs
);
182 arch
->file_name
= savestr(filename
);
183 arch
->type
= ofile
->file_type
;
185 breakout_loop_through_archive(filename
, arch
, ofile
);
187 else if(ofile
->file_type
== OFILE_Mach_O
&& errors
== 0){
188 arch
= new_arch(archs
, narchs
);
189 arch
->file_name
= savestr(filename
);
190 arch
->type
= ofile
->file_type
;
191 arch
->object
= allocate(sizeof(struct object
));
192 memset(arch
->object
, '\0', sizeof(struct object
));
193 arch
->object
->object_addr
= ofile
->object_addr
;
194 arch
->object
->object_size
= ofile
->object_size
;
195 arch
->object
->object_byte_sex
= ofile
->object_byte_sex
;
196 arch
->object
->mh64
= ofile
->mh64
;
197 arch
->object
->mh
= ofile
->mh
;
198 arch
->object
->mh_filetype
= ofile
->mh_filetype
;
199 arch
->object
->mh_cputype
= ofile
->mh_cputype
;
200 arch
->object
->mh_cpusubtype
= ofile
->mh_cpusubtype
;
201 arch
->object
->load_commands
= ofile
->load_commands
;
202 cksum_object(arch
, calculate_input_prebind_cksum
);
204 else if(errors
== 0){ /* ofile->file_type == OFILE_UNKNOWN */
205 arch
= new_arch(archs
, narchs
);
206 arch
->file_name
= savestr(filename
);
207 arch
->type
= ofile
->file_type
;
208 arch
->unknown_addr
= ofile
->file_addr
;
209 arch
->unknown_size
= ofile
->file_size
;
212 free_archs(*archs
, *narchs
);
220 breakout_loop_through_archive(
225 struct member
*member
;
227 struct ar_hdr
*ar_hdr
;
228 uint32_t size
, ar_name_size
;
229 char ar_name_buf
[sizeof(ofile
->member_ar_hdr
->ar_name
) + 1];
230 char ar_size_buf
[sizeof(ofile
->member_ar_hdr
->ar_size
) + 1];
232 /* loop through archive (can be empty) */
233 if((flag
= ofile_first_member(ofile
)) == TRUE
&& errors
== 0){
235 * If the first member is a table of contents then skip
236 * it as it is always rebuilt (so to get the time to
237 * match the modtime so it won't appear out of date).
238 * Also force it to be a long name so members can be 8 byte
241 if(ofile
->member_ar_hdr
!= NULL
&&
242 strncmp(ofile
->member_name
, SYMDEF
,
243 sizeof(SYMDEF
) - 1) == 0){
244 arch
->toc_long_name
= TRUE
;
245 flag
= ofile_next_member(ofile
);
247 while(flag
== TRUE
&& errors
== 0){
248 member
= new_member(arch
);
249 member
->type
= ofile
->member_type
;
250 member
->member_name
= ofile
->member_name
;
252 * Determine the size this member will have in the library which
253 * includes the padding as a result of rounding the size of the
254 * member. To get all members on an 8 byte boundary (so that
255 * mapping in object files can be used directly) the size of the
256 * member is CHANGED to reflect this padding. In the UNIX
257 * definition of archives the size of the member is never
258 * changed but the offset to the next member is defined to be
259 * the offset of the previous member plus the size of the
260 * previous member rounded to 2. So to get 8 byte boundaries
261 * without breaking the UNIX definition of archives the size is
262 * changed here. As with the UNIX ar(1) program the padded
263 * bytes will be set to the character '\n'.
265 if(ofile
->mh
!= NULL
|| ofile
->mh64
!= NULL
)
266 size
= rnd(ofile
->object_size
, 8);
268 size
= rnd(ofile
->member_size
, 8);
270 * We will force the use of long names so we can make sure the
271 * size of the name and the size of struct ar_hdr are rounded to
272 * 8 bytes. And that rounded size is what will be in the
273 * ar_name with the AR_EFMT1 string. To avoid growing the size
274 * of names first trim the name size before rounding up.
276 member
->member_long_name
= TRUE
;
277 for(ar_name_size
= ofile
->member_name_size
;
280 if(ofile
->member_name
[ar_name_size
- 1] != '\0')
283 member
->member_name_size
= ar_name_size
;
284 ar_name_size
= rnd(ar_name_size
, 8) +
285 (rnd(sizeof(struct ar_hdr
), 8) -
286 sizeof(struct ar_hdr
));
287 size
+= ar_name_size
;
289 * Now with the output sizes of the long member name and rounded
290 * size of the member the offset to this member can be set and
291 * then left incremented for the next member's offset.
293 member
->offset
= arch
->library_size
;
294 arch
->library_size
+= sizeof(struct ar_hdr
) + size
;
296 * Since we are rounding the member size and forcing a the use
297 * of a long name make a new ar_hdr with this information.
298 * Note the code in writeout() will do the padding with '\n'
299 * characters as needed.
301 ar_hdr
= allocate(sizeof(struct ar_hdr
));
302 *ar_hdr
= *(ofile
->member_ar_hdr
);
303 sprintf(ar_name_buf
, "%s%-*lu", AR_EFMT1
,
304 (int)(sizeof(ar_hdr
->ar_name
) - (sizeof(AR_EFMT1
) - 1)),
305 (long unsigned int)ar_name_size
);
306 memcpy(ar_hdr
->ar_name
, ar_name_buf
,
307 sizeof(ar_hdr
->ar_name
));
308 sprintf(ar_size_buf
, "%-*ld",
309 (int)sizeof(ar_hdr
->ar_size
), (long unsigned int)size
);
310 memcpy(ar_hdr
->ar_size
, ar_size_buf
,
311 sizeof(ar_hdr
->ar_size
));
313 member
->ar_hdr
= ar_hdr
;
314 member
->input_ar_hdr
= ofile
->member_ar_hdr
;
315 member
->input_file_name
= filename
;
317 if(ofile
->member_type
== OFILE_Mach_O
){
318 member
->object
= allocate(sizeof(struct object
));
319 memset(member
->object
, '\0', sizeof(struct object
));
320 member
->object
->object_addr
= ofile
->object_addr
;
321 member
->object
->object_size
= ofile
->object_size
;
322 member
->object
->object_byte_sex
= ofile
->object_byte_sex
;
323 member
->object
->mh64
= ofile
->mh64
;
324 member
->object
->mh
= ofile
->mh
;
325 member
->object
->mh_filetype
= ofile
->mh_filetype
;
326 member
->object
->mh_cputype
= ofile
->mh_cputype
;
327 member
->object
->mh_cpusubtype
= ofile
->mh_cpusubtype
;
328 member
->object
->load_commands
= ofile
->load_commands
;
330 else{ /* ofile->member_type == OFILE_UNKNOWN */
331 member
->unknown_addr
= ofile
->member_addr
;
332 member
->unknown_size
= ofile
->member_size
;
334 flag
= ofile_next_member(ofile
);
340 * cksum_object() is called to set the pointer to the LC_PREBIND_CKSUM load
341 * command in the object struct for the specified arch. If the parameter
342 * calculate_input_prebind_cksum is TRUE then calculate the value
343 * of the check sum for the input object if needed, set that into the
344 * the calculated_input_prebind_cksum field of the object struct for the
345 * specified arch. This is needed for prebound files where the original
346 * checksum (or zero) is recorded in the LC_PREBIND_CKSUM load command.
347 * Only redo_prebinding operations sets the value of the cksum field to
348 * non-zero and only if previously zero. All other operations will set this
349 * field to zero indicating a new original prebound file.
355 enum bool calculate_input_prebind_cksum
)
357 uint32_t i
, buf_size
, ncmds
;
358 struct load_command
*lc
;
359 enum byte_sex host_byte_sex
;
362 arch
->object
->cs
= NULL
;
363 lc
= arch
->object
->load_commands
;
364 if(arch
->object
->mh
!= NULL
)
365 ncmds
= arch
->object
->mh
->ncmds
;
367 ncmds
= arch
->object
->mh64
->ncmds
;
369 i
< ncmds
&& arch
->object
->cs
== NULL
;
371 if(lc
->cmd
== LC_PREBIND_CKSUM
)
372 arch
->object
->cs
= (struct prebind_cksum_command
*)lc
;
373 lc
= (struct load_command
*)((char *)lc
+ lc
->cmdsize
);
377 * If we don't want to calculate the input check sum, or there is no
378 * LC_PREBIND_CKSUM load command or there is one and the check sum is
379 * not zero then return.
381 if(calculate_input_prebind_cksum
== FALSE
||
382 arch
->object
->cs
== NULL
||
383 arch
->object
->cs
->cksum
!= 0)
387 host_byte_sex
= get_host_byte_sex();
390 if(arch
->object
->object_byte_sex
!= host_byte_sex
){
391 if(arch
->object
->mh
!= NULL
){
392 buf_size
= sizeof(struct mach_header
) +
393 arch
->object
->mh
->sizeofcmds
;
394 buf
= allocate(buf_size
);
395 memcpy(buf
, arch
->object
->mh
, buf_size
);
396 if(swap_object_headers(arch
->object
->mh
,
397 arch
->object
->load_commands
) == FALSE
)
401 buf_size
= sizeof(struct mach_header_64
) +
402 arch
->object
->mh64
->sizeofcmds
;
403 buf
= allocate(buf_size
);
404 memcpy(buf
, arch
->object
->mh64
, buf_size
);
405 if(swap_object_headers(arch
->object
->mh64
,
406 arch
->object
->load_commands
) == FALSE
)
411 arch
->object
->calculated_input_prebind_cksum
=
412 crc32(arch
->object
->object_addr
, arch
->object
->object_size
);
414 if(arch
->object
->object_byte_sex
!= host_byte_sex
){
415 if(arch
->object
->mh
!= NULL
)
416 memcpy(arch
->object
->mh
, buf
, buf_size
);
418 memcpy(arch
->object
->mh64
, buf
, buf_size
);
431 for(i
= 0; i
< narchs
; i
++){
432 if(archs
[i
].type
== OFILE_ARCHIVE
){
433 for(j
= 0; j
< archs
[i
].nmembers
; j
++){
434 if(archs
[i
].members
[j
].type
== OFILE_Mach_O
){
435 if(archs
[i
].members
[j
].object
->ld_r_ofile
!= NULL
)
436 ofile_unmap(archs
[i
].members
[j
].object
->ld_r_ofile
);
437 free(archs
[i
].members
[j
].object
);
440 if(archs
[i
].nmembers
> 0 && archs
[i
].members
!= NULL
)
441 free(archs
[i
].members
);
443 else if(archs
[i
].type
== OFILE_Mach_O
){
444 if(archs
[i
].object
->ld_r_ofile
!= NULL
)
445 ofile_unmap(archs
[i
].object
->ld_r_ofile
);
446 free(archs
[i
].object
);
449 if(narchs
> 0 && archs
!= NULL
)
461 *archs
= reallocate(*archs
, (*narchs
+ 1) * sizeof(struct arch
));
462 arch
= *archs
+ *narchs
;
463 *narchs
= *narchs
+ 1;
464 memset(arch
, '\0', sizeof(struct arch
));
473 struct member
*member
;
475 arch
->members
= reallocate(arch
->members
,
476 (arch
->nmembers
+ 1) * sizeof(struct member
));
477 member
= arch
->members
+ arch
->nmembers
;
479 memset(member
, '\0', sizeof(struct member
));
482 #endif /* !defined(RLD) */