xref: /onnv-gate/usr/src/cmd/sgs/librtld/common/dldump.c (revision 3118:7f60028f32a1)
10Sstevel@tonic-gate /*
20Sstevel@tonic-gate  * CDDL HEADER START
30Sstevel@tonic-gate  *
40Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
51618Srie  * Common Development and Distribution License (the "License").
61618Srie  * You may not use this file except in compliance with the License.
70Sstevel@tonic-gate  *
80Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
90Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
100Sstevel@tonic-gate  * See the License for the specific language governing permissions
110Sstevel@tonic-gate  * and limitations under the License.
120Sstevel@tonic-gate  *
130Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
140Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
150Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
160Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
170Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
180Sstevel@tonic-gate  *
190Sstevel@tonic-gate  * CDDL HEADER END
200Sstevel@tonic-gate  */
211618Srie 
220Sstevel@tonic-gate /*
231618Srie  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
240Sstevel@tonic-gate  * Use is subject to license terms.
250Sstevel@tonic-gate  *
260Sstevel@tonic-gate  * dldump(3c) creates a new file image from the specified input file.
270Sstevel@tonic-gate  */
280Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
290Sstevel@tonic-gate 
300Sstevel@tonic-gate #include	<sys/param.h>
310Sstevel@tonic-gate #include	<sys/procfs.h>
320Sstevel@tonic-gate #include	<fcntl.h>
330Sstevel@tonic-gate #include	<stdio.h>
340Sstevel@tonic-gate #include	<libelf.h>
350Sstevel@tonic-gate #include	<link.h>
360Sstevel@tonic-gate #include	<dlfcn.h>
370Sstevel@tonic-gate #include	<stdlib.h>
380Sstevel@tonic-gate #include	<string.h>
390Sstevel@tonic-gate #include	<unistd.h>
400Sstevel@tonic-gate #include	<errno.h>
410Sstevel@tonic-gate #include	"libld.h"
420Sstevel@tonic-gate #include	"msg.h"
430Sstevel@tonic-gate #include	"_librtld.h"
440Sstevel@tonic-gate 
450Sstevel@tonic-gate /*
460Sstevel@tonic-gate  * Generic clean up routine
470Sstevel@tonic-gate  */
480Sstevel@tonic-gate static void
cleanup(Elf * ielf,Elf * oelf,Elf * melf,Cache * icache,Cache * mcache,int fd,const char * opath)490Sstevel@tonic-gate cleanup(Elf *ielf, Elf *oelf, Elf *melf, Cache *icache, Cache *mcache,
500Sstevel@tonic-gate     int fd, const char *opath)
510Sstevel@tonic-gate {
520Sstevel@tonic-gate 	if (icache) {
530Sstevel@tonic-gate 		Cache *	_icache = icache;
540Sstevel@tonic-gate 
550Sstevel@tonic-gate 		for (++_icache; _icache->c_flags != FLG_C_END; _icache++) {
560Sstevel@tonic-gate 			if (_icache->c_info)
570Sstevel@tonic-gate 				(void) free(_icache->c_info);
580Sstevel@tonic-gate 		}
590Sstevel@tonic-gate 		(void) free((void *)icache);
600Sstevel@tonic-gate 	}
610Sstevel@tonic-gate 	if (mcache)
620Sstevel@tonic-gate 		(void) free((void *)mcache);
630Sstevel@tonic-gate 
640Sstevel@tonic-gate 	if (ielf)
650Sstevel@tonic-gate 		(void) elf_end(ielf);
660Sstevel@tonic-gate 	if (oelf)
670Sstevel@tonic-gate 		(void) elf_end(oelf);
680Sstevel@tonic-gate 	if (melf)
690Sstevel@tonic-gate 		(void) elf_end(melf);
700Sstevel@tonic-gate 	if (fd)
710Sstevel@tonic-gate 		(void) close(fd);
720Sstevel@tonic-gate 	if (opath)
730Sstevel@tonic-gate 		(void) unlink(opath);
740Sstevel@tonic-gate }
750Sstevel@tonic-gate 
760Sstevel@tonic-gate /*
770Sstevel@tonic-gate  * The dldump(3x) interface directs control to the runtime linker.  The runtime
780Sstevel@tonic-gate  * linker brings in librtld.so.1 to provide the underlying support for this
790Sstevel@tonic-gate  * call (this is because librtld.so.1 requires libelf.so.1, and the whole wad
800Sstevel@tonic-gate  * is rather expensive to drag around with ld.so.1).
810Sstevel@tonic-gate  *
820Sstevel@tonic-gate  * rt_dldump(Rt_map * lmp, const char * opath, int flags, Addr addr)
830Sstevel@tonic-gate  *
840Sstevel@tonic-gate  * lmp provides the link-map of the ipath (the input file).
850Sstevel@tonic-gate  *
860Sstevel@tonic-gate  * opath specifies the output file.
870Sstevel@tonic-gate  *
880Sstevel@tonic-gate  * flags provides a variety of options that control how the new image will be
890Sstevel@tonic-gate  * relocated (if required).
900Sstevel@tonic-gate  *
910Sstevel@tonic-gate  * addr indicates the base address at which the associated input image is mapped
920Sstevel@tonic-gate  * within the process.
930Sstevel@tonic-gate  *
940Sstevel@tonic-gate  * The modes of operation and the various flags provide a number of combinations
950Sstevel@tonic-gate  * of images that can be created, some are useful, some maybe not.  The
960Sstevel@tonic-gate  * following provide a couple of basic models for dldump(3x) use:
970Sstevel@tonic-gate  *
980Sstevel@tonic-gate  *  new executable -	dldump(0, outfile, RTLD_MEMORY)
990Sstevel@tonic-gate  *
1000Sstevel@tonic-gate  *			A dynamic executable may undergo some initialization
1010Sstevel@tonic-gate  *			and the results of this saved in a new file for later
1020Sstevel@tonic-gate  *			execution.  The executable will presumable update
1030Sstevel@tonic-gate  *			parts of its data segment and heap (note that the heap
1040Sstevel@tonic-gate  *			should be acquired using malloc() so that it follows
1050Sstevel@tonic-gate  *			the end of the data segment for this technique to be
1060Sstevel@tonic-gate  *			useful).  These updated memory elements are saved to the
1070Sstevel@tonic-gate  *			new file, including a new .SUNW_heap section if
1080Sstevel@tonic-gate  *			required.
1090Sstevel@tonic-gate  *
1100Sstevel@tonic-gate  *			For greatest flexibility, no relocated information
1110Sstevel@tonic-gate  *			should be saved (by default any relocated information is
1120Sstevel@tonic-gate  *			returned to the value it had in its original file).
1130Sstevel@tonic-gate  *			This allows the new image to bind to new dynamic objects
1140Sstevel@tonic-gate  *			when executed on the same or newer upgrades of the OS.
1150Sstevel@tonic-gate  *
1160Sstevel@tonic-gate  *			Fixing relocations by applying RTLD_REL_ALL will bind
1170Sstevel@tonic-gate  *			the image to the dependencies presently mapped as part
1180Sstevel@tonic-gate  *			of the process.  Thus the new executable will only work
1190Sstevel@tonic-gate  *			correctly when these same dependencies map to exactly
1200Sstevel@tonic-gate  *			to the same locations. (note that RTLD_REL_RELATIVE will
1210Sstevel@tonic-gate  *			have no effect as dynamic executables commonly don't
1220Sstevel@tonic-gate  *			contain any relative relocations).
1230Sstevel@tonic-gate  *
1240Sstevel@tonic-gate  *  new shared object -	dldump(infile, outfile, RTLD_REL_RELATIVE)
1250Sstevel@tonic-gate  *
1260Sstevel@tonic-gate  *			A shared object can be fixed to a known address so as
1270Sstevel@tonic-gate  *			to reduce its relocation overhead on startup.  Because
1280Sstevel@tonic-gate  *			the new file is fixed to a new base address (which is
1290Sstevel@tonic-gate  *			the address at which the object was found mapped to the
1300Sstevel@tonic-gate  *			process) it is now a dynamic executable.
1310Sstevel@tonic-gate  *
1320Sstevel@tonic-gate  *			Data changes that have occurred due to the object
1330Sstevel@tonic-gate  *			gaining control (at the least this would be .init
1340Sstevel@tonic-gate  *			processing) will not be carried over to the new image.
1350Sstevel@tonic-gate  *
1360Sstevel@tonic-gate  *			By only performing relative relocations all global
1370Sstevel@tonic-gate  *			relocations are available for unique binding to each
1380Sstevel@tonic-gate  *			process - thus interposition etc. is still available.
1390Sstevel@tonic-gate  *
1400Sstevel@tonic-gate  *			Using RTLD_REL_ALL will fix all relocations in the new
1410Sstevel@tonic-gate  *			file, which will certainly provide for faster startup
1420Sstevel@tonic-gate  *			of the new image, but at the loss of interposition
1430Sstevel@tonic-gate  *			flexibility.
1440Sstevel@tonic-gate  */
1450Sstevel@tonic-gate int
rt_dldump(Rt_map * lmp,const char * opath,int flags,Addr addr)1460Sstevel@tonic-gate rt_dldump(Rt_map *lmp, const char *opath, int flags, Addr addr)
1470Sstevel@tonic-gate {
1480Sstevel@tonic-gate 	Elf *		ielf = 0, *oelf = 0, *melf = 0;
1490Sstevel@tonic-gate 	Ehdr		*iehdr, *oehdr, *mehdr;
1500Sstevel@tonic-gate 	Phdr		*iphdr, *ophdr, *data_phdr = 0;
1510Sstevel@tonic-gate 	Cache		*icache = 0, *_icache, *mcache = 0, *_mcache;
1520Sstevel@tonic-gate 	Cache		*data_cache = 0, *dyn_cache = 0;
1530Sstevel@tonic-gate 	Xword		rel_null_no = 0, rel_data_no = 0, rel_func_no = 0;
1540Sstevel@tonic-gate 	Xword		rel_entsize;
1550Sstevel@tonic-gate 	Rel		*rel_base = 0, *rel_null, *rel_data, *rel_func;
1560Sstevel@tonic-gate 	Elf_Scn		*scn;
1570Sstevel@tonic-gate 	Shdr		*shdr;
1580Sstevel@tonic-gate 	Elf_Data	*data;
1590Sstevel@tonic-gate 	Half		endx = 1;
1600Sstevel@tonic-gate 	int		fd = 0, err, num;
1610Sstevel@tonic-gate 	size_t		shstr_size = 1;
1620Sstevel@tonic-gate 	Addr		edata;
1630Sstevel@tonic-gate 	char		*shstr, *_shstr, *ipath = NAME(lmp);
1640Sstevel@tonic-gate 	prstatus_t	*status = 0, _status;
1651618Srie 	Lm_list		*lml = LIST(lmp);
1662850Srie 	Alist		*nodirect = 0;
1670Sstevel@tonic-gate 
1680Sstevel@tonic-gate 	if (lmp == lml_main.lm_head) {
1690Sstevel@tonic-gate 		char	proc[16];
1700Sstevel@tonic-gate 		int	pfd;
1710Sstevel@tonic-gate 
1720Sstevel@tonic-gate 		/*
1730Sstevel@tonic-gate 		 * Get a /proc descriptor.
1740Sstevel@tonic-gate 		 */
1750Sstevel@tonic-gate 		(void) snprintf(proc, 16, MSG_ORIG(MSG_FMT_PROC),
1760Sstevel@tonic-gate 		    (int)getpid());
1770Sstevel@tonic-gate 		if ((pfd = open(proc, O_RDONLY)) == -1) {
1780Sstevel@tonic-gate 			err = errno;
1791618Srie 			eprintf(lml, ERR_FATAL, MSG_INTL(MSG_SYS_OPEN), proc,
1800Sstevel@tonic-gate 			    strerror(err));
1810Sstevel@tonic-gate 			return (1);
1820Sstevel@tonic-gate 		}
1830Sstevel@tonic-gate 
1840Sstevel@tonic-gate 		/*
1850Sstevel@tonic-gate 		 * If we've been asked to process the dynamic executable we
1860Sstevel@tonic-gate 		 * might not know its full path (this is prior to realpath()
1870Sstevel@tonic-gate 		 * processing becoming default), and thus use /proc to obtain a
1880Sstevel@tonic-gate 		 * file descriptor of the input file.
1890Sstevel@tonic-gate 		 */
1900Sstevel@tonic-gate 		if ((fd = ioctl(pfd, PIOCOPENM, (void *)0)) == -1) {
1910Sstevel@tonic-gate 			err = errno;
1921618Srie 			eprintf(lml, ERR_FATAL, MSG_INTL(MSG_SYS_PROC), ipath,
1930Sstevel@tonic-gate 			    strerror(err));
1940Sstevel@tonic-gate 			(void) close(pfd);
1950Sstevel@tonic-gate 			return (1);
1960Sstevel@tonic-gate 		}
1970Sstevel@tonic-gate 
1980Sstevel@tonic-gate 		/*
1990Sstevel@tonic-gate 		 * Obtain the process's status structure from which we can
2000Sstevel@tonic-gate 		 * determine the size of the process's heap.  Note, if the
2010Sstevel@tonic-gate 		 * application is using mapmalloc then the heap size is going
2020Sstevel@tonic-gate 		 * to be zero, and if we're dumping a data section that makes
2030Sstevel@tonic-gate 		 * reference to the malloc'ed area we're not going to get a
2040Sstevel@tonic-gate 		 * useful image.
2050Sstevel@tonic-gate 		 */
2060Sstevel@tonic-gate 		if (!(flags & RTLD_NOHEAP)) {
2070Sstevel@tonic-gate 			if (ioctl(pfd, PIOCSTATUS, (void *)&_status) == -1) {
2080Sstevel@tonic-gate 				err = errno;
2091618Srie 				eprintf(lml, ERR_FATAL, MSG_INTL(MSG_SYS_PROC),
2100Sstevel@tonic-gate 				    ipath, strerror(err));
2110Sstevel@tonic-gate 				(void) close(fd);
2120Sstevel@tonic-gate 				(void) close(pfd);
2130Sstevel@tonic-gate 				return (1);
2140Sstevel@tonic-gate 			}
2150Sstevel@tonic-gate 			if ((flags & RTLD_MEMORY) && _status.pr_brksize)
2160Sstevel@tonic-gate 				status = &_status;
2170Sstevel@tonic-gate 		}
2180Sstevel@tonic-gate 		(void) close(pfd);
2190Sstevel@tonic-gate 	} else {
2200Sstevel@tonic-gate 		/*
2210Sstevel@tonic-gate 		 * Open the specified file.
2220Sstevel@tonic-gate 		 */
2230Sstevel@tonic-gate 		if ((fd = open(ipath, O_RDONLY, 0)) == -1) {
2240Sstevel@tonic-gate 			err = errno;
2251618Srie 			eprintf(lml, ERR_FATAL, MSG_INTL(MSG_SYS_OPEN), ipath,
2260Sstevel@tonic-gate 			    strerror(err));
2270Sstevel@tonic-gate 			return (1);
2280Sstevel@tonic-gate 		}
2290Sstevel@tonic-gate 	}
2300Sstevel@tonic-gate 
2310Sstevel@tonic-gate 	/*
2320Sstevel@tonic-gate 	 * Initialize with the ELF library and make sure this is a suitable
2330Sstevel@tonic-gate 	 * ELF file we're dealing with.
2340Sstevel@tonic-gate 	 */
2350Sstevel@tonic-gate 	(void) elf_version(EV_CURRENT);
2360Sstevel@tonic-gate 	if ((ielf = elf_begin(fd, ELF_C_READ, NULL)) == NULL) {
2371618Srie 		eprintf(lml, ERR_ELF, MSG_ORIG(MSG_ELF_BEGIN), ipath);
2380Sstevel@tonic-gate 		cleanup(ielf, oelf, melf, icache, mcache, fd, 0);
2390Sstevel@tonic-gate 		return (1);
2400Sstevel@tonic-gate 	}
2410Sstevel@tonic-gate 	(void) close(fd);
2420Sstevel@tonic-gate 
2430Sstevel@tonic-gate 	if ((elf_kind(ielf) != ELF_K_ELF) ||
2440Sstevel@tonic-gate 	    ((iehdr = elf_getehdr(ielf)) == NULL) ||
2450Sstevel@tonic-gate 	    ((iehdr->e_type != ET_EXEC) && (iehdr->e_type != ET_DYN))) {
2461618Srie 		eprintf(lml, ERR_FATAL, MSG_INTL(MSG_IMG_ELF), ipath);
2470Sstevel@tonic-gate 		cleanup(ielf, oelf, melf, icache, mcache, 0, 0);
2480Sstevel@tonic-gate 		return (1);
2490Sstevel@tonic-gate 	}
2500Sstevel@tonic-gate 
2510Sstevel@tonic-gate 	/*
2520Sstevel@tonic-gate 	 * Make sure we can create the new output file.
2530Sstevel@tonic-gate 	 */
2540Sstevel@tonic-gate 	if ((fd = open(opath, (O_RDWR | O_CREAT | O_TRUNC), 0777)) == -1) {
2550Sstevel@tonic-gate 		err = errno;
2561618Srie 		eprintf(lml, ERR_FATAL, MSG_INTL(MSG_SYS_OPEN), opath,
2570Sstevel@tonic-gate 		    strerror(err));
2580Sstevel@tonic-gate 		cleanup(ielf, oelf, melf, icache, mcache, 0, 0);
2590Sstevel@tonic-gate 		return (1);
2600Sstevel@tonic-gate 	}
2610Sstevel@tonic-gate 	if ((oelf = elf_begin(fd, ELF_C_WRITE, NULL)) == NULL) {
2621618Srie 		eprintf(lml, ERR_ELF, MSG_ORIG(MSG_ELF_BEGIN), opath);
2630Sstevel@tonic-gate 		cleanup(ielf, oelf, melf, icache, mcache, fd, opath);
2640Sstevel@tonic-gate 		return (1);
2650Sstevel@tonic-gate 	}
2660Sstevel@tonic-gate 
2670Sstevel@tonic-gate 	/*
2680Sstevel@tonic-gate 	 * Obtain the input program headers.  Remember the last data segments
2690Sstevel@tonic-gate 	 * program header entry as this will be updated later to reflect any new
2700Sstevel@tonic-gate 	 * heap section size.
2710Sstevel@tonic-gate 	 */
2720Sstevel@tonic-gate 	if ((iphdr = elf_getphdr(ielf)) == NULL) {
2731618Srie 		eprintf(lml, ERR_ELF, MSG_ORIG(MSG_ELF_GETPHDR), ipath);
2740Sstevel@tonic-gate 		cleanup(ielf, oelf, melf, icache, mcache, fd, opath);
2750Sstevel@tonic-gate 		return (1);
2760Sstevel@tonic-gate 	}
2770Sstevel@tonic-gate 
2780Sstevel@tonic-gate 	for (num = 0, ophdr = iphdr; num != iehdr->e_phnum; num++, ophdr++) {
2790Sstevel@tonic-gate 		/*
2800Sstevel@tonic-gate 		 * Save the program header that contains the NOBITS section, or
2810Sstevel@tonic-gate 		 * the last loadable program header if no NOBITS exists.  A
2820Sstevel@tonic-gate 		 * NOBITS section translates to a memory size requirement that
2830Sstevel@tonic-gate 		 * is greater than the file data it is mapped from.  Note that
2840Sstevel@tonic-gate 		 * we inspect all headers just incase there only exist text
2850Sstevel@tonic-gate 		 * segments.
2860Sstevel@tonic-gate 		 */
2870Sstevel@tonic-gate 		if (ophdr->p_type == PT_LOAD) {
2880Sstevel@tonic-gate 			if (ophdr->p_filesz != ophdr->p_memsz)
2890Sstevel@tonic-gate 				data_phdr = ophdr;
2900Sstevel@tonic-gate 			else if (data_phdr) {
2910Sstevel@tonic-gate 				if (data_phdr->p_vaddr < ophdr->p_vaddr)
2920Sstevel@tonic-gate 					data_phdr = ophdr;
2930Sstevel@tonic-gate 			} else
2940Sstevel@tonic-gate 				data_phdr = ophdr;
2950Sstevel@tonic-gate 		}
2960Sstevel@tonic-gate 	}
2970Sstevel@tonic-gate 
2980Sstevel@tonic-gate 	/*
2990Sstevel@tonic-gate 	 * If there is no data segment, and a heap section is required,
3000Sstevel@tonic-gate 	 * warn the user and disable the heap addition (Note that you can't
3010Sstevel@tonic-gate 	 * simply append the heap to the last segment, as it might be a text
3020Sstevel@tonic-gate 	 * segment, and would therefore have the wrong permissions).
3030Sstevel@tonic-gate 	 */
3040Sstevel@tonic-gate 	if (status && !data_phdr) {
3051618Srie 		eprintf(lml, ERR_WARNING, MSG_INTL(MSG_IMG_DATASEG), ipath);
3060Sstevel@tonic-gate 		status = 0;
3070Sstevel@tonic-gate 	}
3080Sstevel@tonic-gate 
3090Sstevel@tonic-gate 	/*
3100Sstevel@tonic-gate 	 * Obtain the input files section header string table.
3110Sstevel@tonic-gate 	 */
3120Sstevel@tonic-gate 	if ((scn = elf_getscn(ielf, iehdr->e_shstrndx)) == NULL) {
3131618Srie 		eprintf(lml, ERR_ELF, MSG_ORIG(MSG_ELF_GETSCN), ipath);
3140Sstevel@tonic-gate 		cleanup(ielf, oelf, melf, icache, mcache, fd, opath);
3150Sstevel@tonic-gate 		return (1);
3160Sstevel@tonic-gate 	}
3170Sstevel@tonic-gate 	if ((data = elf_getdata(scn, NULL)) == NULL) {
3181618Srie 		eprintf(lml, ERR_ELF, MSG_ORIG(MSG_ELF_GETDATA), ipath);
3190Sstevel@tonic-gate 		cleanup(ielf, oelf, melf, icache, mcache, fd, opath);
3200Sstevel@tonic-gate 		return (1);
3210Sstevel@tonic-gate 	}
3220Sstevel@tonic-gate 	shstr = (char *)data->d_buf;
3230Sstevel@tonic-gate 
3240Sstevel@tonic-gate 	/*
3250Sstevel@tonic-gate 	 * Construct a cache to maintain the input files section information.
3260Sstevel@tonic-gate 	 * Obtain an extra cache element if a heap addition is required.  Also
3270Sstevel@tonic-gate 	 * add an additional entry (marked FLG_C_END) to make the processing of
3280Sstevel@tonic-gate 	 * this cache easier.
3290Sstevel@tonic-gate 	 */
3300Sstevel@tonic-gate 	num = iehdr->e_shnum;
3310Sstevel@tonic-gate 	if (status)
3320Sstevel@tonic-gate 		num++;
3330Sstevel@tonic-gate 	if ((icache = malloc((num + 1) * sizeof (Cache))) == 0) {
3340Sstevel@tonic-gate 		cleanup(ielf, oelf, melf, icache, mcache, fd, opath);
3350Sstevel@tonic-gate 		return (1);
3360Sstevel@tonic-gate 	}
3370Sstevel@tonic-gate 	icache[num].c_flags = FLG_C_END;
3380Sstevel@tonic-gate 
3390Sstevel@tonic-gate 	_icache = icache;
3400Sstevel@tonic-gate 	_icache++;
3410Sstevel@tonic-gate 
3420Sstevel@tonic-gate 	/*
3430Sstevel@tonic-gate 	 * Traverse each section from the input file collecting the appropriate
3440Sstevel@tonic-gate 	 * ELF information.  Indicate how the section will be processed to
3450Sstevel@tonic-gate 	 * generate the output image.
3460Sstevel@tonic-gate 	 */
3470Sstevel@tonic-gate 	for (scn = 0; scn = elf_nextscn(ielf, scn); _icache++) {
3480Sstevel@tonic-gate 
3490Sstevel@tonic-gate 		if ((_icache->c_shdr = shdr = elf_getshdr(scn)) == NULL) {
3501618Srie 			eprintf(lml, ERR_ELF, MSG_ORIG(MSG_ELF_GETSHDR), ipath);
3510Sstevel@tonic-gate 			cleanup(ielf, oelf, melf, icache, mcache, fd, opath);
3520Sstevel@tonic-gate 			return (1);
3530Sstevel@tonic-gate 		}
3540Sstevel@tonic-gate 
3550Sstevel@tonic-gate 		if ((_icache->c_data = elf_getdata(scn, NULL)) == NULL) {
3561618Srie 			eprintf(lml, ERR_ELF, MSG_ORIG(MSG_ELF_GETDATA), ipath);
3570Sstevel@tonic-gate 			cleanup(ielf, oelf, melf, icache, mcache, fd, opath);
3580Sstevel@tonic-gate 			return (1);
3590Sstevel@tonic-gate 		}
3600Sstevel@tonic-gate 		_icache->c_name = shstr + (size_t)(shdr->sh_name);
3610Sstevel@tonic-gate 		_icache->c_scn = scn;
3620Sstevel@tonic-gate 		_icache->c_flags = 0;
3630Sstevel@tonic-gate 		_icache->c_info = 0;
3640Sstevel@tonic-gate 
3650Sstevel@tonic-gate 		/*
3662850Srie 		 * Process any .SUNW_syminfo section.  Symbols that are tagged
3672850Srie 		 * as NO_DIRECT are collected, as they should not be bound to.
3682850Srie 		 */
3692850Srie 		if ((flags & ~RTLD_REL_RELATIVE) &&
3702850Srie 		    (shdr->sh_type == SHT_SUNW_syminfo)) {
3712850Srie 			if (syminfo(_icache, &nodirect)) {
3722850Srie 				cleanup(ielf, oelf, melf, icache, mcache,
3732850Srie 				    fd, opath);
3742850Srie 				return (1);
3752850Srie 			}
3762850Srie 		}
3772850Srie 
3782850Srie 		/*
3790Sstevel@tonic-gate 		 * If the section has no address it is not part of the mapped
3800Sstevel@tonic-gate 		 * image, and is unlikely to require any further processing.
3810Sstevel@tonic-gate 		 * The section header string table will be rewritten (this isn't
3820Sstevel@tonic-gate 		 * always necessary, it's only really required when relocation
3830Sstevel@tonic-gate 		 * sections are renamed or sections are stripped, but we do
3840Sstevel@tonic-gate 		 * things the same way regardless).
3850Sstevel@tonic-gate 		 */
3860Sstevel@tonic-gate 		if (shdr->sh_addr == 0) {
3870Sstevel@tonic-gate 			if ((shdr->sh_type == SHT_STRTAB) &&
3880Sstevel@tonic-gate 			    ((strcmp(_icache->c_name,
3890Sstevel@tonic-gate 			    MSG_ORIG(MSG_SCN_SHSTR))) == 0))
3900Sstevel@tonic-gate 				_icache->c_flags = FLG_C_SHSTR;
3910Sstevel@tonic-gate 			else if (flags & RTLD_STRIP) {
3920Sstevel@tonic-gate 				_icache->c_flags = FLG_C_EXCLUDE;
3930Sstevel@tonic-gate 				continue;
3940Sstevel@tonic-gate 			}
3950Sstevel@tonic-gate 		}
3960Sstevel@tonic-gate 
3970Sstevel@tonic-gate 		/*
3980Sstevel@tonic-gate 		 * Skip relocation sections for the time being, they'll be
3990Sstevel@tonic-gate 		 * analyzed after all sections have been processed.
4000Sstevel@tonic-gate 		 */
4010Sstevel@tonic-gate 		if ((shdr->sh_type == M_REL_SHT_TYPE) && shdr->sh_addr)
4020Sstevel@tonic-gate 			continue;
4030Sstevel@tonic-gate 
4040Sstevel@tonic-gate 		/*
4050Sstevel@tonic-gate 		 * Sections at this point will simply be passed through to the
4060Sstevel@tonic-gate 		 * output file.  Keep track of the section header string table
4070Sstevel@tonic-gate 		 * size.
4080Sstevel@tonic-gate 		 */
4090Sstevel@tonic-gate 		shstr_size += strlen(_icache->c_name) + 1;
4100Sstevel@tonic-gate 
4110Sstevel@tonic-gate 		/*
4120Sstevel@tonic-gate 		 * If a heap section is to be added to the output image,
4130Sstevel@tonic-gate 		 * indicate that it will be added following the last data
4140Sstevel@tonic-gate 		 * section.
4150Sstevel@tonic-gate 		 */
4160Sstevel@tonic-gate 		if (shdr->sh_addr && ((shdr->sh_addr + shdr->sh_size) ==
4170Sstevel@tonic-gate 		    (data_phdr->p_vaddr + data_phdr->p_memsz))) {
4180Sstevel@tonic-gate 			data_cache = _icache;
4190Sstevel@tonic-gate 
4200Sstevel@tonic-gate 			if (status) {
4210Sstevel@tonic-gate 				_icache++;
4220Sstevel@tonic-gate 				_icache->c_name =
4230Sstevel@tonic-gate 					(char *)MSG_ORIG(MSG_SCN_HEAP);
4240Sstevel@tonic-gate 				_icache->c_flags = FLG_C_HEAP;
4250Sstevel@tonic-gate 
4260Sstevel@tonic-gate 				_icache->c_scn = 0;
4270Sstevel@tonic-gate 				_icache->c_shdr = 0;
4280Sstevel@tonic-gate 				_icache->c_data = 0;
4290Sstevel@tonic-gate 				_icache->c_info = 0;
4300Sstevel@tonic-gate 
4310Sstevel@tonic-gate 				shstr_size += strlen(_icache->c_name) + 1;
4320Sstevel@tonic-gate 			}
4330Sstevel@tonic-gate 		}
4340Sstevel@tonic-gate 	}
4350Sstevel@tonic-gate 
4360Sstevel@tonic-gate 	/*
4370Sstevel@tonic-gate 	 * Now that we've processed all input sections count the relocation
4380Sstevel@tonic-gate 	 * entries (relocation sections need to reference their symbol tables).
4390Sstevel@tonic-gate 	 */
4400Sstevel@tonic-gate 	_icache = icache;
4410Sstevel@tonic-gate 	for (_icache++; _icache->c_flags != FLG_C_END; _icache++) {
4420Sstevel@tonic-gate 
4430Sstevel@tonic-gate 		if ((shdr = _icache->c_shdr) == 0)
4440Sstevel@tonic-gate 			continue;
4450Sstevel@tonic-gate 
4460Sstevel@tonic-gate 		/*
4470Sstevel@tonic-gate 		 * If any form of relocations are to be applied to the output
4480Sstevel@tonic-gate 		 * image determine what relocation counts exist.  These will be
4490Sstevel@tonic-gate 		 * used to reorganize (localize) the relocation records.
4500Sstevel@tonic-gate 		 */
4510Sstevel@tonic-gate 		if ((shdr->sh_type == M_REL_SHT_TYPE) && shdr->sh_addr) {
4520Sstevel@tonic-gate 			rel_entsize = shdr->sh_entsize;
4530Sstevel@tonic-gate 
4540Sstevel@tonic-gate 			if (count_reloc(icache, _icache, lmp, flags, addr,
4552850Srie 			    &rel_null_no, &rel_data_no, &rel_func_no,
4562850Srie 			    nodirect)) {
4570Sstevel@tonic-gate 				cleanup(ielf, oelf, melf, icache, mcache,
4580Sstevel@tonic-gate 				    fd, opath);
4590Sstevel@tonic-gate 				return (1);
4600Sstevel@tonic-gate 			}
4610Sstevel@tonic-gate 		}
4620Sstevel@tonic-gate 	}
4630Sstevel@tonic-gate 
4640Sstevel@tonic-gate 	/*
4650Sstevel@tonic-gate 	 * If any form of relocations are to be applied to the output image
4660Sstevel@tonic-gate 	 * then we will reorganize (localize) the relocation records.  If this
4670Sstevel@tonic-gate 	 * reorganization occurs, the relocation sections will no longer have a
4680Sstevel@tonic-gate 	 * one-to-one relationship with the section they relocate, hence we
4690Sstevel@tonic-gate 	 * rename them to a more generic name.
4700Sstevel@tonic-gate 	 */
4710Sstevel@tonic-gate 	_icache = icache;
4720Sstevel@tonic-gate 	for (_icache++; _icache->c_flags != FLG_C_END; _icache++) {
4730Sstevel@tonic-gate 
4740Sstevel@tonic-gate 		if ((shdr = _icache->c_shdr) == 0)
4750Sstevel@tonic-gate 			continue;
4760Sstevel@tonic-gate 
4770Sstevel@tonic-gate 		if ((shdr->sh_type == M_REL_SHT_TYPE) && shdr->sh_addr) {
4780Sstevel@tonic-gate 			if (rel_null_no) {
4790Sstevel@tonic-gate 				_icache->c_flags = FLG_C_RELOC;
4800Sstevel@tonic-gate 				_icache->c_name =
4810Sstevel@tonic-gate 				    (char *)MSG_ORIG(MSG_SCN_RELOC);
4820Sstevel@tonic-gate 			}
4830Sstevel@tonic-gate 			shstr_size += strlen(_icache->c_name) + 1;
4840Sstevel@tonic-gate 		}
4850Sstevel@tonic-gate 	}
4860Sstevel@tonic-gate 
4870Sstevel@tonic-gate 
4880Sstevel@tonic-gate 	/*
4890Sstevel@tonic-gate 	 * If there is no data section, and a heap is required, warn the user
4900Sstevel@tonic-gate 	 * and disable the heap addition.
4910Sstevel@tonic-gate 	 */
4920Sstevel@tonic-gate 	if (!data_cache) {
4931618Srie 		eprintf(lml, ERR_WARNING, MSG_INTL(MSG_IMG_DATASEC), ipath);
4940Sstevel@tonic-gate 		status = 0;
4950Sstevel@tonic-gate 		endx = 0;
4960Sstevel@tonic-gate 	}
4970Sstevel@tonic-gate 
4980Sstevel@tonic-gate 	/*
4990Sstevel@tonic-gate 	 * Determine the value of _edata (which will also be _end) and its
5000Sstevel@tonic-gate 	 * section index for updating the data segments phdr and symbol table
5010Sstevel@tonic-gate 	 * information later.  If a new heap section is being added, update
5020Sstevel@tonic-gate 	 * the values appropriately.
5030Sstevel@tonic-gate 	 */
5040Sstevel@tonic-gate 	edata = data_phdr->p_vaddr + data_phdr->p_memsz;
5050Sstevel@tonic-gate 	if (status)
5060Sstevel@tonic-gate 		edata += status->pr_brksize;
5070Sstevel@tonic-gate 
5080Sstevel@tonic-gate 	if (endx) {
5090Sstevel@tonic-gate 		/* LINTED */
5100Sstevel@tonic-gate 		endx = (Half)elf_ndxscn(data_cache->c_scn);
5110Sstevel@tonic-gate 		if (status)
5120Sstevel@tonic-gate 			endx++;
5130Sstevel@tonic-gate 	}
5140Sstevel@tonic-gate 
5150Sstevel@tonic-gate 	/*
5160Sstevel@tonic-gate 	 * We're now ready to construct the new elf image.
5170Sstevel@tonic-gate 	 *
5180Sstevel@tonic-gate 	 * Obtain a new elf header and initialize it with any basic information
5190Sstevel@tonic-gate 	 * that isn't calculated as part of elf_update().
5200Sstevel@tonic-gate 	 */
5210Sstevel@tonic-gate 	if ((oehdr = elf_newehdr(oelf)) == NULL) {
5221618Srie 		eprintf(lml, ERR_ELF, MSG_ORIG(MSG_ELF_NEWEHDR), opath);
5230Sstevel@tonic-gate 		cleanup(ielf, oelf, melf, icache, mcache, fd, opath);
5240Sstevel@tonic-gate 		return (1);
5250Sstevel@tonic-gate 	}
5260Sstevel@tonic-gate 	oehdr->e_machine = iehdr->e_machine;
5270Sstevel@tonic-gate 	oehdr->e_flags = iehdr->e_flags;
5280Sstevel@tonic-gate 	oehdr->e_type = ET_EXEC;
5290Sstevel@tonic-gate 	oehdr->e_entry = iehdr->e_entry;
5300Sstevel@tonic-gate 	if (addr)
5310Sstevel@tonic-gate 		oehdr->e_entry += addr;
5320Sstevel@tonic-gate 
5330Sstevel@tonic-gate 	/*
5340Sstevel@tonic-gate 	 * Obtain a new set of program headers.  Initialize these with the same
5350Sstevel@tonic-gate 	 * information as the input program headers.  Update the virtual address
5360Sstevel@tonic-gate 	 * and the data segments size to reflect any new heap section.
5370Sstevel@tonic-gate 	 */
5380Sstevel@tonic-gate 	if ((ophdr = elf_newphdr(oelf, iehdr->e_phnum)) == NULL) {
5391618Srie 		eprintf(lml, ERR_ELF, MSG_ORIG(MSG_ELF_NEWPHDR), opath);
5400Sstevel@tonic-gate 		cleanup(ielf, oelf, melf, icache, mcache, fd, opath);
5410Sstevel@tonic-gate 		return (1);
5420Sstevel@tonic-gate 	}
5430Sstevel@tonic-gate 	for (num = 0; num != iehdr->e_phnum; num++, iphdr++, ophdr++) {
5440Sstevel@tonic-gate 		*ophdr = *iphdr;
5450Sstevel@tonic-gate 		if ((ophdr->p_type != PT_INTERP) && (ophdr->p_type != PT_NOTE))
5460Sstevel@tonic-gate 			ophdr->p_vaddr += addr;
5470Sstevel@tonic-gate 		if (data_phdr == iphdr) {
5480Sstevel@tonic-gate 			if (status)
5490Sstevel@tonic-gate 				ophdr->p_memsz = edata - ophdr->p_vaddr;
5500Sstevel@tonic-gate 			ophdr->p_filesz = ophdr->p_memsz;
5510Sstevel@tonic-gate 		}
5520Sstevel@tonic-gate 	}
5530Sstevel@tonic-gate 
5540Sstevel@tonic-gate 	/*
5550Sstevel@tonic-gate 	 * Establish a buffer for the new section header string table.  This
5560Sstevel@tonic-gate 	 * will be filled in as each new section is created.
5570Sstevel@tonic-gate 	 */
5580Sstevel@tonic-gate 	if ((shstr = malloc(shstr_size)) == 0) {
5590Sstevel@tonic-gate 		cleanup(ielf, oelf, melf, icache, mcache, fd, opath);
5600Sstevel@tonic-gate 		return (1);
5610Sstevel@tonic-gate 	}
5620Sstevel@tonic-gate 	_shstr = shstr;
5630Sstevel@tonic-gate 	*_shstr++ = '\0';
5640Sstevel@tonic-gate 
5650Sstevel@tonic-gate 	/*
5660Sstevel@tonic-gate 	 * Use the input files cache information to generate new sections.
5670Sstevel@tonic-gate 	 */
5680Sstevel@tonic-gate 	_icache = icache;
5690Sstevel@tonic-gate 	for (_icache++; _icache->c_flags != FLG_C_END; _icache++) {
5700Sstevel@tonic-gate 		/*
5710Sstevel@tonic-gate 		 * Skip any excluded sections.
5720Sstevel@tonic-gate 		 */
5730Sstevel@tonic-gate 		if (_icache->c_flags == FLG_C_EXCLUDE)
5740Sstevel@tonic-gate 			continue;
5750Sstevel@tonic-gate 
5760Sstevel@tonic-gate 		/*
5770Sstevel@tonic-gate 		 * Create a matching section header in the output file.
5780Sstevel@tonic-gate 		 */
5790Sstevel@tonic-gate 		if ((scn = elf_newscn(oelf)) == NULL) {
5801618Srie 			eprintf(lml, ERR_ELF, MSG_ORIG(MSG_ELF_NEWSCN), opath);
5810Sstevel@tonic-gate 			cleanup(ielf, oelf, melf, icache, mcache, fd, opath);
5820Sstevel@tonic-gate 			return (1);
5830Sstevel@tonic-gate 		}
5840Sstevel@tonic-gate 		if ((shdr = elf_getshdr(scn)) == NULL) {
5851618Srie 			eprintf(lml, ERR_ELF, MSG_ORIG(MSG_ELF_NEWSHDR), opath);
5860Sstevel@tonic-gate 			cleanup(ielf, oelf, melf, icache, mcache, fd, opath);
5870Sstevel@tonic-gate 			return (1);
5880Sstevel@tonic-gate 		}
5890Sstevel@tonic-gate 
5900Sstevel@tonic-gate 		/*
5910Sstevel@tonic-gate 		 * If this is the heap section initialize the appropriate
5920Sstevel@tonic-gate 		 * entries, otherwise simply use the original section header
5930Sstevel@tonic-gate 		 * information.
5940Sstevel@tonic-gate 		 */
5950Sstevel@tonic-gate 		if (_icache->c_flags == FLG_C_HEAP) {
5960Sstevel@tonic-gate 			shdr->sh_type = SHT_PROGBITS;
5970Sstevel@tonic-gate 			shdr->sh_flags = SHF_ALLOC | SHF_WRITE;
5980Sstevel@tonic-gate 		} else
5990Sstevel@tonic-gate 			*shdr = *_icache->c_shdr;
6000Sstevel@tonic-gate 
6010Sstevel@tonic-gate 		/*
6020Sstevel@tonic-gate 		 * Create a matching data buffer for this section.
6030Sstevel@tonic-gate 		 */
6040Sstevel@tonic-gate 		if ((data = elf_newdata(scn)) == NULL) {
6051618Srie 			eprintf(lml, ERR_ELF, MSG_ORIG(MSG_ELF_NEWDATA), opath);
6060Sstevel@tonic-gate 			cleanup(ielf, oelf, melf, icache, mcache, fd, opath);
6070Sstevel@tonic-gate 			return (1);
6080Sstevel@tonic-gate 		}
6090Sstevel@tonic-gate 
6100Sstevel@tonic-gate 		/*
6110Sstevel@tonic-gate 		 * Determine what data will be used for this section.
6120Sstevel@tonic-gate 		 */
6130Sstevel@tonic-gate 		if (_icache->c_flags == FLG_C_SHSTR) {
6140Sstevel@tonic-gate 			/*
6150Sstevel@tonic-gate 			 * Reassign the shstrtab to the new data buffer we're
6160Sstevel@tonic-gate 			 * creating.  Insure that the new elf header references
6170Sstevel@tonic-gate 			 * this section header table.
6180Sstevel@tonic-gate 			 */
6190Sstevel@tonic-gate 			*data = *_icache->c_data;
6200Sstevel@tonic-gate 
6210Sstevel@tonic-gate 			data->d_buf = (void *)shstr;
6220Sstevel@tonic-gate 			data->d_size = shstr_size;
6230Sstevel@tonic-gate 
6240Sstevel@tonic-gate 			_icache->c_info = shstr;
6250Sstevel@tonic-gate 
6260Sstevel@tonic-gate 			/* LINTED */
6270Sstevel@tonic-gate 			oehdr->e_shstrndx = (Half)elf_ndxscn(scn);
6280Sstevel@tonic-gate 
6290Sstevel@tonic-gate 		} else if (_icache->c_flags == FLG_C_HEAP) {
6300Sstevel@tonic-gate 			/*
6310Sstevel@tonic-gate 			 * Assign the heap to the appropriate memory offset.
6320Sstevel@tonic-gate 			 */
6330Sstevel@tonic-gate 			data->d_buf = status->pr_brkbase;
6340Sstevel@tonic-gate 			data->d_type = ELF_T_BYTE;
6350Sstevel@tonic-gate 			data->d_size = (size_t)status->pr_brksize;
6360Sstevel@tonic-gate 			data->d_off = 0;
6370Sstevel@tonic-gate 			data->d_align = 1;
6380Sstevel@tonic-gate 			data->d_version = EV_CURRENT;
6390Sstevel@tonic-gate 
6400Sstevel@tonic-gate 			shdr->sh_addr = data_cache->c_shdr->sh_addr +
6410Sstevel@tonic-gate 			    data_cache->c_shdr->sh_size;
6420Sstevel@tonic-gate 
6430Sstevel@tonic-gate 		} else if (_icache->c_flags == FLG_C_RELOC) {
6440Sstevel@tonic-gate 			/*
6450Sstevel@tonic-gate 			 * If some relocations are to be saved in the new image
6460Sstevel@tonic-gate 			 * then the relocation sections will be reorganized to
6470Sstevel@tonic-gate 			 * localize their contents.  These relocation sections
6480Sstevel@tonic-gate 			 * will no longer have a one-to-one relationship with
6490Sstevel@tonic-gate 			 * the section they relocate, hence we rename them and
6500Sstevel@tonic-gate 			 * remove their sh_info info.
6510Sstevel@tonic-gate 			 */
6520Sstevel@tonic-gate 			*data = *_icache->c_data;
6530Sstevel@tonic-gate 
6540Sstevel@tonic-gate 			shdr->sh_info = 0;
6550Sstevel@tonic-gate 
6560Sstevel@tonic-gate 		} else {
6570Sstevel@tonic-gate 			/*
6580Sstevel@tonic-gate 			 * By default simply pass the section through.  If
6590Sstevel@tonic-gate 			 * we've been asked to use the memory image of the
6600Sstevel@tonic-gate 			 * input file reestablish the data buffer address.
6610Sstevel@tonic-gate 			 */
6620Sstevel@tonic-gate 			*data = *_icache->c_data;
6630Sstevel@tonic-gate 
6640Sstevel@tonic-gate 			if ((shdr->sh_addr) && (flags & RTLD_MEMORY))
6650Sstevel@tonic-gate 				data->d_buf = (void *)(shdr->sh_addr + addr);
6660Sstevel@tonic-gate 
6670Sstevel@tonic-gate 			/*
6680Sstevel@tonic-gate 			 * Update any NOBITS section to indicate that it now
6690Sstevel@tonic-gate 			 * contains data.  If this image is being created
6700Sstevel@tonic-gate 			 * directly from the input file, zero out the .bss
6710Sstevel@tonic-gate 			 * section (this saves ld.so.1 having to zero out memory
6720Sstevel@tonic-gate 			 * or do any /dev/zero mappings).
6730Sstevel@tonic-gate 			 */
6740Sstevel@tonic-gate 			if (shdr->sh_type == SHT_NOBITS) {
6750Sstevel@tonic-gate 				shdr->sh_type = SHT_PROGBITS;
6760Sstevel@tonic-gate 				if (!(flags & RTLD_MEMORY)) {
6770Sstevel@tonic-gate 					if ((data->d_buf = calloc(1,
6780Sstevel@tonic-gate 					    data->d_size)) == 0) {
6790Sstevel@tonic-gate 						cleanup(ielf, oelf, melf,
6800Sstevel@tonic-gate 						    icache, mcache, fd, opath);
6810Sstevel@tonic-gate 						return (1);
6820Sstevel@tonic-gate 					}
6830Sstevel@tonic-gate 				}
6840Sstevel@tonic-gate 			}
6850Sstevel@tonic-gate 		}
6860Sstevel@tonic-gate 
6870Sstevel@tonic-gate 		/*
6880Sstevel@tonic-gate 		 * Update the section header string table.
6890Sstevel@tonic-gate 		 */
6900Sstevel@tonic-gate 		/* LINTED */
6910Sstevel@tonic-gate 		shdr->sh_name = (Word)(_shstr - shstr);
6920Sstevel@tonic-gate 		(void) strcpy(_shstr, _icache->c_name);
6930Sstevel@tonic-gate 		_shstr = _shstr + strlen(_icache->c_name) + 1;
6940Sstevel@tonic-gate 
6950Sstevel@tonic-gate 		/*
6960Sstevel@tonic-gate 		 * For each section that has a virtual address update its
6970Sstevel@tonic-gate 		 * address to the fixed location of the new image.
6980Sstevel@tonic-gate 		 */
6990Sstevel@tonic-gate 		if (shdr->sh_addr)
7000Sstevel@tonic-gate 			shdr->sh_addr += addr;
7010Sstevel@tonic-gate 
7020Sstevel@tonic-gate 		/*
7030Sstevel@tonic-gate 		 * If we've inserted a new section any later sections may need
7040Sstevel@tonic-gate 		 * their sh_link fields updated (.stabs comes to mind).
7050Sstevel@tonic-gate 		 */
7060Sstevel@tonic-gate 		if (status && endx && (shdr->sh_link >= endx))
7070Sstevel@tonic-gate 			shdr->sh_link++;
7080Sstevel@tonic-gate 	}
7090Sstevel@tonic-gate 
7100Sstevel@tonic-gate 	/*
7110Sstevel@tonic-gate 	 * Generate the new image, and obtain a new elf descriptor that will
7120Sstevel@tonic-gate 	 * allow us to write and update the new image.
7130Sstevel@tonic-gate 	 */
7140Sstevel@tonic-gate 	if (elf_update(oelf, ELF_C_WRIMAGE) == -1) {
7151618Srie 		eprintf(lml, ERR_ELF, MSG_ORIG(MSG_ELF_UPDATE), opath);
7160Sstevel@tonic-gate 		cleanup(ielf, oelf, melf, icache, mcache, fd, opath);
7170Sstevel@tonic-gate 		return (1);
7180Sstevel@tonic-gate 	}
7190Sstevel@tonic-gate 	if ((melf = elf_begin(0, ELF_C_IMAGE, oelf)) == NULL) {
7201618Srie 		eprintf(lml, ERR_ELF, MSG_ORIG(MSG_ELF_BEGIN), opath);
7210Sstevel@tonic-gate 		cleanup(ielf, oelf, melf, icache, mcache, fd, opath);
7220Sstevel@tonic-gate 		return (1);
7230Sstevel@tonic-gate 	}
7240Sstevel@tonic-gate 	if ((mehdr = elf_getehdr(melf)) == NULL) {
7251618Srie 		eprintf(lml, ERR_ELF, MSG_ORIG(MSG_ELF_GETEHDR), opath);
7260Sstevel@tonic-gate 		cleanup(ielf, oelf, melf, icache, mcache, fd, opath);
7270Sstevel@tonic-gate 		return (1);
7280Sstevel@tonic-gate 	}
7290Sstevel@tonic-gate 
7300Sstevel@tonic-gate 	/*
7310Sstevel@tonic-gate 	 * Construct a cache to maintain the memory files section information.
7320Sstevel@tonic-gate 	 */
7330Sstevel@tonic-gate 	if ((mcache = malloc(mehdr->e_shnum * sizeof (Cache))) == 0) {
7340Sstevel@tonic-gate 		cleanup(ielf, oelf, melf, icache, mcache, fd, opath);
7350Sstevel@tonic-gate 		return (1);
7360Sstevel@tonic-gate 	}
7370Sstevel@tonic-gate 	_mcache = mcache;
7380Sstevel@tonic-gate 	_mcache++;
7390Sstevel@tonic-gate 
7400Sstevel@tonic-gate 	for (scn = 0; scn = elf_nextscn(melf, scn); _mcache++) {
7410Sstevel@tonic-gate 
7420Sstevel@tonic-gate 		if ((_mcache->c_shdr = elf_getshdr(scn)) == NULL) {
7431618Srie 			eprintf(lml, ERR_ELF, MSG_ORIG(MSG_ELF_GETSHDR), opath);
7440Sstevel@tonic-gate 			cleanup(ielf, oelf, melf, icache, mcache, fd, opath);
7450Sstevel@tonic-gate 			return (1);
7460Sstevel@tonic-gate 		}
7470Sstevel@tonic-gate 
7480Sstevel@tonic-gate 		if ((_mcache->c_data = elf_getdata(scn, NULL)) == NULL) {
7491618Srie 			eprintf(lml, ERR_ELF, MSG_ORIG(MSG_ELF_GETDATA), opath);
7500Sstevel@tonic-gate 			cleanup(ielf, oelf, melf, icache, mcache, fd, opath);
7510Sstevel@tonic-gate 			return (1);
7520Sstevel@tonic-gate 		}
7530Sstevel@tonic-gate 	}
7540Sstevel@tonic-gate 
7550Sstevel@tonic-gate 	/*
7560Sstevel@tonic-gate 	 * Now that we have a complete description of the new image update any
7570Sstevel@tonic-gate 	 * sections that are required.
7580Sstevel@tonic-gate 	 *
7590Sstevel@tonic-gate 	 *  o	reset any symbol table entries.
7600Sstevel@tonic-gate 	 *
7610Sstevel@tonic-gate 	 *  o	reset any relocation entries.
7620Sstevel@tonic-gate 	 *
7630Sstevel@tonic-gate 	 *  o	reset dynamic entries.
7640Sstevel@tonic-gate 	 */
7650Sstevel@tonic-gate 	_mcache = &mcache[0];
7660Sstevel@tonic-gate 	for (_icache = &icache[1]; _icache->c_flags != FLG_C_END; _icache++) {
7670Sstevel@tonic-gate 
7680Sstevel@tonic-gate 		if (_icache->c_flags == FLG_C_EXCLUDE)
7690Sstevel@tonic-gate 			continue;
7700Sstevel@tonic-gate 
7710Sstevel@tonic-gate 		_mcache++;
7720Sstevel@tonic-gate 		shdr = _mcache->c_shdr;
7730Sstevel@tonic-gate 
7740Sstevel@tonic-gate 		/*
7750Sstevel@tonic-gate 		 * Update the symbol table entries.  _end and _edata will be
7760Sstevel@tonic-gate 		 * changed to reflect any heap addition.  All global symbols
7770Sstevel@tonic-gate 		 * will be updated to their new fixed address.
7780Sstevel@tonic-gate 		 */
7790Sstevel@tonic-gate 		if ((shdr->sh_type == SHT_SYMTAB) ||
780*3118Sab196087 		    (shdr->sh_type == SHT_DYNSYM) ||
781*3118Sab196087 		    (shdr->sh_type == SHT_SUNW_LDYNSYM)) {
7820Sstevel@tonic-gate 			update_sym(mcache, _mcache, edata, endx, addr);
7830Sstevel@tonic-gate 			continue;
7840Sstevel@tonic-gate 		}
7850Sstevel@tonic-gate 
7860Sstevel@tonic-gate 		/*
7870Sstevel@tonic-gate 		 * Update any relocations.  All relocation requirements will
7880Sstevel@tonic-gate 		 * have been established in count_reloc().
7890Sstevel@tonic-gate 		 */
7900Sstevel@tonic-gate 		if (shdr->sh_type == M_REL_SHT_TYPE) {
7910Sstevel@tonic-gate 			if (rel_base == (Rel *)0) {
7920Sstevel@tonic-gate 				rel_base = (Rel *)_mcache->c_data->d_buf;
7930Sstevel@tonic-gate 				rel_null = rel_base;
7940Sstevel@tonic-gate 				rel_data = (Rel *)((Xword)rel_null +
7950Sstevel@tonic-gate 				    (rel_null_no * rel_entsize));
7960Sstevel@tonic-gate 				rel_func = (Rel *)((Xword)rel_data +
7970Sstevel@tonic-gate 				    (rel_data_no * rel_entsize));
7980Sstevel@tonic-gate 			}
7990Sstevel@tonic-gate 
8000Sstevel@tonic-gate 			update_reloc(mcache, icache, _icache, opath, lmp,
8010Sstevel@tonic-gate 			    &rel_null, &rel_data, &rel_func);
8020Sstevel@tonic-gate 			continue;
8030Sstevel@tonic-gate 		}
8040Sstevel@tonic-gate 
8050Sstevel@tonic-gate 		/*
8060Sstevel@tonic-gate 		 * Perform any dynamic entry updates after all relocation
8070Sstevel@tonic-gate 		 * processing has been carried out (as its possible the .dynamic
8080Sstevel@tonic-gate 		 * section could occur before the .rel sections, delay this
8090Sstevel@tonic-gate 		 * processing until last).
8100Sstevel@tonic-gate 		 */
8110Sstevel@tonic-gate 		if (shdr->sh_type == SHT_DYNAMIC)
8120Sstevel@tonic-gate 			dyn_cache = _mcache;
8130Sstevel@tonic-gate 	}
8140Sstevel@tonic-gate 
8150Sstevel@tonic-gate 	if (dyn_cache) {
8160Sstevel@tonic-gate 		Xword	off = (Xword)rel_base - (Xword)mehdr;
8170Sstevel@tonic-gate 
8180Sstevel@tonic-gate 		/*
8190Sstevel@tonic-gate 		 * If we're dumping a fixed object (typically the dynamic
8200Sstevel@tonic-gate 		 * executable) compensate for its real base address.
8210Sstevel@tonic-gate 		 */
8220Sstevel@tonic-gate 		if (!addr)
8230Sstevel@tonic-gate 			off += ADDR(lmp);
8240Sstevel@tonic-gate 
8250Sstevel@tonic-gate 		if (update_dynamic(mcache, dyn_cache, lmp, flags, addr, off,
8260Sstevel@tonic-gate 		    opath, rel_null_no, rel_data_no, rel_func_no, rel_entsize,
8270Sstevel@tonic-gate 		    elf_checksum(melf))) {
8280Sstevel@tonic-gate 			cleanup(ielf, oelf, melf, icache, mcache, fd, opath);
8290Sstevel@tonic-gate 			return (1);
8300Sstevel@tonic-gate 		}
8310Sstevel@tonic-gate 	}
8320Sstevel@tonic-gate 
8330Sstevel@tonic-gate 	/*
8340Sstevel@tonic-gate 	 * Having completed all section updates write the memory file out.
8350Sstevel@tonic-gate 	 */
8360Sstevel@tonic-gate 	if (elf_update(oelf, ELF_C_WRITE) == -1) {
8371618Srie 		eprintf(lml, ERR_ELF, MSG_ORIG(MSG_ELF_UPDATE), opath);
8380Sstevel@tonic-gate 		cleanup(ielf, oelf, melf, icache, mcache, fd, opath);
8390Sstevel@tonic-gate 		return (1);
8400Sstevel@tonic-gate 	}
8410Sstevel@tonic-gate 
8420Sstevel@tonic-gate 	cleanup(ielf, oelf, melf, icache, mcache, fd, 0);
8430Sstevel@tonic-gate 	return (0);
8440Sstevel@tonic-gate }
845