xref: /freebsd/contrib/elftoolchain/libelf/elf_update.c (revision bd6313b66ee9f5ff929ebdb305239390d189bde3)
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 
44b00fe64fSEd Maste ELFTC_VCSID("$Id: elf_update.c 3190 2015-05-04 15:23:08Z 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;
115cf781b2eSEd 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,
255cf781b2eSEd 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) {
274b00fe64fSEd Maste 		if (scn_alignment > sh_align ||
275b00fe64fSEd Maste 		    sh_offset % sh_align ||
276b00fe64fSEd Maste 		    sh_size < scn_size ||
277b00fe64fSEd Maste 		    sh_offset % _libelf_falign(elftype, ec)) {
2782de3b87aSKai Wang 			LIBELF_SET_ERROR(LAYOUT, 0);
2792de3b87aSKai Wang 			return (0);
2802de3b87aSKai Wang 		}
2812de3b87aSKai Wang 		goto updatedescriptor;
2822de3b87aSKai Wang 	}
2832de3b87aSKai Wang 
2842de3b87aSKai Wang 	/*
2852de3b87aSKai Wang 	 * Otherwise, compute the values in the section header.
2862de3b87aSKai Wang 	 *
2872de3b87aSKai Wang 	 * The section alignment is the maximum alignment for any of
2882de3b87aSKai Wang 	 * its contained data descriptors.
2892de3b87aSKai Wang 	 */
2902de3b87aSKai Wang 	if (scn_alignment > sh_align)
2912de3b87aSKai Wang 		sh_align = scn_alignment;
2922de3b87aSKai Wang 
2932de3b87aSKai Wang 	/*
2942de3b87aSKai Wang 	 * If the section entry size is zero, try and fill in an
2952de3b87aSKai Wang 	 * appropriate entry size.  Per the elf(5) manual page
2962de3b87aSKai Wang 	 * sections without fixed-size entries should have their
2972de3b87aSKai Wang 	 * 'sh_entsize' field set to zero.
2982de3b87aSKai Wang 	 */
2992de3b87aSKai Wang 	if (sh_entsize == 0 &&
3002de3b87aSKai Wang 	    (sh_entsize = _libelf_fsize(elftype, ec, e->e_version,
3012de3b87aSKai Wang 		(size_t) 1)) == 1)
3022de3b87aSKai Wang 		sh_entsize = 0;
3032de3b87aSKai Wang 
3042de3b87aSKai Wang 	sh_size = scn_size;
3052de3b87aSKai Wang 
3062de3b87aSKai Wang computeoffset:
3072de3b87aSKai Wang 	/*
3082de3b87aSKai Wang 	 * Compute the new offset for the section based on
3092de3b87aSKai Wang 	 * the section's alignment needs.
3102de3b87aSKai Wang 	 */
311cf781b2eSEd Maste 	sh_offset = roundup((uint64_t) rc, sh_align);
3122de3b87aSKai Wang 
3132de3b87aSKai Wang 	/*
3142de3b87aSKai Wang 	 * Update the section header.
3152de3b87aSKai Wang 	 */
3162de3b87aSKai Wang 	if (ec == ELFCLASS32) {
3172de3b87aSKai Wang 		shdr32->sh_addralign = (uint32_t) sh_align;
3182de3b87aSKai Wang 		shdr32->sh_entsize   = (uint32_t) sh_entsize;
3192de3b87aSKai Wang 		shdr32->sh_offset    = (uint32_t) sh_offset;
3202de3b87aSKai Wang 		shdr32->sh_size      = (uint32_t) sh_size;
3212de3b87aSKai Wang 	} else {
3222de3b87aSKai Wang 		shdr64->sh_addralign = sh_align;
3232de3b87aSKai Wang 		shdr64->sh_entsize   = sh_entsize;
3242de3b87aSKai Wang 		shdr64->sh_offset    = sh_offset;
3252de3b87aSKai Wang 		shdr64->sh_size      = sh_size;
3262de3b87aSKai Wang 	}
3272de3b87aSKai Wang 
3282de3b87aSKai Wang updatedescriptor:
3292de3b87aSKai Wang 	/*
3302de3b87aSKai Wang 	 * Update the section descriptor.
3312de3b87aSKai Wang 	 */
3322de3b87aSKai Wang 	s->s_size = sh_size;
3332de3b87aSKai Wang 	s->s_offset = sh_offset;
3342de3b87aSKai Wang 
3352de3b87aSKai Wang 	return (1);
3362de3b87aSKai Wang }
3372de3b87aSKai Wang 
3382de3b87aSKai Wang /*
3392de3b87aSKai Wang  * Free a list of extent descriptors.
3402de3b87aSKai Wang  */
3412de3b87aSKai Wang 
3422de3b87aSKai Wang static void
3432de3b87aSKai Wang _libelf_release_extents(struct _Elf_Extent_List *extents)
3442de3b87aSKai Wang {
3452de3b87aSKai Wang 	struct _Elf_Extent *ex;
3462de3b87aSKai Wang 
3472de3b87aSKai Wang 	while ((ex = SLIST_FIRST(extents)) != NULL) {
3482de3b87aSKai Wang 		SLIST_REMOVE_HEAD(extents, ex_next);
3492de3b87aSKai Wang 		free(ex);
3502de3b87aSKai Wang 	}
3512de3b87aSKai Wang }
3522de3b87aSKai Wang 
3532de3b87aSKai Wang /*
3542de3b87aSKai Wang  * Check if an extent 's' defined by [start..start+size) is free.
3552de3b87aSKai Wang  * This routine assumes that the given extent list is sorted in order
3562de3b87aSKai Wang  * of ascending extent offsets.
3572de3b87aSKai Wang  */
3582de3b87aSKai Wang 
3592de3b87aSKai Wang static int
3602de3b87aSKai Wang _libelf_extent_is_unused(struct _Elf_Extent_List *extents,
3612de3b87aSKai Wang     const uint64_t start, const uint64_t size, struct _Elf_Extent **prevt)
3622de3b87aSKai Wang {
3632de3b87aSKai Wang 	uint64_t tmax, tmin;
3642de3b87aSKai Wang 	struct _Elf_Extent *t, *pt;
3652de3b87aSKai Wang 	const uint64_t smax = start + size;
3662de3b87aSKai Wang 
3672de3b87aSKai Wang 	/* First, look for overlaps with existing extents. */
3682de3b87aSKai Wang 	pt = NULL;
3692de3b87aSKai Wang 	SLIST_FOREACH(t, extents, ex_next) {
3702de3b87aSKai Wang 		tmin = t->ex_start;
3712de3b87aSKai Wang 		tmax = tmin + t->ex_size;
3722de3b87aSKai Wang 
3732de3b87aSKai Wang 		if (tmax <= start) {
3742de3b87aSKai Wang 			/*
3752de3b87aSKai Wang 			 * 't' lies entirely before 's': ...| t |...| s |...
3762de3b87aSKai Wang 			 */
3772de3b87aSKai Wang 			pt = t;
3782de3b87aSKai Wang 			continue;
3792de3b87aSKai Wang 		} else if (smax <= tmin) {
3802de3b87aSKai Wang 			/*
3812de3b87aSKai Wang 			 * 's' lies entirely before 't', and after 'pt':
3822de3b87aSKai Wang 			 *      ...| pt |...| s |...| t |...
3832de3b87aSKai Wang 			 */
3842de3b87aSKai Wang 			assert(pt == NULL ||
3852de3b87aSKai Wang 			    pt->ex_start + pt->ex_size <= start);
3862de3b87aSKai Wang 			break;
3872de3b87aSKai Wang 		} else
3882de3b87aSKai Wang 			/* 's' and 't' overlap. */
3892de3b87aSKai Wang 			return (0);
3902de3b87aSKai Wang 	}
3912de3b87aSKai Wang 
3922de3b87aSKai Wang 	if (prevt)
3932de3b87aSKai Wang 		*prevt = pt;
3942de3b87aSKai Wang 	return (1);
3952de3b87aSKai Wang }
3962de3b87aSKai Wang 
3972de3b87aSKai Wang /*
3982de3b87aSKai Wang  * Insert an extent into the list of extents.
3992de3b87aSKai Wang  */
4002de3b87aSKai Wang 
4012de3b87aSKai Wang static int
4022de3b87aSKai Wang _libelf_insert_extent(struct _Elf_Extent_List *extents, int type,
4032de3b87aSKai Wang     uint64_t start, uint64_t size, void *desc)
4042de3b87aSKai Wang {
4052de3b87aSKai Wang 	struct _Elf_Extent *ex, *prevt;
4062de3b87aSKai Wang 
4072de3b87aSKai Wang 	assert(type >= ELF_EXTENT_EHDR && type <= ELF_EXTENT_SHDR);
4082de3b87aSKai Wang 
4092de3b87aSKai Wang 	prevt = NULL;
4102de3b87aSKai Wang 
4112de3b87aSKai Wang 	/*
4122de3b87aSKai Wang 	 * If the requested range overlaps with an existing extent,
4132de3b87aSKai Wang 	 * signal an error.
4142de3b87aSKai Wang 	 */
4152de3b87aSKai Wang 	if (!_libelf_extent_is_unused(extents, start, size, &prevt)) {
4162de3b87aSKai Wang 		LIBELF_SET_ERROR(LAYOUT, 0);
4172de3b87aSKai Wang 		return (0);
4182de3b87aSKai Wang 	}
4192de3b87aSKai Wang 
4202de3b87aSKai Wang 	/* Allocate and fill in a new extent descriptor. */
4212de3b87aSKai Wang 	if ((ex = malloc(sizeof(struct _Elf_Extent))) == NULL) {
4222de3b87aSKai Wang 		LIBELF_SET_ERROR(RESOURCE, errno);
4232de3b87aSKai Wang 		return (0);
4242de3b87aSKai Wang 	}
4252de3b87aSKai Wang 	ex->ex_start = start;
4262de3b87aSKai Wang 	ex->ex_size = size;
4272de3b87aSKai Wang 	ex->ex_desc = desc;
4282de3b87aSKai Wang 	ex->ex_type = type;
4292de3b87aSKai Wang 
4302de3b87aSKai Wang 	/* Insert the region descriptor into the list. */
4312de3b87aSKai Wang 	if (prevt)
4322de3b87aSKai Wang 		SLIST_INSERT_AFTER(prevt, ex, ex_next);
4332de3b87aSKai Wang 	else
4342de3b87aSKai Wang 		SLIST_INSERT_HEAD(extents, ex, ex_next);
4352de3b87aSKai Wang 	return (1);
4362de3b87aSKai Wang }
4372de3b87aSKai Wang 
4382de3b87aSKai Wang /*
4392de3b87aSKai Wang  * Recompute section layout.
4402de3b87aSKai Wang  */
4412de3b87aSKai Wang 
4422de3b87aSKai Wang static off_t
4432de3b87aSKai Wang _libelf_resync_sections(Elf *e, off_t rc, struct _Elf_Extent_List *extents)
4442de3b87aSKai Wang {
4452de3b87aSKai Wang 	int ec;
4462de3b87aSKai Wang 	Elf_Scn *s;
4472de3b87aSKai Wang 	size_t sh_type;
4482de3b87aSKai Wang 
4492de3b87aSKai Wang 	ec = e->e_class;
4502de3b87aSKai Wang 
4512de3b87aSKai Wang 	/*
4522de3b87aSKai Wang 	 * Make a pass through sections, computing the extent of each
4532de3b87aSKai Wang 	 * section.
4542de3b87aSKai Wang 	 */
4552de3b87aSKai Wang 	STAILQ_FOREACH(s, &e->e_u.e_elf.e_scn, s_next) {
4562de3b87aSKai Wang 		if (ec == ELFCLASS32)
4572de3b87aSKai Wang 			sh_type = s->s_shdr.s_shdr32.sh_type;
4582de3b87aSKai Wang 		else
4592de3b87aSKai Wang 			sh_type = s->s_shdr.s_shdr64.sh_type;
4602de3b87aSKai Wang 
4612de3b87aSKai Wang 		if (sh_type == SHT_NOBITS || sh_type == SHT_NULL)
4622de3b87aSKai Wang 			continue;
4632de3b87aSKai Wang 
4642de3b87aSKai Wang 		if (_libelf_compute_section_extents(e, s, rc) == 0)
4652de3b87aSKai Wang 			return ((off_t) -1);
4662de3b87aSKai Wang 
4672de3b87aSKai Wang 		if (s->s_size == 0)
4682de3b87aSKai Wang 			continue;
4692de3b87aSKai Wang 
4702de3b87aSKai Wang 		if (!_libelf_insert_extent(extents, ELF_EXTENT_SECTION,
4712de3b87aSKai Wang 		    s->s_offset, s->s_size, s))
4722de3b87aSKai Wang 			return ((off_t) -1);
4732de3b87aSKai Wang 
4742de3b87aSKai Wang 		if ((size_t) rc < s->s_offset + s->s_size)
475cf781b2eSEd Maste 			rc = (off_t) (s->s_offset + s->s_size);
4762de3b87aSKai Wang 	}
4772de3b87aSKai Wang 
4782de3b87aSKai Wang 	return (rc);
4792de3b87aSKai Wang }
4802de3b87aSKai Wang 
4812de3b87aSKai Wang /*
4822de3b87aSKai Wang  * Recompute the layout of the ELF object and update the internal data
4832de3b87aSKai Wang  * structures associated with the ELF descriptor.
4842de3b87aSKai Wang  *
4852de3b87aSKai Wang  * Returns the size in bytes the ELF object would occupy in its file
4862de3b87aSKai Wang  * representation.
4872de3b87aSKai Wang  *
4882de3b87aSKai Wang  * After a successful call to this function, the following structures
4892de3b87aSKai Wang  * are updated:
4902de3b87aSKai Wang  *
4912de3b87aSKai Wang  * - The ELF header is updated.
4922de3b87aSKai Wang  * - All extents in the ELF object are sorted in order of ascending
4932de3b87aSKai Wang  *   addresses.  Sections have their section header table entries
4942de3b87aSKai Wang  *   updated.  An error is signalled if an overlap was detected among
4952de3b87aSKai Wang  *   extents.
4962de3b87aSKai Wang  * - Data descriptors associated with sections are checked for valid
4972de3b87aSKai Wang  *   types, offsets and alignment.
4982de3b87aSKai Wang  *
4992de3b87aSKai Wang  * After a resync_elf() successfully returns, the ELF descriptor is
5002de3b87aSKai Wang  * ready for being handed over to _libelf_write_elf().
5012de3b87aSKai Wang  */
5022de3b87aSKai Wang 
5032de3b87aSKai Wang static off_t
5042de3b87aSKai Wang _libelf_resync_elf(Elf *e, struct _Elf_Extent_List *extents)
5052de3b87aSKai Wang {
5062de3b87aSKai Wang 	int ec, eh_class;
5072de3b87aSKai Wang 	unsigned int eh_byteorder, eh_version;
5082de3b87aSKai Wang 	size_t align, fsz;
5092de3b87aSKai Wang 	size_t phnum, shnum;
5102de3b87aSKai Wang 	off_t rc, phoff, shoff;
5112de3b87aSKai Wang 	void *ehdr, *phdr;
5122de3b87aSKai Wang 	Elf32_Ehdr *eh32;
5132de3b87aSKai Wang 	Elf64_Ehdr *eh64;
5142de3b87aSKai Wang 
5152de3b87aSKai Wang 	rc = 0;
5162de3b87aSKai Wang 
5172de3b87aSKai Wang 	ec = e->e_class;
5182de3b87aSKai Wang 
5192de3b87aSKai Wang 	assert(ec == ELFCLASS32 || ec == ELFCLASS64);
5202de3b87aSKai Wang 
5212de3b87aSKai Wang 	/*
5222de3b87aSKai Wang 	 * Prepare the EHDR.
5232de3b87aSKai Wang 	 */
5242de3b87aSKai Wang 	if ((ehdr = _libelf_ehdr(e, ec, 0)) == NULL)
5252de3b87aSKai Wang 		return ((off_t) -1);
5262de3b87aSKai Wang 
5272de3b87aSKai Wang 	eh32 = ehdr;
5282de3b87aSKai Wang 	eh64 = ehdr;
5292de3b87aSKai Wang 
5302de3b87aSKai Wang 	if (ec == ELFCLASS32) {
5312de3b87aSKai Wang 		eh_byteorder = eh32->e_ident[EI_DATA];
5322de3b87aSKai Wang 		eh_class     = eh32->e_ident[EI_CLASS];
533cf781b2eSEd Maste 		phoff        = (off_t) eh32->e_phoff;
534cf781b2eSEd Maste 		shoff        = (off_t) eh32->e_shoff;
5352de3b87aSKai Wang 		eh_version   = eh32->e_version;
5362de3b87aSKai Wang 	} else {
5372de3b87aSKai Wang 		eh_byteorder = eh64->e_ident[EI_DATA];
5382de3b87aSKai Wang 		eh_class     = eh64->e_ident[EI_CLASS];
539cf781b2eSEd Maste 		phoff        = (off_t) eh64->e_phoff;
540cf781b2eSEd Maste 		shoff        = (off_t) eh64->e_shoff;
5412de3b87aSKai Wang 		eh_version   = eh64->e_version;
5422de3b87aSKai Wang 	}
5432de3b87aSKai Wang 
544cf781b2eSEd Maste 	if (phoff < 0 || shoff < 0) {
545cf781b2eSEd Maste 		LIBELF_SET_ERROR(HEADER, 0);
546cf781b2eSEd Maste 		return ((off_t) -1);
547cf781b2eSEd Maste 	}
548cf781b2eSEd Maste 
5492de3b87aSKai Wang 	if (eh_version == EV_NONE)
5502de3b87aSKai Wang 		eh_version = EV_CURRENT;
5512de3b87aSKai Wang 
5522de3b87aSKai Wang 	if (eh_version != e->e_version) {	/* always EV_CURRENT */
5532de3b87aSKai Wang 		LIBELF_SET_ERROR(VERSION, 0);
5542de3b87aSKai Wang 		return ((off_t) -1);
5552de3b87aSKai Wang 	}
5562de3b87aSKai Wang 
5572de3b87aSKai Wang 	if (eh_class != e->e_class) {
5582de3b87aSKai Wang 		LIBELF_SET_ERROR(CLASS, 0);
5592de3b87aSKai Wang 		return ((off_t) -1);
5602de3b87aSKai Wang 	}
5612de3b87aSKai Wang 
5622de3b87aSKai Wang 	if (e->e_cmd != ELF_C_WRITE && eh_byteorder != e->e_byteorder) {
5632de3b87aSKai Wang 		LIBELF_SET_ERROR(HEADER, 0);
5642de3b87aSKai Wang 		return ((off_t) -1);
5652de3b87aSKai Wang 	}
5662de3b87aSKai Wang 
5672de3b87aSKai Wang 	shnum = e->e_u.e_elf.e_nscn;
5682de3b87aSKai Wang 	phnum = e->e_u.e_elf.e_nphdr;
5692de3b87aSKai Wang 
5702de3b87aSKai Wang 	e->e_byteorder = eh_byteorder;
5712de3b87aSKai Wang 
5722de3b87aSKai Wang #define	INITIALIZE_EHDR(E,EC,V)	do {					\
573cf781b2eSEd Maste 		unsigned int _version = (unsigned int) (V);		\
5742de3b87aSKai Wang 		(E)->e_ident[EI_MAG0] = ELFMAG0;			\
5752de3b87aSKai Wang 		(E)->e_ident[EI_MAG1] = ELFMAG1;			\
5762de3b87aSKai Wang 		(E)->e_ident[EI_MAG2] = ELFMAG2;			\
5772de3b87aSKai Wang 		(E)->e_ident[EI_MAG3] = ELFMAG3;			\
578cf781b2eSEd Maste 		(E)->e_ident[EI_CLASS] = (unsigned char) (EC);		\
579cf781b2eSEd Maste 		(E)->e_ident[EI_VERSION] = (_version & 0xFFU);		\
580cf781b2eSEd Maste 		(E)->e_ehsize = (uint16_t) _libelf_fsize(ELF_T_EHDR,	\
581cf781b2eSEd Maste 		    (EC), _version, (size_t) 1);			\
582cf781b2eSEd Maste 		(E)->e_phentsize = (uint16_t) ((phnum == 0) ? 0 :	\
583cf781b2eSEd Maste 		    _libelf_fsize(ELF_T_PHDR, (EC), _version,		\
584cf781b2eSEd Maste 			(size_t) 1));					\
585cf781b2eSEd Maste 		(E)->e_shentsize = (uint16_t) _libelf_fsize(ELF_T_SHDR,	\
586cf781b2eSEd Maste 		    (EC), _version, (size_t) 1);			\
5872de3b87aSKai Wang 	} while (0)
5882de3b87aSKai Wang 
5892de3b87aSKai Wang 	if (ec == ELFCLASS32)
5902de3b87aSKai Wang 		INITIALIZE_EHDR(eh32, ec, eh_version);
5912de3b87aSKai Wang 	else
5922de3b87aSKai Wang 		INITIALIZE_EHDR(eh64, ec, eh_version);
5932de3b87aSKai Wang 
5942de3b87aSKai Wang 	(void) elf_flagehdr(e, ELF_C_SET, ELF_F_DIRTY);
5952de3b87aSKai Wang 
596cf781b2eSEd Maste 	rc += (off_t) _libelf_fsize(ELF_T_EHDR, ec, eh_version, (size_t) 1);
5972de3b87aSKai Wang 
598cf781b2eSEd Maste 	if (!_libelf_insert_extent(extents, ELF_EXTENT_EHDR, 0, (uint64_t) rc,
599cf781b2eSEd Maste 		ehdr))
6002de3b87aSKai Wang 		return ((off_t) -1);
6012de3b87aSKai Wang 
6022de3b87aSKai Wang 	/*
6032de3b87aSKai Wang 	 * Compute the layout the program header table, if one is
6042de3b87aSKai Wang 	 * present.  The program header table needs to be aligned to a
6052de3b87aSKai Wang 	 * `natural' boundary.
6062de3b87aSKai Wang 	 */
6072de3b87aSKai Wang 	if (phnum) {
6082de3b87aSKai Wang 		fsz = _libelf_fsize(ELF_T_PHDR, ec, eh_version, phnum);
6092de3b87aSKai Wang 		align = _libelf_falign(ELF_T_PHDR, ec);
6102de3b87aSKai Wang 
6112de3b87aSKai Wang 		if (e->e_flags & ELF_F_LAYOUT) {
6122de3b87aSKai Wang 			/*
6132de3b87aSKai Wang 			 * Check offsets for sanity.
6142de3b87aSKai Wang 			 */
6152de3b87aSKai Wang 			if (rc > phoff) {
6162de3b87aSKai Wang 				LIBELF_SET_ERROR(LAYOUT, 0);
6172de3b87aSKai Wang 				return ((off_t) -1);
6182de3b87aSKai Wang 			}
6192de3b87aSKai Wang 
620cf781b2eSEd Maste 			if (phoff % (off_t) align) {
6212de3b87aSKai Wang 				LIBELF_SET_ERROR(LAYOUT, 0);
6222de3b87aSKai Wang 				return ((off_t) -1);
6232de3b87aSKai Wang 			}
6242de3b87aSKai Wang 
6252de3b87aSKai Wang 		} else
626cf781b2eSEd Maste 			phoff = roundup(rc, (off_t) align);
6272de3b87aSKai Wang 
628cf781b2eSEd Maste 		rc = phoff + (off_t) fsz;
6292de3b87aSKai Wang 
6302de3b87aSKai Wang 		phdr = _libelf_getphdr(e, ec);
6312de3b87aSKai Wang 
632cf781b2eSEd Maste 		if (!_libelf_insert_extent(extents, ELF_EXTENT_PHDR,
633cf781b2eSEd Maste 			(uint64_t) phoff, fsz, phdr))
6342de3b87aSKai Wang 			return ((off_t) -1);
6352de3b87aSKai Wang 	} else
6362de3b87aSKai Wang 		phoff = 0;
6372de3b87aSKai Wang 
6382de3b87aSKai Wang 	/*
6392de3b87aSKai Wang 	 * Compute the layout of the sections associated with the
6402de3b87aSKai Wang 	 * file.
6412de3b87aSKai Wang 	 */
6422de3b87aSKai Wang 
6432de3b87aSKai Wang 	if (e->e_cmd != ELF_C_WRITE &&
6442de3b87aSKai Wang 	    (e->e_flags & LIBELF_F_SHDRS_LOADED) == 0 &&
6452de3b87aSKai Wang 	    _libelf_load_section_headers(e, ehdr) == 0)
6462de3b87aSKai Wang 		return ((off_t) -1);
6472de3b87aSKai Wang 
6482de3b87aSKai Wang 	if ((rc = _libelf_resync_sections(e, rc, extents)) < 0)
6492de3b87aSKai Wang 		return ((off_t) -1);
6502de3b87aSKai Wang 
6512de3b87aSKai Wang 	/*
6522de3b87aSKai Wang 	 * Compute the space taken up by the section header table, if
6532de3b87aSKai Wang 	 * one is needed.
6542de3b87aSKai Wang 	 *
6552de3b87aSKai Wang 	 * If ELF_F_LAYOUT has been asserted, the application may have
6562de3b87aSKai Wang 	 * placed the section header table in between existing
6572de3b87aSKai Wang 	 * sections, so the net size of the file need not increase due
6582de3b87aSKai Wang 	 * to the presence of the section header table.
6592de3b87aSKai Wang 	 *
6602de3b87aSKai Wang 	 * If the library is responsible for laying out the object,
6612de3b87aSKai Wang 	 * the section header table is placed after section data.
6622de3b87aSKai Wang 	 */
6632de3b87aSKai Wang 	if (shnum) {
6642de3b87aSKai Wang 		fsz = _libelf_fsize(ELF_T_SHDR, ec, eh_version, shnum);
6652de3b87aSKai Wang 		align = _libelf_falign(ELF_T_SHDR, ec);
6662de3b87aSKai Wang 
6672de3b87aSKai Wang 		if (e->e_flags & ELF_F_LAYOUT) {
668cf781b2eSEd Maste 			if (shoff % (off_t) align) {
6692de3b87aSKai Wang 				LIBELF_SET_ERROR(LAYOUT, 0);
6702de3b87aSKai Wang 				return ((off_t) -1);
6712de3b87aSKai Wang 			}
6722de3b87aSKai Wang 		} else
673cf781b2eSEd Maste 			shoff = roundup(rc, (off_t) align);
6742de3b87aSKai Wang 
675cf781b2eSEd Maste 		if (shoff + (off_t) fsz > rc)
676cf781b2eSEd Maste 			rc = shoff + (off_t) fsz;
6772de3b87aSKai Wang 
678cf781b2eSEd Maste 		if (!_libelf_insert_extent(extents, ELF_EXTENT_SHDR,
679cf781b2eSEd Maste 			(uint64_t) shoff, fsz, NULL))
6802de3b87aSKai Wang 			return ((off_t) -1);
6812de3b87aSKai Wang 	} else
6822de3b87aSKai Wang 		shoff = 0;
6832de3b87aSKai Wang 
6842de3b87aSKai Wang 	/*
6852de3b87aSKai Wang 	 * Set the fields of the Executable Header that could potentially use
6862de3b87aSKai Wang 	 * extended numbering.
6872de3b87aSKai Wang 	 */
6882de3b87aSKai Wang 	_libelf_setphnum(e, ehdr, ec, phnum);
6892de3b87aSKai Wang 	_libelf_setshnum(e, ehdr, ec, shnum);
6902de3b87aSKai Wang 
6912de3b87aSKai Wang 	/*
6922de3b87aSKai Wang 	 * Update the `e_phoff' and `e_shoff' fields if the library is
6932de3b87aSKai Wang 	 * doing the layout.
6942de3b87aSKai Wang 	 */
6952de3b87aSKai Wang 	if ((e->e_flags & ELF_F_LAYOUT) == 0) {
6962de3b87aSKai Wang 		if (ec == ELFCLASS32) {
6972de3b87aSKai Wang 			eh32->e_phoff = (uint32_t) phoff;
6982de3b87aSKai Wang 			eh32->e_shoff = (uint32_t) shoff;
6992de3b87aSKai Wang 		} else {
7002de3b87aSKai Wang 			eh64->e_phoff = (uint64_t) phoff;
7012de3b87aSKai Wang 			eh64->e_shoff = (uint64_t) shoff;
7022de3b87aSKai Wang 		}
7032de3b87aSKai Wang 	}
7042de3b87aSKai Wang 
7052de3b87aSKai Wang 	return (rc);
7062de3b87aSKai Wang }
7072de3b87aSKai Wang 
7082de3b87aSKai Wang /*
7092de3b87aSKai Wang  * Write out the contents of an ELF section.
7102de3b87aSKai Wang  */
7112de3b87aSKai Wang 
712cf781b2eSEd Maste static off_t
713cf781b2eSEd Maste _libelf_write_scn(Elf *e, unsigned char *nf, struct _Elf_Extent *ex)
7142de3b87aSKai Wang {
7152de3b87aSKai Wang 	int ec;
716cf781b2eSEd Maste 	off_t rc;
7172de3b87aSKai Wang 	Elf_Scn *s;
7182de3b87aSKai Wang 	int elftype;
7192de3b87aSKai Wang 	Elf_Data *d, dst;
7202de3b87aSKai Wang 	uint32_t sh_type;
7212de3b87aSKai Wang 	struct _Libelf_Data *ld;
7222de3b87aSKai Wang 	uint64_t sh_off, sh_size;
723cf781b2eSEd Maste 	size_t fsz, msz, nobjects;
7242de3b87aSKai Wang 
7252de3b87aSKai Wang 	assert(ex->ex_type == ELF_EXTENT_SECTION);
7262de3b87aSKai Wang 
7272de3b87aSKai Wang 	s = ex->ex_desc;
728cf781b2eSEd Maste 	rc = (off_t) ex->ex_start;
7292de3b87aSKai Wang 
7302de3b87aSKai Wang 	if ((ec = e->e_class) == ELFCLASS32) {
7312de3b87aSKai Wang 		sh_type = s->s_shdr.s_shdr32.sh_type;
7322de3b87aSKai Wang 		sh_size = (uint64_t) s->s_shdr.s_shdr32.sh_size;
7332de3b87aSKai Wang 	} else {
7342de3b87aSKai Wang 		sh_type = s->s_shdr.s_shdr64.sh_type;
7352de3b87aSKai Wang 		sh_size = s->s_shdr.s_shdr64.sh_size;
7362de3b87aSKai Wang 	}
7372de3b87aSKai Wang 
7382de3b87aSKai Wang 	/*
7392de3b87aSKai Wang 	 * Ignore sections that do not allocate space in the file.
7402de3b87aSKai Wang 	 */
7412de3b87aSKai Wang 	if (sh_type == SHT_NOBITS || sh_type == SHT_NULL || sh_size == 0)
7422de3b87aSKai Wang 		return (rc);
7432de3b87aSKai Wang 
7442de3b87aSKai Wang 	elftype = _libelf_xlate_shtype(sh_type);
7452de3b87aSKai Wang 	assert(elftype >= ELF_T_FIRST && elftype <= ELF_T_LAST);
7462de3b87aSKai Wang 
7472de3b87aSKai Wang 	sh_off = s->s_offset;
7482de3b87aSKai Wang 	assert(sh_off % _libelf_falign(elftype, ec) == 0);
7492de3b87aSKai Wang 
7502de3b87aSKai Wang 	/*
7512de3b87aSKai Wang 	 * If the section has a `rawdata' descriptor, and the section
7522de3b87aSKai Wang 	 * contents have not been modified, use its contents directly.
7532de3b87aSKai Wang 	 * The `s_rawoff' member contains the offset into the original
7542de3b87aSKai Wang 	 * file, while `s_offset' contains its new location in the
7552de3b87aSKai Wang 	 * destination.
7562de3b87aSKai Wang 	 */
7572de3b87aSKai Wang 
7582de3b87aSKai Wang 	if (STAILQ_EMPTY(&s->s_data)) {
7592de3b87aSKai Wang 
7602de3b87aSKai Wang 		if ((d = elf_rawdata(s, NULL)) == NULL)
7612de3b87aSKai Wang 			return ((off_t) -1);
7622de3b87aSKai Wang 
7632de3b87aSKai Wang 		STAILQ_FOREACH(ld, &s->s_rawdata, d_next) {
7642de3b87aSKai Wang 
7652de3b87aSKai Wang 			d = &ld->d_data;
7662de3b87aSKai Wang 
7672de3b87aSKai Wang 			if ((uint64_t) rc < sh_off + d->d_off)
7682de3b87aSKai Wang 				(void) memset(nf + rc,
769cf781b2eSEd Maste 				    LIBELF_PRIVATE(fillchar),
770cf781b2eSEd Maste 				    (size_t) (sh_off + d->d_off -
771cf781b2eSEd Maste 					(uint64_t) rc));
772cf781b2eSEd Maste 			rc = (off_t) (sh_off + d->d_off);
7732de3b87aSKai Wang 
7742de3b87aSKai Wang 			assert(d->d_buf != NULL);
7752de3b87aSKai Wang 			assert(d->d_type == ELF_T_BYTE);
7762de3b87aSKai Wang 			assert(d->d_version == e->e_version);
7772de3b87aSKai Wang 
7782de3b87aSKai Wang 			(void) memcpy(nf + rc,
779cf781b2eSEd Maste 			    e->e_rawfile + s->s_rawoff + d->d_off,
780cf781b2eSEd Maste 			    (size_t) d->d_size);
7812de3b87aSKai Wang 
782cf781b2eSEd Maste 			rc += (off_t) d->d_size;
7832de3b87aSKai Wang 		}
7842de3b87aSKai Wang 
7852de3b87aSKai Wang 		return (rc);
7862de3b87aSKai Wang 	}
7872de3b87aSKai Wang 
7882de3b87aSKai Wang 	/*
7892de3b87aSKai Wang 	 * Iterate over the set of data descriptors for this section.
7902de3b87aSKai Wang 	 * The prior call to _libelf_resync_elf() would have setup the
7912de3b87aSKai Wang 	 * descriptors for this step.
7922de3b87aSKai Wang 	 */
7932de3b87aSKai Wang 
7942de3b87aSKai Wang 	dst.d_version = e->e_version;
7952de3b87aSKai Wang 
7962de3b87aSKai Wang 	STAILQ_FOREACH(ld, &s->s_data, d_next) {
7972de3b87aSKai Wang 
7982de3b87aSKai Wang 		d = &ld->d_data;
7992de3b87aSKai Wang 
8002de3b87aSKai Wang 		msz = _libelf_msize(d->d_type, ec, e->e_version);
8012de3b87aSKai Wang 
8022de3b87aSKai Wang 		if ((uint64_t) rc < sh_off + d->d_off)
8032de3b87aSKai Wang 			(void) memset(nf + rc,
804cf781b2eSEd Maste 			    LIBELF_PRIVATE(fillchar),
805cf781b2eSEd Maste 			    (size_t) (sh_off + d->d_off - (uint64_t) rc));
8062de3b87aSKai Wang 
807cf781b2eSEd Maste 		rc = (off_t) (sh_off + d->d_off);
8082de3b87aSKai Wang 
8092de3b87aSKai Wang 		assert(d->d_buf != NULL);
8102de3b87aSKai Wang 		assert(d->d_version == e->e_version);
811f2911fa4SEd Maste 		assert(msz != 0);
8122de3b87aSKai Wang 		assert(d->d_size % msz == 0);
8132de3b87aSKai Wang 
814cf781b2eSEd Maste 		nobjects = (size_t) (d->d_size / msz);
8152de3b87aSKai Wang 
8162de3b87aSKai Wang 		fsz = _libelf_fsize(d->d_type, ec, e->e_version, nobjects);
8172de3b87aSKai Wang 
8182de3b87aSKai Wang 		dst.d_buf    = nf + rc;
8192de3b87aSKai Wang 		dst.d_size   = fsz;
8202de3b87aSKai Wang 
8212de3b87aSKai Wang 		if (_libelf_xlate(&dst, d, e->e_byteorder, ec, ELF_TOFILE) ==
8222de3b87aSKai Wang 		    NULL)
8232de3b87aSKai Wang 			return ((off_t) -1);
8242de3b87aSKai Wang 
825cf781b2eSEd Maste 		rc += (off_t) fsz;
8262de3b87aSKai Wang 	}
8272de3b87aSKai Wang 
828cf781b2eSEd Maste 	return (rc);
8292de3b87aSKai Wang }
8302de3b87aSKai Wang 
8312de3b87aSKai Wang /*
8322de3b87aSKai Wang  * Write out an ELF Executable Header.
8332de3b87aSKai Wang  */
8342de3b87aSKai Wang 
8352de3b87aSKai Wang static off_t
836cf781b2eSEd Maste _libelf_write_ehdr(Elf *e, unsigned char *nf, struct _Elf_Extent *ex)
8372de3b87aSKai Wang {
8382de3b87aSKai Wang 	int ec;
8392de3b87aSKai Wang 	void *ehdr;
8402de3b87aSKai Wang 	size_t fsz, msz;
8412de3b87aSKai Wang 	Elf_Data dst, src;
8422de3b87aSKai Wang 
8432de3b87aSKai Wang 	assert(ex->ex_type == ELF_EXTENT_EHDR);
8442de3b87aSKai Wang 	assert(ex->ex_start == 0); /* Ehdr always comes first. */
8452de3b87aSKai Wang 
8462de3b87aSKai Wang 	ec = e->e_class;
8472de3b87aSKai Wang 
8482de3b87aSKai Wang 	ehdr = _libelf_ehdr(e, ec, 0);
8492de3b87aSKai Wang 	assert(ehdr != NULL);
8502de3b87aSKai Wang 
8512de3b87aSKai Wang 	fsz = _libelf_fsize(ELF_T_EHDR, ec, e->e_version, (size_t) 1);
8522de3b87aSKai Wang 	msz = _libelf_msize(ELF_T_EHDR, ec, e->e_version);
8532de3b87aSKai Wang 
8542de3b87aSKai Wang 	(void) memset(&dst, 0, sizeof(dst));
8552de3b87aSKai Wang 	(void) memset(&src, 0, sizeof(src));
8562de3b87aSKai Wang 
8572de3b87aSKai Wang 	src.d_buf     = ehdr;
8582de3b87aSKai Wang 	src.d_size    = msz;
8592de3b87aSKai Wang 	src.d_type    = ELF_T_EHDR;
8602de3b87aSKai Wang 	src.d_version = dst.d_version = e->e_version;
8612de3b87aSKai Wang 
8622de3b87aSKai Wang 	dst.d_buf     = nf;
8632de3b87aSKai Wang 	dst.d_size    = fsz;
8642de3b87aSKai Wang 
8652de3b87aSKai Wang 	if (_libelf_xlate(&dst, &src, e->e_byteorder, ec, ELF_TOFILE) ==
8662de3b87aSKai Wang 	    NULL)
8672de3b87aSKai Wang 		return ((off_t) -1);
8682de3b87aSKai Wang 
8692de3b87aSKai Wang 	return ((off_t) fsz);
8702de3b87aSKai Wang }
8712de3b87aSKai Wang 
8722de3b87aSKai Wang /*
8732de3b87aSKai Wang  * Write out an ELF program header table.
8742de3b87aSKai Wang  */
8752de3b87aSKai Wang 
8762de3b87aSKai Wang static off_t
877cf781b2eSEd Maste _libelf_write_phdr(Elf *e, unsigned char *nf, struct _Elf_Extent *ex)
8782de3b87aSKai Wang {
8792de3b87aSKai Wang 	int ec;
8802de3b87aSKai Wang 	void *ehdr;
8812de3b87aSKai Wang 	Elf32_Ehdr *eh32;
8822de3b87aSKai Wang 	Elf64_Ehdr *eh64;
8832de3b87aSKai Wang 	Elf_Data dst, src;
8842de3b87aSKai Wang 	size_t fsz, phnum;
8852de3b87aSKai Wang 	uint64_t phoff;
8862de3b87aSKai Wang 
8872de3b87aSKai Wang 	assert(ex->ex_type == ELF_EXTENT_PHDR);
8882de3b87aSKai Wang 
8892de3b87aSKai Wang 	ec = e->e_class;
8902de3b87aSKai Wang 	ehdr = _libelf_ehdr(e, ec, 0);
8912de3b87aSKai Wang 	phnum = e->e_u.e_elf.e_nphdr;
8922de3b87aSKai Wang 
8932de3b87aSKai Wang 	assert(phnum > 0);
8942de3b87aSKai Wang 
8952de3b87aSKai Wang 	if (ec == ELFCLASS32) {
8962de3b87aSKai Wang 		eh32 = (Elf32_Ehdr *) ehdr;
8972de3b87aSKai Wang 		phoff = (uint64_t) eh32->e_phoff;
8982de3b87aSKai Wang 	} else {
8992de3b87aSKai Wang 		eh64 = (Elf64_Ehdr *) ehdr;
9002de3b87aSKai Wang 		phoff = eh64->e_phoff;
9012de3b87aSKai Wang 	}
9022de3b87aSKai Wang 
9032de3b87aSKai Wang 	assert(phoff > 0);
9042de3b87aSKai Wang 	assert(ex->ex_start == phoff);
9052de3b87aSKai Wang 	assert(phoff % _libelf_falign(ELF_T_PHDR, ec) == 0);
9062de3b87aSKai Wang 
9072de3b87aSKai Wang 	(void) memset(&dst, 0, sizeof(dst));
9082de3b87aSKai Wang 	(void) memset(&src, 0, sizeof(src));
9092de3b87aSKai Wang 
9102de3b87aSKai Wang 	fsz = _libelf_fsize(ELF_T_PHDR, ec, e->e_version, phnum);
9112de3b87aSKai Wang 	assert(fsz > 0);
9122de3b87aSKai Wang 
9132de3b87aSKai Wang 	src.d_buf = _libelf_getphdr(e, ec);
9142de3b87aSKai Wang 	src.d_version = dst.d_version = e->e_version;
9152de3b87aSKai Wang 	src.d_type = ELF_T_PHDR;
9162de3b87aSKai Wang 	src.d_size = phnum * _libelf_msize(ELF_T_PHDR, ec,
9172de3b87aSKai Wang 	    e->e_version);
9182de3b87aSKai Wang 
9192de3b87aSKai Wang 	dst.d_size = fsz;
9202de3b87aSKai Wang 	dst.d_buf = nf + ex->ex_start;
9212de3b87aSKai Wang 
9222de3b87aSKai Wang 	if (_libelf_xlate(&dst, &src, e->e_byteorder, ec, ELF_TOFILE) ==
9232de3b87aSKai Wang 	    NULL)
9242de3b87aSKai Wang 		return ((off_t) -1);
9252de3b87aSKai Wang 
926cf781b2eSEd Maste 	return ((off_t) (phoff + fsz));
9272de3b87aSKai Wang }
9282de3b87aSKai Wang 
9292de3b87aSKai Wang /*
9302de3b87aSKai Wang  * Write out an ELF section header table.
9312de3b87aSKai Wang  */
9322de3b87aSKai Wang 
9332de3b87aSKai Wang static off_t
934cf781b2eSEd Maste _libelf_write_shdr(Elf *e, unsigned char *nf, struct _Elf_Extent *ex)
9352de3b87aSKai Wang {
9362de3b87aSKai Wang 	int ec;
9372de3b87aSKai Wang 	void *ehdr;
9382de3b87aSKai Wang 	Elf_Scn *scn;
9392de3b87aSKai Wang 	uint64_t shoff;
9402de3b87aSKai Wang 	Elf32_Ehdr *eh32;
9412de3b87aSKai Wang 	Elf64_Ehdr *eh64;
9422de3b87aSKai Wang 	size_t fsz, nscn;
9432de3b87aSKai Wang 	Elf_Data dst, src;
9442de3b87aSKai Wang 
9452de3b87aSKai Wang 	assert(ex->ex_type == ELF_EXTENT_SHDR);
9462de3b87aSKai Wang 
9472de3b87aSKai Wang 	ec = e->e_class;
9482de3b87aSKai Wang 	ehdr = _libelf_ehdr(e, ec, 0);
9492de3b87aSKai Wang 	nscn = e->e_u.e_elf.e_nscn;
9502de3b87aSKai Wang 
9512de3b87aSKai Wang 	if (ec == ELFCLASS32) {
9522de3b87aSKai Wang 		eh32 = (Elf32_Ehdr *) ehdr;
9532de3b87aSKai Wang 		shoff = (uint64_t) eh32->e_shoff;
9542de3b87aSKai Wang 	} else {
9552de3b87aSKai Wang 		eh64 = (Elf64_Ehdr *) ehdr;
9562de3b87aSKai Wang 		shoff = eh64->e_shoff;
9572de3b87aSKai Wang 	}
9582de3b87aSKai Wang 
9592de3b87aSKai Wang 	assert(nscn > 0);
9602de3b87aSKai Wang 	assert(shoff % _libelf_falign(ELF_T_SHDR, ec) == 0);
9612de3b87aSKai Wang 	assert(ex->ex_start == shoff);
9622de3b87aSKai Wang 
9632de3b87aSKai Wang 	(void) memset(&dst, 0, sizeof(dst));
9642de3b87aSKai Wang 	(void) memset(&src, 0, sizeof(src));
9652de3b87aSKai Wang 
9662de3b87aSKai Wang 	src.d_type = ELF_T_SHDR;
9672de3b87aSKai Wang 	src.d_size = _libelf_msize(ELF_T_SHDR, ec, e->e_version);
9682de3b87aSKai Wang 	src.d_version = dst.d_version = e->e_version;
9692de3b87aSKai Wang 
9702de3b87aSKai Wang 	fsz = _libelf_fsize(ELF_T_SHDR, ec, e->e_version, (size_t) 1);
9712de3b87aSKai Wang 
9722de3b87aSKai Wang 	STAILQ_FOREACH(scn, &e->e_u.e_elf.e_scn, s_next) {
9732de3b87aSKai Wang 		if (ec == ELFCLASS32)
9742de3b87aSKai Wang 			src.d_buf = &scn->s_shdr.s_shdr32;
9752de3b87aSKai Wang 		else
9762de3b87aSKai Wang 			src.d_buf = &scn->s_shdr.s_shdr64;
9772de3b87aSKai Wang 
9782de3b87aSKai Wang 		dst.d_size = fsz;
9792de3b87aSKai Wang 		dst.d_buf = nf + ex->ex_start + scn->s_ndx * fsz;
9802de3b87aSKai Wang 
9812de3b87aSKai Wang 		if (_libelf_xlate(&dst, &src, e->e_byteorder, ec,
9822de3b87aSKai Wang 		    ELF_TOFILE) == NULL)
9832de3b87aSKai Wang 			return ((off_t) -1);
9842de3b87aSKai Wang 	}
9852de3b87aSKai Wang 
986cf781b2eSEd Maste 	return ((off_t) (ex->ex_start + nscn * fsz));
9872de3b87aSKai Wang }
9882de3b87aSKai Wang 
9892de3b87aSKai Wang /*
9902de3b87aSKai Wang  * Write out the file image.
9912de3b87aSKai Wang  *
9922de3b87aSKai Wang  * The original file could have been mapped in with an ELF_C_RDWR
9932de3b87aSKai Wang  * command and the application could have added new content or
9942de3b87aSKai Wang  * re-arranged its sections before calling elf_update().  Consequently
9952de3b87aSKai Wang  * its not safe to work `in place' on the original file.  So we
9962de3b87aSKai Wang  * malloc() the required space for the updated ELF object and build
9972de3b87aSKai Wang  * the object there and write it out to the underlying file at the
9982de3b87aSKai Wang  * end.  Note that the application may have opened the underlying file
9992de3b87aSKai Wang  * in ELF_C_RDWR and only retrieved/modified a few sections.  We take
10002de3b87aSKai Wang  * care to avoid translating file sections unnecessarily.
10012de3b87aSKai Wang  *
10022de3b87aSKai Wang  * Gaps in the coverage of the file by the file's sections will be
10032de3b87aSKai Wang  * filled with the fill character set by elf_fill(3).
10042de3b87aSKai Wang  */
10052de3b87aSKai Wang 
10062de3b87aSKai Wang static off_t
10072de3b87aSKai Wang _libelf_write_elf(Elf *e, off_t newsize, struct _Elf_Extent_List *extents)
10082de3b87aSKai Wang {
10092de3b87aSKai Wang 	off_t nrc, rc;
10102de3b87aSKai Wang 	Elf_Scn *scn, *tscn;
10112de3b87aSKai Wang 	struct _Elf_Extent *ex;
1012cf781b2eSEd Maste 	unsigned char *newfile;
10132de3b87aSKai Wang 
10142de3b87aSKai Wang 	assert(e->e_kind == ELF_K_ELF);
10152de3b87aSKai Wang 	assert(e->e_cmd == ELF_C_RDWR || e->e_cmd == ELF_C_WRITE);
10162de3b87aSKai Wang 	assert(e->e_fd >= 0);
10172de3b87aSKai Wang 
10182de3b87aSKai Wang 	if ((newfile = malloc((size_t) newsize)) == NULL) {
10192de3b87aSKai Wang 		LIBELF_SET_ERROR(RESOURCE, errno);
10202de3b87aSKai Wang 		return ((off_t) -1);
10212de3b87aSKai Wang 	}
10222de3b87aSKai Wang 
10232de3b87aSKai Wang 	nrc = rc = 0;
10242de3b87aSKai Wang 	SLIST_FOREACH(ex, extents, ex_next) {
10252de3b87aSKai Wang 
10262de3b87aSKai Wang 		/* Fill inter-extent gaps. */
10272de3b87aSKai Wang 		if (ex->ex_start > (size_t) rc)
10282de3b87aSKai Wang 			(void) memset(newfile + rc, LIBELF_PRIVATE(fillchar),
1029cf781b2eSEd Maste 			    (size_t) (ex->ex_start - (uint64_t) rc));
10302de3b87aSKai Wang 
10312de3b87aSKai Wang 		switch (ex->ex_type) {
10322de3b87aSKai Wang 		case ELF_EXTENT_EHDR:
10332de3b87aSKai Wang 			if ((nrc = _libelf_write_ehdr(e, newfile, ex)) < 0)
10342de3b87aSKai Wang 				goto error;
10352de3b87aSKai Wang 			break;
10362de3b87aSKai Wang 
10372de3b87aSKai Wang 		case ELF_EXTENT_PHDR:
10382de3b87aSKai Wang 			if ((nrc = _libelf_write_phdr(e, newfile, ex)) < 0)
10392de3b87aSKai Wang 				goto error;
10402de3b87aSKai Wang 			break;
10412de3b87aSKai Wang 
10422de3b87aSKai Wang 		case ELF_EXTENT_SECTION:
10432de3b87aSKai Wang 			if ((nrc = _libelf_write_scn(e, newfile, ex)) < 0)
10442de3b87aSKai Wang 				goto error;
10452de3b87aSKai Wang 			break;
10462de3b87aSKai Wang 
10472de3b87aSKai Wang 		case ELF_EXTENT_SHDR:
10482de3b87aSKai Wang 			if ((nrc = _libelf_write_shdr(e, newfile, ex)) < 0)
10492de3b87aSKai Wang 				goto error;
10502de3b87aSKai Wang 			break;
10512de3b87aSKai Wang 
10522de3b87aSKai Wang 		default:
10532de3b87aSKai Wang 			assert(0);
10542de3b87aSKai Wang 			break;
10552de3b87aSKai Wang 		}
10562de3b87aSKai Wang 
10572de3b87aSKai Wang 		assert(ex->ex_start + ex->ex_size == (size_t) nrc);
10582de3b87aSKai Wang 		assert(rc < nrc);
10592de3b87aSKai Wang 
10602de3b87aSKai Wang 		rc = nrc;
10612de3b87aSKai Wang 	}
10622de3b87aSKai Wang 
10632de3b87aSKai Wang 	assert(rc == newsize);
10642de3b87aSKai Wang 
10652de3b87aSKai Wang 	/*
10662de3b87aSKai Wang 	 * For regular files, throw away existing file content and
10672de3b87aSKai Wang 	 * unmap any existing mappings.
10682de3b87aSKai Wang 	 */
10692de3b87aSKai Wang 	if ((e->e_flags & LIBELF_F_SPECIAL_FILE) == 0) {
10702de3b87aSKai Wang 		if (ftruncate(e->e_fd, (off_t) 0) < 0 ||
10712de3b87aSKai Wang 		    lseek(e->e_fd, (off_t) 0, SEEK_SET)) {
10722de3b87aSKai Wang 			LIBELF_SET_ERROR(IO, errno);
10732de3b87aSKai Wang 			goto error;
10742de3b87aSKai Wang 		}
10752de3b87aSKai Wang #if	ELFTC_HAVE_MMAP
10762de3b87aSKai Wang 		if (e->e_flags & LIBELF_F_RAWFILE_MMAP) {
10772de3b87aSKai Wang 			assert(e->e_rawfile != NULL);
10782de3b87aSKai Wang 			assert(e->e_cmd == ELF_C_RDWR);
10792de3b87aSKai Wang 			if (munmap(e->e_rawfile, e->e_rawsize) < 0) {
10802de3b87aSKai Wang 				LIBELF_SET_ERROR(IO, errno);
10812de3b87aSKai Wang 				goto error;
10822de3b87aSKai Wang 			}
10832de3b87aSKai Wang 		}
10842de3b87aSKai Wang #endif
10852de3b87aSKai Wang 	}
10862de3b87aSKai Wang 
10872de3b87aSKai Wang 	/*
10882de3b87aSKai Wang 	 * Write out the new contents.
10892de3b87aSKai Wang 	 */
10902de3b87aSKai Wang 	if (write(e->e_fd, newfile, (size_t) newsize) != newsize) {
10912de3b87aSKai Wang 		LIBELF_SET_ERROR(IO, errno);
10922de3b87aSKai Wang 		goto error;
10932de3b87aSKai Wang 	}
10942de3b87aSKai Wang 
10952de3b87aSKai Wang 	/*
10962de3b87aSKai Wang 	 * For files opened in ELF_C_RDWR mode, set up the new 'raw'
10972de3b87aSKai Wang 	 * contents.
10982de3b87aSKai Wang 	 */
10992de3b87aSKai Wang 	if (e->e_cmd == ELF_C_RDWR) {
11002de3b87aSKai Wang 		assert(e->e_rawfile != NULL);
11012de3b87aSKai Wang 		assert((e->e_flags & LIBELF_F_RAWFILE_MALLOC) ||
11022de3b87aSKai Wang 		    (e->e_flags & LIBELF_F_RAWFILE_MMAP));
11032de3b87aSKai Wang 		if (e->e_flags & LIBELF_F_RAWFILE_MALLOC) {
11042de3b87aSKai Wang 			free(e->e_rawfile);
11052de3b87aSKai Wang 			e->e_rawfile = newfile;
11062de3b87aSKai Wang 			newfile = NULL;
11072de3b87aSKai Wang 		}
11082de3b87aSKai Wang #if	ELFTC_HAVE_MMAP
11092de3b87aSKai Wang 		else if (e->e_flags & LIBELF_F_RAWFILE_MMAP) {
11102de3b87aSKai Wang 			if ((e->e_rawfile = mmap(NULL, (size_t) newsize,
11112de3b87aSKai Wang 			    PROT_READ, MAP_PRIVATE, e->e_fd, (off_t) 0)) ==
11122de3b87aSKai Wang 			    MAP_FAILED) {
11132de3b87aSKai Wang 				LIBELF_SET_ERROR(IO, errno);
11142de3b87aSKai Wang 				goto error;
11152de3b87aSKai Wang 			}
11162de3b87aSKai Wang 		}
11172de3b87aSKai Wang #endif	/* ELFTC_HAVE_MMAP */
11182de3b87aSKai Wang 
11192de3b87aSKai Wang 		/* Record the new size of the file. */
1120cf781b2eSEd Maste 		e->e_rawsize = (size_t) newsize;
11212de3b87aSKai Wang 	} else {
11222de3b87aSKai Wang 		/* File opened in ELF_C_WRITE mode. */
11232de3b87aSKai Wang 		assert(e->e_rawfile == NULL);
11242de3b87aSKai Wang 	}
11252de3b87aSKai Wang 
11262de3b87aSKai Wang 	/*
11272de3b87aSKai Wang 	 * Reset flags, remove existing section descriptors and
11282de3b87aSKai Wang 	 * {E,P}HDR pointers so that a subsequent elf_get{e,p}hdr()
11292de3b87aSKai Wang 	 * and elf_getscn() will function correctly.
11302de3b87aSKai Wang 	 */
11312de3b87aSKai Wang 
11322de3b87aSKai Wang 	e->e_flags &= ~ELF_F_DIRTY;
11332de3b87aSKai Wang 
11342de3b87aSKai Wang 	STAILQ_FOREACH_SAFE(scn, &e->e_u.e_elf.e_scn, s_next, tscn)
11352de3b87aSKai Wang 		_libelf_release_scn(scn);
11362de3b87aSKai Wang 
11372de3b87aSKai Wang 	if (e->e_class == ELFCLASS32) {
11382de3b87aSKai Wang 		free(e->e_u.e_elf.e_ehdr.e_ehdr32);
11392de3b87aSKai Wang 		if (e->e_u.e_elf.e_phdr.e_phdr32)
11402de3b87aSKai Wang 			free(e->e_u.e_elf.e_phdr.e_phdr32);
11412de3b87aSKai Wang 
11422de3b87aSKai Wang 		e->e_u.e_elf.e_ehdr.e_ehdr32 = NULL;
11432de3b87aSKai Wang 		e->e_u.e_elf.e_phdr.e_phdr32 = NULL;
11442de3b87aSKai Wang 	} else {
11452de3b87aSKai Wang 		free(e->e_u.e_elf.e_ehdr.e_ehdr64);
11462de3b87aSKai Wang 		if (e->e_u.e_elf.e_phdr.e_phdr64)
11472de3b87aSKai Wang 			free(e->e_u.e_elf.e_phdr.e_phdr64);
11482de3b87aSKai Wang 
11492de3b87aSKai Wang 		e->e_u.e_elf.e_ehdr.e_ehdr64 = NULL;
11502de3b87aSKai Wang 		e->e_u.e_elf.e_phdr.e_phdr64 = NULL;
11512de3b87aSKai Wang 	}
11522de3b87aSKai Wang 
11532de3b87aSKai Wang 	/* Free the temporary buffer. */
11542de3b87aSKai Wang 	if (newfile)
11552de3b87aSKai Wang 		free(newfile);
11562de3b87aSKai Wang 
11572de3b87aSKai Wang 	return (rc);
11582de3b87aSKai Wang 
11592de3b87aSKai Wang  error:
11602de3b87aSKai Wang 	free(newfile);
11612de3b87aSKai Wang 
11622de3b87aSKai Wang 	return ((off_t) -1);
11632de3b87aSKai Wang }
11642de3b87aSKai Wang 
11652de3b87aSKai Wang /*
11662de3b87aSKai Wang  * Update an ELF object.
11672de3b87aSKai Wang  */
11682de3b87aSKai Wang 
11692de3b87aSKai Wang off_t
11702de3b87aSKai Wang elf_update(Elf *e, Elf_Cmd c)
11712de3b87aSKai Wang {
11722de3b87aSKai Wang 	int ec;
11732de3b87aSKai Wang 	off_t rc;
11742de3b87aSKai Wang 	struct _Elf_Extent_List extents;
11752de3b87aSKai Wang 
11762de3b87aSKai Wang 	rc = (off_t) -1;
11772de3b87aSKai Wang 
11782de3b87aSKai Wang 	if (e == NULL || e->e_kind != ELF_K_ELF ||
11792de3b87aSKai Wang 	    (c != ELF_C_NULL && c != ELF_C_WRITE)) {
11802de3b87aSKai Wang 		LIBELF_SET_ERROR(ARGUMENT, 0);
11812de3b87aSKai Wang 		return (rc);
11822de3b87aSKai Wang 	}
11832de3b87aSKai Wang 
11842de3b87aSKai Wang 	if ((ec = e->e_class) != ELFCLASS32 && ec != ELFCLASS64) {
11852de3b87aSKai Wang 		LIBELF_SET_ERROR(CLASS, 0);
11862de3b87aSKai Wang 		return (rc);
11872de3b87aSKai Wang 	}
11882de3b87aSKai Wang 
11892de3b87aSKai Wang 	if (e->e_version == EV_NONE)
11902de3b87aSKai Wang 		e->e_version = EV_CURRENT;
11912de3b87aSKai Wang 
11922de3b87aSKai Wang 	if (c == ELF_C_WRITE && e->e_cmd == ELF_C_READ) {
11932de3b87aSKai Wang 		LIBELF_SET_ERROR(MODE, 0);
11942de3b87aSKai Wang 		return (rc);
11952de3b87aSKai Wang 	}
11962de3b87aSKai Wang 
11972de3b87aSKai Wang 	SLIST_INIT(&extents);
11982de3b87aSKai Wang 
11992de3b87aSKai Wang 	if ((rc = _libelf_resync_elf(e, &extents)) < 0)
12002de3b87aSKai Wang 		goto done;
12012de3b87aSKai Wang 
12022de3b87aSKai Wang 	if (c == ELF_C_NULL)
12032de3b87aSKai Wang 		goto done;
12042de3b87aSKai Wang 
12052de3b87aSKai Wang 	if (e->e_fd < 0) {
12062de3b87aSKai Wang 		rc = (off_t) -1;
12072de3b87aSKai Wang 		LIBELF_SET_ERROR(SEQUENCE, 0);
12082de3b87aSKai Wang 		goto done;
12092de3b87aSKai Wang 	}
12102de3b87aSKai Wang 
12112de3b87aSKai Wang 	rc = _libelf_write_elf(e, rc, &extents);
12122de3b87aSKai Wang 
12132de3b87aSKai Wang done:
12142de3b87aSKai Wang 	_libelf_release_extents(&extents);
1215*bd6313b6SEd Maste 	e->e_flags &= ~LIBELF_F_SHDRS_LOADED;
12162de3b87aSKai Wang 	return (rc);
12172de3b87aSKai Wang }
1218