1/*
2 * Copyright (c) 1999 Apple Computer, Inc. All rights reserved.
3 *
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.
12 *
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.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
23#ifndef RLD
24#include <stdio.h>
25#include <string.h>
26#include "stuff/ofile.h"
27#include "stuff/breakout.h"
28#include "stuff/rnd.h"
29
30static void check_object(
31    struct arch *arch,
32    struct member *member,
33    struct object *object);
34
35static void symbol_string_at_end(
36    struct arch *arch,
37    struct member *member,
38    struct object *object);
39
40static void dyld_order(
41    struct arch *arch,
42    struct member *member,
43    struct object *object);
44
45static void order_error(
46    struct arch *arch,
47    struct member *member,
48    char *reason);
49
50__private_extern__
51void
52checkout(
53struct arch *archs,
54uint32_t narchs)
55{
56    uint32_t i, j;
57
58	for(i = 0; i < narchs; i++){
59	    if(archs[i].type == OFILE_ARCHIVE){
60		for(j = 0; j < archs[i].nmembers; j++){
61		    if(archs[i].members[j].type == OFILE_Mach_O){
62			check_object(archs + i, archs[i].members + j,
63					 archs[i].members[j].object);
64		    }
65		}
66	    }
67	    else if(archs[i].type == OFILE_Mach_O){
68		check_object(archs + i, NULL, archs[i].object);
69	    }
70	}
71}
72
73static
74void
75check_object(
76struct arch *arch,
77struct member *member,
78struct object *object)
79{
80    uint32_t i, ncmds, flags;
81    struct load_command *lc;
82    struct segment_command *sg;
83    struct segment_command_64 *sg64;
84    struct dylib_command *dl_id;
85
86	/*
87	 * Set up the symtab load command field and link edit segment feilds in
88	 * the object structure.
89	 */
90	object->st = NULL;
91	object->dyst = NULL;
92	object->hints_cmd = NULL;
93	object->seg_linkedit = NULL;
94	object->seg_linkedit64 = NULL;
95	object->code_sig_cmd = NULL;
96	dl_id = NULL;
97	lc = object->load_commands;
98	if(object->mh != NULL){
99	    ncmds = object->mh->ncmds;
100	    flags = object->mh->flags;
101	}
102	else{
103	    ncmds = object->mh64->ncmds;
104	    flags = object->mh64->flags;
105	}
106	for(i = 0; i < ncmds; i++){
107	    if(lc->cmd == LC_SYMTAB){
108		if(object->st != NULL)
109		    fatal_arch(arch, member, "malformed file (more than one "
110			"LC_SYMTAB load command): ");
111		object->st = (struct symtab_command *)lc;
112	    }
113	    else if(lc->cmd == LC_DYSYMTAB){
114		if(object->dyst != NULL)
115		    fatal_arch(arch, member, "malformed file (more than one "
116			"LC_DYSYMTAB load command): ");
117		object->dyst = (struct dysymtab_command *)lc;
118	    }
119	    else if(lc->cmd == LC_TWOLEVEL_HINTS){
120		if(object->hints_cmd != NULL)
121		    fatal_arch(arch, member, "malformed file (more than one "
122			"LC_TWOLEVEL_HINTS load command): ");
123		object->hints_cmd = (struct twolevel_hints_command *)lc;
124	    }
125	    else if(lc->cmd == LC_CODE_SIGNATURE){
126		if(object->code_sig_cmd != NULL)
127		    fatal_arch(arch, member, "malformed file (more than one "
128			"LC_CODE_SIGNATURE load command): ");
129		object->code_sig_cmd = (struct linkedit_data_command *)lc;
130	    }
131	    else if(lc->cmd == LC_SEGMENT_SPLIT_INFO){
132		if(object->split_info_cmd != NULL)
133		    fatal_arch(arch, member, "malformed file (more than one "
134			"LC_SEGMENT_SPLIT_INFO load command): ");
135		object->split_info_cmd = (struct linkedit_data_command *)lc;
136	    }
137	    else if(lc->cmd == LC_FUNCTION_STARTS){
138		if(object->func_starts_info_cmd != NULL)
139		    fatal_arch(arch, member, "malformed file (more than one "
140			"LC_FUNCTION_STARTS load command): ");
141		object->func_starts_info_cmd =
142			(struct linkedit_data_command *)lc;
143	    }
144	    else if(lc->cmd == LC_DATA_IN_CODE){
145		if(object->data_in_code_cmd != NULL)
146		    fatal_arch(arch, member, "malformed file (more than one "
147			"LC_DATA_IN_CODE load command): ");
148		object->data_in_code_cmd =
149			(struct linkedit_data_command *)lc;
150	    }
151	    else if(lc->cmd == LC_DYLIB_CODE_SIGN_DRS){
152		if(object->code_sign_drs_cmd != NULL)
153		    fatal_arch(arch, member, "malformed file (more than one "
154			"LC_DYLIB_CODE_SIGN_DRS load command): ");
155		object->code_sign_drs_cmd =
156			(struct linkedit_data_command *)lc;
157	    }
158	    else if((lc->cmd == LC_DYLD_INFO) ||(lc->cmd == LC_DYLD_INFO_ONLY)){
159		if(object->dyld_info != NULL)
160		    fatal_arch(arch, member, "malformed file (more than one "
161			"LC_DYLD_INFO load command): ");
162		object->dyld_info = (struct dyld_info_command *)lc;
163	    }
164	    else if(lc->cmd == LC_SEGMENT){
165		sg = (struct segment_command *)lc;
166		if(strcmp(sg->segname, SEG_LINKEDIT) == 0){
167		    if(object->seg_linkedit != NULL)
168			fatal_arch(arch, member, "malformed file (more than "
169			    "one " SEG_LINKEDIT "segment): ");
170		    object->seg_linkedit = sg;
171		}
172	    }
173	    else if(lc->cmd == LC_SEGMENT_64){
174		sg64 = (struct segment_command_64 *)lc;
175		if(strcmp(sg64->segname, SEG_LINKEDIT) == 0){
176		    if(object->seg_linkedit64 != NULL)
177			fatal_arch(arch, member, "malformed file (more than "
178			    "one " SEG_LINKEDIT "segment): ");
179		    object->seg_linkedit64 = sg64;
180		}
181	    }
182	    else if(lc->cmd == LC_ID_DYLIB){
183		if(dl_id != NULL)
184		    fatal_arch(arch, member, "malformed file (more than one "
185			"LC_ID_DYLIB load command): ");
186		dl_id = (struct dylib_command *)lc;
187		if(dl_id->dylib.name.offset >= dl_id->cmdsize)
188		    fatal_arch(arch, member, "malformed file (name.offset of "
189			"load command %u extends past the end of the load "
190			"command): ", i);
191	    }
192	    lc = (struct load_command *)((char *)lc + lc->cmdsize);
193	}
194	if((object->mh_filetype == MH_DYLIB ||
195 	    (object->mh_filetype == MH_DYLIB_STUB && ncmds > 0)) &&
196		dl_id == NULL)
197	    fatal_arch(arch, member, "malformed file (no LC_ID_DYLIB load "
198		"command in %s file): ", object->mh_filetype == MH_DYLIB ?
199		"MH_DYLIB" : "MH_DYLIB_STUB");
200	if(object->hints_cmd != NULL){
201	    if(object->dyst == NULL && object->hints_cmd->nhints != 0)
202		fatal_arch(arch, member, "malformed file (LC_TWOLEVEL_HINTS "
203		"load command present without an LC_DYSYMTAB load command):");
204	    if(object->hints_cmd->nhints != 0 &&
205	       object->hints_cmd->nhints != object->dyst->nundefsym)
206		fatal_arch(arch, member, "malformed file (LC_TWOLEVEL_HINTS "
207		"load command's nhints does not match LC_DYSYMTAB load "
208		"command's nundefsym):");
209	}
210
211	/*
212	 * For objects without a dynamic symbol table check to see that the
213	 * string table is at the end of the file and that the symbol table is
214	 * just before it.
215	 */
216	if(object->dyst == NULL){
217	    symbol_string_at_end(arch, member, object);
218	}
219	else{
220	    /*
221	     * This file has a dynamic symbol table command.  We handle three
222	     * cases, a dynamic shared library, a file for the dynamic linker,
223	     * and a relocatable object file.  Since it has a dynamic symbol
224	     * table command it could have an indirect symbol table.
225	     */
226	    if(object->mh_filetype == MH_DYLIB /* ||
227	       object->mh_filetype == MH_DYLIB_STUB */ ){
228		/*
229		 * This is a dynamic shared library.
230		 * The order of the symbolic info is:
231		 * 	local relocation entries
232		 *	symbol table
233		 *		local symbols
234		 *		defined external symbols
235		 *		undefined symbols
236		 *	two-level namespace hints
237		 * 	external relocation entries
238		 *	indirect symbol table
239		 *	table of contents
240		 * 	module table
241		 *	reference table
242		 *	string table
243		 *		strings for external symbols
244		 *		strings for local symbols
245		 *	code signature data (16 byte aligned)
246		 */
247		dyld_order(arch, member, object);
248	    }
249	    else if(flags & MH_DYLDLINK){
250		/*
251		 * This is a file for the dynamic linker (output of ld(1) with
252		 * -output_for_dyld .  That is the relocation entries are split
253		 * into local and external and hanging off the dysymtab not off
254		 * the sections.
255		 * The order of the symbolic info is:
256		 * 	local relocation entries
257		 *	symbol table
258		 *		local symbols (in order as appeared in stabs)
259		 *		defined external symbols (sorted by name)
260		 *		undefined symbols (sorted by name)
261		 * 	external relocation entries
262		 *	indirect symbol table
263		 *	string table
264		 *		strings for external symbols
265		 *		strings for local symbols
266		 *	code signature data (16 byte aligned)
267		 */
268		dyld_order(arch, member, object);
269	    }
270	    else{
271		/*
272		 * This is a relocatable object file either the output of the
273		 * assembler or output of ld(1) with -r.  For the output of
274		 * the assembler:
275		 * The order of the symbolic info is:
276		 * 	relocation entries (by section)
277		 *	indirect symbol table
278		 *	symbol table
279		 *		local symbols (in order as appeared in stabs)
280		 *		defined external symbols (sorted by name)
281		 *		undefined symbols (sorted by name)
282		 *	string table
283		 *		strings for external symbols
284		 *		strings for local symbols
285		 * With this order the symbol table can be replaced and the
286		 * relocation entries and the indirect symbol table entries
287		 * can be updated in the file and not moved.
288		 * For the output of ld -r:
289		 * The order of the symbolic info is:
290		 * 	relocation entries (by section)
291		 *	symbol table
292		 *		local symbols (in order as appeared in stabs)
293		 *		defined external symbols (sorted by name)
294		 *		undefined symbols (sorted by name)
295		 *	indirect symbol table
296		 *	string table
297		 *		strings for external symbols
298		 *		strings for local symbols
299		 *		code signature
300		 */
301		symbol_string_at_end(arch, member, object);
302	    }
303	}
304}
305
306static
307void
308dyld_order(
309struct arch *arch,
310struct member *member,
311struct object *object)
312{
313    uint32_t offset, rounded_offset, isym;
314
315	if(object->mh != NULL){
316	    if(object->seg_linkedit == NULL)
317		fatal_arch(arch, member, "malformed file (no " SEG_LINKEDIT
318		    " segment): ");
319	    if(object->seg_linkedit->filesize != 0 &&
320	       object->seg_linkedit->fileoff +
321	       object->seg_linkedit->filesize != object->object_size)
322		fatal_arch(arch, member, "the " SEG_LINKEDIT " segment "
323		    "does not cover the end of the file (can't "
324		    "be processed) in: ");
325
326	    offset = object->seg_linkedit->fileoff;
327	}
328	else{
329	    if(object->seg_linkedit64 == NULL)
330		fatal_arch(arch, member, "malformed file (no " SEG_LINKEDIT
331		    " segment): ");
332	    if(object->seg_linkedit64->filesize != 0 &&
333	       object->seg_linkedit64->fileoff +
334	       object->seg_linkedit64->filesize != object->object_size)
335		fatal_arch(arch, member, "the " SEG_LINKEDIT " segment "
336		    "does not cover the end of the file (can't "
337		    "be processed) in: ");
338
339	    offset = object->seg_linkedit64->fileoff;
340	}
341	if(object->dyld_info != NULL){
342	    /* dyld_info starts at beginning of __LINKEDIT */
343	    if (object->dyld_info->rebase_off != 0){
344		if (object->dyld_info->rebase_off != offset)
345		    order_error(arch, member, "dyld_info "
346			"out of place");
347	    }
348	    else if (object->dyld_info->bind_off != 0){
349		if (object->dyld_info->bind_off != offset)
350		    order_error(arch, member, "dyld_info "
351			"out of place");
352	    }
353	    /* update offset to end of dyld_info contents */
354	    if (object->dyld_info->export_size != 0)
355		offset = object->dyld_info->export_off +
356			    object->dyld_info->export_size;
357	    else if (object->dyld_info->lazy_bind_size != 0)
358		offset = object->dyld_info->lazy_bind_off +
359			    object->dyld_info->lazy_bind_size;
360	    else if (object->dyld_info->weak_bind_size != 0)
361		offset = object->dyld_info->weak_bind_off +
362			    object->dyld_info->weak_bind_size;
363	    else if (object->dyld_info->bind_size != 0)
364		offset = object->dyld_info->bind_off +
365			    object->dyld_info->bind_size;
366	    else if (object->dyld_info->rebase_size != 0)
367		offset = object->dyld_info->rebase_off +
368			    object->dyld_info->rebase_size;
369	}
370	if(object->dyst->nlocrel != 0){
371	    if(object->dyst->locreloff != offset)
372		order_error(arch, member, "local relocation entries "
373		    "out of place");
374	    offset += object->dyst->nlocrel *
375		      sizeof(struct relocation_info);
376	}
377	if(object->split_info_cmd != NULL){
378	    if(object->split_info_cmd->dataoff != offset)
379		order_error(arch, member, "split info data out of place");
380	    offset += object->split_info_cmd->datasize;
381	}
382	if(object->func_starts_info_cmd != NULL){
383	    if(object->func_starts_info_cmd->dataoff != offset)
384		order_error(arch, member, "function starts data out of place");
385	    offset += object->func_starts_info_cmd->datasize;
386	}
387	if(object->data_in_code_cmd != NULL){
388	    if(object->data_in_code_cmd->dataoff != offset)
389		order_error(arch, member, "data in code info out of place");
390	    offset += object->data_in_code_cmd->datasize;
391	}
392	if(object->code_sign_drs_cmd != NULL){
393	    if(object->code_sign_drs_cmd->dataoff != offset)
394		order_error(arch, member, "code signing DRs info out of place");
395	    offset += object->code_sign_drs_cmd->datasize;
396	}
397	if(object->st->nsyms != 0){
398	    if(object->st->symoff != offset)
399		order_error(arch, member, "symbol table out of place");
400	    if(object->mh != NULL)
401		offset += object->st->nsyms * sizeof(struct nlist);
402	    else
403		offset += object->st->nsyms * sizeof(struct nlist_64);
404	}
405	isym = 0;
406	if(object->dyst->nlocalsym != 0){
407	    if(object->dyst->ilocalsym != isym)
408		order_error(arch, member, "local symbols out of place");
409	    isym += object->dyst->nlocalsym;
410	}
411	if(object->dyst->nextdefsym != 0){
412	    if(object->dyst->iextdefsym != isym)
413		order_error(arch, member, "externally defined symbols out of "
414			    "place");
415	    isym += object->dyst->nextdefsym;
416	}
417	if(object->dyst->nundefsym != 0){
418	    if(object->dyst->iundefsym != isym)
419		order_error(arch, member, "undefined symbols out of place");
420	    isym += object->dyst->nundefsym;
421	}
422	if(object->hints_cmd != NULL && object->hints_cmd->nhints != 0){
423	    if(object->hints_cmd->offset != offset)
424		order_error(arch, member, "hints table out of place");
425	    offset += object->hints_cmd->nhints * sizeof(struct twolevel_hint);
426	}
427	if(object->dyst->nextrel != 0){
428	    if(object->dyst->extreloff != offset)
429		order_error(arch, member, "external relocation entries"
430		    " out of place");
431	    offset += object->dyst->nextrel *
432		      sizeof(struct relocation_info);
433	}
434	if(object->dyst->nindirectsyms != 0){
435	    if(object->dyst->indirectsymoff != offset)
436		order_error(arch, member, "indirect symbol table "
437		    "out of place");
438	    offset += object->dyst->nindirectsyms *
439		      sizeof(uint32_t);
440	}
441
442	/*
443	 * If this is a 64-bit Mach-O file and has an odd number of indirect
444	 * symbol table entries the next offset MAYBE rounded to a multiple of
445	 * 8 or MAY NOT BE. This should done to keep all the tables aligned but
446	 * was not done for 64-bit Mach-O in Mac OS X 10.4.
447	 */
448 	object->input_indirectsym_pad = 0;
449	if(object->mh64 != NULL &&
450	   (object->dyst->nindirectsyms % 2) != 0){
451	    rounded_offset = rnd(offset, 8);
452	}
453	else{
454	    rounded_offset = offset;
455	}
456
457	if(object->dyst->ntoc != 0){
458	    if(object->dyst->tocoff != offset &&
459	       object->dyst->tocoff != rounded_offset)
460		order_error(arch, member, "table of contents out of place");
461	    if(object->dyst->tocoff == offset){
462		offset += object->dyst->ntoc *
463			  sizeof(struct dylib_table_of_contents);
464		rounded_offset = offset;
465	    }
466	    else if(object->dyst->tocoff == rounded_offset){
467		object->input_indirectsym_pad = rounded_offset - offset;
468		rounded_offset += object->dyst->ntoc *
469			          sizeof(struct dylib_table_of_contents);
470		offset = rounded_offset;
471	    }
472	}
473	if(object->dyst->nmodtab != 0){
474	    if(object->dyst->modtaboff != offset &&
475	       object->dyst->modtaboff != rounded_offset)
476		order_error(arch, member, "module table out of place");
477	    if(object->mh != NULL){
478		offset += object->dyst->nmodtab *
479			  sizeof(struct dylib_module);
480		rounded_offset = offset;
481	    }
482	    else{
483		if(object->dyst->modtaboff == offset){
484		    offset += object->dyst->nmodtab *
485			      sizeof(struct dylib_module_64);
486		    rounded_offset = offset;
487		}
488		else if(object->dyst->modtaboff == rounded_offset){
489		    object->input_indirectsym_pad = rounded_offset - offset;
490		    rounded_offset += object->dyst->nmodtab *
491				      sizeof(struct dylib_module_64);
492		    offset = rounded_offset;
493		}
494	    }
495	}
496	if(object->dyst->nextrefsyms != 0){
497	    if(object->dyst->extrefsymoff != offset &&
498	       object->dyst->extrefsymoff != rounded_offset)
499		order_error(arch, member, "reference table out of place");
500	    if(object->dyst->extrefsymoff == offset){
501		offset += object->dyst->nextrefsyms *
502			  sizeof(struct dylib_reference);
503		rounded_offset = offset;
504	    }
505	    else if(object->dyst->extrefsymoff == rounded_offset){
506		object->input_indirectsym_pad = rounded_offset - offset;
507		rounded_offset += object->dyst->nextrefsyms *
508			          sizeof(struct dylib_reference);
509		offset = rounded_offset;
510	    }
511	}
512	if(object->st->strsize != 0){
513	    if(object->st->stroff != offset &&
514	       object->st->stroff != rounded_offset)
515		order_error(arch, member, "string table out of place");
516	    if(object->st->stroff == offset){
517		offset += object->st->strsize;
518		rounded_offset = offset;
519	    }
520	    else if(object->st->stroff == rounded_offset){
521		object->input_indirectsym_pad = rounded_offset - offset;
522		rounded_offset += object->st->strsize;
523		offset = rounded_offset;
524	    }
525	}
526	if(object->code_sig_cmd != NULL){
527	    rounded_offset = rnd(rounded_offset, 16);
528	    if(object->code_sig_cmd->dataoff != rounded_offset)
529		order_error(arch, member, "code signature data out of place");
530	    rounded_offset += object->code_sig_cmd->datasize;
531	    offset = rounded_offset;
532	}
533	if(offset != object->object_size &&
534	   rounded_offset != object->object_size)
535	    order_error(arch, member, "link edit information does not fill the "
536			SEG_LINKEDIT " segment");
537}
538
539static
540void
541order_error(
542struct arch *arch,
543struct member *member,
544char *reason)
545{
546	fatal_arch(arch, member, "file not in an order that can be processed "
547		   "(%s): ", reason);
548}
549
550static
551void
552symbol_string_at_end(
553struct arch *arch,
554struct member *member,
555struct object *object)
556{
557    uint32_t end, sigend, strend, rounded_strend;
558    uint32_t indirectend, rounded_indirectend;
559
560	if(object->st != NULL && object->st->nsyms != 0){
561	    end = object->object_size;
562	    if(object->code_sig_cmd != NULL){
563		sigend = object->code_sig_cmd->dataoff +
564			 object->code_sig_cmd->datasize;
565		if(sigend != end)
566		    fatal_arch(arch, member, "code signature not at the end "
567			"of the file (can't be processed) in file: ");
568		/*
569		 * The code signature starts at a 16 byte offset.  So if the
570		 * string table end rouned to 16 bytes is the offset where the
571		 * code signature starts then just back up the current "end" to
572		 * the end of the string table.
573		 */
574		end = object->code_sig_cmd->dataoff;
575		if(object->st->strsize != 0){
576		    strend = object->st->stroff + object->st->strsize;
577		    rounded_strend = rnd(strend, 16);
578		    if(object->code_sig_cmd->dataoff == rounded_strend)
579		       end = strend;
580		}
581	    }
582	    if(object->st->strsize != 0){
583		strend = object->st->stroff + object->st->strsize;
584		/*
585		 * Since archive member sizes are now rounded to 8 bytes the
586		 * string table may not be exactly at the end of the
587		 * object_size due to rounding.
588		 */
589		rounded_strend = rnd(strend, 8);
590		if(strend != end && rounded_strend != end)
591		    fatal_arch(arch, member, "string table not at the end "
592			"of the file (can't be processed) in file: ");
593		/*
594		 * To make the code work that assumes the end of string table is
595		 * at the end of the object file change the object_size to be
596		 * the end of the string table here.  This could be done at the
597		 * end of this routine but since all the later checks are fatal
598		 * we'll just do this here.
599		 */
600		if(rounded_strend != strend)
601		    object->object_size = strend;
602		end = object->st->stroff;
603	    }
604	    if(object->dyst != NULL &&
605	       object->dyst->nindirectsyms != 0 &&
606	       object->st->nsyms != 0 &&
607	       object->dyst->indirectsymoff > object->st->symoff){
608
609		indirectend = object->dyst->indirectsymoff +
610		    object->dyst->nindirectsyms * sizeof(uint32_t);
611
612		/*
613		 * If this is a 64-bit Mach-O file and has an odd number of
614		 * indirect symbol table entries the next offset MAYBE rounded
615		 * to a multiple of 8 or MAY NOT BE. This should done to keep
616		 * all the tables aligned but was not done for 64-bit Mach-O in
617		 * Mac OS X 10.4.
618		 */
619		if(object->mh64 != NULL &&
620		   (object->dyst->nindirectsyms % 2) != 0){
621		    rounded_indirectend = rnd(indirectend, 8);
622		}
623		else{
624		    rounded_indirectend = indirectend;
625		}
626
627		if(indirectend != end && rounded_indirectend != end){
628		    fatal_arch(arch, member, "indirect symbol table does not "
629			"directly preceed the string table (can't be "
630			"processed) in file: ");
631		}
632		object->input_indirectsym_pad = end - indirectend;
633		end = object->dyst->indirectsymoff;
634		if(object->mh != NULL){
635		    if(object->st->symoff +
636		       object->st->nsyms * sizeof(struct nlist) != end)
637			fatal_arch(arch, member, "symbol table does not "
638			    "directly preceed the indirect symbol table (can't "
639			    "be processed) in file: ");
640		}
641		else{
642		    if(object->st->symoff +
643		       object->st->nsyms * sizeof(struct nlist_64) != end)
644			fatal_arch(arch, member, "symbol table does not "
645			    "directly preceed the indirect symbol table (can't "
646			    "be processed) in file: ");
647		}
648	    }
649	    else{
650		if(object->mh != NULL){
651		    if(object->st->symoff +
652		       object->st->nsyms * sizeof(struct nlist) != end)
653			fatal_arch(arch, member, "symbol table and string "
654			    "table not at the end of the file (can't be "
655			    "processed) in file: ");
656		}
657		else{
658		    if(object->st->symoff +
659		       object->st->nsyms * sizeof(struct nlist_64) != end)
660			fatal_arch(arch, member, "symbol table and string "
661			    "table not at the end of the file (can't be "
662			    "processed) in file: ");
663		}
664	    }
665	    if(object->seg_linkedit != NULL &&
666	       (object->seg_linkedit->flags & SG_FVMLIB) != SG_FVMLIB &&
667	       object->seg_linkedit->filesize != 0){
668		if(object->seg_linkedit->fileoff +
669		   object->seg_linkedit->filesize != object->object_size)
670		    fatal_arch(arch, member, "the " SEG_LINKEDIT " segment "
671			"does not cover the symbol and string table (can't "
672			"be processed) in file: ");
673	    }
674	}
675}
676#endif /* !defined(RLD) */
677