xref: /freebsd/contrib/elftoolchain/libelf/elf_update.c (revision cf781b2e16c26535788abe648f5917f4db09c123)
12de3b87aSKai Wang /*-
22de3b87aSKai Wang  * Copyright (c) 2006-2011 Joseph Koshy
32de3b87aSKai Wang  * All rights reserved.
42de3b87aSKai Wang  *
52de3b87aSKai Wang  * Redistribution and use in source and binary forms, with or without
62de3b87aSKai Wang  * modification, are permitted provided that the following conditions
72de3b87aSKai Wang  * are met:
82de3b87aSKai Wang  * 1. Redistributions of source code must retain the above copyright
92de3b87aSKai Wang  *    notice, this list of conditions and the following disclaimer.
102de3b87aSKai Wang  * 2. Redistributions in binary form must reproduce the above copyright
112de3b87aSKai Wang  *    notice, this list of conditions and the following disclaimer in the
122de3b87aSKai Wang  *    documentation and/or other materials provided with the distribution.
132de3b87aSKai Wang  *
142de3b87aSKai Wang  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
152de3b87aSKai Wang  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
162de3b87aSKai Wang  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
172de3b87aSKai Wang  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
182de3b87aSKai Wang  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
192de3b87aSKai Wang  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
202de3b87aSKai Wang  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
212de3b87aSKai Wang  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
222de3b87aSKai Wang  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
232de3b87aSKai Wang  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
242de3b87aSKai Wang  * SUCH DAMAGE.
252de3b87aSKai Wang  */
262de3b87aSKai Wang 
272de3b87aSKai Wang #include <sys/param.h>
282de3b87aSKai Wang #include <sys/stat.h>
292de3b87aSKai Wang 
302de3b87aSKai Wang #include <assert.h>
312de3b87aSKai Wang #include <errno.h>
322de3b87aSKai Wang #include <gelf.h>
332de3b87aSKai Wang #include <libelf.h>
342de3b87aSKai Wang #include <stdlib.h>
352de3b87aSKai Wang #include <string.h>
362de3b87aSKai Wang #include <unistd.h>
372de3b87aSKai Wang 
382de3b87aSKai Wang #include "_libelf.h"
392de3b87aSKai Wang 
402de3b87aSKai Wang #if	ELFTC_HAVE_MMAP
412de3b87aSKai Wang #include <sys/mman.h>
422de3b87aSKai Wang #endif
432de3b87aSKai Wang 
44*cf781b2eSEd Maste ELFTC_VCSID("$Id: elf_update.c 3013 2014-03-23 06:16:59Z jkoshy $");
452de3b87aSKai Wang 
462de3b87aSKai Wang /*
472de3b87aSKai Wang  * Layout strategy:
482de3b87aSKai Wang  *
492de3b87aSKai Wang  * - Case 1: ELF_F_LAYOUT is asserted
502de3b87aSKai Wang  *     In this case the application has full control over where the
512de3b87aSKai Wang  *     section header table, program header table, and section data
522de3b87aSKai Wang  *     will reside.   The library only perform error checks.
532de3b87aSKai Wang  *
542de3b87aSKai Wang  * - Case 2: ELF_F_LAYOUT is not asserted
552de3b87aSKai Wang  *
562de3b87aSKai Wang  *     The library will do the object layout using the following
572de3b87aSKai Wang  *     ordering:
582de3b87aSKai Wang  *     - The executable header is placed first, are required by the
592de3b87aSKai Wang  *     	 ELF specification.
602de3b87aSKai Wang  *     - The program header table is placed immediately following the
612de3b87aSKai Wang  *       executable header.
622de3b87aSKai Wang  *     - Section data, if any, is placed after the program header
632de3b87aSKai Wang  *       table, aligned appropriately.
642de3b87aSKai Wang  *     - The section header table, if needed, is placed last.
652de3b87aSKai Wang  *
662de3b87aSKai Wang  *     There are two sub-cases to be taken care of:
672de3b87aSKai Wang  *
682de3b87aSKai Wang  *     - Case 2a: e->e_cmd == ELF_C_READ or ELF_C_RDWR
692de3b87aSKai Wang  *
702de3b87aSKai Wang  *       In this sub-case, the underlying ELF object may already have
712de3b87aSKai Wang  *       content in it, which the application may have modified.  The
722de3b87aSKai Wang  *       library will retrieve content from the existing object as
732de3b87aSKai Wang  *       needed.
742de3b87aSKai Wang  *
752de3b87aSKai Wang  *     - Case 2b: e->e_cmd == ELF_C_WRITE
762de3b87aSKai Wang  *
772de3b87aSKai Wang  *       The ELF object is being created afresh in this sub-case;
782de3b87aSKai Wang  *       there is no pre-existing content in the underlying ELF
792de3b87aSKai Wang  *       object.
802de3b87aSKai Wang  */
812de3b87aSKai Wang 
822de3b87aSKai Wang /*
832de3b87aSKai Wang  * The types of extents in an ELF object.
842de3b87aSKai Wang  */
852de3b87aSKai Wang enum elf_extent {
862de3b87aSKai Wang 	ELF_EXTENT_EHDR,
872de3b87aSKai Wang 	ELF_EXTENT_PHDR,
882de3b87aSKai Wang 	ELF_EXTENT_SECTION,
892de3b87aSKai Wang 	ELF_EXTENT_SHDR
902de3b87aSKai Wang };
912de3b87aSKai Wang 
922de3b87aSKai Wang /*
932de3b87aSKai Wang  * A extent descriptor, used when laying out an ELF object.
942de3b87aSKai Wang  */
952de3b87aSKai Wang struct _Elf_Extent {
962de3b87aSKai Wang 	SLIST_ENTRY(_Elf_Extent) ex_next;
972de3b87aSKai Wang 	uint64_t	ex_start; /* Start of the region. */
982de3b87aSKai Wang 	uint64_t	ex_size;  /* The size of the region. */
992de3b87aSKai Wang 	enum elf_extent	ex_type;  /* Type of region. */
1002de3b87aSKai Wang 	void		*ex_desc; /* Associated descriptor. */
1012de3b87aSKai Wang };
1022de3b87aSKai Wang 
1032de3b87aSKai Wang SLIST_HEAD(_Elf_Extent_List, _Elf_Extent);
1042de3b87aSKai Wang 
1052de3b87aSKai Wang /*
1062de3b87aSKai Wang  * Compute the extents of a section, by looking at the data
1072de3b87aSKai Wang  * descriptors associated with it.  The function returns 1
1082de3b87aSKai Wang  * if successful, or zero if an error was detected.
1092de3b87aSKai Wang  */
1102de3b87aSKai Wang static int
1112de3b87aSKai Wang _libelf_compute_section_extents(Elf *e, Elf_Scn *s, off_t rc)
1122de3b87aSKai Wang {
1132de3b87aSKai Wang 	Elf_Data *d;
1142de3b87aSKai Wang 	size_t fsz, msz;
115*cf781b2eSEd Maste 	int ec, elftype;
1162de3b87aSKai Wang 	uint32_t sh_type;
1172de3b87aSKai Wang 	uint64_t d_align;
1182de3b87aSKai Wang 	Elf32_Shdr *shdr32;
1192de3b87aSKai Wang 	Elf64_Shdr *shdr64;
1202de3b87aSKai Wang 	struct _Libelf_Data *ld;
1212de3b87aSKai Wang 	uint64_t scn_size, scn_alignment;
1222de3b87aSKai Wang 	uint64_t sh_align, sh_entsize, sh_offset, sh_size;
1232de3b87aSKai Wang 
1242de3b87aSKai Wang 	ec = e->e_class;
1252de3b87aSKai Wang 
1262de3b87aSKai Wang 	shdr32 = &s->s_shdr.s_shdr32;
1272de3b87aSKai Wang 	shdr64 = &s->s_shdr.s_shdr64;
1282de3b87aSKai Wang 	if (ec == ELFCLASS32) {
1292de3b87aSKai Wang 		sh_type    = shdr32->sh_type;
1302de3b87aSKai Wang 		sh_align   = (uint64_t) shdr32->sh_addralign;
1312de3b87aSKai Wang 		sh_entsize = (uint64_t) shdr32->sh_entsize;
1322de3b87aSKai Wang 		sh_offset  = (uint64_t) shdr32->sh_offset;
1332de3b87aSKai Wang 		sh_size    = (uint64_t) shdr32->sh_size;
1342de3b87aSKai Wang 	} else {
1352de3b87aSKai Wang 		sh_type    = shdr64->sh_type;
1362de3b87aSKai Wang 		sh_align   = shdr64->sh_addralign;
1372de3b87aSKai Wang 		sh_entsize = shdr64->sh_entsize;
1382de3b87aSKai Wang 		sh_offset  = shdr64->sh_offset;
1392de3b87aSKai Wang 		sh_size    = shdr64->sh_size;
1402de3b87aSKai Wang 	}
1412de3b87aSKai Wang 
1422de3b87aSKai Wang 	assert(sh_type != SHT_NULL && sh_type != SHT_NOBITS);
1432de3b87aSKai Wang 
1442de3b87aSKai Wang 	elftype = _libelf_xlate_shtype(sh_type);
1452de3b87aSKai Wang 	if (elftype > ELF_T_LAST) {
1462de3b87aSKai Wang 		LIBELF_SET_ERROR(SECTION, 0);
1472de3b87aSKai Wang 		return (0);
1482de3b87aSKai Wang 	}
1492de3b87aSKai Wang 
1502de3b87aSKai Wang 	if (sh_align == 0)
1512de3b87aSKai Wang 		sh_align = _libelf_falign(elftype, ec);
1522de3b87aSKai Wang 
1532de3b87aSKai Wang 	/*
1542de3b87aSKai Wang 	 * Compute the section's size and alignment using the data
1552de3b87aSKai Wang 	 * descriptors associated with the section.
1562de3b87aSKai Wang 	 */
1572de3b87aSKai Wang 	if (STAILQ_EMPTY(&s->s_data)) {
1582de3b87aSKai Wang 		/*
1592de3b87aSKai Wang 		 * The section's content (if any) has not been read in
1602de3b87aSKai Wang 		 * yet.  If section is not dirty marked dirty, we can
1612de3b87aSKai Wang 		 * reuse the values in the 'sh_size' and 'sh_offset'
1622de3b87aSKai Wang 		 * fields of the section header.
1632de3b87aSKai Wang 		 */
1642de3b87aSKai Wang 		if ((s->s_flags & ELF_F_DIRTY) == 0) {
1652de3b87aSKai Wang 			/*
1662de3b87aSKai Wang 			 * If the library is doing the layout, then we
1672de3b87aSKai Wang 			 * compute the new start offset for the
1682de3b87aSKai Wang 			 * section based on the current offset and the
1692de3b87aSKai Wang 			 * section's alignment needs.
1702de3b87aSKai Wang 			 *
1712de3b87aSKai Wang 			 * If the application is doing the layout, we
1722de3b87aSKai Wang 			 * can use the value in the 'sh_offset' field
1732de3b87aSKai Wang 			 * in the section header directly.
1742de3b87aSKai Wang 			 */
1752de3b87aSKai Wang 			if (e->e_flags & ELF_F_LAYOUT)
1762de3b87aSKai Wang 				goto updatedescriptor;
1772de3b87aSKai Wang 			else
1782de3b87aSKai Wang 				goto computeoffset;
1792de3b87aSKai Wang 		}
1802de3b87aSKai Wang 
1812de3b87aSKai Wang 		/*
1822de3b87aSKai Wang 		 * Otherwise, we need to bring in the section's data
1832de3b87aSKai Wang 		 * from the underlying ELF object.
1842de3b87aSKai Wang 		 */
1852de3b87aSKai Wang 		if (e->e_cmd != ELF_C_WRITE && elf_getdata(s, NULL) == NULL)
1862de3b87aSKai Wang 			return (0);
1872de3b87aSKai Wang 	}
1882de3b87aSKai Wang 
1892de3b87aSKai Wang 	/*
1902de3b87aSKai Wang 	 * Loop through the section's data descriptors.
1912de3b87aSKai Wang 	 */
1922de3b87aSKai Wang 	scn_size = 0L;
1932de3b87aSKai Wang 	scn_alignment = 0;
1942de3b87aSKai Wang 	STAILQ_FOREACH(ld, &s->s_data, d_next)  {
1952de3b87aSKai Wang 
1962de3b87aSKai Wang 		d = &ld->d_data;
1972de3b87aSKai Wang 
1982de3b87aSKai Wang 		/*
1992de3b87aSKai Wang 		 * The data buffer's type is known.
2002de3b87aSKai Wang 		 */
2012de3b87aSKai Wang 		if (d->d_type >= ELF_T_NUM) {
2022de3b87aSKai Wang 			LIBELF_SET_ERROR(DATA, 0);
2032de3b87aSKai Wang 			return (0);
2042de3b87aSKai Wang 		}
2052de3b87aSKai Wang 
2062de3b87aSKai Wang 		/*
2072de3b87aSKai Wang 		 * The data buffer's version is supported.
2082de3b87aSKai Wang 		 */
2092de3b87aSKai Wang 		if (d->d_version != e->e_version) {
2102de3b87aSKai Wang 			LIBELF_SET_ERROR(VERSION, 0);
2112de3b87aSKai Wang 			return (0);
2122de3b87aSKai Wang 		}
2132de3b87aSKai Wang 
2142de3b87aSKai Wang 		/*
2152de3b87aSKai Wang 		 * The buffer's alignment is non-zero and a power of
2162de3b87aSKai Wang 		 * two.
2172de3b87aSKai Wang 		 */
2182de3b87aSKai Wang 		if ((d_align = d->d_align) == 0 ||
2192de3b87aSKai Wang 		    (d_align & (d_align - 1))) {
2202de3b87aSKai Wang 			LIBELF_SET_ERROR(DATA, 0);
2212de3b87aSKai Wang 			return (0);
2222de3b87aSKai Wang 		}
2232de3b87aSKai Wang 
2242de3b87aSKai Wang 		/*
2252de3b87aSKai Wang 		 * The buffer's size should be a multiple of the
2262de3b87aSKai Wang 		 * memory size of the underlying type.
2272de3b87aSKai Wang 		 */
2282de3b87aSKai Wang 		msz = _libelf_msize(d->d_type, ec, e->e_version);
2292de3b87aSKai Wang 		if (d->d_size % msz) {
2302de3b87aSKai Wang 			LIBELF_SET_ERROR(DATA, 0);
2312de3b87aSKai Wang 			return (0);
2322de3b87aSKai Wang 		}
2332de3b87aSKai Wang 
2342de3b87aSKai Wang 		/*
2352de3b87aSKai Wang 		 * If the application is controlling layout, then the
2362de3b87aSKai Wang 		 * d_offset field should be compatible with the
2372de3b87aSKai Wang 		 * buffer's specified alignment.
2382de3b87aSKai Wang 		 */
2392de3b87aSKai Wang 		if ((e->e_flags & ELF_F_LAYOUT) &&
2402de3b87aSKai Wang 		    (d->d_off & (d_align - 1))) {
2412de3b87aSKai Wang 			LIBELF_SET_ERROR(LAYOUT, 0);
2422de3b87aSKai Wang 			return (0);
2432de3b87aSKai Wang 		}
2442de3b87aSKai Wang 
2452de3b87aSKai Wang 		/*
2462de3b87aSKai Wang 		 * Compute the section's size.
2472de3b87aSKai Wang 		 */
2482de3b87aSKai Wang 		if (e->e_flags & ELF_F_LAYOUT) {
2492de3b87aSKai Wang 			if ((uint64_t) d->d_off + d->d_size > scn_size)
2502de3b87aSKai Wang 				scn_size = d->d_off + d->d_size;
2512de3b87aSKai Wang 		} else {
2522de3b87aSKai Wang 			scn_size = roundup2(scn_size, d->d_align);
2532de3b87aSKai Wang 			d->d_off = scn_size;
2542de3b87aSKai Wang 			fsz = _libelf_fsize(d->d_type, ec, d->d_version,
255*cf781b2eSEd Maste 			    (size_t) d->d_size / msz);
2562de3b87aSKai Wang 			scn_size += fsz;
2572de3b87aSKai Wang 		}
2582de3b87aSKai Wang 
2592de3b87aSKai Wang 		/*
2602de3b87aSKai Wang 		 * The section's alignment is the maximum alignment
2612de3b87aSKai Wang 		 * needed for its data buffers.
2622de3b87aSKai Wang 		 */
2632de3b87aSKai Wang 		if (d_align > scn_alignment)
2642de3b87aSKai Wang 			scn_alignment = d_align;
2652de3b87aSKai Wang 	}
2662de3b87aSKai Wang 
2672de3b87aSKai Wang 
2682de3b87aSKai Wang 	/*
2692de3b87aSKai Wang 	 * If the application is requesting full control over the
2702de3b87aSKai Wang 	 * layout of the section, check the section's specified size,
2712de3b87aSKai Wang 	 * offsets and alignment for sanity.
2722de3b87aSKai Wang 	 */
2732de3b87aSKai Wang 	if (e->e_flags & ELF_F_LAYOUT) {
2742de3b87aSKai Wang 		if (scn_alignment > sh_align || sh_offset % sh_align ||
2752de3b87aSKai Wang 		    sh_size < scn_size) {
2762de3b87aSKai Wang 			LIBELF_SET_ERROR(LAYOUT, 0);
2772de3b87aSKai Wang 			return (0);
2782de3b87aSKai Wang 		}
2792de3b87aSKai Wang 		goto updatedescriptor;
2802de3b87aSKai Wang 	}
2812de3b87aSKai Wang 
2822de3b87aSKai Wang 	/*
2832de3b87aSKai Wang 	 * Otherwise, compute the values in the section header.
2842de3b87aSKai Wang 	 *
2852de3b87aSKai Wang 	 * The section alignment is the maximum alignment for any of
2862de3b87aSKai Wang 	 * its contained data descriptors.
2872de3b87aSKai Wang 	 */
2882de3b87aSKai Wang 	if (scn_alignment > sh_align)
2892de3b87aSKai Wang 		sh_align = scn_alignment;
2902de3b87aSKai Wang 
2912de3b87aSKai Wang 	/*
2922de3b87aSKai Wang 	 * If the section entry size is zero, try and fill in an
2932de3b87aSKai Wang 	 * appropriate entry size.  Per the elf(5) manual page
2942de3b87aSKai Wang 	 * sections without fixed-size entries should have their
2952de3b87aSKai Wang 	 * 'sh_entsize' field set to zero.
2962de3b87aSKai Wang 	 */
2972de3b87aSKai Wang 	if (sh_entsize == 0 &&
2982de3b87aSKai Wang 	    (sh_entsize = _libelf_fsize(elftype, ec, e->e_version,
2992de3b87aSKai Wang 		(size_t) 1)) == 1)
3002de3b87aSKai Wang 		sh_entsize = 0;
3012de3b87aSKai Wang 
3022de3b87aSKai Wang 	sh_size = scn_size;
3032de3b87aSKai Wang 
3042de3b87aSKai Wang computeoffset:
3052de3b87aSKai Wang 	/*
3062de3b87aSKai Wang 	 * Compute the new offset for the section based on
3072de3b87aSKai Wang 	 * the section's alignment needs.
3082de3b87aSKai Wang 	 */
309*cf781b2eSEd Maste 	sh_offset = roundup((uint64_t) rc, sh_align);
3102de3b87aSKai Wang 
3112de3b87aSKai Wang 	/*
3122de3b87aSKai Wang 	 * Update the section header.
3132de3b87aSKai Wang 	 */
3142de3b87aSKai Wang 	if (ec == ELFCLASS32) {
3152de3b87aSKai Wang 		shdr32->sh_addralign = (uint32_t) sh_align;
3162de3b87aSKai Wang 		shdr32->sh_entsize   = (uint32_t) sh_entsize;
3172de3b87aSKai Wang 		shdr32->sh_offset    = (uint32_t) sh_offset;
3182de3b87aSKai Wang 		shdr32->sh_size      = (uint32_t) sh_size;
3192de3b87aSKai Wang 	} else {
3202de3b87aSKai Wang 		shdr64->sh_addralign = sh_align;
3212de3b87aSKai Wang 		shdr64->sh_entsize   = sh_entsize;
3222de3b87aSKai Wang 		shdr64->sh_offset    = sh_offset;
3232de3b87aSKai Wang 		shdr64->sh_size      = sh_size;
3242de3b87aSKai Wang 	}
3252de3b87aSKai Wang 
3262de3b87aSKai Wang updatedescriptor:
3272de3b87aSKai Wang 	/*
3282de3b87aSKai Wang 	 * Update the section descriptor.
3292de3b87aSKai Wang 	 */
3302de3b87aSKai Wang 	s->s_size = sh_size;
3312de3b87aSKai Wang 	s->s_offset = sh_offset;
3322de3b87aSKai Wang 
3332de3b87aSKai Wang 	return (1);
3342de3b87aSKai Wang }
3352de3b87aSKai Wang 
3362de3b87aSKai Wang /*
3372de3b87aSKai Wang  * Free a list of extent descriptors.
3382de3b87aSKai Wang  */
3392de3b87aSKai Wang 
3402de3b87aSKai Wang static void
3412de3b87aSKai Wang _libelf_release_extents(struct _Elf_Extent_List *extents)
3422de3b87aSKai Wang {
3432de3b87aSKai Wang 	struct _Elf_Extent *ex;
3442de3b87aSKai Wang 
3452de3b87aSKai Wang 	while ((ex = SLIST_FIRST(extents)) != NULL) {
3462de3b87aSKai Wang 		SLIST_REMOVE_HEAD(extents, ex_next);
3472de3b87aSKai Wang 		free(ex);
3482de3b87aSKai Wang 	}
3492de3b87aSKai Wang }
3502de3b87aSKai Wang 
3512de3b87aSKai Wang /*
3522de3b87aSKai Wang  * Check if an extent 's' defined by [start..start+size) is free.
3532de3b87aSKai Wang  * This routine assumes that the given extent list is sorted in order
3542de3b87aSKai Wang  * of ascending extent offsets.
3552de3b87aSKai Wang  */
3562de3b87aSKai Wang 
3572de3b87aSKai Wang static int
3582de3b87aSKai Wang _libelf_extent_is_unused(struct _Elf_Extent_List *extents,
3592de3b87aSKai Wang     const uint64_t start, const uint64_t size, struct _Elf_Extent **prevt)
3602de3b87aSKai Wang {
3612de3b87aSKai Wang 	uint64_t tmax, tmin;
3622de3b87aSKai Wang 	struct _Elf_Extent *t, *pt;
3632de3b87aSKai Wang 	const uint64_t smax = start + size;
3642de3b87aSKai Wang 
3652de3b87aSKai Wang 	/* First, look for overlaps with existing extents. */
3662de3b87aSKai Wang 	pt = NULL;
3672de3b87aSKai Wang 	SLIST_FOREACH(t, extents, ex_next) {
3682de3b87aSKai Wang 		tmin = t->ex_start;
3692de3b87aSKai Wang 		tmax = tmin + t->ex_size;
3702de3b87aSKai Wang 
3712de3b87aSKai Wang 		if (tmax <= start) {
3722de3b87aSKai Wang 			/*
3732de3b87aSKai Wang 			 * 't' lies entirely before 's': ...| t |...| s |...
3742de3b87aSKai Wang 			 */
3752de3b87aSKai Wang 			pt = t;
3762de3b87aSKai Wang 			continue;
3772de3b87aSKai Wang 		} else if (smax <= tmin) {
3782de3b87aSKai Wang 			/*
3792de3b87aSKai Wang 			 * 's' lies entirely before 't', and after 'pt':
3802de3b87aSKai Wang 			 *      ...| pt |...| s |...| t |...
3812de3b87aSKai Wang 			 */
3822de3b87aSKai Wang 			assert(pt == NULL ||
3832de3b87aSKai Wang 			    pt->ex_start + pt->ex_size <= start);
3842de3b87aSKai Wang 			break;
3852de3b87aSKai Wang 		} else
3862de3b87aSKai Wang 			/* 's' and 't' overlap. */
3872de3b87aSKai Wang 			return (0);
3882de3b87aSKai Wang 	}
3892de3b87aSKai Wang 
3902de3b87aSKai Wang 	if (prevt)
3912de3b87aSKai Wang 		*prevt = pt;
3922de3b87aSKai Wang 	return (1);
3932de3b87aSKai Wang }
3942de3b87aSKai Wang 
3952de3b87aSKai Wang /*
3962de3b87aSKai Wang  * Insert an extent into the list of extents.
3972de3b87aSKai Wang  */
3982de3b87aSKai Wang 
3992de3b87aSKai Wang static int
4002de3b87aSKai Wang _libelf_insert_extent(struct _Elf_Extent_List *extents, int type,
4012de3b87aSKai Wang     uint64_t start, uint64_t size, void *desc)
4022de3b87aSKai Wang {
4032de3b87aSKai Wang 	struct _Elf_Extent *ex, *prevt;
4042de3b87aSKai Wang 
4052de3b87aSKai Wang 	assert(type >= ELF_EXTENT_EHDR && type <= ELF_EXTENT_SHDR);
4062de3b87aSKai Wang 
4072de3b87aSKai Wang 	prevt = NULL;
4082de3b87aSKai Wang 
4092de3b87aSKai Wang 	/*
4102de3b87aSKai Wang 	 * If the requested range overlaps with an existing extent,
4112de3b87aSKai Wang 	 * signal an error.
4122de3b87aSKai Wang 	 */
4132de3b87aSKai Wang 	if (!_libelf_extent_is_unused(extents, start, size, &prevt)) {
4142de3b87aSKai Wang 		LIBELF_SET_ERROR(LAYOUT, 0);
4152de3b87aSKai Wang 		return (0);
4162de3b87aSKai Wang 	}
4172de3b87aSKai Wang 
4182de3b87aSKai Wang 	/* Allocate and fill in a new extent descriptor. */
4192de3b87aSKai Wang 	if ((ex = malloc(sizeof(struct _Elf_Extent))) == NULL) {
4202de3b87aSKai Wang 		LIBELF_SET_ERROR(RESOURCE, errno);
4212de3b87aSKai Wang 		return (0);
4222de3b87aSKai Wang 	}
4232de3b87aSKai Wang 	ex->ex_start = start;
4242de3b87aSKai Wang 	ex->ex_size = size;
4252de3b87aSKai Wang 	ex->ex_desc = desc;
4262de3b87aSKai Wang 	ex->ex_type = type;
4272de3b87aSKai Wang 
4282de3b87aSKai Wang 	/* Insert the region descriptor into the list. */
4292de3b87aSKai Wang 	if (prevt)
4302de3b87aSKai Wang 		SLIST_INSERT_AFTER(prevt, ex, ex_next);
4312de3b87aSKai Wang 	else
4322de3b87aSKai Wang 		SLIST_INSERT_HEAD(extents, ex, ex_next);
4332de3b87aSKai Wang 	return (1);
4342de3b87aSKai Wang }
4352de3b87aSKai Wang 
4362de3b87aSKai Wang /*
4372de3b87aSKai Wang  * Recompute section layout.
4382de3b87aSKai Wang  */
4392de3b87aSKai Wang 
4402de3b87aSKai Wang static off_t
4412de3b87aSKai Wang _libelf_resync_sections(Elf *e, off_t rc, struct _Elf_Extent_List *extents)
4422de3b87aSKai Wang {
4432de3b87aSKai Wang 	int ec;
4442de3b87aSKai Wang 	Elf_Scn *s;
4452de3b87aSKai Wang 	size_t sh_type;
4462de3b87aSKai Wang 
4472de3b87aSKai Wang 	ec = e->e_class;
4482de3b87aSKai Wang 
4492de3b87aSKai Wang 	/*
4502de3b87aSKai Wang 	 * Make a pass through sections, computing the extent of each
4512de3b87aSKai Wang 	 * section.
4522de3b87aSKai Wang 	 */
4532de3b87aSKai Wang 	STAILQ_FOREACH(s, &e->e_u.e_elf.e_scn, s_next) {
4542de3b87aSKai Wang 		if (ec == ELFCLASS32)
4552de3b87aSKai Wang 			sh_type = s->s_shdr.s_shdr32.sh_type;
4562de3b87aSKai Wang 		else
4572de3b87aSKai Wang 			sh_type = s->s_shdr.s_shdr64.sh_type;
4582de3b87aSKai Wang 
4592de3b87aSKai Wang 		if (sh_type == SHT_NOBITS || sh_type == SHT_NULL)
4602de3b87aSKai Wang 			continue;
4612de3b87aSKai Wang 
4622de3b87aSKai Wang 		if (_libelf_compute_section_extents(e, s, rc) == 0)
4632de3b87aSKai Wang 			return ((off_t) -1);
4642de3b87aSKai Wang 
4652de3b87aSKai Wang 		if (s->s_size == 0)
4662de3b87aSKai Wang 			continue;
4672de3b87aSKai Wang 
4682de3b87aSKai Wang 		if (!_libelf_insert_extent(extents, ELF_EXTENT_SECTION,
4692de3b87aSKai Wang 		    s->s_offset, s->s_size, s))
4702de3b87aSKai Wang 			return ((off_t) -1);
4712de3b87aSKai Wang 
4722de3b87aSKai Wang 		if ((size_t) rc < s->s_offset + s->s_size)
473*cf781b2eSEd Maste 			rc = (off_t) (s->s_offset + s->s_size);
4742de3b87aSKai Wang 	}
4752de3b87aSKai Wang 
4762de3b87aSKai Wang 	return (rc);
4772de3b87aSKai Wang }
4782de3b87aSKai Wang 
4792de3b87aSKai Wang /*
4802de3b87aSKai Wang  * Recompute the layout of the ELF object and update the internal data
4812de3b87aSKai Wang  * structures associated with the ELF descriptor.
4822de3b87aSKai Wang  *
4832de3b87aSKai Wang  * Returns the size in bytes the ELF object would occupy in its file
4842de3b87aSKai Wang  * representation.
4852de3b87aSKai Wang  *
4862de3b87aSKai Wang  * After a successful call to this function, the following structures
4872de3b87aSKai Wang  * are updated:
4882de3b87aSKai Wang  *
4892de3b87aSKai Wang  * - The ELF header is updated.
4902de3b87aSKai Wang  * - All extents in the ELF object are sorted in order of ascending
4912de3b87aSKai Wang  *   addresses.  Sections have their section header table entries
4922de3b87aSKai Wang  *   updated.  An error is signalled if an overlap was detected among
4932de3b87aSKai Wang  *   extents.
4942de3b87aSKai Wang  * - Data descriptors associated with sections are checked for valid
4952de3b87aSKai Wang  *   types, offsets and alignment.
4962de3b87aSKai Wang  *
4972de3b87aSKai Wang  * After a resync_elf() successfully returns, the ELF descriptor is
4982de3b87aSKai Wang  * ready for being handed over to _libelf_write_elf().
4992de3b87aSKai Wang  */
5002de3b87aSKai Wang 
5012de3b87aSKai Wang static off_t
5022de3b87aSKai Wang _libelf_resync_elf(Elf *e, struct _Elf_Extent_List *extents)
5032de3b87aSKai Wang {
5042de3b87aSKai Wang 	int ec, eh_class;
5052de3b87aSKai Wang 	unsigned int eh_byteorder, eh_version;
5062de3b87aSKai Wang 	size_t align, fsz;
5072de3b87aSKai Wang 	size_t phnum, shnum;
5082de3b87aSKai Wang 	off_t rc, phoff, shoff;
5092de3b87aSKai Wang 	void *ehdr, *phdr;
5102de3b87aSKai Wang 	Elf32_Ehdr *eh32;
5112de3b87aSKai Wang 	Elf64_Ehdr *eh64;
5122de3b87aSKai Wang 
5132de3b87aSKai Wang 	rc = 0;
5142de3b87aSKai Wang 
5152de3b87aSKai Wang 	ec = e->e_class;
5162de3b87aSKai Wang 
5172de3b87aSKai Wang 	assert(ec == ELFCLASS32 || ec == ELFCLASS64);
5182de3b87aSKai Wang 
5192de3b87aSKai Wang 	/*
5202de3b87aSKai Wang 	 * Prepare the EHDR.
5212de3b87aSKai Wang 	 */
5222de3b87aSKai Wang 	if ((ehdr = _libelf_ehdr(e, ec, 0)) == NULL)
5232de3b87aSKai Wang 		return ((off_t) -1);
5242de3b87aSKai Wang 
5252de3b87aSKai Wang 	eh32 = ehdr;
5262de3b87aSKai Wang 	eh64 = ehdr;
5272de3b87aSKai Wang 
5282de3b87aSKai Wang 	if (ec == ELFCLASS32) {
5292de3b87aSKai Wang 		eh_byteorder = eh32->e_ident[EI_DATA];
5302de3b87aSKai Wang 		eh_class     = eh32->e_ident[EI_CLASS];
531*cf781b2eSEd Maste 		phoff        = (off_t) eh32->e_phoff;
532*cf781b2eSEd Maste 		shoff        = (off_t) eh32->e_shoff;
5332de3b87aSKai Wang 		eh_version   = eh32->e_version;
5342de3b87aSKai Wang 	} else {
5352de3b87aSKai Wang 		eh_byteorder = eh64->e_ident[EI_DATA];
5362de3b87aSKai Wang 		eh_class     = eh64->e_ident[EI_CLASS];
537*cf781b2eSEd Maste 		phoff        = (off_t) eh64->e_phoff;
538*cf781b2eSEd Maste 		shoff        = (off_t) eh64->e_shoff;
5392de3b87aSKai Wang 		eh_version   = eh64->e_version;
5402de3b87aSKai Wang 	}
5412de3b87aSKai Wang 
542*cf781b2eSEd Maste 	if (phoff < 0 || shoff < 0) {
543*cf781b2eSEd Maste 		LIBELF_SET_ERROR(HEADER, 0);
544*cf781b2eSEd Maste 		return ((off_t) -1);
545*cf781b2eSEd Maste 	}
546*cf781b2eSEd Maste 
5472de3b87aSKai Wang 	if (eh_version == EV_NONE)
5482de3b87aSKai Wang 		eh_version = EV_CURRENT;
5492de3b87aSKai Wang 
5502de3b87aSKai Wang 	if (eh_version != e->e_version) {	/* always EV_CURRENT */
5512de3b87aSKai Wang 		LIBELF_SET_ERROR(VERSION, 0);
5522de3b87aSKai Wang 		return ((off_t) -1);
5532de3b87aSKai Wang 	}
5542de3b87aSKai Wang 
5552de3b87aSKai Wang 	if (eh_class != e->e_class) {
5562de3b87aSKai Wang 		LIBELF_SET_ERROR(CLASS, 0);
5572de3b87aSKai Wang 		return ((off_t) -1);
5582de3b87aSKai Wang 	}
5592de3b87aSKai Wang 
5602de3b87aSKai Wang 	if (e->e_cmd != ELF_C_WRITE && eh_byteorder != e->e_byteorder) {
5612de3b87aSKai Wang 		LIBELF_SET_ERROR(HEADER, 0);
5622de3b87aSKai Wang 		return ((off_t) -1);
5632de3b87aSKai Wang 	}
5642de3b87aSKai Wang 
5652de3b87aSKai Wang 	shnum = e->e_u.e_elf.e_nscn;
5662de3b87aSKai Wang 	phnum = e->e_u.e_elf.e_nphdr;
5672de3b87aSKai Wang 
5682de3b87aSKai Wang 	e->e_byteorder = eh_byteorder;
5692de3b87aSKai Wang 
5702de3b87aSKai Wang #define	INITIALIZE_EHDR(E,EC,V)	do {					\
571*cf781b2eSEd Maste 		unsigned int _version = (unsigned int) (V);		\
5722de3b87aSKai Wang 		(E)->e_ident[EI_MAG0] = ELFMAG0;			\
5732de3b87aSKai Wang 		(E)->e_ident[EI_MAG1] = ELFMAG1;			\
5742de3b87aSKai Wang 		(E)->e_ident[EI_MAG2] = ELFMAG2;			\
5752de3b87aSKai Wang 		(E)->e_ident[EI_MAG3] = ELFMAG3;			\
576*cf781b2eSEd Maste 		(E)->e_ident[EI_CLASS] = (unsigned char) (EC);		\
577*cf781b2eSEd Maste 		(E)->e_ident[EI_VERSION] = (_version & 0xFFU);		\
578*cf781b2eSEd Maste 		(E)->e_ehsize = (uint16_t) _libelf_fsize(ELF_T_EHDR,	\
579*cf781b2eSEd Maste 		    (EC), _version, (size_t) 1);			\
580*cf781b2eSEd Maste 		(E)->e_phentsize = (uint16_t) ((phnum == 0) ? 0 :	\
581*cf781b2eSEd Maste 		    _libelf_fsize(ELF_T_PHDR, (EC), _version,		\
582*cf781b2eSEd Maste 			(size_t) 1));					\
583*cf781b2eSEd Maste 		(E)->e_shentsize = (uint16_t) _libelf_fsize(ELF_T_SHDR,	\
584*cf781b2eSEd Maste 		    (EC), _version, (size_t) 1);			\
5852de3b87aSKai Wang 	} while (0)
5862de3b87aSKai Wang 
5872de3b87aSKai Wang 	if (ec == ELFCLASS32)
5882de3b87aSKai Wang 		INITIALIZE_EHDR(eh32, ec, eh_version);
5892de3b87aSKai Wang 	else
5902de3b87aSKai Wang 		INITIALIZE_EHDR(eh64, ec, eh_version);
5912de3b87aSKai Wang 
5922de3b87aSKai Wang 	(void) elf_flagehdr(e, ELF_C_SET, ELF_F_DIRTY);
5932de3b87aSKai Wang 
594*cf781b2eSEd Maste 	rc += (off_t) _libelf_fsize(ELF_T_EHDR, ec, eh_version, (size_t) 1);
5952de3b87aSKai Wang 
596*cf781b2eSEd Maste 	if (!_libelf_insert_extent(extents, ELF_EXTENT_EHDR, 0, (uint64_t) rc,
597*cf781b2eSEd Maste 		ehdr))
5982de3b87aSKai Wang 		return ((off_t) -1);
5992de3b87aSKai Wang 
6002de3b87aSKai Wang 	/*
6012de3b87aSKai Wang 	 * Compute the layout the program header table, if one is
6022de3b87aSKai Wang 	 * present.  The program header table needs to be aligned to a
6032de3b87aSKai Wang 	 * `natural' boundary.
6042de3b87aSKai Wang 	 */
6052de3b87aSKai Wang 	if (phnum) {
6062de3b87aSKai Wang 		fsz = _libelf_fsize(ELF_T_PHDR, ec, eh_version, phnum);
6072de3b87aSKai Wang 		align = _libelf_falign(ELF_T_PHDR, ec);
6082de3b87aSKai Wang 
6092de3b87aSKai Wang 		if (e->e_flags & ELF_F_LAYOUT) {
6102de3b87aSKai Wang 			/*
6112de3b87aSKai Wang 			 * Check offsets for sanity.
6122de3b87aSKai Wang 			 */
6132de3b87aSKai Wang 			if (rc > phoff) {
6142de3b87aSKai Wang 				LIBELF_SET_ERROR(LAYOUT, 0);
6152de3b87aSKai Wang 				return ((off_t) -1);
6162de3b87aSKai Wang 			}
6172de3b87aSKai Wang 
618*cf781b2eSEd Maste 			if (phoff % (off_t) align) {
6192de3b87aSKai Wang 				LIBELF_SET_ERROR(LAYOUT, 0);
6202de3b87aSKai Wang 				return ((off_t) -1);
6212de3b87aSKai Wang 			}
6222de3b87aSKai Wang 
6232de3b87aSKai Wang 		} else
624*cf781b2eSEd Maste 			phoff = roundup(rc, (off_t) align);
6252de3b87aSKai Wang 
626*cf781b2eSEd Maste 		rc = phoff + (off_t) fsz;
6272de3b87aSKai Wang 
6282de3b87aSKai Wang 		phdr = _libelf_getphdr(e, ec);
6292de3b87aSKai Wang 
630*cf781b2eSEd Maste 		if (!_libelf_insert_extent(extents, ELF_EXTENT_PHDR,
631*cf781b2eSEd Maste 			(uint64_t) phoff, fsz, phdr))
6322de3b87aSKai Wang 			return ((off_t) -1);
6332de3b87aSKai Wang 	} else
6342de3b87aSKai Wang 		phoff = 0;
6352de3b87aSKai Wang 
6362de3b87aSKai Wang 	/*
6372de3b87aSKai Wang 	 * Compute the layout of the sections associated with the
6382de3b87aSKai Wang 	 * file.
6392de3b87aSKai Wang 	 */
6402de3b87aSKai Wang 
6412de3b87aSKai Wang 	if (e->e_cmd != ELF_C_WRITE &&
6422de3b87aSKai Wang 	    (e->e_flags & LIBELF_F_SHDRS_LOADED) == 0 &&
6432de3b87aSKai Wang 	    _libelf_load_section_headers(e, ehdr) == 0)
6442de3b87aSKai Wang 		return ((off_t) -1);
6452de3b87aSKai Wang 
6462de3b87aSKai Wang 	if ((rc = _libelf_resync_sections(e, rc, extents)) < 0)
6472de3b87aSKai Wang 		return ((off_t) -1);
6482de3b87aSKai Wang 
6492de3b87aSKai Wang 	/*
6502de3b87aSKai Wang 	 * Compute the space taken up by the section header table, if
6512de3b87aSKai Wang 	 * one is needed.
6522de3b87aSKai Wang 	 *
6532de3b87aSKai Wang 	 * If ELF_F_LAYOUT has been asserted, the application may have
6542de3b87aSKai Wang 	 * placed the section header table in between existing
6552de3b87aSKai Wang 	 * sections, so the net size of the file need not increase due
6562de3b87aSKai Wang 	 * to the presence of the section header table.
6572de3b87aSKai Wang 	 *
6582de3b87aSKai Wang 	 * If the library is responsible for laying out the object,
6592de3b87aSKai Wang 	 * the section header table is placed after section data.
6602de3b87aSKai Wang 	 */
6612de3b87aSKai Wang 	if (shnum) {
6622de3b87aSKai Wang 		fsz = _libelf_fsize(ELF_T_SHDR, ec, eh_version, shnum);
6632de3b87aSKai Wang 		align = _libelf_falign(ELF_T_SHDR, ec);
6642de3b87aSKai Wang 
6652de3b87aSKai Wang 		if (e->e_flags & ELF_F_LAYOUT) {
666*cf781b2eSEd Maste 			if (shoff % (off_t) align) {
6672de3b87aSKai Wang 				LIBELF_SET_ERROR(LAYOUT, 0);
6682de3b87aSKai Wang 				return ((off_t) -1);
6692de3b87aSKai Wang 			}
6702de3b87aSKai Wang 		} else
671*cf781b2eSEd Maste 			shoff = roundup(rc, (off_t) align);
6722de3b87aSKai Wang 
673*cf781b2eSEd Maste 		if (shoff + (off_t) fsz > rc)
674*cf781b2eSEd Maste 			rc = shoff + (off_t) fsz;
6752de3b87aSKai Wang 
676*cf781b2eSEd Maste 		if (!_libelf_insert_extent(extents, ELF_EXTENT_SHDR,
677*cf781b2eSEd Maste 			(uint64_t) shoff, fsz, NULL))
6782de3b87aSKai Wang 			return ((off_t) -1);
6792de3b87aSKai Wang 	} else
6802de3b87aSKai Wang 		shoff = 0;
6812de3b87aSKai Wang 
6822de3b87aSKai Wang 	/*
6832de3b87aSKai Wang 	 * Set the fields of the Executable Header that could potentially use
6842de3b87aSKai Wang 	 * extended numbering.
6852de3b87aSKai Wang 	 */
6862de3b87aSKai Wang 	_libelf_setphnum(e, ehdr, ec, phnum);
6872de3b87aSKai Wang 	_libelf_setshnum(e, ehdr, ec, shnum);
6882de3b87aSKai Wang 
6892de3b87aSKai Wang 	/*
6902de3b87aSKai Wang 	 * Update the `e_phoff' and `e_shoff' fields if the library is
6912de3b87aSKai Wang 	 * doing the layout.
6922de3b87aSKai Wang 	 */
6932de3b87aSKai Wang 	if ((e->e_flags & ELF_F_LAYOUT) == 0) {
6942de3b87aSKai Wang 		if (ec == ELFCLASS32) {
6952de3b87aSKai Wang 			eh32->e_phoff = (uint32_t) phoff;
6962de3b87aSKai Wang 			eh32->e_shoff = (uint32_t) shoff;
6972de3b87aSKai Wang 		} else {
6982de3b87aSKai Wang 			eh64->e_phoff = (uint64_t) phoff;
6992de3b87aSKai Wang 			eh64->e_shoff = (uint64_t) shoff;
7002de3b87aSKai Wang 		}
7012de3b87aSKai Wang 	}
7022de3b87aSKai Wang 
7032de3b87aSKai Wang 	return (rc);
7042de3b87aSKai Wang }
7052de3b87aSKai Wang 
7062de3b87aSKai Wang /*
7072de3b87aSKai Wang  * Write out the contents of an ELF section.
7082de3b87aSKai Wang  */
7092de3b87aSKai Wang 
710*cf781b2eSEd Maste static off_t
711*cf781b2eSEd Maste _libelf_write_scn(Elf *e, unsigned char *nf, struct _Elf_Extent *ex)
7122de3b87aSKai Wang {
7132de3b87aSKai Wang 	int ec;
714*cf781b2eSEd Maste 	off_t rc;
7152de3b87aSKai Wang 	Elf_Scn *s;
7162de3b87aSKai Wang 	int elftype;
7172de3b87aSKai Wang 	Elf_Data *d, dst;
7182de3b87aSKai Wang 	uint32_t sh_type;
7192de3b87aSKai Wang 	struct _Libelf_Data *ld;
7202de3b87aSKai Wang 	uint64_t sh_off, sh_size;
721*cf781b2eSEd Maste 	size_t fsz, msz, nobjects;
7222de3b87aSKai Wang 
7232de3b87aSKai Wang 	assert(ex->ex_type == ELF_EXTENT_SECTION);
7242de3b87aSKai Wang 
7252de3b87aSKai Wang 	s = ex->ex_desc;
726*cf781b2eSEd Maste 	rc = (off_t) ex->ex_start;
7272de3b87aSKai Wang 
7282de3b87aSKai Wang 	if ((ec = e->e_class) == ELFCLASS32) {
7292de3b87aSKai Wang 		sh_type = s->s_shdr.s_shdr32.sh_type;
7302de3b87aSKai Wang 		sh_size = (uint64_t) s->s_shdr.s_shdr32.sh_size;
7312de3b87aSKai Wang 	} else {
7322de3b87aSKai Wang 		sh_type = s->s_shdr.s_shdr64.sh_type;
7332de3b87aSKai Wang 		sh_size = s->s_shdr.s_shdr64.sh_size;
7342de3b87aSKai Wang 	}
7352de3b87aSKai Wang 
7362de3b87aSKai Wang 	/*
7372de3b87aSKai Wang 	 * Ignore sections that do not allocate space in the file.
7382de3b87aSKai Wang 	 */
7392de3b87aSKai Wang 	if (sh_type == SHT_NOBITS || sh_type == SHT_NULL || sh_size == 0)
7402de3b87aSKai Wang 		return (rc);
7412de3b87aSKai Wang 
7422de3b87aSKai Wang 	elftype = _libelf_xlate_shtype(sh_type);
7432de3b87aSKai Wang 	assert(elftype >= ELF_T_FIRST && elftype <= ELF_T_LAST);
7442de3b87aSKai Wang 
7452de3b87aSKai Wang 	sh_off = s->s_offset;
7462de3b87aSKai Wang 	assert(sh_off % _libelf_falign(elftype, ec) == 0);
7472de3b87aSKai Wang 
7482de3b87aSKai Wang 	/*
7492de3b87aSKai Wang 	 * If the section has a `rawdata' descriptor, and the section
7502de3b87aSKai Wang 	 * contents have not been modified, use its contents directly.
7512de3b87aSKai Wang 	 * The `s_rawoff' member contains the offset into the original
7522de3b87aSKai Wang 	 * file, while `s_offset' contains its new location in the
7532de3b87aSKai Wang 	 * destination.
7542de3b87aSKai Wang 	 */
7552de3b87aSKai Wang 
7562de3b87aSKai Wang 	if (STAILQ_EMPTY(&s->s_data)) {
7572de3b87aSKai Wang 
7582de3b87aSKai Wang 		if ((d = elf_rawdata(s, NULL)) == NULL)
7592de3b87aSKai Wang 			return ((off_t) -1);
7602de3b87aSKai Wang 
7612de3b87aSKai Wang 		STAILQ_FOREACH(ld, &s->s_rawdata, d_next) {
7622de3b87aSKai Wang 
7632de3b87aSKai Wang 			d = &ld->d_data;
7642de3b87aSKai Wang 
7652de3b87aSKai Wang 			if ((uint64_t) rc < sh_off + d->d_off)
7662de3b87aSKai Wang 				(void) memset(nf + rc,
767*cf781b2eSEd Maste 				    LIBELF_PRIVATE(fillchar),
768*cf781b2eSEd Maste 				    (size_t) (sh_off + d->d_off -
769*cf781b2eSEd Maste 					(uint64_t) rc));
770*cf781b2eSEd Maste 			rc = (off_t) (sh_off + d->d_off);
7712de3b87aSKai Wang 
7722de3b87aSKai Wang 			assert(d->d_buf != NULL);
7732de3b87aSKai Wang 			assert(d->d_type == ELF_T_BYTE);
7742de3b87aSKai Wang 			assert(d->d_version == e->e_version);
7752de3b87aSKai Wang 
7762de3b87aSKai Wang 			(void) memcpy(nf + rc,
777*cf781b2eSEd Maste 			    e->e_rawfile + s->s_rawoff + d->d_off,
778*cf781b2eSEd Maste 			    (size_t) d->d_size);
7792de3b87aSKai Wang 
780*cf781b2eSEd Maste 			rc += (off_t) d->d_size;
7812de3b87aSKai Wang 		}
7822de3b87aSKai Wang 
7832de3b87aSKai Wang 		return (rc);
7842de3b87aSKai Wang 	}
7852de3b87aSKai Wang 
7862de3b87aSKai Wang 	/*
7872de3b87aSKai Wang 	 * Iterate over the set of data descriptors for this section.
7882de3b87aSKai Wang 	 * The prior call to _libelf_resync_elf() would have setup the
7892de3b87aSKai Wang 	 * descriptors for this step.
7902de3b87aSKai Wang 	 */
7912de3b87aSKai Wang 
7922de3b87aSKai Wang 	dst.d_version = e->e_version;
7932de3b87aSKai Wang 
7942de3b87aSKai Wang 	STAILQ_FOREACH(ld, &s->s_data, d_next) {
7952de3b87aSKai Wang 
7962de3b87aSKai Wang 		d = &ld->d_data;
7972de3b87aSKai Wang 
7982de3b87aSKai Wang 		msz = _libelf_msize(d->d_type, ec, e->e_version);
7992de3b87aSKai Wang 
8002de3b87aSKai Wang 		if ((uint64_t) rc < sh_off + d->d_off)
8012de3b87aSKai Wang 			(void) memset(nf + rc,
802*cf781b2eSEd Maste 			    LIBELF_PRIVATE(fillchar),
803*cf781b2eSEd Maste 			    (size_t) (sh_off + d->d_off - (uint64_t) rc));
8042de3b87aSKai Wang 
805*cf781b2eSEd Maste 		rc = (off_t) (sh_off + d->d_off);
8062de3b87aSKai Wang 
8072de3b87aSKai Wang 		assert(d->d_buf != NULL);
8082de3b87aSKai Wang 		assert(d->d_version == e->e_version);
8092de3b87aSKai Wang 		assert(d->d_size % msz == 0);
8102de3b87aSKai Wang 
811*cf781b2eSEd Maste 		nobjects = (size_t) (d->d_size / msz);
8122de3b87aSKai Wang 
8132de3b87aSKai Wang 		fsz = _libelf_fsize(d->d_type, ec, e->e_version, nobjects);
8142de3b87aSKai Wang 
8152de3b87aSKai Wang 		dst.d_buf    = nf + rc;
8162de3b87aSKai Wang 		dst.d_size   = fsz;
8172de3b87aSKai Wang 
8182de3b87aSKai Wang 		if (_libelf_xlate(&dst, d, e->e_byteorder, ec, ELF_TOFILE) ==
8192de3b87aSKai Wang 		    NULL)
8202de3b87aSKai Wang 			return ((off_t) -1);
8212de3b87aSKai Wang 
822*cf781b2eSEd Maste 		rc += (off_t) fsz;
8232de3b87aSKai Wang 	}
8242de3b87aSKai Wang 
825*cf781b2eSEd Maste 	return (rc);
8262de3b87aSKai Wang }
8272de3b87aSKai Wang 
8282de3b87aSKai Wang /*
8292de3b87aSKai Wang  * Write out an ELF Executable Header.
8302de3b87aSKai Wang  */
8312de3b87aSKai Wang 
8322de3b87aSKai Wang static off_t
833*cf781b2eSEd Maste _libelf_write_ehdr(Elf *e, unsigned char *nf, struct _Elf_Extent *ex)
8342de3b87aSKai Wang {
8352de3b87aSKai Wang 	int ec;
8362de3b87aSKai Wang 	void *ehdr;
8372de3b87aSKai Wang 	size_t fsz, msz;
8382de3b87aSKai Wang 	Elf_Data dst, src;
8392de3b87aSKai Wang 
8402de3b87aSKai Wang 	assert(ex->ex_type == ELF_EXTENT_EHDR);
8412de3b87aSKai Wang 	assert(ex->ex_start == 0); /* Ehdr always comes first. */
8422de3b87aSKai Wang 
8432de3b87aSKai Wang 	ec = e->e_class;
8442de3b87aSKai Wang 
8452de3b87aSKai Wang 	ehdr = _libelf_ehdr(e, ec, 0);
8462de3b87aSKai Wang 	assert(ehdr != NULL);
8472de3b87aSKai Wang 
8482de3b87aSKai Wang 	fsz = _libelf_fsize(ELF_T_EHDR, ec, e->e_version, (size_t) 1);
8492de3b87aSKai Wang 	msz = _libelf_msize(ELF_T_EHDR, ec, e->e_version);
8502de3b87aSKai Wang 
8512de3b87aSKai Wang 	(void) memset(&dst, 0, sizeof(dst));
8522de3b87aSKai Wang 	(void) memset(&src, 0, sizeof(src));
8532de3b87aSKai Wang 
8542de3b87aSKai Wang 	src.d_buf     = ehdr;
8552de3b87aSKai Wang 	src.d_size    = msz;
8562de3b87aSKai Wang 	src.d_type    = ELF_T_EHDR;
8572de3b87aSKai Wang 	src.d_version = dst.d_version = e->e_version;
8582de3b87aSKai Wang 
8592de3b87aSKai Wang 	dst.d_buf     = nf;
8602de3b87aSKai Wang 	dst.d_size    = fsz;
8612de3b87aSKai Wang 
8622de3b87aSKai Wang 	if (_libelf_xlate(&dst, &src, e->e_byteorder, ec, ELF_TOFILE) ==
8632de3b87aSKai Wang 	    NULL)
8642de3b87aSKai Wang 		return ((off_t) -1);
8652de3b87aSKai Wang 
8662de3b87aSKai Wang 	return ((off_t) fsz);
8672de3b87aSKai Wang }
8682de3b87aSKai Wang 
8692de3b87aSKai Wang /*
8702de3b87aSKai Wang  * Write out an ELF program header table.
8712de3b87aSKai Wang  */
8722de3b87aSKai Wang 
8732de3b87aSKai Wang static off_t
874*cf781b2eSEd Maste _libelf_write_phdr(Elf *e, unsigned char *nf, struct _Elf_Extent *ex)
8752de3b87aSKai Wang {
8762de3b87aSKai Wang 	int ec;
8772de3b87aSKai Wang 	void *ehdr;
8782de3b87aSKai Wang 	Elf32_Ehdr *eh32;
8792de3b87aSKai Wang 	Elf64_Ehdr *eh64;
8802de3b87aSKai Wang 	Elf_Data dst, src;
8812de3b87aSKai Wang 	size_t fsz, phnum;
8822de3b87aSKai Wang 	uint64_t phoff;
8832de3b87aSKai Wang 
8842de3b87aSKai Wang 	assert(ex->ex_type == ELF_EXTENT_PHDR);
8852de3b87aSKai Wang 
8862de3b87aSKai Wang 	ec = e->e_class;
8872de3b87aSKai Wang 	ehdr = _libelf_ehdr(e, ec, 0);
8882de3b87aSKai Wang 	phnum = e->e_u.e_elf.e_nphdr;
8892de3b87aSKai Wang 
8902de3b87aSKai Wang 	assert(phnum > 0);
8912de3b87aSKai Wang 
8922de3b87aSKai Wang 	if (ec == ELFCLASS32) {
8932de3b87aSKai Wang 		eh32 = (Elf32_Ehdr *) ehdr;
8942de3b87aSKai Wang 		phoff = (uint64_t) eh32->e_phoff;
8952de3b87aSKai Wang 	} else {
8962de3b87aSKai Wang 		eh64 = (Elf64_Ehdr *) ehdr;
8972de3b87aSKai Wang 		phoff = eh64->e_phoff;
8982de3b87aSKai Wang 	}
8992de3b87aSKai Wang 
9002de3b87aSKai Wang 	assert(phoff > 0);
9012de3b87aSKai Wang 	assert(ex->ex_start == phoff);
9022de3b87aSKai Wang 	assert(phoff % _libelf_falign(ELF_T_PHDR, ec) == 0);
9032de3b87aSKai Wang 
9042de3b87aSKai Wang 	(void) memset(&dst, 0, sizeof(dst));
9052de3b87aSKai Wang 	(void) memset(&src, 0, sizeof(src));
9062de3b87aSKai Wang 
9072de3b87aSKai Wang 	fsz = _libelf_fsize(ELF_T_PHDR, ec, e->e_version, phnum);
9082de3b87aSKai Wang 	assert(fsz > 0);
9092de3b87aSKai Wang 
9102de3b87aSKai Wang 	src.d_buf = _libelf_getphdr(e, ec);
9112de3b87aSKai Wang 	src.d_version = dst.d_version = e->e_version;
9122de3b87aSKai Wang 	src.d_type = ELF_T_PHDR;
9132de3b87aSKai Wang 	src.d_size = phnum * _libelf_msize(ELF_T_PHDR, ec,
9142de3b87aSKai Wang 	    e->e_version);
9152de3b87aSKai Wang 
9162de3b87aSKai Wang 	dst.d_size = fsz;
9172de3b87aSKai Wang 	dst.d_buf = nf + ex->ex_start;
9182de3b87aSKai Wang 
9192de3b87aSKai Wang 	if (_libelf_xlate(&dst, &src, e->e_byteorder, ec, ELF_TOFILE) ==
9202de3b87aSKai Wang 	    NULL)
9212de3b87aSKai Wang 		return ((off_t) -1);
9222de3b87aSKai Wang 
923*cf781b2eSEd Maste 	return ((off_t) (phoff + fsz));
9242de3b87aSKai Wang }
9252de3b87aSKai Wang 
9262de3b87aSKai Wang /*
9272de3b87aSKai Wang  * Write out an ELF section header table.
9282de3b87aSKai Wang  */
9292de3b87aSKai Wang 
9302de3b87aSKai Wang static off_t
931*cf781b2eSEd Maste _libelf_write_shdr(Elf *e, unsigned char *nf, struct _Elf_Extent *ex)
9322de3b87aSKai Wang {
9332de3b87aSKai Wang 	int ec;
9342de3b87aSKai Wang 	void *ehdr;
9352de3b87aSKai Wang 	Elf_Scn *scn;
9362de3b87aSKai Wang 	uint64_t shoff;
9372de3b87aSKai Wang 	Elf32_Ehdr *eh32;
9382de3b87aSKai Wang 	Elf64_Ehdr *eh64;
9392de3b87aSKai Wang 	size_t fsz, nscn;
9402de3b87aSKai Wang 	Elf_Data dst, src;
9412de3b87aSKai Wang 
9422de3b87aSKai Wang 	assert(ex->ex_type == ELF_EXTENT_SHDR);
9432de3b87aSKai Wang 
9442de3b87aSKai Wang 	ec = e->e_class;
9452de3b87aSKai Wang 	ehdr = _libelf_ehdr(e, ec, 0);
9462de3b87aSKai Wang 	nscn = e->e_u.e_elf.e_nscn;
9472de3b87aSKai Wang 
9482de3b87aSKai Wang 	if (ec == ELFCLASS32) {
9492de3b87aSKai Wang 		eh32 = (Elf32_Ehdr *) ehdr;
9502de3b87aSKai Wang 		shoff = (uint64_t) eh32->e_shoff;
9512de3b87aSKai Wang 	} else {
9522de3b87aSKai Wang 		eh64 = (Elf64_Ehdr *) ehdr;
9532de3b87aSKai Wang 		shoff = eh64->e_shoff;
9542de3b87aSKai Wang 	}
9552de3b87aSKai Wang 
9562de3b87aSKai Wang 	assert(nscn > 0);
9572de3b87aSKai Wang 	assert(shoff % _libelf_falign(ELF_T_SHDR, ec) == 0);
9582de3b87aSKai Wang 	assert(ex->ex_start == shoff);
9592de3b87aSKai Wang 
9602de3b87aSKai Wang 	(void) memset(&dst, 0, sizeof(dst));
9612de3b87aSKai Wang 	(void) memset(&src, 0, sizeof(src));
9622de3b87aSKai Wang 
9632de3b87aSKai Wang 	src.d_type = ELF_T_SHDR;
9642de3b87aSKai Wang 	src.d_size = _libelf_msize(ELF_T_SHDR, ec, e->e_version);
9652de3b87aSKai Wang 	src.d_version = dst.d_version = e->e_version;
9662de3b87aSKai Wang 
9672de3b87aSKai Wang 	fsz = _libelf_fsize(ELF_T_SHDR, ec, e->e_version, (size_t) 1);
9682de3b87aSKai Wang 
9692de3b87aSKai Wang 	STAILQ_FOREACH(scn, &e->e_u.e_elf.e_scn, s_next) {
9702de3b87aSKai Wang 		if (ec == ELFCLASS32)
9712de3b87aSKai Wang 			src.d_buf = &scn->s_shdr.s_shdr32;
9722de3b87aSKai Wang 		else
9732de3b87aSKai Wang 			src.d_buf = &scn->s_shdr.s_shdr64;
9742de3b87aSKai Wang 
9752de3b87aSKai Wang 		dst.d_size = fsz;
9762de3b87aSKai Wang 		dst.d_buf = nf + ex->ex_start + scn->s_ndx * fsz;
9772de3b87aSKai Wang 
9782de3b87aSKai Wang 		if (_libelf_xlate(&dst, &src, e->e_byteorder, ec,
9792de3b87aSKai Wang 		    ELF_TOFILE) == NULL)
9802de3b87aSKai Wang 			return ((off_t) -1);
9812de3b87aSKai Wang 	}
9822de3b87aSKai Wang 
983*cf781b2eSEd Maste 	return ((off_t) (ex->ex_start + nscn * fsz));
9842de3b87aSKai Wang }
9852de3b87aSKai Wang 
9862de3b87aSKai Wang /*
9872de3b87aSKai Wang  * Write out the file image.
9882de3b87aSKai Wang  *
9892de3b87aSKai Wang  * The original file could have been mapped in with an ELF_C_RDWR
9902de3b87aSKai Wang  * command and the application could have added new content or
9912de3b87aSKai Wang  * re-arranged its sections before calling elf_update().  Consequently
9922de3b87aSKai Wang  * its not safe to work `in place' on the original file.  So we
9932de3b87aSKai Wang  * malloc() the required space for the updated ELF object and build
9942de3b87aSKai Wang  * the object there and write it out to the underlying file at the
9952de3b87aSKai Wang  * end.  Note that the application may have opened the underlying file
9962de3b87aSKai Wang  * in ELF_C_RDWR and only retrieved/modified a few sections.  We take
9972de3b87aSKai Wang  * care to avoid translating file sections unnecessarily.
9982de3b87aSKai Wang  *
9992de3b87aSKai Wang  * Gaps in the coverage of the file by the file's sections will be
10002de3b87aSKai Wang  * filled with the fill character set by elf_fill(3).
10012de3b87aSKai Wang  */
10022de3b87aSKai Wang 
10032de3b87aSKai Wang static off_t
10042de3b87aSKai Wang _libelf_write_elf(Elf *e, off_t newsize, struct _Elf_Extent_List *extents)
10052de3b87aSKai Wang {
10062de3b87aSKai Wang 	off_t nrc, rc;
10072de3b87aSKai Wang 	Elf_Scn *scn, *tscn;
10082de3b87aSKai Wang 	struct _Elf_Extent *ex;
1009*cf781b2eSEd Maste 	unsigned char *newfile;
10102de3b87aSKai Wang 
10112de3b87aSKai Wang 	assert(e->e_kind == ELF_K_ELF);
10122de3b87aSKai Wang 	assert(e->e_cmd == ELF_C_RDWR || e->e_cmd == ELF_C_WRITE);
10132de3b87aSKai Wang 	assert(e->e_fd >= 0);
10142de3b87aSKai Wang 
10152de3b87aSKai Wang 	if ((newfile = malloc((size_t) newsize)) == NULL) {
10162de3b87aSKai Wang 		LIBELF_SET_ERROR(RESOURCE, errno);
10172de3b87aSKai Wang 		return ((off_t) -1);
10182de3b87aSKai Wang 	}
10192de3b87aSKai Wang 
10202de3b87aSKai Wang 	nrc = rc = 0;
10212de3b87aSKai Wang 	SLIST_FOREACH(ex, extents, ex_next) {
10222de3b87aSKai Wang 
10232de3b87aSKai Wang 		/* Fill inter-extent gaps. */
10242de3b87aSKai Wang 		if (ex->ex_start > (size_t) rc)
10252de3b87aSKai Wang 			(void) memset(newfile + rc, LIBELF_PRIVATE(fillchar),
1026*cf781b2eSEd Maste 			    (size_t) (ex->ex_start - (uint64_t) rc));
10272de3b87aSKai Wang 
10282de3b87aSKai Wang 		switch (ex->ex_type) {
10292de3b87aSKai Wang 		case ELF_EXTENT_EHDR:
10302de3b87aSKai Wang 			if ((nrc = _libelf_write_ehdr(e, newfile, ex)) < 0)
10312de3b87aSKai Wang 				goto error;
10322de3b87aSKai Wang 			break;
10332de3b87aSKai Wang 
10342de3b87aSKai Wang 		case ELF_EXTENT_PHDR:
10352de3b87aSKai Wang 			if ((nrc = _libelf_write_phdr(e, newfile, ex)) < 0)
10362de3b87aSKai Wang 				goto error;
10372de3b87aSKai Wang 			break;
10382de3b87aSKai Wang 
10392de3b87aSKai Wang 		case ELF_EXTENT_SECTION:
10402de3b87aSKai Wang 			if ((nrc = _libelf_write_scn(e, newfile, ex)) < 0)
10412de3b87aSKai Wang 				goto error;
10422de3b87aSKai Wang 			break;
10432de3b87aSKai Wang 
10442de3b87aSKai Wang 		case ELF_EXTENT_SHDR:
10452de3b87aSKai Wang 			if ((nrc = _libelf_write_shdr(e, newfile, ex)) < 0)
10462de3b87aSKai Wang 				goto error;
10472de3b87aSKai Wang 			break;
10482de3b87aSKai Wang 
10492de3b87aSKai Wang 		default:
10502de3b87aSKai Wang 			assert(0);
10512de3b87aSKai Wang 			break;
10522de3b87aSKai Wang 		}
10532de3b87aSKai Wang 
10542de3b87aSKai Wang 		assert(ex->ex_start + ex->ex_size == (size_t) nrc);
10552de3b87aSKai Wang 		assert(rc < nrc);
10562de3b87aSKai Wang 
10572de3b87aSKai Wang 		rc = nrc;
10582de3b87aSKai Wang 	}
10592de3b87aSKai Wang 
10602de3b87aSKai Wang 	assert(rc == newsize);
10612de3b87aSKai Wang 
10622de3b87aSKai Wang 	/*
10632de3b87aSKai Wang 	 * For regular files, throw away existing file content and
10642de3b87aSKai Wang 	 * unmap any existing mappings.
10652de3b87aSKai Wang 	 */
10662de3b87aSKai Wang 	if ((e->e_flags & LIBELF_F_SPECIAL_FILE) == 0) {
10672de3b87aSKai Wang 		if (ftruncate(e->e_fd, (off_t) 0) < 0 ||
10682de3b87aSKai Wang 		    lseek(e->e_fd, (off_t) 0, SEEK_SET)) {
10692de3b87aSKai Wang 			LIBELF_SET_ERROR(IO, errno);
10702de3b87aSKai Wang 			goto error;
10712de3b87aSKai Wang 		}
10722de3b87aSKai Wang #if	ELFTC_HAVE_MMAP
10732de3b87aSKai Wang 		if (e->e_flags & LIBELF_F_RAWFILE_MMAP) {
10742de3b87aSKai Wang 			assert(e->e_rawfile != NULL);
10752de3b87aSKai Wang 			assert(e->e_cmd == ELF_C_RDWR);
10762de3b87aSKai Wang 			if (munmap(e->e_rawfile, e->e_rawsize) < 0) {
10772de3b87aSKai Wang 				LIBELF_SET_ERROR(IO, errno);
10782de3b87aSKai Wang 				goto error;
10792de3b87aSKai Wang 			}
10802de3b87aSKai Wang 		}
10812de3b87aSKai Wang #endif
10822de3b87aSKai Wang 	}
10832de3b87aSKai Wang 
10842de3b87aSKai Wang 	/*
10852de3b87aSKai Wang 	 * Write out the new contents.
10862de3b87aSKai Wang 	 */
10872de3b87aSKai Wang 	if (write(e->e_fd, newfile, (size_t) newsize) != newsize) {
10882de3b87aSKai Wang 		LIBELF_SET_ERROR(IO, errno);
10892de3b87aSKai Wang 		goto error;
10902de3b87aSKai Wang 	}
10912de3b87aSKai Wang 
10922de3b87aSKai Wang 	/*
10932de3b87aSKai Wang 	 * For files opened in ELF_C_RDWR mode, set up the new 'raw'
10942de3b87aSKai Wang 	 * contents.
10952de3b87aSKai Wang 	 */
10962de3b87aSKai Wang 	if (e->e_cmd == ELF_C_RDWR) {
10972de3b87aSKai Wang 		assert(e->e_rawfile != NULL);
10982de3b87aSKai Wang 		assert((e->e_flags & LIBELF_F_RAWFILE_MALLOC) ||
10992de3b87aSKai Wang 		    (e->e_flags & LIBELF_F_RAWFILE_MMAP));
11002de3b87aSKai Wang 		if (e->e_flags & LIBELF_F_RAWFILE_MALLOC) {
11012de3b87aSKai Wang 			free(e->e_rawfile);
11022de3b87aSKai Wang 			e->e_rawfile = newfile;
11032de3b87aSKai Wang 			newfile = NULL;
11042de3b87aSKai Wang 		}
11052de3b87aSKai Wang #if	ELFTC_HAVE_MMAP
11062de3b87aSKai Wang 		else if (e->e_flags & LIBELF_F_RAWFILE_MMAP) {
11072de3b87aSKai Wang 			if ((e->e_rawfile = mmap(NULL, (size_t) newsize,
11082de3b87aSKai Wang 			    PROT_READ, MAP_PRIVATE, e->e_fd, (off_t) 0)) ==
11092de3b87aSKai Wang 			    MAP_FAILED) {
11102de3b87aSKai Wang 				LIBELF_SET_ERROR(IO, errno);
11112de3b87aSKai Wang 				goto error;
11122de3b87aSKai Wang 			}
11132de3b87aSKai Wang 		}
11142de3b87aSKai Wang #endif	/* ELFTC_HAVE_MMAP */
11152de3b87aSKai Wang 
11162de3b87aSKai Wang 		/* Record the new size of the file. */
1117*cf781b2eSEd Maste 		e->e_rawsize = (size_t) newsize;
11182de3b87aSKai Wang 	} else {
11192de3b87aSKai Wang 		/* File opened in ELF_C_WRITE mode. */
11202de3b87aSKai Wang 		assert(e->e_rawfile == NULL);
11212de3b87aSKai Wang 	}
11222de3b87aSKai Wang 
11232de3b87aSKai Wang 	/*
11242de3b87aSKai Wang 	 * Reset flags, remove existing section descriptors and
11252de3b87aSKai Wang 	 * {E,P}HDR pointers so that a subsequent elf_get{e,p}hdr()
11262de3b87aSKai Wang 	 * and elf_getscn() will function correctly.
11272de3b87aSKai Wang 	 */
11282de3b87aSKai Wang 
11292de3b87aSKai Wang 	e->e_flags &= ~ELF_F_DIRTY;
11302de3b87aSKai Wang 
11312de3b87aSKai Wang 	STAILQ_FOREACH_SAFE(scn, &e->e_u.e_elf.e_scn, s_next, tscn)
11322de3b87aSKai Wang 		_libelf_release_scn(scn);
11332de3b87aSKai Wang 
11342de3b87aSKai Wang 	if (e->e_class == ELFCLASS32) {
11352de3b87aSKai Wang 		free(e->e_u.e_elf.e_ehdr.e_ehdr32);
11362de3b87aSKai Wang 		if (e->e_u.e_elf.e_phdr.e_phdr32)
11372de3b87aSKai Wang 			free(e->e_u.e_elf.e_phdr.e_phdr32);
11382de3b87aSKai Wang 
11392de3b87aSKai Wang 		e->e_u.e_elf.e_ehdr.e_ehdr32 = NULL;
11402de3b87aSKai Wang 		e->e_u.e_elf.e_phdr.e_phdr32 = NULL;
11412de3b87aSKai Wang 	} else {
11422de3b87aSKai Wang 		free(e->e_u.e_elf.e_ehdr.e_ehdr64);
11432de3b87aSKai Wang 		if (e->e_u.e_elf.e_phdr.e_phdr64)
11442de3b87aSKai Wang 			free(e->e_u.e_elf.e_phdr.e_phdr64);
11452de3b87aSKai Wang 
11462de3b87aSKai Wang 		e->e_u.e_elf.e_ehdr.e_ehdr64 = NULL;
11472de3b87aSKai Wang 		e->e_u.e_elf.e_phdr.e_phdr64 = NULL;
11482de3b87aSKai Wang 	}
11492de3b87aSKai Wang 
11502de3b87aSKai Wang 	/* Free the temporary buffer. */
11512de3b87aSKai Wang 	if (newfile)
11522de3b87aSKai Wang 		free(newfile);
11532de3b87aSKai Wang 
11542de3b87aSKai Wang 	return (rc);
11552de3b87aSKai Wang 
11562de3b87aSKai Wang  error:
11572de3b87aSKai Wang 	free(newfile);
11582de3b87aSKai Wang 
11592de3b87aSKai Wang 	return ((off_t) -1);
11602de3b87aSKai Wang }
11612de3b87aSKai Wang 
11622de3b87aSKai Wang /*
11632de3b87aSKai Wang  * Update an ELF object.
11642de3b87aSKai Wang  */
11652de3b87aSKai Wang 
11662de3b87aSKai Wang off_t
11672de3b87aSKai Wang elf_update(Elf *e, Elf_Cmd c)
11682de3b87aSKai Wang {
11692de3b87aSKai Wang 	int ec;
11702de3b87aSKai Wang 	off_t rc;
11712de3b87aSKai Wang 	struct _Elf_Extent_List extents;
11722de3b87aSKai Wang 
11732de3b87aSKai Wang 	rc = (off_t) -1;
11742de3b87aSKai Wang 
11752de3b87aSKai Wang 	if (e == NULL || e->e_kind != ELF_K_ELF ||
11762de3b87aSKai Wang 	    (c != ELF_C_NULL && c != ELF_C_WRITE)) {
11772de3b87aSKai Wang 		LIBELF_SET_ERROR(ARGUMENT, 0);
11782de3b87aSKai Wang 		return (rc);
11792de3b87aSKai Wang 	}
11802de3b87aSKai Wang 
11812de3b87aSKai Wang 	if ((ec = e->e_class) != ELFCLASS32 && ec != ELFCLASS64) {
11822de3b87aSKai Wang 		LIBELF_SET_ERROR(CLASS, 0);
11832de3b87aSKai Wang 		return (rc);
11842de3b87aSKai Wang 	}
11852de3b87aSKai Wang 
11862de3b87aSKai Wang 	if (e->e_version == EV_NONE)
11872de3b87aSKai Wang 		e->e_version = EV_CURRENT;
11882de3b87aSKai Wang 
11892de3b87aSKai Wang 	if (c == ELF_C_WRITE && e->e_cmd == ELF_C_READ) {
11902de3b87aSKai Wang 		LIBELF_SET_ERROR(MODE, 0);
11912de3b87aSKai Wang 		return (rc);
11922de3b87aSKai Wang 	}
11932de3b87aSKai Wang 
11942de3b87aSKai Wang 	SLIST_INIT(&extents);
11952de3b87aSKai Wang 
11962de3b87aSKai Wang 	if ((rc = _libelf_resync_elf(e, &extents)) < 0)
11972de3b87aSKai Wang 		goto done;
11982de3b87aSKai Wang 
11992de3b87aSKai Wang 	if (c == ELF_C_NULL)
12002de3b87aSKai Wang 		goto done;
12012de3b87aSKai Wang 
12022de3b87aSKai Wang 	if (e->e_fd < 0) {
12032de3b87aSKai Wang 		rc = (off_t) -1;
12042de3b87aSKai Wang 		LIBELF_SET_ERROR(SEQUENCE, 0);
12052de3b87aSKai Wang 		goto done;
12062de3b87aSKai Wang 	}
12072de3b87aSKai Wang 
12082de3b87aSKai Wang 	rc = _libelf_write_elf(e, rc, &extents);
12092de3b87aSKai Wang 
12102de3b87aSKai Wang done:
12112de3b87aSKai Wang 	_libelf_release_extents(&extents);
12122de3b87aSKai Wang 	return (rc);
12132de3b87aSKai Wang }
1214