xref: /illumos-gate/usr/src/cmd/sgs/mcs/common/file.c (revision 24da5b34f49324ed742a340010ed5bd3d4e06625)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 
22 /*
23  *	Copyright (c) 1988 AT&T
24  *	  All Rights Reserved
25  *
26  * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
27  * Use is subject to license terms.
28  */
29 #pragma ident	"%Z%%M%	%I%	%E% SMI"
30 
31 #include <errno.h>
32 #include "mcs.h"
33 #include "extern.h"
34 #include "gelf.h"
35 
36 static int Sect_exists = 0;
37 static int notesegndx = -1;
38 static int notesctndx = -1;
39 static Seg_Table *b_e_seg_table;
40 
41 static section_info_table *sec_table;
42 static int64_t *off_table;	/* array maintains section's offset; */
43 				/* set to retain old offset, else 0 */
44 static int64_t *nobits_table;  	/* array maintains NOBITS sections */
45 
46 static char *new_sec_string = NULL;
47 
48 #define	MMAP_USED	1
49 #define	MMAP_UNUSED	2
50 
51 /*
52  * Function prototypes.
53  */
54 static void copy_file(int, char *, char *);
55 static void
56 copy_non_elf_to_temp_ar(int, Elf *, int, Elf_Arhdr *, char *, Cmd_Info *);
57 static void copy_elf_file_to_temp_ar_file(int, Elf_Arhdr *, char *);
58 static int process_file(Elf *, char *, Cmd_Info *);
59 static void initialize(int shnum, Cmd_Info *);
60 static int build_segment_table(Elf*, GElf_Ehdr *);
61 static int traverse_file(Elf *, GElf_Ehdr *, char *, Cmd_Info *);
62 static uint64_t location(int64_t, int, Elf *);
63 static uint64_t scn_location(Elf_Scn *, Elf *);
64 static int build_file(Elf *, GElf_Ehdr *, Cmd_Info *);
65 static void post_process(Cmd_Info *);
66 
67 int
68 each_file(char *cur_file, Cmd_Info *cmd_info)
69 {
70 	Elf *elf = 0;
71 	Elf_Cmd cmd;
72 	Elf *arf = 0;
73 	Elf_Arhdr *mem_header;
74 	char *cur_filenm = NULL;
75 	int code = 0;
76 	int error = 0, err = 0;
77 	int ar_file = 0;
78 	int fdartmp;
79 	int fd;
80 	int oflag;
81 
82 	if (cmd_info->flags & MIGHT_CHG)
83 		oflag = O_RDWR;
84 	else
85 		oflag = O_RDONLY;
86 
87 	if ((fd = open(cur_file, oflag)) == -1) {
88 		error_message(OPEN_ERROR,
89 		SYSTEM_ERROR, strerror(errno), prog, cur_file);
90 		return (FAILURE);
91 	}
92 
93 	/*
94 	 * Note, elf_begin requires ELF_C_READ even if MIGHT_CHK is in effect.
95 	 * libelf does not allow elf_begin() with ELF_C_RDWR when processing
96 	 * archive file members.  Because we are limited to ELF_C_READ use, any
97 	 * ELF data modification must be provided by updating a copy of
98 	 * the data, rather than updating the original file data.
99 	 */
100 	cmd = ELF_C_READ;
101 	if ((arf = elf_begin(fd, cmd, (Elf *)0)) == 0) {
102 		error_message(LIBELF_ERROR,
103 		LIBelf_ERROR, elf_errmsg(-1), prog);
104 		(void) elf_end(arf);
105 		(void) close(fd);   /* done processing this file */
106 		return (FAILURE);
107 	}
108 
109 	if ((elf_kind(arf) == ELF_K_AR)) {
110 		ar_file = 1;
111 		if (CHK_OPT(cmd_info, MIGHT_CHG)) {
112 			artmpfile = tempnam(TMPDIR, "mcs2");
113 			if ((fdartmp = open(artmpfile,
114 			    O_WRONLY | O_APPEND | O_CREAT,
115 			    (mode_t)0666)) == NULL) {
116 				error_message(OPEN_TEMP_ERROR,
117 				SYSTEM_ERROR, strerror(errno),
118 				prog, artmpfile);
119 				(void) elf_end(arf);
120 				(void) close(fd);
121 				exit(FAILURE);
122 			}
123 			/* write magic string to artmpfile */
124 			if ((write(fdartmp, ARMAG, SARMAG)) != SARMAG) {
125 				error_message(WRITE_ERROR,
126 				SYSTEM_ERROR, strerror(errno),
127 				prog, artmpfile, cur_file);
128 				mcs_exit(FAILURE);
129 			}
130 		}
131 	} else {
132 		ar_file = 0;
133 		cur_filenm = cur_file;
134 	}
135 
136 	/*
137 	 * Holds temporary file;
138 	 * if archive, holds the current member file if it has an ehdr,
139 	 * and there were no errors in
140 	 * processing the object file.
141 	 */
142 	elftmpfile = tempnam(TMPDIR, "mcs1");
143 
144 	while ((elf = elf_begin(fd, cmd, arf)) != 0) {
145 		if (ar_file) /* get header info */ {
146 			size_t	len;
147 
148 			if ((mem_header = elf_getarhdr(elf)) == NULL) {
149 				error_message(GETARHDR_ERROR,
150 				LIBelf_ERROR, elf_errmsg(-1),
151 				prog, cur_file, elf_getbase(elf));
152 				(void) elf_end(elf);
153 				(void) elf_end(arf);
154 				(void) close(fd);
155 				(void) unlink(artmpfile);
156 				return (FAILURE);
157 			}
158 
159 			if (cur_filenm != NULL)
160 				free(cur_filenm);
161 
162 			len = (strlen(cur_file) + 3 +
163 			    strlen(mem_header->ar_name));
164 
165 			if ((cur_filenm = malloc(len)) == NULL) {
166 				error_message(MALLOC_ERROR,
167 				PLAIN_ERROR, (char *)0,
168 				prog);
169 				mcs_exit(FAILURE);
170 			}
171 
172 			(void) snprintf(cur_filenm, len, "%s[%s]",
173 				cur_file, mem_header->ar_name);
174 		}
175 
176 		if (elf_kind(elf) == ELF_K_ELF) {
177 			if ((code = process_file(elf, cur_filenm, cmd_info)) ==
178 			    FAILURE) {
179 				if (!ar_file) {
180 					(void) elf_end(arf);
181 					(void) elf_end(elf);
182 					(void) close(fd);
183 					return (FAILURE);
184 				} else {
185 					copy_non_elf_to_temp_ar(
186 					fd, elf, fdartmp, mem_header,
187 					cur_file, cmd_info);
188 					error++;
189 				}
190 			} else if (ar_file && CHK_OPT(cmd_info, MIGHT_CHG)) {
191 				if (code == DONT_BUILD)
192 					copy_non_elf_to_temp_ar(
193 					fd, elf, fdartmp, mem_header,
194 					cur_file, cmd_info);
195 				else
196 					copy_elf_file_to_temp_ar_file(
197 						fdartmp, mem_header, cur_file);
198 			}
199 		} else {
200 			/*
201 			 * decide what to do with non-ELF file
202 			 */
203 			if (!ar_file) {
204 				error_message(FILE_TYPE_ERROR,
205 				PLAIN_ERROR, (char *)0,
206 				prog, cur_filenm);
207 				(void) close(fd);
208 				return (FAILURE);
209 			} else {
210 				if (CHK_OPT(cmd_info, MIGHT_CHG))
211 					copy_non_elf_to_temp_ar(
212 					fd, elf, fdartmp, mem_header,
213 					cur_file, cmd_info);
214 			}
215 		}
216 		cmd = elf_next(elf);
217 		(void) elf_end(elf);
218 	}
219 
220 	err = elf_errno();
221 	if (err != 0) {
222 		error_message(LIBELF_ERROR,
223 		LIBelf_ERROR, elf_errmsg(err), prog);
224 		error_message(NOT_MANIPULATED_ERROR,
225 		PLAIN_ERROR, (char *)0,
226 		prog, cur_file);
227 		return (FAILURE);
228 	}
229 
230 	(void) elf_end(arf);
231 
232 	if (ar_file && CHK_OPT(cmd_info, MIGHT_CHG)) {
233 		(void) close(fdartmp); /* done writing to ar_temp_file */
234 		/* copy ar_temp_file to FILE */
235 		copy_file(fd, cur_file, artmpfile);
236 	} else if (code != DONT_BUILD && CHK_OPT(cmd_info, MIGHT_CHG))
237 		copy_file(fd, cur_file, elftmpfile);
238 	(void) close(fd);   /* done processing this file */
239 	return (error);
240 }
241 
242 static int
243 process_file(Elf *elf, char *cur_file, Cmd_Info *cmd_info)
244 {
245 	int error = SUCCESS;
246 	int x;
247 	GElf_Ehdr ehdr;
248 	size_t shnum;
249 
250 	/*
251 	 * Initialize
252 	 */
253 	if (gelf_getehdr(elf, &ehdr) == NULL) {
254 		error_message(LIBELF_ERROR,
255 		LIBelf_ERROR, elf_errmsg(-1), prog);
256 		return (FAILURE);
257 	}
258 
259 	if (elf_getshnum(elf, &shnum) == NULL) {
260 		error_message(LIBELF_ERROR,
261 		LIBelf_ERROR, elf_errmsg(-1), prog);
262 		return (FAILURE);
263 	}
264 
265 	initialize(shnum, cmd_info);
266 
267 	if (ehdr.e_phnum != 0) {
268 		if (build_segment_table(elf, &ehdr) == FAILURE)
269 			return (FAILURE);
270 	}
271 
272 	if ((x = traverse_file(elf, &ehdr, cur_file, cmd_info)) ==
273 	    FAILURE) {
274 		error_message(WRN_MANIPULATED_ERROR,
275 		PLAIN_ERROR, (char *)0,
276 		prog, cur_file);
277 		error = FAILURE;
278 	} else if (x != DONT_BUILD && x != FAILURE) {
279 		post_process(cmd_info);
280 		if (build_file(elf, &ehdr, cmd_info) == FAILURE) {
281 			error_message(WRN_MANIPULATED_ERROR,
282 			PLAIN_ERROR, (char *)0,
283 			prog, cur_file);
284 			error = FAILURE;
285 		}
286 	}
287 
288 	free(off_table);
289 	free(sec_table);
290 	free(nobits_table);
291 
292 	if (x == DONT_BUILD)
293 		return (DONT_BUILD);
294 	else
295 		return (error);
296 }
297 
298 static int
299 traverse_file(Elf *elf, GElf_Ehdr * ehdr, char *cur_file, Cmd_Info *cmd_info)
300 {
301 	Elf_Scn *	scn;
302 	Elf_Scn *	temp_scn;
303 	Elf_Data *	data;
304 	GElf_Shdr *	shdr;
305 	char 		*temp_name;
306 	section_info_table *	sinfo;
307 	GElf_Xword 	x;
308 	int 		ret = 0, SYM = 0;	/* used by strip command */
309 	int 		phnum = ehdr->e_phnum;
310 	unsigned 	int i, scn_index;
311 	size_t 		shstrndx, shnum;
312 
313 	Sect_exists = 0;
314 
315 	if (elf_getshnum(elf, &shnum) == NULL) {
316 		error_message(LIBELF_ERROR,
317 		LIBelf_ERROR, elf_errmsg(-1), prog);
318 		return (FAILURE);
319 	}
320 	if (elf_getshstrndx(elf, &shstrndx) == NULL) {
321 		error_message(LIBELF_ERROR,
322 		LIBelf_ERROR, elf_errmsg(-1), prog);
323 		return (FAILURE);
324 	}
325 
326 	scn = 0;
327 	scn_index = 1;
328 	sinfo = &sec_table[scn_index];
329 	while ((scn = elf_nextscn(elf, scn)) != 0) {
330 		char *name;
331 
332 		shdr = &(sinfo->shdr);
333 		if (gelf_getshdr(scn, shdr) == NULL) {
334 			error_message(NO_SECT_TABLE_ERROR,
335 			LIBelf_ERROR, elf_errmsg(-1),
336 			prog, cur_file);
337 			return (FAILURE);
338 		} else {
339 			name = elf_strptr(elf, shstrndx,
340 				(size_t)shdr->sh_name);
341 			if (name == NULL)
342 				name = "_@@@###";
343 		}
344 
345 		sinfo->scn	= scn;
346 		sinfo->secno	= scn_index;
347 		sinfo->osecno	= scn_index;
348 		SET_ACTION(sinfo->flags, ACT_NOP);
349 		sinfo->name	= name;
350 		if (ehdr->e_phnum == 0)
351 			SET_LOC(sinfo->flags, NOSEG);
352 		else
353 			SET_LOC(sinfo->flags, scn_location(scn, elf));
354 
355 		if (shdr->sh_type == SHT_GROUP) {
356 		    if (list_appendc(&cmd_info->sh_groups, sinfo) == 0) {
357 			error_message(MALLOC_ERROR,
358 				PLAIN_ERROR, (char *)0, prog);
359 			mcs_exit(FAILURE);
360 		    }
361 		}
362 
363 		/*
364 		 * If the target section is pointed by a section
365 		 * holding relocation infomation, then the
366 		 * pointing section would be useless if the
367 		 * target section is removed.
368 		 */
369 		if ((shdr->sh_type == SHT_REL ||
370 		    shdr->sh_type == SHT_RELA) &&
371 		    (shdr->sh_info != SHN_UNDEF &&
372 		    (temp_scn = elf_getscn(elf, shdr->sh_info)) != 0)) {
373 			GElf_Shdr tmp_shdr;
374 			if (gelf_getshdr(temp_scn, &tmp_shdr) != NULL) {
375 				temp_name = elf_strptr(elf, shstrndx,
376 					(size_t)tmp_shdr.sh_name);
377 				sinfo->rel_name = temp_name;
378 				sinfo->rel_scn_index =
379 				    shdr->sh_info;
380 				if (phnum == 0)
381 					sinfo->rel_loc = NOSEG;
382 				    else
383 					sinfo->rel_loc =
384 						scn_location(temp_scn, elf);
385 			}
386 		}
387 		data = 0;
388 		if ((data = elf_getdata(scn, data)) == NULL) {
389 			error_message(LIBELF_ERROR,
390 			LIBelf_ERROR, elf_errmsg(-1), prog);
391 			return (FAILURE);
392 		}
393 		sinfo->data = data;
394 
395 		/*
396 		 * Check if this section is a candidate for
397 		 * action to be processes.
398 		 */
399 		if (sectcmp(name) == 0) {
400 			SET_CANDIDATE(sinfo->flags);
401 
402 			/*
403 			 * This flag just shows that there was a
404 			 * candidate.
405 			 */
406 			Sect_exists++;
407 		}
408 
409 		/*
410 		 * Any of the following section types should
411 		 * also be removed (if possible) if invoked via
412 		 * the 'strip' command.
413 		 */
414 		if (CHK_OPT(cmd_info, I_AM_STRIP) &&
415 		    ((shdr->sh_type == SHT_SUNW_DEBUG) ||
416 		    (shdr->sh_type == SHT_SUNW_DEBUGSTR))) {
417 			SET_CANDIDATE(sinfo->flags);
418 			Sect_exists++;
419 		}
420 
421 
422 		/*
423 		 * Zap this file ?
424 		 */
425 		if ((cmd_info->flags & zFLAG) &&
426 		    (shdr->sh_type == SHT_PROGBITS)) {
427 			SET_CANDIDATE(sinfo->flags);
428 			Sect_exists++;
429 		}
430 		x = GET_LOC(sinfo->flags);
431 
432 		/*
433 		 * Remeber the note sections index so that we can
434 		 * reset the NOTE segments offset to point to it.
435 		 *
436 		 * It may have been assigned a new location in the
437 		 * resulting output elf image.
438 		 */
439 		if (shdr->sh_type == SHT_NOTE)
440 			notesctndx = scn_index;
441 
442 		if (x == IN || x == PRIOR)
443 			off_table[scn_index] =
444 				shdr->sh_offset;
445 		if (shdr->sh_type == SHT_NOBITS)
446 			nobits_table[scn_index] = 1;
447 
448 		/*
449 		 * If this section satisfies the condition,
450 		 * apply the actions specified.
451 		 */
452 		if (ISCANDIDATE(sinfo->flags)) {
453 			ret += apply_action(sinfo, cur_file, cmd_info);
454 		}
455 
456 		/*
457 		 * If I am strip command, determine if symtab can go or not.
458 		 */
459 		if (CHK_OPT(cmd_info, I_AM_STRIP) &&
460 		    (CHK_OPT(cmd_info, xFLAG) == 0) &&
461 		    (CHK_OPT(cmd_info, lFLAG) == 0)) {
462 			if (shdr->sh_type == SHT_SYMTAB &&
463 			    GET_LOC(sinfo->flags) == AFTER) {
464 				SYM = scn_index;
465 			}
466 		}
467 		scn_index++;
468 		sinfo++;
469 	}
470 	sinfo->scn	= (Elf_Scn *) -1;
471 
472 	/*
473 	 * If there were any errors traversing the file,
474 	 * just return error.
475 	 */
476 	if (ret != 0)
477 		return (FAILURE);
478 
479 	/*
480 	 * Remove symbol table if possible
481 	 */
482 	if (CHK_OPT(cmd_info, I_AM_STRIP) && SYM != 0) {
483 		GElf_Shdr tmp_shdr;
484 
485 		(void) gelf_getshdr(sec_table[SYM].scn, &tmp_shdr);
486 		sec_table[SYM].secno = (GElf_Word)DELETED;
487 		++(cmd_info->no_of_nulled);
488 		if (Sect_exists == 0)
489 			++Sect_exists;
490 		SET_ACTION(sec_table[SYM].flags, ACT_DELETE);
491 		off_table[SYM] = 0;
492 		/*
493 		 * Can I remove section header
494 		 * string table ?
495 		 */
496 		if ((tmp_shdr.sh_link < shnum) &&
497 		    (tmp_shdr.sh_link != SHN_UNDEF) &&
498 		    (tmp_shdr.sh_link != shstrndx) &&
499 		    (GET_LOC(sec_table[tmp_shdr.sh_link].flags) == AFTER)) {
500 			sec_table[tmp_shdr.sh_link].secno = (GElf_Word)DELETED;
501 			++(cmd_info->no_of_nulled);
502 			if (Sect_exists == 0)
503 				++Sect_exists;
504 			SET_ACTION(sec_table[tmp_shdr.sh_link].flags,\
505 				ACT_DELETE);
506 			off_table[tmp_shdr.sh_link] = 0;
507 		}
508 	}
509 
510 	/*
511 	 * If I only printed the contents, then
512 	 * just report so.
513 	 */
514 	if (CHK_OPT(cmd_info, pFLAG) && !CHK_OPT(cmd_info, MIGHT_CHG))
515 		return (DONT_BUILD); /* don't bother creating a new file */
516 				/* since the file has not changed */
517 
518 	/*
519 	 * I might need to add a new section. Check it.
520 	 */
521 	if (Sect_exists == 0 && CHK_OPT(cmd_info, aFLAG)) {
522 		int act = 0;
523 		new_sec_string = calloc(1, cmd_info->str_size + 1);
524 		if (new_sec_string == NULL)
525 			return (FAILURE);
526 		for (act = 0; act < actmax; act++) {
527 			if (Action[act].a_action == ACT_APPEND) {
528 				(void) strcat(new_sec_string,
529 					Action[act].a_string);
530 				(void) strcat(new_sec_string, "\n");
531 				cmd_info->no_of_append = 1;
532 			}
533 		}
534 	}
535 
536 	/*
537 	 * If I did not append any new sections, and I did not
538 	 * modify/delete any sections, then just report so.
539 	 */
540 	if ((Sect_exists == 0 && cmd_info->no_of_append == 0) ||
541 	    !CHK_OPT(cmd_info, MIGHT_CHG))
542 		return (DONT_BUILD);
543 
544 	/*
545 	 * Found at least one section which was processed.
546 	 *	Deleted or Appended or Compressed.
547 	 */
548 	if (Sect_exists) {
549 		/*
550 		 * First, handle the deleted sections.
551 		 */
552 		if (cmd_info->no_of_delete != 0 ||
553 		    cmd_info->no_of_nulled != 0) {
554 			int acc = 0;
555 			int rel_idx;
556 
557 			/*
558 			 * Handle relocation/target
559 			 * sections.
560 			 */
561 			sinfo = &(sec_table[0]);
562 			for (i = 1; i < shnum; i++) {
563 				sinfo++;
564 				rel_idx = sinfo->rel_scn_index;
565 				if (rel_idx == 0)
566 					continue;
567 
568 				/*
569 				 * If I am removed, then remove my
570 				 * target section.
571 				 */
572 				if (((sinfo->secno ==
573 				    (GElf_Word)DELETED) ||
574 				    (sinfo->secno ==
575 				    (GElf_Word)NULLED)) &&
576 				    sinfo->rel_loc != IN) {
577 					if (GET_LOC(sec_table[rel_idx].flags) ==
578 					    PRIOR)
579 						sec_table[rel_idx].secno =
580 							(GElf_Word)NULLED;
581 					else
582 						sec_table[rel_idx].secno =
583 							(GElf_Word)DELETED;
584 					SET_ACTION(sec_table[rel_idx].flags,\
585 						ACT_DELETE);
586 				}
587 
588 				/*
589 				 * I am not removed. Check if my target is
590 				 * removed or nulled. If so, let me try to
591 				 * remove my self.
592 				 */
593 				if (((sec_table[rel_idx].secno ==
594 				    (GElf_Word)DELETED) ||
595 				    (sec_table[rel_idx].secno ==
596 				    (GElf_Word)NULLED)) &&
597 				    (GET_LOC(sinfo->flags) != IN)) {
598 					if (GET_LOC(sinfo->flags) ==
599 					    PRIOR)
600 						sinfo->secno =
601 							(GElf_Word)NULLED;
602 					else
603 						sinfo->secno =
604 							(GElf_Word)DELETED;
605 					SET_ACTION(sinfo->flags,\
606 						ACT_DELETE);
607 				}
608 			}
609 
610 			/*
611 			 * Now, take care of DELETED sections
612 			 */
613 			sinfo = &(sec_table[1]);
614 			for (i = 1; i < shnum; i++) {
615 			    shdr = &(sinfo->shdr);
616 			    if (sinfo->secno == (GElf_Word)DELETED) {
617 				acc++;
618 				/*
619 				 * The SHT_GROUP section which this section
620 				 * is a member may be able to be removed.
621 				 * See post_process().
622 				 */
623 				if (shdr->sh_flags & SHF_GROUP)
624 				    cmd_info->flags |= SHF_GROUP_DEL;
625 			    } else {
626 				/*
627 				 * The data buffer of SHT_GROUP this section
628 				 * is a member needs to be updated.
629 				 * See post_process().
630 				 */
631 				sinfo->secno -= acc;
632 				if ((shdr->sh_flags &
633 				    SHF_GROUP) && (acc != 0))
634 				    cmd_info->flags |= SHF_GROUP_MOVE;
635 			    }
636 			    sinfo++;
637 			}
638 		}
639 	}
640 
641 	/*
642 	 * I know that the file has been modified.
643 	 * A new file need to be created.
644 	 */
645 	return (SUCCESS);
646 }
647 
648 static int
649 build_file(Elf *src_elf, GElf_Ehdr *src_ehdr, Cmd_Info *cmd_info)
650 {
651 	Elf_Scn *src_scn;
652 	Elf_Scn *dst_scn;
653 	int	new_sh_name = 0;	/* to hold the offset for the new */
654 					/* section's name */
655 	Elf *dst_elf = 0;
656 	Elf_Data *elf_data;
657 	Elf_Data *data;
658 	int64_t scn_no, x;
659 	size_t no_of_symbols = 0;
660 	section_info_table *info;
661 	unsigned int    c = 0;
662 	int fdtmp;
663 	GElf_Shdr src_shdr;
664 	GElf_Shdr dst_shdr;
665 	GElf_Ehdr dst_ehdr;
666 	GElf_Off  new_offset = 0, r;
667 	size_t shnum, shstrndx;
668 
669 
670 	if (elf_getshnum(src_elf, &shnum) == NULL) {
671 		error_message(LIBELF_ERROR,
672 		LIBelf_ERROR, elf_errmsg(-1), prog);
673 		return (FAILURE);
674 	}
675 	if (elf_getshstrndx(src_elf, &shstrndx) == NULL) {
676 		error_message(LIBELF_ERROR,
677 		LIBelf_ERROR, elf_errmsg(-1), prog);
678 		return (FAILURE);
679 	}
680 
681 	if ((fdtmp = open(elftmpfile, O_RDWR |
682 		O_TRUNC | O_CREAT, (mode_t)0666)) == -1) {
683 		error_message(OPEN_TEMP_ERROR,
684 		SYSTEM_ERROR, strerror(errno),
685 		prog, elftmpfile);
686 		return (FAILURE);
687 	}
688 
689 	if ((dst_elf = elf_begin(fdtmp, ELF_C_WRITE, (Elf *) 0)) == NULL) {
690 		error_message(READ_ERROR,
691 		LIBelf_ERROR, elf_errmsg(-1),
692 		prog, elftmpfile);
693 		(void) close(fdtmp);
694 		return (FAILURE);
695 	}
696 
697 	if (gelf_newehdr(dst_elf, gelf_getclass(src_elf)) == NULL) {
698 		error_message(LIBELF_ERROR,
699 		LIBelf_ERROR, elf_errmsg(-1), prog);
700 		return (FAILURE);
701 	}
702 
703 	/* initialize dst_ehdr */
704 	(void) gelf_getehdr(dst_elf, &dst_ehdr);
705 	dst_ehdr = *src_ehdr;
706 
707 	/*
708 	 * If we are removing the header string table section,
709 	 * remove the reference to it from the ELF header.
710 	 */
711 	if ((shstrndx != SHN_UNDEF) &&
712 	    (sec_table[shstrndx].secno == (GElf_Word)DELETED))
713 		dst_ehdr.e_shstrndx = SHN_UNDEF;
714 
715 	/*
716 	 * flush the changes to the ehdr so the ident
717 	 * array and header string table index are filled in.
718 	 */
719 	(void) gelf_update_ehdr(dst_elf, &dst_ehdr);
720 
721 
722 	if (src_ehdr->e_phnum != 0) {
723 		(void) elf_flagelf(dst_elf, ELF_C_SET, ELF_F_LAYOUT);
724 
725 		if (gelf_newphdr(dst_elf, src_ehdr->e_phnum) == NULL) {
726 			error_message(LIBELF_ERROR,
727 			LIBelf_ERROR, elf_errmsg(-1), prog);
728 			return (FAILURE);
729 		}
730 
731 		for (x = 0; x < src_ehdr->e_phnum; ++x) {
732 			GElf_Phdr dst;
733 			GElf_Phdr src;
734 
735 			/* LINTED */
736 			(void) gelf_getphdr(src_elf, (int)x, &src);
737 			/* LINTED */
738 			(void) gelf_getphdr(dst_elf, (int)x, &dst);
739 			(void) memcpy(&dst, &src, sizeof (GElf_Phdr));
740 			/* LINTED */
741 			(void) gelf_update_phdr(dst_elf, (int)x, &dst);
742 		}
743 
744 		x = location(dst_ehdr.e_phoff, 0, src_elf);
745 		if (x == AFTER)
746 			new_offset = (GElf_Off)src_ehdr->e_ehsize;
747 	}
748 
749 	scn_no = 1;
750 	while ((src_scn = sec_table[scn_no].scn) != (Elf_Scn *) -1) {
751 		info = &sec_table[scn_no];
752 		/*  If section should be copied to new file NOW */
753 		if ((info->secno != (GElf_Word)DELETED) &&
754 		    info->secno <= scn_no) {
755 			if ((dst_scn = elf_newscn(dst_elf)) == NULL) {
756 				error_message(LIBELF_ERROR,
757 				LIBelf_ERROR, elf_errmsg(-1), prog);
758 				return (FAILURE);
759 			}
760 			(void) gelf_getshdr(dst_scn, &dst_shdr);
761 			(void) gelf_getshdr(info->scn, &src_shdr);
762 			(void) memcpy(&dst_shdr, &src_shdr, sizeof (GElf_Shdr));
763 
764 			/*
765 			 * Update link and info fields
766 			 * The sh_link field may have special values so
767 			 * check them first.
768 			 */
769 			if ((src_shdr.sh_link >= shnum) ||
770 			    (src_shdr.sh_link == 0))
771 				dst_shdr.sh_link = src_shdr.sh_link;
772 			else if ((int)sec_table[src_shdr.sh_link].secno < 0)
773 				dst_shdr.sh_link = 0;
774 			else
775 				dst_shdr.sh_link =
776 				sec_table[src_shdr.sh_link].secno;
777 
778 			if ((src_shdr.sh_type == SHT_REL) ||
779 			    (src_shdr.sh_type == SHT_RELA)) {
780 				if ((src_shdr.sh_info >= shnum) ||
781 				    ((int)sec_table[src_shdr.
782 				    sh_info].secno < 0))
783 					dst_shdr.sh_info = 0;
784 				else
785 					dst_shdr.sh_info =
786 					    sec_table[src_shdr.sh_info].secno;
787 			}
788 
789 			data = sec_table[scn_no].data;
790 			if ((elf_data = elf_newdata(dst_scn)) == NULL) {
791 				error_message(LIBELF_ERROR,
792 				LIBelf_ERROR, elf_errmsg(-1), prog);
793 				return (FAILURE);
794 			}
795 			*elf_data = *data;
796 
797 			/*
798 			 * SHT_{DYNSYM, SYMTAB} might need some change, as
799 			 * they may contain section symbols that reference
800 			 * removed sections. SHT_SUNW_LDYNSYM does not
801 			 * contain section symbols, and therefore does not
802 			 * have this issue.
803 			 */
804 			if (((src_shdr.sh_type == SHT_SYMTAB) ||
805 			    (src_shdr.sh_type == SHT_DYNSYM)) &&
806 			    src_shdr.sh_entsize != 0 &&
807 			    (cmd_info->no_of_delete != 0 ||
808 			    cmd_info->no_of_nulled != 0)) {
809 				char	*new_sym;
810 
811 				no_of_symbols = src_shdr.sh_size /
812 				    src_shdr.sh_entsize;
813 				new_sym = malloc(no_of_symbols *
814 						src_shdr.sh_entsize);
815 				if (new_sym == NULL) {
816 					error_message(MALLOC_ERROR,
817 					PLAIN_ERROR, (char *)0, prog);
818 					mcs_exit(FAILURE);
819 				}
820 
821 				/* CSTYLED */
822 				elf_data->d_buf = (void *) new_sym;
823 				for (c = 0; c < no_of_symbols; c++) {
824 					GElf_Sym csym;
825 
826 					(void) gelf_getsym(data, c, &csym);
827 
828 					if ((csym.st_shndx < SHN_LORESERVE) &&
829 					    (csym.st_shndx != SHN_UNDEF)) {
830 						section_info_table *i;
831 						i = &sec_table[csym.st_shndx];
832 						if (((int)i->secno !=
833 						    DELETED) &&
834 						    ((int)i->secno != NULLED))
835 							csym.st_shndx =
836 							    i->secno;
837 						else {
838 							if (src_shdr.sh_type ==
839 							    SHT_SYMTAB)
840 							/*
841 							 * The section which
842 							 * this * symbol relates
843 							 * to is removed.
844 							 * There is no way to
845 							 * specify this fact,
846 							 * just change the shndx
847 							 * to 1.
848 							 */
849 							    csym.st_shndx = 1;
850 							else {
851 							/*
852 							 * If this is in a
853 							 * .dynsym, NULL it out.
854 							 */
855 							    csym.st_shndx = 0;
856 							    csym.st_name = 0;
857 							    csym.st_value = 0;
858 							    csym.st_size = 0;
859 							    csym.st_info = 0;
860 							    csym.st_other = 0;
861 							    csym.st_shndx = 0;
862 							}
863 						}
864 					}
865 
866 					(void) gelf_update_sym(elf_data, c,
867 					    &csym);
868 				}
869 			}
870 
871 			/* update SHT_SYMTAB_SHNDX */
872 			if ((src_shdr.sh_type == SHT_SYMTAB_SHNDX) &&
873 			    (src_shdr.sh_entsize != 0) &&
874 			    ((cmd_info->no_of_delete != 0) ||
875 			    (cmd_info->no_of_nulled != 0))) {
876 				GElf_Word	*oldshndx;
877 				GElf_Word	*newshndx;
878 				uint_t		entcnt;
879 
880 				entcnt = src_shdr.sh_size /
881 				    src_shdr.sh_entsize;
882 				oldshndx = data->d_buf;
883 				newshndx = malloc(entcnt *
884 					src_shdr.sh_entsize);
885 				if (newshndx == NULL) {
886 					error_message(MALLOC_ERROR,
887 					PLAIN_ERROR, (char *)0, prog);
888 					mcs_exit(FAILURE);
889 				}
890 				elf_data->d_buf = (void *)newshndx;
891 				for (c = 0; c < entcnt; c++) {
892 					if (oldshndx[c] != SHN_UNDEF) {
893 						section_info_table *i;
894 						i = &sec_table[oldshndx[c]];
895 						if (((int)i->secno !=
896 						    DELETED) &&
897 						    ((int)i->secno != NULLED))
898 							newshndx[c] = i->secno;
899 						else
900 							newshndx[c] =
901 							    oldshndx[c];
902 					} else
903 							newshndx[c] =
904 							    oldshndx[c];
905 				}
906 			}
907 
908 			/*
909 			 * If the section is to be updated,
910 			 * do so.
911 			 */
912 			if (ISCANDIDATE(info->flags)) {
913 				if ((GET_LOC(info->flags) == PRIOR) &&
914 				    (((int)info->secno == NULLED) ||
915 				    ((int)info->secno == EXPANDED) ||
916 				    ((int)info->secno == SHRUNK))) {
917 					/*
918 					 * The section is updated,
919 					 * but the position is not too
920 					 * good. Need to NULL this out.
921 					 */
922 					dst_shdr.sh_name = 0;
923 					dst_shdr.sh_type = SHT_PROGBITS;
924 					if ((int)info->secno != NULLED) {
925 						(cmd_info->no_of_moved)++;
926 						SET_MOVING(info->flags);
927 					}
928 				} else {
929 					/*
930 					 * The section is positioned AFTER,
931 					 * or there are no segments.
932 					 * It is safe to update this section.
933 					 */
934 					data = sec_table[scn_no].mdata;
935 					*elf_data = *data;
936 					dst_shdr.sh_size = elf_data->d_size;
937 				}
938 			}
939 			/* add new section name to shstrtab? */
940 			else if (!Sect_exists &&
941 			    (new_sec_string != NULL) &&
942 			    (scn_no == shstrndx) &&
943 			    (dst_shdr.sh_type == SHT_STRTAB) &&
944 			    ((src_ehdr->e_phnum == 0) ||
945 			    ((x = scn_location(dst_scn, dst_elf)) != IN) ||
946 			    (x != PRIOR))) {
947 				size_t sect_len;
948 
949 				sect_len = strlen(SECT_NAME);
950 				if ((elf_data->d_buf =
951 				malloc((dst_shdr.sh_size +
952 				sect_len + 1))) == NULL) {
953 					error_message(MALLOC_ERROR,
954 					PLAIN_ERROR, (char *)0, prog);
955 					mcs_exit(FAILURE);
956 				}
957 				/* put original data plus new data in section */
958 				(void) memcpy(elf_data->d_buf,
959 					data->d_buf, data->d_size);
960 				(void) memcpy(&((char *)elf_data->d_buf)
961 					[data->d_size],
962 					SECT_NAME,
963 					sect_len + 1);
964 				/* LINTED */
965 				new_sh_name = (int)dst_shdr.sh_size;
966 				dst_shdr.sh_size += sect_len + 1;
967 				elf_data->d_size += sect_len + 1;
968 			}
969 
970 			/*
971 			 * Compute offsets.
972 			 */
973 			if (src_ehdr->e_phnum != 0) {
974 				/*
975 				 * Compute section offset.
976 				 */
977 				if (off_table[scn_no] == 0) {
978 					if (dst_shdr.sh_addralign != 0) {
979 						r = new_offset %
980 						    dst_shdr.sh_addralign;
981 						if (r)
982 						    new_offset +=
983 						    dst_shdr.sh_addralign - r;
984 					}
985 					dst_shdr.sh_offset = new_offset;
986 					elf_data->d_off = 0;
987 				} else {
988 					if (nobits_table[scn_no] == 0)
989 						new_offset = off_table[scn_no];
990 				}
991 				if (nobits_table[scn_no] == 0)
992 					new_offset += dst_shdr.sh_size;
993 			}
994 
995 			/* flush changes */
996 			(void) gelf_update_shdr(dst_scn, &dst_shdr);
997 		}
998 		scn_no++;
999 	}
1000 
1001 	/*
1002 	 * This is the real new section.
1003 	 */
1004 	if (!Sect_exists && new_sec_string != NULL) {
1005 		size_t string_size;
1006 		string_size = strlen(new_sec_string) + 1;
1007 		if ((dst_scn = elf_newscn(dst_elf)) == NULL) {
1008 			error_message(LIBELF_ERROR,
1009 			LIBelf_ERROR, elf_errmsg(-1), prog);
1010 			return (FAILURE);
1011 		}
1012 		(void) gelf_getshdr(dst_scn, &dst_shdr);
1013 
1014 		dst_shdr.sh_name = new_sh_name;
1015 		dst_shdr.sh_type = SHT_PROGBITS;
1016 		dst_shdr.sh_flags = 0;
1017 		dst_shdr.sh_addr = 0;
1018 		if (src_ehdr->e_phnum != NULL)
1019 			dst_shdr.sh_offset = new_offset;
1020 		else
1021 			dst_shdr.sh_offset = 0;
1022 		dst_shdr.sh_size = string_size + 1;
1023 		dst_shdr.sh_link = 0;
1024 		dst_shdr.sh_info = 0;
1025 		dst_shdr.sh_addralign = 1;
1026 		dst_shdr.sh_entsize = 0;
1027 		(void) gelf_update_shdr(dst_scn, &dst_shdr); /* flush changes */
1028 
1029 		if ((elf_data = elf_newdata(dst_scn)) == NULL) {
1030 			error_message(LIBELF_ERROR,
1031 			LIBelf_ERROR, elf_errmsg(-1), prog);
1032 			return (FAILURE);
1033 		}
1034 		elf_data->d_size = string_size + 1;
1035 		if ((elf_data->d_buf = (char *)
1036 		    calloc(1, string_size + 1)) == NULL) {
1037 			error_message(MALLOC_ERROR,
1038 			PLAIN_ERROR, (char *)0,
1039 			prog);
1040 			mcs_exit(FAILURE);
1041 		}
1042 		(void) memcpy(&((char *)elf_data->d_buf)[1],
1043 			new_sec_string, string_size);
1044 		elf_data->d_align = 1;
1045 		new_offset += string_size + 1;
1046 	}
1047 
1048 	/*
1049 	 * If there are sections which needed to be moved,
1050 	 * then do it here.
1051 	 */
1052 	if (cmd_info->no_of_moved != 0) {
1053 		int cnt;
1054 		info = &sec_table[0];
1055 
1056 		for (cnt = 0; cnt < shnum; cnt++, info++) {
1057 			if ((GET_MOVING(info->flags)) == 0)
1058 				continue;
1059 
1060 			if ((src_scn = elf_getscn(src_elf, info->osecno)) ==
1061 			    NULL) {
1062 				error_message(LIBELF_ERROR,
1063 				LIBelf_ERROR, elf_errmsg(-1), prog);
1064 				return (FAILURE);
1065 			}
1066 			if (gelf_getshdr(src_scn, &src_shdr) == NULL) {
1067 				error_message(LIBELF_ERROR,
1068 				LIBelf_ERROR, elf_errmsg(-1), prog);
1069 				return (FAILURE);
1070 			}
1071 			if ((dst_scn = elf_newscn(dst_elf)) == NULL) {
1072 				error_message(LIBELF_ERROR,
1073 				LIBelf_ERROR, elf_errmsg(-1), prog);
1074 				return (FAILURE);
1075 			}
1076 			if (gelf_getshdr(dst_scn, &dst_shdr) == NULL) {
1077 				error_message(LIBELF_ERROR,
1078 				LIBelf_ERROR, elf_errmsg(-1), prog);
1079 				return (FAILURE);
1080 			}
1081 			dst_shdr = src_shdr;
1082 
1083 			data = info->mdata;
1084 
1085 			dst_shdr.sh_offset = new_offset;  /* UPDATE fields */
1086 			dst_shdr.sh_size = data->d_size;
1087 
1088 			if ((shnum >= src_shdr.sh_link) ||
1089 			    (src_shdr.sh_link == 0))
1090 				dst_shdr.sh_link = src_shdr.sh_link;
1091 			else
1092 				dst_shdr.sh_link =
1093 					sec_table[src_shdr.sh_link].osecno;
1094 
1095 			if ((shnum >= src_shdr.sh_info) ||
1096 			    (src_shdr.sh_info == 0))
1097 				dst_shdr.sh_info = src_shdr.sh_info;
1098 			else
1099 				dst_shdr.sh_info =
1100 					sec_table[src_shdr.sh_info].osecno;
1101 			(void) gelf_update_shdr(dst_scn, &dst_shdr);
1102 			if ((elf_data = elf_newdata(dst_scn)) == NULL) {
1103 				error_message(LIBELF_ERROR,
1104 				LIBelf_ERROR, elf_errmsg(-1), prog);
1105 				return (FAILURE);
1106 			}
1107 			(void) memcpy(elf_data, data, sizeof (Elf_Data));
1108 
1109 			new_offset += data->d_size;
1110 		}
1111 	}
1112 
1113 	/*
1114 	 * In the event that the position of the sting table has changed,
1115 	 * as a result of deleted sections, update the ehdr->e_shstrndx.
1116 	 */
1117 	if ((shstrndx > 0) && (shnum > 0) &&
1118 	    (sec_table[shstrndx].secno < shnum)) {
1119 		if (sec_table[shstrndx].secno < SHN_LORESERVE) {
1120 			dst_ehdr.e_shstrndx =
1121 				sec_table[dst_ehdr.e_shstrndx].secno;
1122 		} else {
1123 			Elf_Scn		*_scn;
1124 			GElf_Shdr	shdr0;
1125 
1126 			/*
1127 			 * If shstrndx requires 'Extended ELF Sections'
1128 			 * then it is stored in shdr[0].sh_link
1129 			 */
1130 			dst_ehdr.e_shstrndx = SHN_XINDEX;
1131 			if ((_scn = elf_getscn(dst_elf, 0)) == NULL) {
1132 				error_message(LIBELF_ERROR,
1133 				LIBelf_ERROR, elf_errmsg(-1), prog);
1134 				return (FAILURE);
1135 			}
1136 			(void) gelf_getshdr(_scn, &shdr0);
1137 			shdr0.sh_link = sec_table[shstrndx].secno;
1138 			(void) gelf_update_shdr(_scn, &shdr0);
1139 		}
1140 	}
1141 
1142 	if (src_ehdr->e_phnum != 0) {
1143 		size_t align = gelf_fsize(dst_elf, ELF_T_ADDR, 1, EV_CURRENT);
1144 
1145 		/* UPDATE location of program header table */
1146 		if (location(dst_ehdr.e_phoff, 0, dst_elf) == AFTER) {
1147 			r = new_offset % align;
1148 			if (r)
1149 				new_offset += align - r;
1150 
1151 			dst_ehdr.e_phoff = new_offset;
1152 			new_offset += dst_ehdr.e_phnum
1153 					* dst_ehdr.e_phentsize;
1154 		}
1155 		/* UPDATE location of section header table */
1156 		if ((location(dst_ehdr.e_shoff, 0, src_elf) == AFTER) ||
1157 		    ((location(dst_ehdr.e_shoff, 0, src_elf) == PRIOR) &&
1158 		    (!Sect_exists && new_sec_string != NULL))) {
1159 			r = new_offset % align;
1160 			if (r)
1161 				new_offset += align - r;
1162 
1163 			dst_ehdr.e_shoff = new_offset;
1164 		}
1165 		free(b_e_seg_table);
1166 
1167 		/*
1168 		 * The NOTE segment is the one segment whos
1169 		 * sections might get moved by mcs processing.
1170 		 * Make sure that the NOTE segments offset points
1171 		 * to the .note section.
1172 		 */
1173 		if ((notesegndx != -1) && (notesctndx != -1) &&
1174 		    (sec_table[notesctndx].secno)) {
1175 			Elf_Scn *	notescn;
1176 			GElf_Shdr	nshdr;
1177 
1178 			notescn = elf_getscn(dst_elf,
1179 				sec_table[notesctndx].secno);
1180 			(void) gelf_getshdr(notescn, &nshdr);
1181 
1182 			if (gelf_getclass(dst_elf) == ELFCLASS32) {
1183 				Elf32_Phdr * ph	= elf32_getphdr(dst_elf) +
1184 				    notesegndx;
1185 				/* LINTED */
1186 				ph->p_offset	= (Elf32_Off)nshdr.sh_offset;
1187 			} else {
1188 				Elf64_Phdr * ph	= elf64_getphdr(dst_elf) +
1189 				    notesegndx;
1190 				ph->p_offset	= (Elf64_Off)nshdr.sh_offset;
1191 			}
1192 		}
1193 	}
1194 
1195 	/* copy ehdr changes back into real ehdr */
1196 	(void) gelf_update_ehdr(dst_elf, &dst_ehdr);
1197 	if (elf_update(dst_elf, ELF_C_WRITE) < 0) {
1198 		error_message(LIBELF_ERROR,
1199 		LIBelf_ERROR, elf_errmsg(-1), prog);
1200 		return (FAILURE);
1201 	}
1202 
1203 	(void) elf_end(dst_elf);
1204 	(void) close(fdtmp);
1205 	return (SUCCESS);
1206 }
1207 
1208 /*
1209  * Search through PHT saving the beginning and ending segment offsets
1210  */
1211 static int
1212 build_segment_table(Elf * elf, GElf_Ehdr * ehdr)
1213 {
1214 	unsigned int i;
1215 
1216 	if ((b_e_seg_table = (Seg_Table *)
1217 		calloc(ehdr->e_phnum, sizeof (Seg_Table))) == NULL) {
1218 		error_message(MALLOC_ERROR,
1219 		PLAIN_ERROR, (char *)0,
1220 		prog);
1221 		mcs_exit(FAILURE);
1222 	}
1223 
1224 	for (i = 0; i < ehdr->e_phnum; i++) {
1225 		GElf_Phdr ph;
1226 
1227 		(void) gelf_getphdr(elf, i, &ph);
1228 
1229 		/*
1230 		 * remember the note SEGMENTS index so that we can
1231 		 * re-set it's p_offset later if needed.
1232 		 */
1233 		if (ph.p_type == PT_NOTE)
1234 			notesegndx = i;
1235 
1236 		b_e_seg_table[i].p_offset = ph.p_offset;
1237 		b_e_seg_table[i].p_memsz  = ph.p_offset + ph.p_memsz;
1238 		b_e_seg_table[i].p_filesz = ph.p_offset + ph.p_filesz;
1239 	}
1240 	return (SUCCESS);
1241 }
1242 
1243 
1244 static void
1245 copy_elf_file_to_temp_ar_file(
1246 	int fdartmp,
1247 	Elf_Arhdr *mem_header,
1248 	char *cur_file)
1249 {
1250 	char *buf;
1251 	char mem_header_buf[sizeof (struct ar_hdr) + 1];
1252 	int fdtmp3;
1253 	struct stat stbuf;
1254 
1255 	if ((fdtmp3 = open(elftmpfile, O_RDONLY)) == -1) {
1256 		error_message(OPEN_TEMP_ERROR,
1257 		SYSTEM_ERROR, strerror(errno),
1258 		prog, elftmpfile);
1259 		mcs_exit(FAILURE);
1260 	}
1261 
1262 	(void) stat(elftmpfile, &stbuf); /* for size of file */
1263 
1264 	if ((buf =
1265 	    malloc(ROUNDUP(stbuf.st_size))) == NULL) {
1266 		error_message(MALLOC_ERROR,
1267 		PLAIN_ERROR, (char *)0,
1268 		prog);
1269 		mcs_exit(FAILURE);
1270 	}
1271 
1272 	if (read(fdtmp3, buf, stbuf.st_size) != stbuf.st_size) {
1273 		error_message(READ_MANI_ERROR,
1274 		SYSTEM_ERROR, strerror(errno),
1275 		prog, elftmpfile, cur_file);
1276 		mcs_exit(FAILURE);
1277 	}
1278 
1279 	(void) sprintf(mem_header_buf, FORMAT,
1280 		mem_header->ar_rawname,
1281 		mem_header->ar_date,
1282 		(unsigned)mem_header->ar_uid,
1283 		(unsigned)mem_header->ar_gid,
1284 		(unsigned)mem_header->ar_mode,
1285 		stbuf.st_size, ARFMAG);
1286 
1287 	if (write(fdartmp, mem_header_buf,
1288 	    (unsigned)sizeof (struct ar_hdr)) !=
1289 	    (unsigned)sizeof (struct ar_hdr)) {
1290 		error_message(WRITE_MANI_ERROR,
1291 		SYSTEM_ERROR, strerror(errno),
1292 		prog, elftmpfile, cur_file);
1293 		mcs_exit(FAILURE);
1294 	}
1295 
1296 	if (stbuf.st_size & 0x1) {
1297 		buf[stbuf.st_size] = '\n';
1298 		if (write(fdartmp, buf, (size_t)ROUNDUP(stbuf.st_size)) !=
1299 		    (size_t)ROUNDUP(stbuf.st_size)) {
1300 			error_message(WRITE_MANI_ERROR,
1301 			SYSTEM_ERROR, strerror(errno),
1302 			prog, elftmpfile, cur_file);
1303 			mcs_exit(FAILURE);
1304 		}
1305 	} else if (write(fdartmp, buf, stbuf.st_size) != stbuf.st_size) {
1306 			error_message(WRITE_MANI_ERROR,
1307 			SYSTEM_ERROR, strerror(errno),
1308 			prog, elftmpfile, cur_file);
1309 			mcs_exit(FAILURE);
1310 	}
1311 	free(buf);
1312 	(void) close(fdtmp3);
1313 }
1314 
1315 static void
1316 copy_non_elf_to_temp_ar(
1317 	int fd,
1318 	Elf *elf,
1319 	int fdartmp,
1320 	Elf_Arhdr *mem_header,
1321 	char *cur_file,
1322 	Cmd_Info *cmd_info)
1323 {
1324 	char    mem_header_buf[sizeof (struct ar_hdr) + 1];
1325 	char *file_buf;
1326 
1327 	if (strcmp(mem_header->ar_name, "/") != 0) {
1328 		(void) sprintf(mem_header_buf, FORMAT,
1329 			mem_header->ar_rawname,
1330 			mem_header->ar_date,
1331 			(unsigned)mem_header->ar_uid,
1332 			(unsigned)mem_header->ar_gid,
1333 			(unsigned)mem_header->ar_mode,
1334 			mem_header->ar_size, ARFMAG);
1335 
1336 		if (write(fdartmp, mem_header_buf, sizeof (struct ar_hdr)) !=
1337 		    sizeof (struct ar_hdr)) {
1338 			error_message(WRITE_MANI_ERROR,
1339 			SYSTEM_ERROR, strerror(errno),
1340 			prog, cur_file);
1341 			mcs_exit(FAILURE);
1342 		}
1343 		if ((file_buf =
1344 		    malloc(ROUNDUP(mem_header->ar_size))) == NULL) {
1345 			error_message(MALLOC_ERROR,
1346 			PLAIN_ERROR, (char *)0,
1347 			prog);
1348 			mcs_exit(FAILURE);
1349 		}
1350 
1351 		if (lseek(fd, elf_getbase(elf), 0) != elf_getbase(elf)) {
1352 			error_message(WRITE_MANI_ERROR,
1353 			prog, cur_file);
1354 			mcs_exit(FAILURE);
1355 		}
1356 
1357 		if (read(fd, file_buf,
1358 		    (size_t)ROUNDUP(mem_header->ar_size)) !=
1359 		    (size_t)ROUNDUP(mem_header->ar_size)) {
1360 			error_message(READ_MANI_ERROR,
1361 			SYSTEM_ERROR, strerror(errno),
1362 			prog, cur_file);
1363 			mcs_exit(FAILURE);
1364 		}
1365 		if (write(fdartmp,
1366 		    file_buf,
1367 		    (size_t)ROUNDUP(mem_header->ar_size)) !=
1368 		    (size_t)ROUNDUP(mem_header->ar_size)) {
1369 			error_message(WRITE_MANI_ERROR,
1370 			SYSTEM_ERROR, strerror(errno),
1371 			prog, cur_file);
1372 			mcs_exit(FAILURE);
1373 		}
1374 		free(file_buf);
1375 	} else if (CHK_OPT(cmd_info, MIGHT_CHG)) {
1376 		error_message(SYM_TAB_AR_ERROR,
1377 		PLAIN_ERROR, (char *)0,
1378 		prog, cur_file);
1379 		error_message(EXEC_AR_ERROR,
1380 		PLAIN_ERROR, (char *)0,
1381 		cur_file);
1382 	}
1383 }
1384 
1385 static void
1386 copy_file(int ofd, char *fname, char *temp_file_name)
1387 {
1388 	int i;
1389 	int fdtmp2;
1390 	struct stat stbuf;
1391 	char *buf;
1392 
1393 	for (i = 0; signum[i]; i++) /* started writing, cannot interrupt */
1394 		(void) signal(signum[i], SIG_IGN);
1395 
1396 	if ((fdtmp2 = open(temp_file_name, O_RDONLY)) == -1) {
1397 		error_message(OPEN_TEMP_ERROR,
1398 		SYSTEM_ERROR, strerror(errno),
1399 		prog, temp_file_name);
1400 		mcs_exit(FAILURE);
1401 	}
1402 
1403 	(void) stat(temp_file_name, &stbuf); /* for size of file */
1404 
1405 	/*
1406 	 * Get the contents of the updated file.
1407 	 * First try mmap()'ing. If mmap() fails,
1408 	 * then use the malloc() and read().
1409 	 */
1410 	i = MMAP_USED;
1411 	if ((buf = (char *)mmap(0, stbuf.st_size,
1412 		PROT_READ, MAP_SHARED, fdtmp2, 0)) == (caddr_t)-1) {
1413 		if ((buf =
1414 		    malloc(stbuf.st_size * sizeof (char))) == NULL) {
1415 			error_message(MALLOC_ERROR,
1416 			PLAIN_ERROR, (char *)0,
1417 			prog);
1418 			mcs_exit(FAILURE);
1419 		}
1420 
1421 		if (read(fdtmp2, buf, stbuf.st_size) != stbuf.st_size) {
1422 			error_message(READ_SYS_ERROR,
1423 			SYSTEM_ERROR, strerror(errno),
1424 			prog, temp_file_name);
1425 			mcs_exit(FAILURE);
1426 		}
1427 		i = MMAP_UNUSED;
1428 	}
1429 
1430 	if (ftruncate(ofd, 0) == -1) {
1431 		error_message(WRITE_MANI_ERROR2,
1432 		SYSTEM_ERROR, strerror(errno),
1433 		prog, fname);
1434 		mcs_exit(FAILURE);
1435 	}
1436 	if (lseek(ofd, 0, SEEK_SET) == -1) {
1437 		error_message(WRITE_MANI_ERROR2,
1438 		SYSTEM_ERROR, strerror(errno),
1439 		prog, fname);
1440 		mcs_exit(FAILURE);
1441 	}
1442 	if ((write(ofd, buf, stbuf.st_size)) != stbuf.st_size) {
1443 		error_message(WRITE_MANI_ERROR2,
1444 		SYSTEM_ERROR, strerror(errno),
1445 		prog, fname);
1446 		mcs_exit(FAILURE);
1447 	}
1448 
1449 	/*
1450 	 * clean
1451 	 */
1452 	if (i == MMAP_USED)
1453 		(void) munmap(buf, stbuf.st_size);
1454 	else
1455 		free(buf);
1456 	(void) close(fdtmp2);
1457 	(void) unlink(temp_file_name); 	/* temp file */
1458 }
1459 
1460 static uint64_t
1461 location(int64_t offset, int mem_search, Elf * elf)
1462 {
1463 	int i;
1464 	uint64_t upper;
1465 	GElf_Ehdr ehdr;
1466 
1467 	(void) gelf_getehdr(elf, &ehdr);
1468 
1469 	for (i = 0; i < ehdr.e_phnum; i++) {
1470 		if (mem_search)
1471 			upper = b_e_seg_table[i].p_memsz;
1472 		else
1473 			upper = b_e_seg_table[i].p_filesz;
1474 		if ((offset >= b_e_seg_table[i].p_offset) &&
1475 		    (offset <= upper))
1476 			return (IN);
1477 		else if (offset < b_e_seg_table[i].p_offset)
1478 			return (PRIOR);
1479 	}
1480 	return (AFTER);
1481 }
1482 
1483 static uint64_t
1484 scn_location(Elf_Scn * scn, Elf * elf)
1485 {
1486 	GElf_Shdr shdr;
1487 
1488 	(void) gelf_getshdr(scn, &shdr);
1489 
1490 	/*
1491 	 * If the section is not a NOTE section and it has no
1492 	 * virtual address then it is not part of a mapped segment.
1493 	 */
1494 	if (shdr.sh_addr == 0)
1495 		return (location(shdr.sh_offset + shdr.sh_size, 0, elf));
1496 
1497 	return (location(shdr.sh_offset + shdr.sh_size, 1, elf));
1498 }
1499 
1500 static void
1501 initialize(int shnum, Cmd_Info *cmd_info)
1502 {
1503 	/*
1504 	 * Initialize command info
1505 	 */
1506 	cmd_info->no_of_append = cmd_info->no_of_delete =
1507 		cmd_info->no_of_nulled = cmd_info->no_of_compressed =
1508 		cmd_info->no_of_moved = 0;
1509 	cmd_info->sh_groups.head = cmd_info->sh_groups.tail = 0;
1510 
1511 	if ((sec_table = (section_info_table *)
1512 		calloc(shnum + 1,
1513 		sizeof (section_info_table))) == NULL) {
1514 		error_message(MALLOC_ERROR,
1515 		PLAIN_ERROR, (char *)0,
1516 		prog);
1517 		exit(FAILURE);
1518 	}
1519 
1520 	if ((off_table = (int64_t *)
1521 		calloc(shnum,
1522 		sizeof (int64_t))) == NULL) {
1523 		error_message(MALLOC_ERROR,
1524 		PLAIN_ERROR, (char *)0,
1525 		prog);
1526 		exit(FAILURE);
1527 	}
1528 
1529 	if ((nobits_table = (int64_t *)
1530 		calloc(shnum, sizeof (int64_t))) == NULL) {
1531 		error_message(MALLOC_ERROR,
1532 		PLAIN_ERROR, (char *)0,
1533 		prog);
1534 		exit(FAILURE);
1535 	}
1536 }
1537 
1538 /*
1539  * Update the contents of SHT_GROUP if needed
1540  */
1541 void
1542 post_process(Cmd_Info *cmd_info)
1543 {
1544 	Listnode *		lnp, *plnp;
1545 	section_info_table *	sinfo;
1546 	Word *			grpdata, *ngrpdata;
1547 	int64_t			sno, sno2;
1548 	Word			i, j, num;
1549 
1550 	/*
1551 	 * If no change is required, then return.
1552 	 */
1553 	if ((cmd_info->flags & (SHF_GROUP_MOVE|SHF_GROUP_DEL)) == 0)
1554 		return;
1555 
1556 	/*
1557 	 * If SHF_GROUP sections were removed, we might need to
1558 	 * remove SHT_GROUP sections.
1559 	 */
1560 	if (cmd_info->flags & SHF_GROUP_DEL) {
1561 		Word	grpcnt;
1562 		int	deleted = 0;
1563 
1564 		for (LIST_TRAVERSE(&cmd_info->sh_groups, lnp, sinfo)) {
1565 			if (sinfo->secno == (GElf_Word)DELETED)
1566 				continue;
1567 			num = (sinfo->shdr).sh_size/sizeof (Word);
1568 			grpcnt = 0;
1569 			grpdata = (Word *)(sinfo->data->d_buf);
1570 			for (i = 1; i < num; i++) {
1571 				if (sec_table[grpdata[i]].secno !=
1572 				    (GElf_Word)DELETED)
1573 					grpcnt++;
1574 			}
1575 
1576 			/*
1577 			 * All members in this SHT_GROUP were removed.
1578 			 * We can remove this SHT_GROUP.
1579 			 */
1580 			if (grpcnt == 0) {
1581 				sinfo->secno = (GElf_Word)DELETED;
1582 				(cmd_info->no_of_delete)++;
1583 				deleted = 1;
1584 			}
1585 		}
1586 
1587 		/*
1588 		 * If we deleted a SHT_GROUP section,
1589 		 * we need to reasign section numbers.
1590 		 */
1591 		if (deleted) {
1592 			section_info_table *sinfo;
1593 
1594 			sno = 1;
1595 			sno2 = 1;
1596 			while (sec_table[sno].scn != (Elf_Scn *)-1) {
1597 				sinfo = &sec_table[sno];
1598 				if (sinfo->secno != (GElf_Word) DELETED)
1599 					sinfo->secno = sno2++;
1600 				sno++;
1601 			}
1602 		}
1603 	}
1604 
1605 	/*
1606 	 * Now we can update data buffers of the
1607 	 * SHT_GROUP sections.
1608 	 */
1609 	plnp = 0;
1610 	for (LIST_TRAVERSE(&cmd_info->sh_groups, lnp, sinfo)) {
1611 		if (plnp)
1612 			free(plnp);
1613 		plnp = lnp;
1614 		if (sinfo->secno == (GElf_Word)DELETED)
1615 			continue;
1616 		num = (sinfo->shdr).sh_size/sizeof (Word);
1617 
1618 		/*
1619 		 * Need to generate the updated data buffer
1620 		 */
1621 		if ((sinfo->mdata = malloc(sizeof (Elf_Data))) == NULL) {
1622 			error_message(MALLOC_ERROR,
1623 			PLAIN_ERROR, (char *)0,
1624 			prog);
1625 			exit(FAILURE);
1626 		}
1627 		*(sinfo->mdata) = *(sinfo->data);
1628 		if ((ngrpdata = sinfo->mdata->d_buf =
1629 		    malloc(sinfo->data->d_size)) == NULL) {
1630 			error_message(MALLOC_ERROR,
1631 			PLAIN_ERROR, (char *)0,
1632 			prog);
1633 			exit(FAILURE);
1634 		}
1635 
1636 		grpdata = (Word *)(sinfo->data->d_buf);
1637 		ngrpdata[0] = grpdata[0];
1638 		j = 1;
1639 		for (i = 1; i < num; i++) {
1640 			if (sec_table[grpdata[i]].secno != (GElf_Word)DELETED) {
1641 				ngrpdata[j++] = sec_table[grpdata[i]].secno;
1642 			}
1643 		}
1644 		sinfo->mdata->d_size = j * sizeof (Word);
1645 		sinfo->data = sinfo->mdata;
1646 	}
1647 	if (plnp)
1648 		free(plnp);
1649 }
1650