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