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*d003e0d7SEd Maste ELFTC_VCSID("$Id: elf_update.c 3763 2019-06-28 21:43:27Z emaste $");
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
_libelf_compute_section_extents(Elf * e,Elf_Scn * s,off_t rc)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);
145*d003e0d7SEd Maste if (elftype < ELF_T_FIRST || 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 /*
225*d003e0d7SEd Maste * The data buffer's ELF type, ELF class and ELF version
226*d003e0d7SEd Maste * should be supported.
227*d003e0d7SEd Maste */
228*d003e0d7SEd Maste if ((msz = _libelf_msize(d->d_type, ec, e->e_version)) == 0)
229*d003e0d7SEd Maste return (0);
230*d003e0d7SEd Maste
231*d003e0d7SEd Maste /*
2322de3b87aSKai Wang * The buffer's size should be a multiple of the
2332de3b87aSKai Wang * memory size of the underlying type.
2342de3b87aSKai Wang */
2352de3b87aSKai Wang if (d->d_size % msz) {
2362de3b87aSKai Wang LIBELF_SET_ERROR(DATA, 0);
2372de3b87aSKai Wang return (0);
2382de3b87aSKai Wang }
2392de3b87aSKai Wang
2402de3b87aSKai Wang /*
2412de3b87aSKai Wang * If the application is controlling layout, then the
2422de3b87aSKai Wang * d_offset field should be compatible with the
2432de3b87aSKai Wang * buffer's specified alignment.
2442de3b87aSKai Wang */
2452de3b87aSKai Wang if ((e->e_flags & ELF_F_LAYOUT) &&
2462de3b87aSKai Wang (d->d_off & (d_align - 1))) {
2472de3b87aSKai Wang LIBELF_SET_ERROR(LAYOUT, 0);
2482de3b87aSKai Wang return (0);
2492de3b87aSKai Wang }
2502de3b87aSKai Wang
2512de3b87aSKai Wang /*
2522de3b87aSKai Wang * Compute the section's size.
2532de3b87aSKai Wang */
2542de3b87aSKai Wang if (e->e_flags & ELF_F_LAYOUT) {
2552de3b87aSKai Wang if ((uint64_t) d->d_off + d->d_size > scn_size)
2562de3b87aSKai Wang scn_size = d->d_off + d->d_size;
2572de3b87aSKai Wang } else {
2582de3b87aSKai Wang scn_size = roundup2(scn_size, d->d_align);
2592de3b87aSKai Wang d->d_off = scn_size;
2602de3b87aSKai Wang fsz = _libelf_fsize(d->d_type, ec, d->d_version,
261cf781b2eSEd Maste (size_t) d->d_size / msz);
2622de3b87aSKai Wang scn_size += fsz;
2632de3b87aSKai Wang }
2642de3b87aSKai Wang
2652de3b87aSKai Wang /*
2662de3b87aSKai Wang * The section's alignment is the maximum alignment
2672de3b87aSKai Wang * needed for its data buffers.
2682de3b87aSKai Wang */
2692de3b87aSKai Wang if (d_align > scn_alignment)
2702de3b87aSKai Wang scn_alignment = d_align;
2712de3b87aSKai Wang }
2722de3b87aSKai Wang
2732de3b87aSKai Wang
2742de3b87aSKai Wang /*
2752de3b87aSKai Wang * If the application is requesting full control over the
2762de3b87aSKai Wang * layout of the section, check the section's specified size,
2772de3b87aSKai Wang * offsets and alignment for sanity.
2782de3b87aSKai Wang */
2792de3b87aSKai Wang if (e->e_flags & ELF_F_LAYOUT) {
280b00fe64fSEd Maste if (scn_alignment > sh_align ||
281b00fe64fSEd Maste sh_offset % sh_align ||
282b00fe64fSEd Maste sh_size < scn_size ||
283b00fe64fSEd Maste sh_offset % _libelf_falign(elftype, ec)) {
2842de3b87aSKai Wang LIBELF_SET_ERROR(LAYOUT, 0);
2852de3b87aSKai Wang return (0);
2862de3b87aSKai Wang }
2872de3b87aSKai Wang goto updatedescriptor;
2882de3b87aSKai Wang }
2892de3b87aSKai Wang
2902de3b87aSKai Wang /*
2912de3b87aSKai Wang * Otherwise, compute the values in the section header.
2922de3b87aSKai Wang *
2932de3b87aSKai Wang * The section alignment is the maximum alignment for any of
2942de3b87aSKai Wang * its contained data descriptors.
2952de3b87aSKai Wang */
2962de3b87aSKai Wang if (scn_alignment > sh_align)
2972de3b87aSKai Wang sh_align = scn_alignment;
2982de3b87aSKai Wang
2992de3b87aSKai Wang /*
3002de3b87aSKai Wang * If the section entry size is zero, try and fill in an
3012de3b87aSKai Wang * appropriate entry size. Per the elf(5) manual page
3022de3b87aSKai Wang * sections without fixed-size entries should have their
3032de3b87aSKai Wang * 'sh_entsize' field set to zero.
3042de3b87aSKai Wang */
3052de3b87aSKai Wang if (sh_entsize == 0 &&
3062de3b87aSKai Wang (sh_entsize = _libelf_fsize(elftype, ec, e->e_version,
3072de3b87aSKai Wang (size_t) 1)) == 1)
3082de3b87aSKai Wang sh_entsize = 0;
3092de3b87aSKai Wang
3102de3b87aSKai Wang sh_size = scn_size;
3112de3b87aSKai Wang
3122de3b87aSKai Wang computeoffset:
3132de3b87aSKai Wang /*
3142de3b87aSKai Wang * Compute the new offset for the section based on
3152de3b87aSKai Wang * the section's alignment needs.
3162de3b87aSKai Wang */
317cf781b2eSEd Maste sh_offset = roundup((uint64_t) rc, sh_align);
3182de3b87aSKai Wang
3192de3b87aSKai Wang /*
3202de3b87aSKai Wang * Update the section header.
3212de3b87aSKai Wang */
3222de3b87aSKai Wang if (ec == ELFCLASS32) {
3232de3b87aSKai Wang shdr32->sh_addralign = (uint32_t) sh_align;
3242de3b87aSKai Wang shdr32->sh_entsize = (uint32_t) sh_entsize;
3252de3b87aSKai Wang shdr32->sh_offset = (uint32_t) sh_offset;
3262de3b87aSKai Wang shdr32->sh_size = (uint32_t) sh_size;
3272de3b87aSKai Wang } else {
3282de3b87aSKai Wang shdr64->sh_addralign = sh_align;
3292de3b87aSKai Wang shdr64->sh_entsize = sh_entsize;
3302de3b87aSKai Wang shdr64->sh_offset = sh_offset;
3312de3b87aSKai Wang shdr64->sh_size = sh_size;
3322de3b87aSKai Wang }
3332de3b87aSKai Wang
3342de3b87aSKai Wang updatedescriptor:
3352de3b87aSKai Wang /*
3362de3b87aSKai Wang * Update the section descriptor.
3372de3b87aSKai Wang */
3382de3b87aSKai Wang s->s_size = sh_size;
3392de3b87aSKai Wang s->s_offset = sh_offset;
3402de3b87aSKai Wang
3412de3b87aSKai Wang return (1);
3422de3b87aSKai Wang }
3432de3b87aSKai Wang
3442de3b87aSKai Wang /*
3452de3b87aSKai Wang * Free a list of extent descriptors.
3462de3b87aSKai Wang */
3472de3b87aSKai Wang
3482de3b87aSKai Wang static void
_libelf_release_extents(struct _Elf_Extent_List * extents)3492de3b87aSKai Wang _libelf_release_extents(struct _Elf_Extent_List *extents)
3502de3b87aSKai Wang {
3512de3b87aSKai Wang struct _Elf_Extent *ex;
3522de3b87aSKai Wang
3532de3b87aSKai Wang while ((ex = SLIST_FIRST(extents)) != NULL) {
3542de3b87aSKai Wang SLIST_REMOVE_HEAD(extents, ex_next);
3552de3b87aSKai Wang free(ex);
3562de3b87aSKai Wang }
3572de3b87aSKai Wang }
3582de3b87aSKai Wang
3592de3b87aSKai Wang /*
3602de3b87aSKai Wang * Check if an extent 's' defined by [start..start+size) is free.
3612de3b87aSKai Wang * This routine assumes that the given extent list is sorted in order
3622de3b87aSKai Wang * of ascending extent offsets.
3632de3b87aSKai Wang */
3642de3b87aSKai Wang
3652de3b87aSKai Wang static int
_libelf_extent_is_unused(struct _Elf_Extent_List * extents,const uint64_t start,const uint64_t size,struct _Elf_Extent ** prevt)3662de3b87aSKai Wang _libelf_extent_is_unused(struct _Elf_Extent_List *extents,
3672de3b87aSKai Wang const uint64_t start, const uint64_t size, struct _Elf_Extent **prevt)
3682de3b87aSKai Wang {
3692de3b87aSKai Wang uint64_t tmax, tmin;
3702de3b87aSKai Wang struct _Elf_Extent *t, *pt;
3712de3b87aSKai Wang const uint64_t smax = start + size;
3722de3b87aSKai Wang
3732de3b87aSKai Wang /* First, look for overlaps with existing extents. */
3742de3b87aSKai Wang pt = NULL;
3752de3b87aSKai Wang SLIST_FOREACH(t, extents, ex_next) {
3762de3b87aSKai Wang tmin = t->ex_start;
3772de3b87aSKai Wang tmax = tmin + t->ex_size;
3782de3b87aSKai Wang
3792de3b87aSKai Wang if (tmax <= start) {
3802de3b87aSKai Wang /*
3812de3b87aSKai Wang * 't' lies entirely before 's': ...| t |...| s |...
3822de3b87aSKai Wang */
3832de3b87aSKai Wang pt = t;
3842de3b87aSKai Wang continue;
3852de3b87aSKai Wang } else if (smax <= tmin) {
3862de3b87aSKai Wang /*
3872de3b87aSKai Wang * 's' lies entirely before 't', and after 'pt':
3882de3b87aSKai Wang * ...| pt |...| s |...| t |...
3892de3b87aSKai Wang */
3902de3b87aSKai Wang assert(pt == NULL ||
3912de3b87aSKai Wang pt->ex_start + pt->ex_size <= start);
3922de3b87aSKai Wang break;
3932de3b87aSKai Wang } else
3942de3b87aSKai Wang /* 's' and 't' overlap. */
3952de3b87aSKai Wang return (0);
3962de3b87aSKai Wang }
3972de3b87aSKai Wang
3982de3b87aSKai Wang if (prevt)
3992de3b87aSKai Wang *prevt = pt;
4002de3b87aSKai Wang return (1);
4012de3b87aSKai Wang }
4022de3b87aSKai Wang
4032de3b87aSKai Wang /*
4042de3b87aSKai Wang * Insert an extent into the list of extents.
4052de3b87aSKai Wang */
4062de3b87aSKai Wang
4072de3b87aSKai Wang static int
_libelf_insert_extent(struct _Elf_Extent_List * extents,int type,uint64_t start,uint64_t size,void * desc)4082de3b87aSKai Wang _libelf_insert_extent(struct _Elf_Extent_List *extents, int type,
4092de3b87aSKai Wang uint64_t start, uint64_t size, void *desc)
4102de3b87aSKai Wang {
4112de3b87aSKai Wang struct _Elf_Extent *ex, *prevt;
4122de3b87aSKai Wang
4132de3b87aSKai Wang assert(type >= ELF_EXTENT_EHDR && type <= ELF_EXTENT_SHDR);
4142de3b87aSKai Wang
4152de3b87aSKai Wang prevt = NULL;
4162de3b87aSKai Wang
4172de3b87aSKai Wang /*
4182de3b87aSKai Wang * If the requested range overlaps with an existing extent,
4192de3b87aSKai Wang * signal an error.
4202de3b87aSKai Wang */
4212de3b87aSKai Wang if (!_libelf_extent_is_unused(extents, start, size, &prevt)) {
4222de3b87aSKai Wang LIBELF_SET_ERROR(LAYOUT, 0);
4232de3b87aSKai Wang return (0);
4242de3b87aSKai Wang }
4252de3b87aSKai Wang
4262de3b87aSKai Wang /* Allocate and fill in a new extent descriptor. */
4272de3b87aSKai Wang if ((ex = malloc(sizeof(struct _Elf_Extent))) == NULL) {
4282de3b87aSKai Wang LIBELF_SET_ERROR(RESOURCE, errno);
4292de3b87aSKai Wang return (0);
4302de3b87aSKai Wang }
4312de3b87aSKai Wang ex->ex_start = start;
4322de3b87aSKai Wang ex->ex_size = size;
4332de3b87aSKai Wang ex->ex_desc = desc;
4342de3b87aSKai Wang ex->ex_type = type;
4352de3b87aSKai Wang
4362de3b87aSKai Wang /* Insert the region descriptor into the list. */
4372de3b87aSKai Wang if (prevt)
4382de3b87aSKai Wang SLIST_INSERT_AFTER(prevt, ex, ex_next);
4392de3b87aSKai Wang else
4402de3b87aSKai Wang SLIST_INSERT_HEAD(extents, ex, ex_next);
4412de3b87aSKai Wang return (1);
4422de3b87aSKai Wang }
4432de3b87aSKai Wang
4442de3b87aSKai Wang /*
4452de3b87aSKai Wang * Recompute section layout.
4462de3b87aSKai Wang */
4472de3b87aSKai Wang
4482de3b87aSKai Wang static off_t
_libelf_resync_sections(Elf * e,off_t rc,struct _Elf_Extent_List * extents)4492de3b87aSKai Wang _libelf_resync_sections(Elf *e, off_t rc, struct _Elf_Extent_List *extents)
4502de3b87aSKai Wang {
4512de3b87aSKai Wang int ec;
4522de3b87aSKai Wang Elf_Scn *s;
4532de3b87aSKai Wang size_t sh_type;
4542de3b87aSKai Wang
4552de3b87aSKai Wang ec = e->e_class;
4562de3b87aSKai Wang
4572de3b87aSKai Wang /*
4582de3b87aSKai Wang * Make a pass through sections, computing the extent of each
4592de3b87aSKai Wang * section.
4602de3b87aSKai Wang */
4618c953901SMark Johnston RB_FOREACH(s, scntree, &e->e_u.e_elf.e_scn) {
4622de3b87aSKai Wang if (ec == ELFCLASS32)
4632de3b87aSKai Wang sh_type = s->s_shdr.s_shdr32.sh_type;
4642de3b87aSKai Wang else
4652de3b87aSKai Wang sh_type = s->s_shdr.s_shdr64.sh_type;
4662de3b87aSKai Wang
4672de3b87aSKai Wang if (sh_type == SHT_NOBITS || sh_type == SHT_NULL)
4682de3b87aSKai Wang continue;
4692de3b87aSKai Wang
4702de3b87aSKai Wang if (_libelf_compute_section_extents(e, s, rc) == 0)
4712de3b87aSKai Wang return ((off_t) -1);
4722de3b87aSKai Wang
4732de3b87aSKai Wang if (s->s_size == 0)
4742de3b87aSKai Wang continue;
4752de3b87aSKai Wang
4762de3b87aSKai Wang if (!_libelf_insert_extent(extents, ELF_EXTENT_SECTION,
4772de3b87aSKai Wang s->s_offset, s->s_size, s))
4782de3b87aSKai Wang return ((off_t) -1);
4792de3b87aSKai Wang
4802de3b87aSKai Wang if ((size_t) rc < s->s_offset + s->s_size)
481cf781b2eSEd Maste rc = (off_t) (s->s_offset + s->s_size);
4822de3b87aSKai Wang }
4832de3b87aSKai Wang
4842de3b87aSKai Wang return (rc);
4852de3b87aSKai Wang }
4862de3b87aSKai Wang
4872de3b87aSKai Wang /*
4882de3b87aSKai Wang * Recompute the layout of the ELF object and update the internal data
4892de3b87aSKai Wang * structures associated with the ELF descriptor.
4902de3b87aSKai Wang *
4912de3b87aSKai Wang * Returns the size in bytes the ELF object would occupy in its file
4922de3b87aSKai Wang * representation.
4932de3b87aSKai Wang *
4942de3b87aSKai Wang * After a successful call to this function, the following structures
4952de3b87aSKai Wang * are updated:
4962de3b87aSKai Wang *
4972de3b87aSKai Wang * - The ELF header is updated.
4982de3b87aSKai Wang * - All extents in the ELF object are sorted in order of ascending
4992de3b87aSKai Wang * addresses. Sections have their section header table entries
5002de3b87aSKai Wang * updated. An error is signalled if an overlap was detected among
5012de3b87aSKai Wang * extents.
5022de3b87aSKai Wang * - Data descriptors associated with sections are checked for valid
5032de3b87aSKai Wang * types, offsets and alignment.
5042de3b87aSKai Wang *
5052de3b87aSKai Wang * After a resync_elf() successfully returns, the ELF descriptor is
5062de3b87aSKai Wang * ready for being handed over to _libelf_write_elf().
5072de3b87aSKai Wang */
5082de3b87aSKai Wang
5092de3b87aSKai Wang static off_t
_libelf_resync_elf(Elf * e,struct _Elf_Extent_List * extents)5102de3b87aSKai Wang _libelf_resync_elf(Elf *e, struct _Elf_Extent_List *extents)
5112de3b87aSKai Wang {
5122de3b87aSKai Wang int ec, eh_class;
5132de3b87aSKai Wang unsigned int eh_byteorder, eh_version;
5142de3b87aSKai Wang size_t align, fsz;
5152de3b87aSKai Wang size_t phnum, shnum;
5162de3b87aSKai Wang off_t rc, phoff, shoff;
5172de3b87aSKai Wang void *ehdr, *phdr;
5182de3b87aSKai Wang Elf32_Ehdr *eh32;
5192de3b87aSKai Wang Elf64_Ehdr *eh64;
5202de3b87aSKai Wang
5212de3b87aSKai Wang rc = 0;
5222de3b87aSKai Wang
5232de3b87aSKai Wang ec = e->e_class;
5242de3b87aSKai Wang
5252de3b87aSKai Wang assert(ec == ELFCLASS32 || ec == ELFCLASS64);
5262de3b87aSKai Wang
5272de3b87aSKai Wang /*
5282de3b87aSKai Wang * Prepare the EHDR.
5292de3b87aSKai Wang */
5302de3b87aSKai Wang if ((ehdr = _libelf_ehdr(e, ec, 0)) == NULL)
5312de3b87aSKai Wang return ((off_t) -1);
5322de3b87aSKai Wang
5332de3b87aSKai Wang eh32 = ehdr;
5342de3b87aSKai Wang eh64 = ehdr;
5352de3b87aSKai Wang
5362de3b87aSKai Wang if (ec == ELFCLASS32) {
5372de3b87aSKai Wang eh_byteorder = eh32->e_ident[EI_DATA];
5382de3b87aSKai Wang eh_class = eh32->e_ident[EI_CLASS];
539cf781b2eSEd Maste phoff = (off_t) eh32->e_phoff;
540cf781b2eSEd Maste shoff = (off_t) eh32->e_shoff;
5412de3b87aSKai Wang eh_version = eh32->e_version;
5422de3b87aSKai Wang } else {
5432de3b87aSKai Wang eh_byteorder = eh64->e_ident[EI_DATA];
5442de3b87aSKai Wang eh_class = eh64->e_ident[EI_CLASS];
545cf781b2eSEd Maste phoff = (off_t) eh64->e_phoff;
546cf781b2eSEd Maste shoff = (off_t) eh64->e_shoff;
5472de3b87aSKai Wang eh_version = eh64->e_version;
5482de3b87aSKai Wang }
5492de3b87aSKai Wang
550cf781b2eSEd Maste if (phoff < 0 || shoff < 0) {
551cf781b2eSEd Maste LIBELF_SET_ERROR(HEADER, 0);
552cf781b2eSEd Maste return ((off_t) -1);
553cf781b2eSEd Maste }
554cf781b2eSEd Maste
5552de3b87aSKai Wang if (eh_version == EV_NONE)
5562de3b87aSKai Wang eh_version = EV_CURRENT;
5572de3b87aSKai Wang
5582de3b87aSKai Wang if (eh_version != e->e_version) { /* always EV_CURRENT */
5592de3b87aSKai Wang LIBELF_SET_ERROR(VERSION, 0);
5602de3b87aSKai Wang return ((off_t) -1);
5612de3b87aSKai Wang }
5622de3b87aSKai Wang
5632de3b87aSKai Wang if (eh_class != e->e_class) {
5642de3b87aSKai Wang LIBELF_SET_ERROR(CLASS, 0);
5652de3b87aSKai Wang return ((off_t) -1);
5662de3b87aSKai Wang }
5672de3b87aSKai Wang
5682de3b87aSKai Wang if (e->e_cmd != ELF_C_WRITE && eh_byteorder != e->e_byteorder) {
5692de3b87aSKai Wang LIBELF_SET_ERROR(HEADER, 0);
5702de3b87aSKai Wang return ((off_t) -1);
5712de3b87aSKai Wang }
5722de3b87aSKai Wang
5732de3b87aSKai Wang shnum = e->e_u.e_elf.e_nscn;
5742de3b87aSKai Wang phnum = e->e_u.e_elf.e_nphdr;
5752de3b87aSKai Wang
5762de3b87aSKai Wang e->e_byteorder = eh_byteorder;
5772de3b87aSKai Wang
5782de3b87aSKai Wang #define INITIALIZE_EHDR(E,EC,V) do { \
579cf781b2eSEd Maste unsigned int _version = (unsigned int) (V); \
5802de3b87aSKai Wang (E)->e_ident[EI_MAG0] = ELFMAG0; \
5812de3b87aSKai Wang (E)->e_ident[EI_MAG1] = ELFMAG1; \
5822de3b87aSKai Wang (E)->e_ident[EI_MAG2] = ELFMAG2; \
5832de3b87aSKai Wang (E)->e_ident[EI_MAG3] = ELFMAG3; \
584cf781b2eSEd Maste (E)->e_ident[EI_CLASS] = (unsigned char) (EC); \
585cf781b2eSEd Maste (E)->e_ident[EI_VERSION] = (_version & 0xFFU); \
586cf781b2eSEd Maste (E)->e_ehsize = (uint16_t) _libelf_fsize(ELF_T_EHDR, \
587cf781b2eSEd Maste (EC), _version, (size_t) 1); \
588cf781b2eSEd Maste (E)->e_phentsize = (uint16_t) ((phnum == 0) ? 0 : \
589cf781b2eSEd Maste _libelf_fsize(ELF_T_PHDR, (EC), _version, \
590cf781b2eSEd Maste (size_t) 1)); \
591cf781b2eSEd Maste (E)->e_shentsize = (uint16_t) _libelf_fsize(ELF_T_SHDR, \
592cf781b2eSEd Maste (EC), _version, (size_t) 1); \
5932de3b87aSKai Wang } while (0)
5942de3b87aSKai Wang
5952de3b87aSKai Wang if (ec == ELFCLASS32)
5962de3b87aSKai Wang INITIALIZE_EHDR(eh32, ec, eh_version);
5972de3b87aSKai Wang else
5982de3b87aSKai Wang INITIALIZE_EHDR(eh64, ec, eh_version);
5992de3b87aSKai Wang
6002de3b87aSKai Wang (void) elf_flagehdr(e, ELF_C_SET, ELF_F_DIRTY);
6012de3b87aSKai Wang
602cf781b2eSEd Maste rc += (off_t) _libelf_fsize(ELF_T_EHDR, ec, eh_version, (size_t) 1);
6032de3b87aSKai Wang
604cf781b2eSEd Maste if (!_libelf_insert_extent(extents, ELF_EXTENT_EHDR, 0, (uint64_t) rc,
605cf781b2eSEd Maste ehdr))
6062de3b87aSKai Wang return ((off_t) -1);
6072de3b87aSKai Wang
6082de3b87aSKai Wang /*
6092de3b87aSKai Wang * Compute the layout the program header table, if one is
6102de3b87aSKai Wang * present. The program header table needs to be aligned to a
6112de3b87aSKai Wang * `natural' boundary.
6122de3b87aSKai Wang */
6132de3b87aSKai Wang if (phnum) {
6142de3b87aSKai Wang fsz = _libelf_fsize(ELF_T_PHDR, ec, eh_version, phnum);
6152de3b87aSKai Wang align = _libelf_falign(ELF_T_PHDR, ec);
6162de3b87aSKai Wang
6172de3b87aSKai Wang if (e->e_flags & ELF_F_LAYOUT) {
6182de3b87aSKai Wang /*
6192de3b87aSKai Wang * Check offsets for sanity.
6202de3b87aSKai Wang */
6212de3b87aSKai Wang if (rc > phoff) {
6222de3b87aSKai Wang LIBELF_SET_ERROR(LAYOUT, 0);
6232de3b87aSKai Wang return ((off_t) -1);
6242de3b87aSKai Wang }
6252de3b87aSKai Wang
626cf781b2eSEd Maste if (phoff % (off_t) align) {
6272de3b87aSKai Wang LIBELF_SET_ERROR(LAYOUT, 0);
6282de3b87aSKai Wang return ((off_t) -1);
6292de3b87aSKai Wang }
6302de3b87aSKai Wang
6312de3b87aSKai Wang } else
632cf781b2eSEd Maste phoff = roundup(rc, (off_t) align);
6332de3b87aSKai Wang
634cf781b2eSEd Maste rc = phoff + (off_t) fsz;
6352de3b87aSKai Wang
6362de3b87aSKai Wang phdr = _libelf_getphdr(e, ec);
6372de3b87aSKai Wang
638cf781b2eSEd Maste if (!_libelf_insert_extent(extents, ELF_EXTENT_PHDR,
639cf781b2eSEd Maste (uint64_t) phoff, fsz, phdr))
6402de3b87aSKai Wang return ((off_t) -1);
6412de3b87aSKai Wang } else
6422de3b87aSKai Wang phoff = 0;
6432de3b87aSKai Wang
6442de3b87aSKai Wang /*
6452de3b87aSKai Wang * Compute the layout of the sections associated with the
6462de3b87aSKai Wang * file.
6472de3b87aSKai Wang */
6482de3b87aSKai Wang
6492de3b87aSKai Wang if (e->e_cmd != ELF_C_WRITE &&
6502de3b87aSKai Wang (e->e_flags & LIBELF_F_SHDRS_LOADED) == 0 &&
6512de3b87aSKai Wang _libelf_load_section_headers(e, ehdr) == 0)
6522de3b87aSKai Wang return ((off_t) -1);
6532de3b87aSKai Wang
6542de3b87aSKai Wang if ((rc = _libelf_resync_sections(e, rc, extents)) < 0)
6552de3b87aSKai Wang return ((off_t) -1);
6562de3b87aSKai Wang
6572de3b87aSKai Wang /*
6582de3b87aSKai Wang * Compute the space taken up by the section header table, if
6592de3b87aSKai Wang * one is needed.
6602de3b87aSKai Wang *
6612de3b87aSKai Wang * If ELF_F_LAYOUT has been asserted, the application may have
6622de3b87aSKai Wang * placed the section header table in between existing
6632de3b87aSKai Wang * sections, so the net size of the file need not increase due
6642de3b87aSKai Wang * to the presence of the section header table.
6652de3b87aSKai Wang *
6662de3b87aSKai Wang * If the library is responsible for laying out the object,
6672de3b87aSKai Wang * the section header table is placed after section data.
6682de3b87aSKai Wang */
6692de3b87aSKai Wang if (shnum) {
6702de3b87aSKai Wang fsz = _libelf_fsize(ELF_T_SHDR, ec, eh_version, shnum);
6712de3b87aSKai Wang align = _libelf_falign(ELF_T_SHDR, ec);
6722de3b87aSKai Wang
6732de3b87aSKai Wang if (e->e_flags & ELF_F_LAYOUT) {
674cf781b2eSEd Maste if (shoff % (off_t) align) {
6752de3b87aSKai Wang LIBELF_SET_ERROR(LAYOUT, 0);
6762de3b87aSKai Wang return ((off_t) -1);
6772de3b87aSKai Wang }
6782de3b87aSKai Wang } else
679cf781b2eSEd Maste shoff = roundup(rc, (off_t) align);
6802de3b87aSKai Wang
681cf781b2eSEd Maste if (shoff + (off_t) fsz > rc)
682cf781b2eSEd Maste rc = shoff + (off_t) fsz;
6832de3b87aSKai Wang
684cf781b2eSEd Maste if (!_libelf_insert_extent(extents, ELF_EXTENT_SHDR,
685cf781b2eSEd Maste (uint64_t) shoff, fsz, NULL))
6862de3b87aSKai Wang return ((off_t) -1);
6872de3b87aSKai Wang } else
6882de3b87aSKai Wang shoff = 0;
6892de3b87aSKai Wang
6902de3b87aSKai Wang /*
6912de3b87aSKai Wang * Set the fields of the Executable Header that could potentially use
6922de3b87aSKai Wang * extended numbering.
6932de3b87aSKai Wang */
6942de3b87aSKai Wang _libelf_setphnum(e, ehdr, ec, phnum);
6952de3b87aSKai Wang _libelf_setshnum(e, ehdr, ec, shnum);
6962de3b87aSKai Wang
6972de3b87aSKai Wang /*
6982de3b87aSKai Wang * Update the `e_phoff' and `e_shoff' fields if the library is
6992de3b87aSKai Wang * doing the layout.
7002de3b87aSKai Wang */
7012de3b87aSKai Wang if ((e->e_flags & ELF_F_LAYOUT) == 0) {
7022de3b87aSKai Wang if (ec == ELFCLASS32) {
7032de3b87aSKai Wang eh32->e_phoff = (uint32_t) phoff;
7042de3b87aSKai Wang eh32->e_shoff = (uint32_t) shoff;
7052de3b87aSKai Wang } else {
7062de3b87aSKai Wang eh64->e_phoff = (uint64_t) phoff;
7072de3b87aSKai Wang eh64->e_shoff = (uint64_t) shoff;
7082de3b87aSKai Wang }
7092de3b87aSKai Wang }
7102de3b87aSKai Wang
7112de3b87aSKai Wang return (rc);
7122de3b87aSKai Wang }
7132de3b87aSKai Wang
7142de3b87aSKai Wang /*
7152de3b87aSKai Wang * Write out the contents of an ELF section.
7162de3b87aSKai Wang */
7172de3b87aSKai Wang
718cf781b2eSEd Maste static off_t
_libelf_write_scn(Elf * e,unsigned char * nf,struct _Elf_Extent * ex)719cf781b2eSEd Maste _libelf_write_scn(Elf *e, unsigned char *nf, struct _Elf_Extent *ex)
7202de3b87aSKai Wang {
721cf781b2eSEd Maste off_t rc;
722ae500c1fSEd Maste int ec, em;
7232de3b87aSKai Wang Elf_Scn *s;
7242de3b87aSKai Wang int elftype;
7252de3b87aSKai Wang Elf_Data *d, dst;
7262de3b87aSKai Wang uint32_t sh_type;
7272de3b87aSKai Wang struct _Libelf_Data *ld;
7282de3b87aSKai Wang uint64_t sh_off, sh_size;
729cf781b2eSEd Maste size_t fsz, msz, nobjects;
7302de3b87aSKai Wang
7312de3b87aSKai Wang assert(ex->ex_type == ELF_EXTENT_SECTION);
7322de3b87aSKai Wang
7332de3b87aSKai Wang s = ex->ex_desc;
734cf781b2eSEd Maste rc = (off_t) ex->ex_start;
7352de3b87aSKai Wang
7362de3b87aSKai Wang if ((ec = e->e_class) == ELFCLASS32) {
7372de3b87aSKai Wang sh_type = s->s_shdr.s_shdr32.sh_type;
7382de3b87aSKai Wang sh_size = (uint64_t) s->s_shdr.s_shdr32.sh_size;
7392de3b87aSKai Wang } else {
7402de3b87aSKai Wang sh_type = s->s_shdr.s_shdr64.sh_type;
7412de3b87aSKai Wang sh_size = s->s_shdr.s_shdr64.sh_size;
7422de3b87aSKai Wang }
7432de3b87aSKai Wang
7442de3b87aSKai Wang /*
7452de3b87aSKai Wang * Ignore sections that do not allocate space in the file.
7462de3b87aSKai Wang */
7472de3b87aSKai Wang if (sh_type == SHT_NOBITS || sh_type == SHT_NULL || sh_size == 0)
7482de3b87aSKai Wang return (rc);
7492de3b87aSKai Wang
7502de3b87aSKai Wang elftype = _libelf_xlate_shtype(sh_type);
7512de3b87aSKai Wang assert(elftype >= ELF_T_FIRST && elftype <= ELF_T_LAST);
7522de3b87aSKai Wang
7532de3b87aSKai Wang sh_off = s->s_offset;
7542de3b87aSKai Wang assert(sh_off % _libelf_falign(elftype, ec) == 0);
7552de3b87aSKai Wang
756ae500c1fSEd Maste em = _libelf_elfmachine(e);
757ae500c1fSEd Maste #if 0
758ae500c1fSEd Maste assert(em >= EM_NONE && em < EM__LAST__);
759ae500c1fSEd Maste #endif
760ae500c1fSEd Maste
7612de3b87aSKai Wang /*
7622de3b87aSKai Wang * If the section has a `rawdata' descriptor, and the section
7632de3b87aSKai Wang * contents have not been modified, use its contents directly.
7642de3b87aSKai Wang * The `s_rawoff' member contains the offset into the original
7652de3b87aSKai Wang * file, while `s_offset' contains its new location in the
7662de3b87aSKai Wang * destination.
7672de3b87aSKai Wang */
7682de3b87aSKai Wang
7692de3b87aSKai Wang if (STAILQ_EMPTY(&s->s_data)) {
7702de3b87aSKai Wang
7712de3b87aSKai Wang if ((d = elf_rawdata(s, NULL)) == NULL)
7722de3b87aSKai Wang return ((off_t) -1);
7732de3b87aSKai Wang
7742de3b87aSKai Wang STAILQ_FOREACH(ld, &s->s_rawdata, d_next) {
7752de3b87aSKai Wang
7762de3b87aSKai Wang d = &ld->d_data;
7772de3b87aSKai Wang
7782de3b87aSKai Wang if ((uint64_t) rc < sh_off + d->d_off)
7792de3b87aSKai Wang (void) memset(nf + rc,
780cf781b2eSEd Maste LIBELF_PRIVATE(fillchar),
781cf781b2eSEd Maste (size_t) (sh_off + d->d_off -
782cf781b2eSEd Maste (uint64_t) rc));
783cf781b2eSEd Maste rc = (off_t) (sh_off + d->d_off);
7842de3b87aSKai Wang
7852de3b87aSKai Wang assert(d->d_buf != NULL);
7862de3b87aSKai Wang assert(d->d_type == ELF_T_BYTE);
7872de3b87aSKai Wang assert(d->d_version == e->e_version);
7882de3b87aSKai Wang
7892de3b87aSKai Wang (void) memcpy(nf + rc,
790cf781b2eSEd Maste e->e_rawfile + s->s_rawoff + d->d_off,
791cf781b2eSEd Maste (size_t) d->d_size);
7922de3b87aSKai Wang
793cf781b2eSEd Maste rc += (off_t) d->d_size;
7942de3b87aSKai Wang }
7952de3b87aSKai Wang
7962de3b87aSKai Wang return (rc);
7972de3b87aSKai Wang }
7982de3b87aSKai Wang
7992de3b87aSKai Wang /*
8002de3b87aSKai Wang * Iterate over the set of data descriptors for this section.
8012de3b87aSKai Wang * The prior call to _libelf_resync_elf() would have setup the
8022de3b87aSKai Wang * descriptors for this step.
8032de3b87aSKai Wang */
8042de3b87aSKai Wang
8052de3b87aSKai Wang dst.d_version = e->e_version;
8062de3b87aSKai Wang
8072de3b87aSKai Wang STAILQ_FOREACH(ld, &s->s_data, d_next) {
8082de3b87aSKai Wang
8092de3b87aSKai Wang d = &ld->d_data;
8102de3b87aSKai Wang
811*d003e0d7SEd Maste if ((msz = _libelf_msize(d->d_type, ec, e->e_version)) == 0)
812*d003e0d7SEd Maste return ((off_t) -1);
8132de3b87aSKai Wang
8142de3b87aSKai Wang if ((uint64_t) rc < sh_off + d->d_off)
8152de3b87aSKai Wang (void) memset(nf + rc,
816cf781b2eSEd Maste LIBELF_PRIVATE(fillchar),
817cf781b2eSEd Maste (size_t) (sh_off + d->d_off - (uint64_t) rc));
8182de3b87aSKai Wang
819cf781b2eSEd Maste rc = (off_t) (sh_off + d->d_off);
8202de3b87aSKai Wang
8212de3b87aSKai Wang assert(d->d_buf != NULL);
8222de3b87aSKai Wang assert(d->d_version == e->e_version);
8232de3b87aSKai Wang assert(d->d_size % msz == 0);
824*d003e0d7SEd Maste assert(msz != 0);
8252de3b87aSKai Wang
826cf781b2eSEd Maste nobjects = (size_t) (d->d_size / msz);
8272de3b87aSKai Wang
8282de3b87aSKai Wang fsz = _libelf_fsize(d->d_type, ec, e->e_version, nobjects);
8292de3b87aSKai Wang
8302de3b87aSKai Wang dst.d_buf = nf + rc;
8312de3b87aSKai Wang dst.d_size = fsz;
8322de3b87aSKai Wang
833ae500c1fSEd Maste if (_libelf_xlate(&dst, d, e->e_byteorder, ec, em, ELF_TOFILE)
834ae500c1fSEd Maste == NULL)
8352de3b87aSKai Wang return ((off_t) -1);
8362de3b87aSKai Wang
837cf781b2eSEd Maste rc += (off_t) fsz;
8382de3b87aSKai Wang }
8392de3b87aSKai Wang
840cf781b2eSEd Maste return (rc);
8412de3b87aSKai Wang }
8422de3b87aSKai Wang
8432de3b87aSKai Wang /*
8442de3b87aSKai Wang * Write out an ELF Executable Header.
8452de3b87aSKai Wang */
8462de3b87aSKai Wang
8472de3b87aSKai Wang static off_t
_libelf_write_ehdr(Elf * e,unsigned char * nf,struct _Elf_Extent * ex)848cf781b2eSEd Maste _libelf_write_ehdr(Elf *e, unsigned char *nf, struct _Elf_Extent *ex)
8492de3b87aSKai Wang {
850ae500c1fSEd Maste int ec, em;
8512de3b87aSKai Wang void *ehdr;
8522de3b87aSKai Wang size_t fsz, msz;
8532de3b87aSKai Wang Elf_Data dst, src;
8542de3b87aSKai Wang
8552de3b87aSKai Wang assert(ex->ex_type == ELF_EXTENT_EHDR);
8562de3b87aSKai Wang assert(ex->ex_start == 0); /* Ehdr always comes first. */
8572de3b87aSKai Wang
8582de3b87aSKai Wang ec = e->e_class;
8592de3b87aSKai Wang
8602de3b87aSKai Wang ehdr = _libelf_ehdr(e, ec, 0);
8612de3b87aSKai Wang assert(ehdr != NULL);
8622de3b87aSKai Wang
8632de3b87aSKai Wang fsz = _libelf_fsize(ELF_T_EHDR, ec, e->e_version, (size_t) 1);
864*d003e0d7SEd Maste if ((msz = _libelf_msize(ELF_T_EHDR, ec, e->e_version)) == 0)
865*d003e0d7SEd Maste return ((off_t) -1);
8662de3b87aSKai Wang
867ae500c1fSEd Maste em = _libelf_elfmachine(e);
868ae500c1fSEd Maste
8692de3b87aSKai Wang (void) memset(&dst, 0, sizeof(dst));
8702de3b87aSKai Wang (void) memset(&src, 0, sizeof(src));
8712de3b87aSKai Wang
8722de3b87aSKai Wang src.d_buf = ehdr;
8732de3b87aSKai Wang src.d_size = msz;
8742de3b87aSKai Wang src.d_type = ELF_T_EHDR;
8752de3b87aSKai Wang src.d_version = dst.d_version = e->e_version;
8762de3b87aSKai Wang
8772de3b87aSKai Wang dst.d_buf = nf;
8782de3b87aSKai Wang dst.d_size = fsz;
8792de3b87aSKai Wang
880ae500c1fSEd Maste if (_libelf_xlate(&dst, &src, e->e_byteorder, ec, em, ELF_TOFILE) ==
8812de3b87aSKai Wang NULL)
8822de3b87aSKai Wang return ((off_t) -1);
8832de3b87aSKai Wang
8842de3b87aSKai Wang return ((off_t) fsz);
8852de3b87aSKai Wang }
8862de3b87aSKai Wang
8872de3b87aSKai Wang /*
8882de3b87aSKai Wang * Write out an ELF program header table.
8892de3b87aSKai Wang */
8902de3b87aSKai Wang
8912de3b87aSKai Wang static off_t
_libelf_write_phdr(Elf * e,unsigned char * nf,struct _Elf_Extent * ex)892cf781b2eSEd Maste _libelf_write_phdr(Elf *e, unsigned char *nf, struct _Elf_Extent *ex)
8932de3b87aSKai Wang {
894ae500c1fSEd Maste int ec, em;
8952de3b87aSKai Wang void *ehdr;
8962de3b87aSKai Wang Elf32_Ehdr *eh32;
8972de3b87aSKai Wang Elf64_Ehdr *eh64;
8982de3b87aSKai Wang Elf_Data dst, src;
899*d003e0d7SEd Maste size_t fsz, msz, phnum;
9002de3b87aSKai Wang uint64_t phoff;
9012de3b87aSKai Wang
9022de3b87aSKai Wang assert(ex->ex_type == ELF_EXTENT_PHDR);
9032de3b87aSKai Wang
9042de3b87aSKai Wang ec = e->e_class;
9052de3b87aSKai Wang
906*d003e0d7SEd Maste ehdr = _libelf_ehdr(e, ec, 0);
907*d003e0d7SEd Maste assert(ehdr != NULL);
908*d003e0d7SEd Maste
909*d003e0d7SEd Maste phnum = e->e_u.e_elf.e_nphdr;
9102de3b87aSKai Wang assert(phnum > 0);
9112de3b87aSKai Wang
9122de3b87aSKai Wang if (ec == ELFCLASS32) {
9132de3b87aSKai Wang eh32 = (Elf32_Ehdr *) ehdr;
9142de3b87aSKai Wang phoff = (uint64_t) eh32->e_phoff;
9152de3b87aSKai Wang } else {
9162de3b87aSKai Wang eh64 = (Elf64_Ehdr *) ehdr;
9172de3b87aSKai Wang phoff = eh64->e_phoff;
9182de3b87aSKai Wang }
9192de3b87aSKai Wang
920ae500c1fSEd Maste em = _libelf_elfmachine(e);
921ae500c1fSEd Maste
9222de3b87aSKai Wang assert(phoff > 0);
9232de3b87aSKai Wang assert(ex->ex_start == phoff);
9242de3b87aSKai Wang assert(phoff % _libelf_falign(ELF_T_PHDR, ec) == 0);
9252de3b87aSKai Wang
9262de3b87aSKai Wang (void) memset(&dst, 0, sizeof(dst));
9272de3b87aSKai Wang (void) memset(&src, 0, sizeof(src));
9282de3b87aSKai Wang
929*d003e0d7SEd Maste if ((msz = _libelf_msize(ELF_T_PHDR, ec, e->e_version)) == 0)
930*d003e0d7SEd Maste return ((off_t) -1);
9312de3b87aSKai Wang fsz = _libelf_fsize(ELF_T_PHDR, ec, e->e_version, phnum);
9322de3b87aSKai Wang assert(fsz > 0);
9332de3b87aSKai Wang
9342de3b87aSKai Wang src.d_buf = _libelf_getphdr(e, ec);
9352de3b87aSKai Wang src.d_version = dst.d_version = e->e_version;
9362de3b87aSKai Wang src.d_type = ELF_T_PHDR;
937*d003e0d7SEd Maste src.d_size = phnum * msz;
9382de3b87aSKai Wang
9392de3b87aSKai Wang dst.d_size = fsz;
9402de3b87aSKai Wang dst.d_buf = nf + ex->ex_start;
9412de3b87aSKai Wang
942ae500c1fSEd Maste if (_libelf_xlate(&dst, &src, e->e_byteorder, ec, em, ELF_TOFILE) ==
9432de3b87aSKai Wang NULL)
9442de3b87aSKai Wang return ((off_t) -1);
9452de3b87aSKai Wang
946cf781b2eSEd Maste return ((off_t) (phoff + fsz));
9472de3b87aSKai Wang }
9482de3b87aSKai Wang
9492de3b87aSKai Wang /*
9502de3b87aSKai Wang * Write out an ELF section header table.
9512de3b87aSKai Wang */
9522de3b87aSKai Wang
9532de3b87aSKai Wang static off_t
_libelf_write_shdr(Elf * e,unsigned char * nf,struct _Elf_Extent * ex)954cf781b2eSEd Maste _libelf_write_shdr(Elf *e, unsigned char *nf, struct _Elf_Extent *ex)
9552de3b87aSKai Wang {
956ae500c1fSEd Maste int ec, em;
9572de3b87aSKai Wang void *ehdr;
9582de3b87aSKai Wang Elf_Scn *scn;
9592de3b87aSKai Wang uint64_t shoff;
9602de3b87aSKai Wang Elf32_Ehdr *eh32;
9612de3b87aSKai Wang Elf64_Ehdr *eh64;
962*d003e0d7SEd Maste size_t fsz, msz, nscn;
9632de3b87aSKai Wang Elf_Data dst, src;
9642de3b87aSKai Wang
9652de3b87aSKai Wang assert(ex->ex_type == ELF_EXTENT_SHDR);
9662de3b87aSKai Wang
9672de3b87aSKai Wang ec = e->e_class;
968*d003e0d7SEd Maste
9692de3b87aSKai Wang ehdr = _libelf_ehdr(e, ec, 0);
970*d003e0d7SEd Maste assert(ehdr != NULL);
971*d003e0d7SEd Maste
9722de3b87aSKai Wang nscn = e->e_u.e_elf.e_nscn;
9732de3b87aSKai Wang
9742de3b87aSKai Wang if (ec == ELFCLASS32) {
9752de3b87aSKai Wang eh32 = (Elf32_Ehdr *) ehdr;
9762de3b87aSKai Wang shoff = (uint64_t) eh32->e_shoff;
9772de3b87aSKai Wang } else {
9782de3b87aSKai Wang eh64 = (Elf64_Ehdr *) ehdr;
9792de3b87aSKai Wang shoff = eh64->e_shoff;
9802de3b87aSKai Wang }
9812de3b87aSKai Wang
982ae500c1fSEd Maste em = _libelf_elfmachine(e);
983ae500c1fSEd Maste
9842de3b87aSKai Wang assert(nscn > 0);
9852de3b87aSKai Wang assert(shoff % _libelf_falign(ELF_T_SHDR, ec) == 0);
9862de3b87aSKai Wang assert(ex->ex_start == shoff);
9872de3b87aSKai Wang
9882de3b87aSKai Wang (void) memset(&dst, 0, sizeof(dst));
9892de3b87aSKai Wang (void) memset(&src, 0, sizeof(src));
9902de3b87aSKai Wang
991*d003e0d7SEd Maste if ((msz = _libelf_msize(ELF_T_SHDR, ec, e->e_version)) == 0)
992*d003e0d7SEd Maste return ((off_t) -1);
993*d003e0d7SEd Maste
9942de3b87aSKai Wang src.d_type = ELF_T_SHDR;
995*d003e0d7SEd Maste src.d_size = msz;
9962de3b87aSKai Wang src.d_version = dst.d_version = e->e_version;
9972de3b87aSKai Wang
9982de3b87aSKai Wang fsz = _libelf_fsize(ELF_T_SHDR, ec, e->e_version, (size_t) 1);
9992de3b87aSKai Wang
10008c953901SMark Johnston RB_FOREACH(scn, scntree, &e->e_u.e_elf.e_scn) {
10012de3b87aSKai Wang if (ec == ELFCLASS32)
10022de3b87aSKai Wang src.d_buf = &scn->s_shdr.s_shdr32;
10032de3b87aSKai Wang else
10042de3b87aSKai Wang src.d_buf = &scn->s_shdr.s_shdr64;
10052de3b87aSKai Wang
10062de3b87aSKai Wang dst.d_size = fsz;
10072de3b87aSKai Wang dst.d_buf = nf + ex->ex_start + scn->s_ndx * fsz;
10082de3b87aSKai Wang
1009ae500c1fSEd Maste if (_libelf_xlate(&dst, &src, e->e_byteorder, ec, em,
10102de3b87aSKai Wang ELF_TOFILE) == NULL)
10112de3b87aSKai Wang return ((off_t) -1);
10122de3b87aSKai Wang }
10132de3b87aSKai Wang
1014cf781b2eSEd Maste return ((off_t) (ex->ex_start + nscn * fsz));
10152de3b87aSKai Wang }
10162de3b87aSKai Wang
10172de3b87aSKai Wang /*
10182de3b87aSKai Wang * Write out the file image.
10192de3b87aSKai Wang *
10202de3b87aSKai Wang * The original file could have been mapped in with an ELF_C_RDWR
10212de3b87aSKai Wang * command and the application could have added new content or
10222de3b87aSKai Wang * re-arranged its sections before calling elf_update(). Consequently
10232de3b87aSKai Wang * its not safe to work `in place' on the original file. So we
10242de3b87aSKai Wang * malloc() the required space for the updated ELF object and build
10252de3b87aSKai Wang * the object there and write it out to the underlying file at the
10262de3b87aSKai Wang * end. Note that the application may have opened the underlying file
10272de3b87aSKai Wang * in ELF_C_RDWR and only retrieved/modified a few sections. We take
10282de3b87aSKai Wang * care to avoid translating file sections unnecessarily.
10292de3b87aSKai Wang *
10302de3b87aSKai Wang * Gaps in the coverage of the file by the file's sections will be
10312de3b87aSKai Wang * filled with the fill character set by elf_fill(3).
10322de3b87aSKai Wang */
10332de3b87aSKai Wang
10342de3b87aSKai Wang static off_t
_libelf_write_elf(Elf * e,off_t newsize,struct _Elf_Extent_List * extents)10352de3b87aSKai Wang _libelf_write_elf(Elf *e, off_t newsize, struct _Elf_Extent_List *extents)
10362de3b87aSKai Wang {
10372de3b87aSKai Wang off_t nrc, rc;
10382de3b87aSKai Wang Elf_Scn *scn, *tscn;
10392de3b87aSKai Wang struct _Elf_Extent *ex;
1040cf781b2eSEd Maste unsigned char *newfile;
10412de3b87aSKai Wang
10422de3b87aSKai Wang assert(e->e_kind == ELF_K_ELF);
10432de3b87aSKai Wang assert(e->e_cmd == ELF_C_RDWR || e->e_cmd == ELF_C_WRITE);
10442de3b87aSKai Wang assert(e->e_fd >= 0);
10452de3b87aSKai Wang
10462de3b87aSKai Wang if ((newfile = malloc((size_t) newsize)) == NULL) {
10472de3b87aSKai Wang LIBELF_SET_ERROR(RESOURCE, errno);
10482de3b87aSKai Wang return ((off_t) -1);
10492de3b87aSKai Wang }
10502de3b87aSKai Wang
10512de3b87aSKai Wang nrc = rc = 0;
10522de3b87aSKai Wang SLIST_FOREACH(ex, extents, ex_next) {
10532de3b87aSKai Wang
10542de3b87aSKai Wang /* Fill inter-extent gaps. */
10552de3b87aSKai Wang if (ex->ex_start > (size_t) rc)
10562de3b87aSKai Wang (void) memset(newfile + rc, LIBELF_PRIVATE(fillchar),
1057cf781b2eSEd Maste (size_t) (ex->ex_start - (uint64_t) rc));
10582de3b87aSKai Wang
10592de3b87aSKai Wang switch (ex->ex_type) {
10602de3b87aSKai Wang case ELF_EXTENT_EHDR:
10612de3b87aSKai Wang if ((nrc = _libelf_write_ehdr(e, newfile, ex)) < 0)
10622de3b87aSKai Wang goto error;
10632de3b87aSKai Wang break;
10642de3b87aSKai Wang
10652de3b87aSKai Wang case ELF_EXTENT_PHDR:
10662de3b87aSKai Wang if ((nrc = _libelf_write_phdr(e, newfile, ex)) < 0)
10672de3b87aSKai Wang goto error;
10682de3b87aSKai Wang break;
10692de3b87aSKai Wang
10702de3b87aSKai Wang case ELF_EXTENT_SECTION:
10712de3b87aSKai Wang if ((nrc = _libelf_write_scn(e, newfile, ex)) < 0)
10722de3b87aSKai Wang goto error;
10732de3b87aSKai Wang break;
10742de3b87aSKai Wang
10752de3b87aSKai Wang case ELF_EXTENT_SHDR:
10762de3b87aSKai Wang if ((nrc = _libelf_write_shdr(e, newfile, ex)) < 0)
10772de3b87aSKai Wang goto error;
10782de3b87aSKai Wang break;
10792de3b87aSKai Wang
10802de3b87aSKai Wang default:
10812de3b87aSKai Wang assert(0);
10822de3b87aSKai Wang break;
10832de3b87aSKai Wang }
10842de3b87aSKai Wang
10852de3b87aSKai Wang assert(ex->ex_start + ex->ex_size == (size_t) nrc);
10862de3b87aSKai Wang assert(rc < nrc);
10872de3b87aSKai Wang
10882de3b87aSKai Wang rc = nrc;
10892de3b87aSKai Wang }
10902de3b87aSKai Wang
10912de3b87aSKai Wang assert(rc == newsize);
10922de3b87aSKai Wang
10932de3b87aSKai Wang /*
10942de3b87aSKai Wang * For regular files, throw away existing file content and
10952de3b87aSKai Wang * unmap any existing mappings.
10962de3b87aSKai Wang */
10972de3b87aSKai Wang if ((e->e_flags & LIBELF_F_SPECIAL_FILE) == 0) {
10982de3b87aSKai Wang if (ftruncate(e->e_fd, (off_t) 0) < 0 ||
10992de3b87aSKai Wang lseek(e->e_fd, (off_t) 0, SEEK_SET)) {
11002de3b87aSKai Wang LIBELF_SET_ERROR(IO, errno);
11012de3b87aSKai Wang goto error;
11022de3b87aSKai Wang }
11032de3b87aSKai Wang #if ELFTC_HAVE_MMAP
11042de3b87aSKai Wang if (e->e_flags & LIBELF_F_RAWFILE_MMAP) {
11052de3b87aSKai Wang assert(e->e_rawfile != NULL);
11062de3b87aSKai Wang assert(e->e_cmd == ELF_C_RDWR);
1107*d003e0d7SEd Maste if (munmap(e->e_rawfile, (size_t) e->e_rawsize) < 0) {
11082de3b87aSKai Wang LIBELF_SET_ERROR(IO, errno);
11092de3b87aSKai Wang goto error;
11102de3b87aSKai Wang }
11112de3b87aSKai Wang }
11122de3b87aSKai Wang #endif
11132de3b87aSKai Wang }
11142de3b87aSKai Wang
11152de3b87aSKai Wang /*
11162de3b87aSKai Wang * Write out the new contents.
11172de3b87aSKai Wang */
11182de3b87aSKai Wang if (write(e->e_fd, newfile, (size_t) newsize) != newsize) {
11192de3b87aSKai Wang LIBELF_SET_ERROR(IO, errno);
11202de3b87aSKai Wang goto error;
11212de3b87aSKai Wang }
11222de3b87aSKai Wang
11232de3b87aSKai Wang /*
11242de3b87aSKai Wang * For files opened in ELF_C_RDWR mode, set up the new 'raw'
11252de3b87aSKai Wang * contents.
11262de3b87aSKai Wang */
11272de3b87aSKai Wang if (e->e_cmd == ELF_C_RDWR) {
11282de3b87aSKai Wang assert(e->e_rawfile != NULL);
11292de3b87aSKai Wang assert((e->e_flags & LIBELF_F_RAWFILE_MALLOC) ||
11302de3b87aSKai Wang (e->e_flags & LIBELF_F_RAWFILE_MMAP));
11312de3b87aSKai Wang if (e->e_flags & LIBELF_F_RAWFILE_MALLOC) {
1132*d003e0d7SEd Maste assert((e->e_flags & LIBELF_F_RAWFILE_MMAP) == 0);
11332de3b87aSKai Wang free(e->e_rawfile);
11342de3b87aSKai Wang e->e_rawfile = newfile;
11352de3b87aSKai Wang newfile = NULL;
11362de3b87aSKai Wang }
11372de3b87aSKai Wang #if ELFTC_HAVE_MMAP
11382de3b87aSKai Wang else if (e->e_flags & LIBELF_F_RAWFILE_MMAP) {
1139*d003e0d7SEd Maste assert((e->e_flags & LIBELF_F_RAWFILE_MALLOC) == 0);
11402de3b87aSKai Wang if ((e->e_rawfile = mmap(NULL, (size_t) newsize,
11412de3b87aSKai Wang PROT_READ, MAP_PRIVATE, e->e_fd, (off_t) 0)) ==
11422de3b87aSKai Wang MAP_FAILED) {
11432de3b87aSKai Wang LIBELF_SET_ERROR(IO, errno);
11442de3b87aSKai Wang goto error;
11452de3b87aSKai Wang }
11462de3b87aSKai Wang }
11472de3b87aSKai Wang #endif /* ELFTC_HAVE_MMAP */
11482de3b87aSKai Wang
11492de3b87aSKai Wang /* Record the new size of the file. */
1150*d003e0d7SEd Maste e->e_rawsize = newsize;
11512de3b87aSKai Wang } else {
11522de3b87aSKai Wang /* File opened in ELF_C_WRITE mode. */
11532de3b87aSKai Wang assert(e->e_rawfile == NULL);
11542de3b87aSKai Wang }
11552de3b87aSKai Wang
11562de3b87aSKai Wang /*
11572de3b87aSKai Wang * Reset flags, remove existing section descriptors and
11582de3b87aSKai Wang * {E,P}HDR pointers so that a subsequent elf_get{e,p}hdr()
11592de3b87aSKai Wang * and elf_getscn() will function correctly.
11602de3b87aSKai Wang */
11612de3b87aSKai Wang
11622de3b87aSKai Wang e->e_flags &= ~ELF_F_DIRTY;
11632de3b87aSKai Wang
11648c953901SMark Johnston RB_FOREACH_SAFE(scn, scntree, &e->e_u.e_elf.e_scn, tscn)
11652de3b87aSKai Wang _libelf_release_scn(scn);
11662de3b87aSKai Wang
11672de3b87aSKai Wang if (e->e_class == ELFCLASS32) {
11682de3b87aSKai Wang free(e->e_u.e_elf.e_ehdr.e_ehdr32);
11692de3b87aSKai Wang if (e->e_u.e_elf.e_phdr.e_phdr32)
11702de3b87aSKai Wang free(e->e_u.e_elf.e_phdr.e_phdr32);
11712de3b87aSKai Wang
11722de3b87aSKai Wang e->e_u.e_elf.e_ehdr.e_ehdr32 = NULL;
11732de3b87aSKai Wang e->e_u.e_elf.e_phdr.e_phdr32 = NULL;
11742de3b87aSKai Wang } else {
11752de3b87aSKai Wang free(e->e_u.e_elf.e_ehdr.e_ehdr64);
11762de3b87aSKai Wang if (e->e_u.e_elf.e_phdr.e_phdr64)
11772de3b87aSKai Wang free(e->e_u.e_elf.e_phdr.e_phdr64);
11782de3b87aSKai Wang
11792de3b87aSKai Wang e->e_u.e_elf.e_ehdr.e_ehdr64 = NULL;
11802de3b87aSKai Wang e->e_u.e_elf.e_phdr.e_phdr64 = NULL;
11812de3b87aSKai Wang }
11822de3b87aSKai Wang
11832de3b87aSKai Wang /* Free the temporary buffer. */
11842de3b87aSKai Wang if (newfile)
11852de3b87aSKai Wang free(newfile);
11862de3b87aSKai Wang
11872de3b87aSKai Wang return (rc);
11882de3b87aSKai Wang
11892de3b87aSKai Wang error:
11902de3b87aSKai Wang free(newfile);
11912de3b87aSKai Wang
11922de3b87aSKai Wang return ((off_t) -1);
11932de3b87aSKai Wang }
11942de3b87aSKai Wang
11952de3b87aSKai Wang /*
11962de3b87aSKai Wang * Update an ELF object.
11972de3b87aSKai Wang */
11982de3b87aSKai Wang
11992de3b87aSKai Wang off_t
elf_update(Elf * e,Elf_Cmd c)12002de3b87aSKai Wang elf_update(Elf *e, Elf_Cmd c)
12012de3b87aSKai Wang {
12022de3b87aSKai Wang int ec;
12032de3b87aSKai Wang off_t rc;
12042de3b87aSKai Wang struct _Elf_Extent_List extents;
12052de3b87aSKai Wang
12062de3b87aSKai Wang rc = (off_t) -1;
12072de3b87aSKai Wang
12082de3b87aSKai Wang if (e == NULL || e->e_kind != ELF_K_ELF ||
12092de3b87aSKai Wang (c != ELF_C_NULL && c != ELF_C_WRITE)) {
12102de3b87aSKai Wang LIBELF_SET_ERROR(ARGUMENT, 0);
12112de3b87aSKai Wang return (rc);
12122de3b87aSKai Wang }
12132de3b87aSKai Wang
12142de3b87aSKai Wang if ((ec = e->e_class) != ELFCLASS32 && ec != ELFCLASS64) {
12152de3b87aSKai Wang LIBELF_SET_ERROR(CLASS, 0);
12162de3b87aSKai Wang return (rc);
12172de3b87aSKai Wang }
12182de3b87aSKai Wang
12192de3b87aSKai Wang if (e->e_version == EV_NONE)
12202de3b87aSKai Wang e->e_version = EV_CURRENT;
12212de3b87aSKai Wang
12222de3b87aSKai Wang if (c == ELF_C_WRITE && e->e_cmd == ELF_C_READ) {
12232de3b87aSKai Wang LIBELF_SET_ERROR(MODE, 0);
12242de3b87aSKai Wang return (rc);
12252de3b87aSKai Wang }
12262de3b87aSKai Wang
12272de3b87aSKai Wang SLIST_INIT(&extents);
12282de3b87aSKai Wang
12292de3b87aSKai Wang if ((rc = _libelf_resync_elf(e, &extents)) < 0)
12302de3b87aSKai Wang goto done;
12312de3b87aSKai Wang
12322de3b87aSKai Wang if (c == ELF_C_NULL)
12332de3b87aSKai Wang goto done;
12342de3b87aSKai Wang
12352de3b87aSKai Wang if (e->e_fd < 0) {
12362de3b87aSKai Wang rc = (off_t) -1;
12372de3b87aSKai Wang LIBELF_SET_ERROR(SEQUENCE, 0);
12382de3b87aSKai Wang goto done;
12392de3b87aSKai Wang }
12402de3b87aSKai Wang
12412de3b87aSKai Wang rc = _libelf_write_elf(e, rc, &extents);
12422de3b87aSKai Wang
12432de3b87aSKai Wang done:
12442de3b87aSKai Wang _libelf_release_extents(&extents);
1245bd6313b6SEd Maste e->e_flags &= ~LIBELF_F_SHDRS_LOADED;
12462de3b87aSKai Wang return (rc);
12472de3b87aSKai Wang }
1248