elf_update.c revision 4484
14484Sbinkertn@umich.edu/*- 24484Sbinkertn@umich.edu * Copyright (c) 2006 Joseph Koshy 34484Sbinkertn@umich.edu * All rights reserved. 44484Sbinkertn@umich.edu * 54484Sbinkertn@umich.edu * Redistribution and use in source and binary forms, with or without 64484Sbinkertn@umich.edu * modification, are permitted provided that the following conditions 74484Sbinkertn@umich.edu * are met: 84484Sbinkertn@umich.edu * 1. Redistributions of source code must retain the above copyright 94484Sbinkertn@umich.edu * notice, this list of conditions and the following disclaimer. 104484Sbinkertn@umich.edu * 2. Redistributions in binary form must reproduce the above copyright 114484Sbinkertn@umich.edu * notice, this list of conditions and the following disclaimer in the 124484Sbinkertn@umich.edu * documentation and/or other materials provided with the distribution. 134484Sbinkertn@umich.edu * 144484Sbinkertn@umich.edu * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 154484Sbinkertn@umich.edu * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 164484Sbinkertn@umich.edu * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 174484Sbinkertn@umich.edu * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 184484Sbinkertn@umich.edu * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 194484Sbinkertn@umich.edu * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 204484Sbinkertn@umich.edu * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 214484Sbinkertn@umich.edu * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 224484Sbinkertn@umich.edu * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 234484Sbinkertn@umich.edu * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 244484Sbinkertn@umich.edu * SUCH DAMAGE. 254484Sbinkertn@umich.edu */ 264484Sbinkertn@umich.edu 274484Sbinkertn@umich.edu 284484Sbinkertn@umich.edu#include <sys/mman.h> 294484Sbinkertn@umich.edu#include <sys/param.h> 304484Sbinkertn@umich.edu 314484Sbinkertn@umich.edu#include <assert.h> 324484Sbinkertn@umich.edu#include <errno.h> 334484Sbinkertn@umich.edu#include "gelf.h" 344484Sbinkertn@umich.edu#include "libelf.h" 354484Sbinkertn@umich.edu#include <stdlib.h> 364484Sbinkertn@umich.edu#include <string.h> 374484Sbinkertn@umich.edu#include <unistd.h> 384484Sbinkertn@umich.edu 394484Sbinkertn@umich.edu#include "_libelf.h" 404484Sbinkertn@umich.edu 414484Sbinkertn@umich.edu/* 424484Sbinkertn@umich.edu * Update the internal data structures associated with an ELF object. 434484Sbinkertn@umich.edu * Returns the size in bytes the ELF object would occupy in its file 444484Sbinkertn@umich.edu * representation. 454484Sbinkertn@umich.edu * 464484Sbinkertn@umich.edu * After a successful call to this function, the following structures 474484Sbinkertn@umich.edu * are updated: 484484Sbinkertn@umich.edu * 494484Sbinkertn@umich.edu * - The ELF header is updated. 504484Sbinkertn@umich.edu * - All sections are sorted in order of ascending addresses and their 514484Sbinkertn@umich.edu * section header table entries updated. An error is signalled 524484Sbinkertn@umich.edu * if an overlap was detected among sections. 534484Sbinkertn@umich.edu * - All data descriptors associated with a section are sorted in order 544484Sbinkertn@umich.edu * of ascending addresses. Overlaps, if detected, are signalled as 554484Sbinkertn@umich.edu * errors. Other sanity checks for alignments, section types etc. are 564484Sbinkertn@umich.edu * made. 574484Sbinkertn@umich.edu * 584484Sbinkertn@umich.edu * After a resync_elf() successfully returns, the ELF descriptor is 594484Sbinkertn@umich.edu * ready for being handed over to _libelf_write_elf(). 604484Sbinkertn@umich.edu * 614484Sbinkertn@umich.edu * File alignments: 624484Sbinkertn@umich.edu * PHDR - Addr 634484Sbinkertn@umich.edu * SHDR - Addr 644484Sbinkertn@umich.edu * 654484Sbinkertn@umich.edu * XXX: how do we handle 'flags'. 664484Sbinkertn@umich.edu */ 674484Sbinkertn@umich.edu 684484Sbinkertn@umich.edu/* 694484Sbinkertn@umich.edu * Compute the extents of a section, by looking at the. 704484Sbinkertn@umich.edu */ 714484Sbinkertn@umich.edustatic int 724484Sbinkertn@umich.edu_libelf_compute_section_extents(Elf *e, Elf_Scn *s, off_t *rc) 734484Sbinkertn@umich.edu{ 744484Sbinkertn@umich.edu int ec; 754484Sbinkertn@umich.edu Elf_Data *d, *td; 764484Sbinkertn@umich.edu unsigned int elftype; 774484Sbinkertn@umich.edu uint32_t sh_type; 784484Sbinkertn@umich.edu uint64_t d_align; 794484Sbinkertn@umich.edu uint64_t sh_align, sh_entsize, sh_offset, sh_size; 804484Sbinkertn@umich.edu uint64_t scn_size, scn_alignment; 814484Sbinkertn@umich.edu 824484Sbinkertn@umich.edu /* 834484Sbinkertn@umich.edu * We need to recompute library private data structures if one 844484Sbinkertn@umich.edu * or more of the following is true: 854484Sbinkertn@umich.edu * - The underlying Shdr structure has been marked `dirty'. Significant 864484Sbinkertn@umich.edu * fields include: `sh_offset', `sh_type', `sh_size', `sh_addralign'. 874484Sbinkertn@umich.edu * - The Elf_Data structures part of this section have been marked 884484Sbinkertn@umich.edu * `dirty'. Affected members include `d_align', `d_offset', `d_type', 894484Sbinkertn@umich.edu * and `d_size'. 904484Sbinkertn@umich.edu * - The section as a whole is `dirty', e.g., it has been allocated 914484Sbinkertn@umich.edu * using elf_newscn(), or if a new Elf_Data structure was added using 924484Sbinkertn@umich.edu * elf_newdata(). 934484Sbinkertn@umich.edu * 944484Sbinkertn@umich.edu * Each of these conditions would result in the ELF_F_DIRTY bit being 954484Sbinkertn@umich.edu * set on the section descriptor's `s_flags' field. 964484Sbinkertn@umich.edu */ 974484Sbinkertn@umich.edu 984484Sbinkertn@umich.edu ec = e->e_class; 994484Sbinkertn@umich.edu 1004484Sbinkertn@umich.edu if (ec == ELFCLASS32) { 1014484Sbinkertn@umich.edu sh_type = s->s_shdr.s_shdr32.sh_type; 1024484Sbinkertn@umich.edu sh_align = (uint64_t) s->s_shdr.s_shdr32.sh_addralign; 1034484Sbinkertn@umich.edu sh_entsize = (uint64_t) s->s_shdr.s_shdr32.sh_entsize; 1044484Sbinkertn@umich.edu sh_offset = (uint64_t) s->s_shdr.s_shdr32.sh_offset; 1054484Sbinkertn@umich.edu sh_size = (uint64_t) s->s_shdr.s_shdr32.sh_size; 1064484Sbinkertn@umich.edu } else { 1074484Sbinkertn@umich.edu sh_type = s->s_shdr.s_shdr64.sh_type; 1084484Sbinkertn@umich.edu sh_align = s->s_shdr.s_shdr64.sh_addralign; 1094484Sbinkertn@umich.edu sh_entsize = s->s_shdr.s_shdr64.sh_entsize; 1104484Sbinkertn@umich.edu sh_offset = s->s_shdr.s_shdr64.sh_offset; 1114484Sbinkertn@umich.edu sh_size = s->s_shdr.s_shdr64.sh_size; 1124484Sbinkertn@umich.edu } 1134484Sbinkertn@umich.edu 1144484Sbinkertn@umich.edu if (sh_type == SHT_NULL || sh_type == SHT_NOBITS) 1154484Sbinkertn@umich.edu return (1); 1164484Sbinkertn@umich.edu 1174484Sbinkertn@umich.edu if ((s->s_flags & ELF_F_DIRTY) == 0) { 1184484Sbinkertn@umich.edu if ((size_t) *rc < sh_offset + sh_size) 1194484Sbinkertn@umich.edu *rc = sh_offset + sh_size; 1204484Sbinkertn@umich.edu return (1); 1214484Sbinkertn@umich.edu } 1224484Sbinkertn@umich.edu 1234484Sbinkertn@umich.edu elftype = _libelf_xlate_shtype(sh_type); 1244484Sbinkertn@umich.edu if (elftype > ELF_T_LAST) { 1254484Sbinkertn@umich.edu LIBELF_SET_ERROR(SECTION, 0); 1264484Sbinkertn@umich.edu return (0); 1274484Sbinkertn@umich.edu } 1284484Sbinkertn@umich.edu 1294484Sbinkertn@umich.edu /* 1304484Sbinkertn@umich.edu * Compute the extent of the data descriptors associated with 1314484Sbinkertn@umich.edu * this section. 1324484Sbinkertn@umich.edu */ 1334484Sbinkertn@umich.edu scn_alignment = 0; 1344484Sbinkertn@umich.edu if (sh_align == 0) 1354484Sbinkertn@umich.edu sh_align = _libelf_falign(elftype, ec); 1364484Sbinkertn@umich.edu 1374484Sbinkertn@umich.edu /* Compute the section alignment. */ 1384484Sbinkertn@umich.edu STAILQ_FOREACH(d, &s->s_data, d_next) { 1394484Sbinkertn@umich.edu if (d->d_type != elftype) { 1404484Sbinkertn@umich.edu LIBELF_SET_ERROR(DATA, 0); 1414484Sbinkertn@umich.edu return (0); 1424484Sbinkertn@umich.edu } 1434484Sbinkertn@umich.edu if (d->d_version != e->e_version) { 1444484Sbinkertn@umich.edu LIBELF_SET_ERROR(VERSION, 0); 1454484Sbinkertn@umich.edu return (0); 1464484Sbinkertn@umich.edu } 1474484Sbinkertn@umich.edu if ((d_align = d->d_align) % sh_align) { 1484484Sbinkertn@umich.edu LIBELF_SET_ERROR(LAYOUT, 0); 1494484Sbinkertn@umich.edu return (0); 1504484Sbinkertn@umich.edu } 1514484Sbinkertn@umich.edu if (d_align == 0 || (d_align & (d_align - 1))) { 1524484Sbinkertn@umich.edu LIBELF_SET_ERROR(DATA, 0); 1534484Sbinkertn@umich.edu return (0); 1544484Sbinkertn@umich.edu } 1554484Sbinkertn@umich.edu if (d_align > scn_alignment) 1564484Sbinkertn@umich.edu scn_alignment = d_align; 1574484Sbinkertn@umich.edu } 1584484Sbinkertn@umich.edu 1594484Sbinkertn@umich.edu scn_size = 0L; 1604484Sbinkertn@umich.edu 1614484Sbinkertn@umich.edu STAILQ_FOREACH_SAFE(d, &s->s_data, d_next, td) { 1624484Sbinkertn@umich.edu if (e->e_flags & ELF_F_LAYOUT) { 1634484Sbinkertn@umich.edu if ((uint64_t) d->d_off + d->d_size > scn_size) 1644484Sbinkertn@umich.edu scn_size = d->d_off + d->d_size; 1654484Sbinkertn@umich.edu } else { 1664484Sbinkertn@umich.edu scn_size = roundup(scn_size, scn_alignment); 1674484Sbinkertn@umich.edu d->d_off = scn_size; 1684484Sbinkertn@umich.edu scn_size += d->d_size; 1694484Sbinkertn@umich.edu } 1704484Sbinkertn@umich.edu } 1714484Sbinkertn@umich.edu 1724484Sbinkertn@umich.edu /* 1734484Sbinkertn@umich.edu * If the application is requesting full control over the layout 1744484Sbinkertn@umich.edu * of the section, check its values for sanity. 1754484Sbinkertn@umich.edu */ 1764484Sbinkertn@umich.edu if (e->e_flags & ELF_F_LAYOUT) { 1774484Sbinkertn@umich.edu if (scn_alignment > sh_align || sh_offset % sh_align || 1784484Sbinkertn@umich.edu sh_size < scn_size) { 1794484Sbinkertn@umich.edu LIBELF_SET_ERROR(LAYOUT, 0); 1804484Sbinkertn@umich.edu return (0); 1814484Sbinkertn@umich.edu } 1824484Sbinkertn@umich.edu } else { 1834484Sbinkertn@umich.edu /* 1844484Sbinkertn@umich.edu * Otherwise compute the values in the section header. 1854484Sbinkertn@umich.edu */ 1864484Sbinkertn@umich.edu 1874484Sbinkertn@umich.edu if (scn_alignment > sh_align) 1884484Sbinkertn@umich.edu sh_align = scn_alignment; 1894484Sbinkertn@umich.edu 1904484Sbinkertn@umich.edu /* 1914484Sbinkertn@umich.edu * If the section entry size is zero, try and fill in an 1924484Sbinkertn@umich.edu * appropriate entry size. Per the elf(5) manual page 1934484Sbinkertn@umich.edu * sections without fixed-size entries should have their 1944484Sbinkertn@umich.edu * 'sh_entsize' field set to zero. 1954484Sbinkertn@umich.edu */ 1964484Sbinkertn@umich.edu if (sh_entsize == 0 && 1974484Sbinkertn@umich.edu (sh_entsize = _libelf_fsize(elftype, ec, e->e_version, 1984484Sbinkertn@umich.edu (size_t) 1)) == 1) 1994484Sbinkertn@umich.edu sh_entsize = 0; 2004484Sbinkertn@umich.edu 2014484Sbinkertn@umich.edu sh_size = scn_size; 2024484Sbinkertn@umich.edu sh_offset = roundup(*rc, sh_align); 2034484Sbinkertn@umich.edu 2044484Sbinkertn@umich.edu if (ec == ELFCLASS32) { 2054484Sbinkertn@umich.edu s->s_shdr.s_shdr32.sh_addralign = (uint32_t) sh_align; 2064484Sbinkertn@umich.edu s->s_shdr.s_shdr32.sh_entsize = (uint32_t) sh_entsize; 2074484Sbinkertn@umich.edu s->s_shdr.s_shdr32.sh_offset = (uint32_t) sh_offset; 2084484Sbinkertn@umich.edu s->s_shdr.s_shdr32.sh_size = (uint32_t) sh_size; 2094484Sbinkertn@umich.edu } else { 2104484Sbinkertn@umich.edu s->s_shdr.s_shdr64.sh_addralign = sh_align; 2114484Sbinkertn@umich.edu s->s_shdr.s_shdr64.sh_entsize = sh_entsize; 2124484Sbinkertn@umich.edu s->s_shdr.s_shdr64.sh_offset = sh_offset; 2134484Sbinkertn@umich.edu s->s_shdr.s_shdr64.sh_size = sh_size; 2144484Sbinkertn@umich.edu } 2154484Sbinkertn@umich.edu } 2164484Sbinkertn@umich.edu 2174484Sbinkertn@umich.edu if ((size_t) *rc < sh_offset + sh_size) 2184484Sbinkertn@umich.edu *rc = sh_offset + sh_size; 2194484Sbinkertn@umich.edu 2204484Sbinkertn@umich.edu s->s_size = sh_size; 2214484Sbinkertn@umich.edu s->s_offset = sh_offset; 2224484Sbinkertn@umich.edu return (1); 2234484Sbinkertn@umich.edu} 2244484Sbinkertn@umich.edu 2254484Sbinkertn@umich.edu 2264484Sbinkertn@umich.edu/* 2274484Sbinkertn@umich.edu * Insert a section in ascending order in the list 2284484Sbinkertn@umich.edu */ 2294484Sbinkertn@umich.edu 2304484Sbinkertn@umich.edustatic int 2314484Sbinkertn@umich.edu_libelf_insert_section(Elf *e, Elf_Scn *s) 2324484Sbinkertn@umich.edu{ 2334484Sbinkertn@umich.edu Elf_Scn *t, *prevt; 2344484Sbinkertn@umich.edu uint64_t smax, smin, tmax, tmin; 2354484Sbinkertn@umich.edu 2364484Sbinkertn@umich.edu smin = s->s_offset; 2374484Sbinkertn@umich.edu smax = smin + s->s_size; 2384484Sbinkertn@umich.edu 2394484Sbinkertn@umich.edu prevt = NULL; 2404484Sbinkertn@umich.edu STAILQ_FOREACH(t, &e->e_u.e_elf.e_scn, s_next) { 2414484Sbinkertn@umich.edu tmin = t->s_offset; 2424484Sbinkertn@umich.edu tmax = tmin + t->s_size; 2434484Sbinkertn@umich.edu 2444484Sbinkertn@umich.edu /* check if there is an overlap */ 2454484Sbinkertn@umich.edu if (tmax < smin) { 2464484Sbinkertn@umich.edu prevt = t; 2474484Sbinkertn@umich.edu continue; 2484484Sbinkertn@umich.edu } else if (smax < tmin) 2494484Sbinkertn@umich.edu break; 2504484Sbinkertn@umich.edu else { 2514484Sbinkertn@umich.edu LIBELF_SET_ERROR(LAYOUT, 0); 2524484Sbinkertn@umich.edu return (0); 2534484Sbinkertn@umich.edu } 2544484Sbinkertn@umich.edu } 2554484Sbinkertn@umich.edu 2564484Sbinkertn@umich.edu if (prevt) 2574484Sbinkertn@umich.edu STAILQ_INSERT_AFTER(&e->e_u.e_elf.e_scn, prevt, s, s_next); 2584484Sbinkertn@umich.edu else 2594484Sbinkertn@umich.edu STAILQ_INSERT_HEAD(&e->e_u.e_elf.e_scn, s, s_next); 2604484Sbinkertn@umich.edu return (1); 2614484Sbinkertn@umich.edu} 2624484Sbinkertn@umich.edu 2634484Sbinkertn@umich.edustatic off_t 2644484Sbinkertn@umich.edu_libelf_resync_sections(Elf *e, off_t rc) 2654484Sbinkertn@umich.edu{ 2664484Sbinkertn@umich.edu int ec; 2674484Sbinkertn@umich.edu off_t nrc; 2684484Sbinkertn@umich.edu size_t sh_type; 2694484Sbinkertn@umich.edu Elf_Scn *s, *ts; 2704484Sbinkertn@umich.edu 2714484Sbinkertn@umich.edu ec = e->e_class; 2724484Sbinkertn@umich.edu 2734484Sbinkertn@umich.edu /* 2744484Sbinkertn@umich.edu * Make a pass through sections, computing the extent of each 2754484Sbinkertn@umich.edu * section. Order in increasing order of addresses. 2764484Sbinkertn@umich.edu */ 2774484Sbinkertn@umich.edu 2784484Sbinkertn@umich.edu nrc = rc; 2794484Sbinkertn@umich.edu STAILQ_FOREACH(s, &e->e_u.e_elf.e_scn, s_next) 2804484Sbinkertn@umich.edu if (_libelf_compute_section_extents(e, s, &nrc) == 0) 2814484Sbinkertn@umich.edu return ((off_t) -1); 2824484Sbinkertn@umich.edu 2834484Sbinkertn@umich.edu STAILQ_FOREACH_SAFE(s, &e->e_u.e_elf.e_scn, s_next, ts) { 2844484Sbinkertn@umich.edu if (ec == ELFCLASS32) 2854484Sbinkertn@umich.edu sh_type = s->s_shdr.s_shdr32.sh_type; 2864484Sbinkertn@umich.edu else 2874484Sbinkertn@umich.edu sh_type = s->s_shdr.s_shdr64.sh_type; 2884484Sbinkertn@umich.edu 2894484Sbinkertn@umich.edu /* XXX Do we need the 'size' field of an SHT_NOBITS section */ 2904484Sbinkertn@umich.edu if (sh_type == SHT_NOBITS || sh_type == SHT_NULL) 2914484Sbinkertn@umich.edu continue; 2924484Sbinkertn@umich.edu 2934484Sbinkertn@umich.edu if (s->s_offset < (uint64_t) rc) { 2944484Sbinkertn@umich.edu if (s->s_offset + s->s_size < (uint64_t) rc) { 2954484Sbinkertn@umich.edu /* 2964484Sbinkertn@umich.edu * Try insert this section in the 2974484Sbinkertn@umich.edu * correct place in the list, 2984484Sbinkertn@umich.edu * detecting overlaps if any. 2994484Sbinkertn@umich.edu */ 3004484Sbinkertn@umich.edu STAILQ_REMOVE(&e->e_u.e_elf.e_scn, s, _Elf_Scn, 3014484Sbinkertn@umich.edu s_next); 3024484Sbinkertn@umich.edu if (_libelf_insert_section(e, s) == 0) 3034484Sbinkertn@umich.edu return ((off_t) -1); 3044484Sbinkertn@umich.edu } else { 3054484Sbinkertn@umich.edu LIBELF_SET_ERROR(LAYOUT, 0); 3064484Sbinkertn@umich.edu return ((off_t) -1); 3074484Sbinkertn@umich.edu } 3084484Sbinkertn@umich.edu } else 3094484Sbinkertn@umich.edu rc = s->s_offset + s->s_size; 3104484Sbinkertn@umich.edu } 3114484Sbinkertn@umich.edu 3124484Sbinkertn@umich.edu assert(nrc == rc); 3134484Sbinkertn@umich.edu 3144484Sbinkertn@umich.edu return (rc); 3154484Sbinkertn@umich.edu} 3164484Sbinkertn@umich.edu 3174484Sbinkertn@umich.edustatic off_t 3184484Sbinkertn@umich.edu_libelf_resync_elf(Elf *e) 3194484Sbinkertn@umich.edu{ 3204484Sbinkertn@umich.edu int ec, eh_class, eh_type; 3214484Sbinkertn@umich.edu unsigned int eh_byteorder, eh_version; 3224484Sbinkertn@umich.edu size_t align, fsz; 3234484Sbinkertn@umich.edu size_t phnum, shnum; 3244484Sbinkertn@umich.edu off_t rc, phoff, shoff; 3254484Sbinkertn@umich.edu void *ehdr; 3264484Sbinkertn@umich.edu Elf32_Ehdr *eh32; 3274484Sbinkertn@umich.edu Elf64_Ehdr *eh64; 3284484Sbinkertn@umich.edu 3294484Sbinkertn@umich.edu rc = 0; 3304484Sbinkertn@umich.edu 3314484Sbinkertn@umich.edu ec = e->e_class; 3324484Sbinkertn@umich.edu 3334484Sbinkertn@umich.edu assert(ec == ELFCLASS32 || ec == ELFCLASS64); 3344484Sbinkertn@umich.edu 3354484Sbinkertn@umich.edu /* 3364484Sbinkertn@umich.edu * Prepare the EHDR. 3374484Sbinkertn@umich.edu */ 3384484Sbinkertn@umich.edu if ((ehdr = _libelf_ehdr(e, ec, 0)) == NULL) 3394484Sbinkertn@umich.edu return ((off_t) -1); 3404484Sbinkertn@umich.edu 3414484Sbinkertn@umich.edu eh32 = ehdr; 3424484Sbinkertn@umich.edu eh64 = ehdr; 3434484Sbinkertn@umich.edu 3444484Sbinkertn@umich.edu if (ec == ELFCLASS32) { 3454484Sbinkertn@umich.edu eh_byteorder = eh32->e_ident[EI_DATA]; 3464484Sbinkertn@umich.edu eh_class = eh32->e_ident[EI_CLASS]; 3474484Sbinkertn@umich.edu phoff = (uint64_t) eh32->e_phoff; 3484484Sbinkertn@umich.edu shoff = (uint64_t) eh32->e_shoff; 3494484Sbinkertn@umich.edu eh_type = eh32->e_type; 3504484Sbinkertn@umich.edu eh_version = eh32->e_version; 3514484Sbinkertn@umich.edu } else { 3524484Sbinkertn@umich.edu eh_byteorder = eh64->e_ident[EI_DATA]; 3534484Sbinkertn@umich.edu eh_class = eh64->e_ident[EI_CLASS]; 3544484Sbinkertn@umich.edu phoff = eh64->e_phoff; 3554484Sbinkertn@umich.edu shoff = eh64->e_shoff; 3564484Sbinkertn@umich.edu eh_type = eh64->e_type; 3574484Sbinkertn@umich.edu eh_version = eh64->e_version; 3584484Sbinkertn@umich.edu } 3594484Sbinkertn@umich.edu 3604484Sbinkertn@umich.edu if (eh_version == EV_NONE) 3614484Sbinkertn@umich.edu eh_version = EV_CURRENT; 3624484Sbinkertn@umich.edu 3634484Sbinkertn@umich.edu if (eh_version != e->e_version) { /* always EV_CURRENT */ 3644484Sbinkertn@umich.edu LIBELF_SET_ERROR(VERSION, 0); 3654484Sbinkertn@umich.edu return ((off_t) -1); 3664484Sbinkertn@umich.edu } 3674484Sbinkertn@umich.edu 3684484Sbinkertn@umich.edu if (eh_class != e->e_class) { 3694484Sbinkertn@umich.edu LIBELF_SET_ERROR(CLASS, 0); 3704484Sbinkertn@umich.edu return ((off_t) -1); 3714484Sbinkertn@umich.edu } 3724484Sbinkertn@umich.edu 3734484Sbinkertn@umich.edu if (e->e_cmd != ELF_C_WRITE && eh_byteorder != e->e_byteorder) { 3744484Sbinkertn@umich.edu LIBELF_SET_ERROR(HEADER, 0); 3754484Sbinkertn@umich.edu return ((off_t) -1); 3764484Sbinkertn@umich.edu } 3774484Sbinkertn@umich.edu 3784484Sbinkertn@umich.edu shnum = e->e_u.e_elf.e_nscn; 3794484Sbinkertn@umich.edu phnum = e->e_u.e_elf.e_nphdr; 3804484Sbinkertn@umich.edu 3814484Sbinkertn@umich.edu e->e_byteorder = eh_byteorder; 3824484Sbinkertn@umich.edu 3834484Sbinkertn@umich.edu#define INITIALIZE_EHDR(E,EC,V) do { \ 3844484Sbinkertn@umich.edu (E)->e_ident[EI_MAG0] = ELFMAG0; \ 3854484Sbinkertn@umich.edu (E)->e_ident[EI_MAG1] = ELFMAG1; \ 3864484Sbinkertn@umich.edu (E)->e_ident[EI_MAG2] = ELFMAG2; \ 3874484Sbinkertn@umich.edu (E)->e_ident[EI_MAG3] = ELFMAG3; \ 3884484Sbinkertn@umich.edu (E)->e_ident[EI_CLASS] = (EC); \ 3894484Sbinkertn@umich.edu (E)->e_ident[EI_VERSION] = (V); \ 3904484Sbinkertn@umich.edu (E)->e_ehsize = _libelf_fsize(ELF_T_EHDR, (EC), (V), \ 3914484Sbinkertn@umich.edu (size_t) 1); \ 3924484Sbinkertn@umich.edu (E)->e_phentsize = _libelf_fsize(ELF_T_PHDR, (EC), (V), \ 3934484Sbinkertn@umich.edu (size_t) 1); \ 3944484Sbinkertn@umich.edu (E)->e_shentsize = _libelf_fsize(ELF_T_SHDR, (EC), (V), \ 3954484Sbinkertn@umich.edu (size_t) 1); \ 3964484Sbinkertn@umich.edu } while (0) 3974484Sbinkertn@umich.edu 3984484Sbinkertn@umich.edu if (ec == ELFCLASS32) 3994484Sbinkertn@umich.edu INITIALIZE_EHDR(eh32, ec, eh_version); 4004484Sbinkertn@umich.edu else 4014484Sbinkertn@umich.edu INITIALIZE_EHDR(eh64, ec, eh_version); 4024484Sbinkertn@umich.edu 4034484Sbinkertn@umich.edu (void) elf_flagehdr(e, ELF_C_SET, ELF_F_DIRTY); 4044484Sbinkertn@umich.edu 4054484Sbinkertn@umich.edu rc += _libelf_fsize(ELF_T_EHDR, ec, eh_version, (size_t) 1); 4064484Sbinkertn@umich.edu 4074484Sbinkertn@umich.edu /* 4084484Sbinkertn@umich.edu * Compute the layout the program header table, if one is 4094484Sbinkertn@umich.edu * present. The program header table needs to be aligned to a 4104484Sbinkertn@umich.edu * `natural' boundary. 4114484Sbinkertn@umich.edu */ 4124484Sbinkertn@umich.edu if (phnum) { 4134484Sbinkertn@umich.edu fsz = _libelf_fsize(ELF_T_PHDR, ec, eh_version, phnum); 4144484Sbinkertn@umich.edu align = _libelf_falign(ELF_T_PHDR, ec); 4154484Sbinkertn@umich.edu 4164484Sbinkertn@umich.edu if (e->e_flags & ELF_F_LAYOUT) { 4174484Sbinkertn@umich.edu /* 4184484Sbinkertn@umich.edu * Check offsets for sanity. 4194484Sbinkertn@umich.edu */ 4204484Sbinkertn@umich.edu if (rc > phoff) { 4214484Sbinkertn@umich.edu LIBELF_SET_ERROR(HEADER, 0); 4224484Sbinkertn@umich.edu return ((off_t) -1); 4234484Sbinkertn@umich.edu } 4244484Sbinkertn@umich.edu 4254484Sbinkertn@umich.edu if (phoff % align) { 4264484Sbinkertn@umich.edu LIBELF_SET_ERROR(LAYOUT, 0); 4274484Sbinkertn@umich.edu return ((off_t) -1); 4284484Sbinkertn@umich.edu } 4294484Sbinkertn@umich.edu 4304484Sbinkertn@umich.edu } else 4314484Sbinkertn@umich.edu phoff = roundup(rc, align); 4324484Sbinkertn@umich.edu 4334484Sbinkertn@umich.edu rc = phoff + fsz; 4344484Sbinkertn@umich.edu } else 4354484Sbinkertn@umich.edu phoff = 0; 4364484Sbinkertn@umich.edu 4374484Sbinkertn@umich.edu /* 4384484Sbinkertn@umich.edu * Compute the layout of the sections associated with the 4394484Sbinkertn@umich.edu * file. 4404484Sbinkertn@umich.edu */ 4414484Sbinkertn@umich.edu 4424484Sbinkertn@umich.edu if ((rc = _libelf_resync_sections(e, rc)) < 0) 4434484Sbinkertn@umich.edu return ((off_t) -1); 4444484Sbinkertn@umich.edu 4454484Sbinkertn@umich.edu /* 4464484Sbinkertn@umich.edu * Compute the space taken up by the section header table, if 4474484Sbinkertn@umich.edu * one is needed. 4484484Sbinkertn@umich.edu */ 4494484Sbinkertn@umich.edu if (shnum) { 4504484Sbinkertn@umich.edu fsz = _libelf_fsize(ELF_T_SHDR, ec, eh_version, (size_t) 1); 4514484Sbinkertn@umich.edu align = _libelf_falign(ELF_T_SHDR, ec); 4524484Sbinkertn@umich.edu 4534484Sbinkertn@umich.edu if (e->e_flags & ELF_F_LAYOUT) { 4544484Sbinkertn@umich.edu if (rc > shoff) { 4554484Sbinkertn@umich.edu LIBELF_SET_ERROR(HEADER, 0); 4564484Sbinkertn@umich.edu return ((off_t) -1); 4574484Sbinkertn@umich.edu } 4584484Sbinkertn@umich.edu 4594484Sbinkertn@umich.edu if (shoff % align) { 4604484Sbinkertn@umich.edu LIBELF_SET_ERROR(LAYOUT, 0); 4614484Sbinkertn@umich.edu return ((off_t) -1); 4624484Sbinkertn@umich.edu } 4634484Sbinkertn@umich.edu } else 4644484Sbinkertn@umich.edu shoff = roundup(rc, align); 4654484Sbinkertn@umich.edu 4664484Sbinkertn@umich.edu rc = shoff + fsz * shnum; 4674484Sbinkertn@umich.edu } else 4684484Sbinkertn@umich.edu shoff = 0; 4694484Sbinkertn@umich.edu 4704484Sbinkertn@umich.edu /* 4714484Sbinkertn@umich.edu * Set the fields of the Executable Header that could potentially use 4724484Sbinkertn@umich.edu * extended numbering. 4734484Sbinkertn@umich.edu */ 4744484Sbinkertn@umich.edu _libelf_setphnum(e, ehdr, ec, phnum); 4754484Sbinkertn@umich.edu _libelf_setshnum(e, ehdr, ec, shnum); 4764484Sbinkertn@umich.edu 4774484Sbinkertn@umich.edu /* 4784484Sbinkertn@umich.edu * Update the `e_phoff' and `e_shoff' fields if the library is 4794484Sbinkertn@umich.edu * doing the layout. 4804484Sbinkertn@umich.edu */ 4814484Sbinkertn@umich.edu if ((e->e_flags & ELF_F_LAYOUT) == 0) { 4824484Sbinkertn@umich.edu if (ec == ELFCLASS32) { 4834484Sbinkertn@umich.edu eh32->e_phoff = (uint32_t) phoff; 4844484Sbinkertn@umich.edu eh32->e_shoff = (uint32_t) shoff; 4854484Sbinkertn@umich.edu } else { 4864484Sbinkertn@umich.edu eh64->e_phoff = (uint64_t) phoff; 4874484Sbinkertn@umich.edu eh64->e_shoff = (uint64_t) shoff; 4884484Sbinkertn@umich.edu } 4894484Sbinkertn@umich.edu } 4904484Sbinkertn@umich.edu 4914484Sbinkertn@umich.edu return (rc); 4924484Sbinkertn@umich.edu} 4934484Sbinkertn@umich.edu 4944484Sbinkertn@umich.edu/* 4954484Sbinkertn@umich.edu * Write out the contents of a section. 4964484Sbinkertn@umich.edu */ 4974484Sbinkertn@umich.edu 4984484Sbinkertn@umich.edustatic off_t 4994484Sbinkertn@umich.edu_libelf_write_scn(Elf *e, char *nf, Elf_Scn *s, off_t rc) 5004484Sbinkertn@umich.edu{ 5014484Sbinkertn@umich.edu int ec; 5024484Sbinkertn@umich.edu size_t fsz, msz, nobjects; 5034484Sbinkertn@umich.edu uint32_t sh_type; 5044484Sbinkertn@umich.edu uint64_t sh_off; 5054484Sbinkertn@umich.edu int elftype; 5064484Sbinkertn@umich.edu Elf_Data *d, dst; 5074484Sbinkertn@umich.edu 5084484Sbinkertn@umich.edu if ((ec = e->e_class) == ELFCLASS32) 5094484Sbinkertn@umich.edu sh_type = s->s_shdr.s_shdr32.sh_type; 5104484Sbinkertn@umich.edu else 5114484Sbinkertn@umich.edu sh_type = s->s_shdr.s_shdr64.sh_type; 5124484Sbinkertn@umich.edu 5134484Sbinkertn@umich.edu /* 5144484Sbinkertn@umich.edu * Ignore sections that do not allocate space in the file. 5154484Sbinkertn@umich.edu */ 5164484Sbinkertn@umich.edu if (sh_type == SHT_NOBITS || sh_type == SHT_NULL) 5174484Sbinkertn@umich.edu return (rc); 5184484Sbinkertn@umich.edu 5194484Sbinkertn@umich.edu 5204484Sbinkertn@umich.edu elftype = _libelf_xlate_shtype(sh_type); 5214484Sbinkertn@umich.edu assert(elftype >= ELF_T_FIRST && elftype <= ELF_T_LAST); 5224484Sbinkertn@umich.edu 5234484Sbinkertn@umich.edu msz = _libelf_msize(elftype, ec, e->e_version); 5244484Sbinkertn@umich.edu 5254484Sbinkertn@umich.edu sh_off = s->s_offset; 5264484Sbinkertn@umich.edu assert(sh_off % _libelf_falign(elftype, ec) == 0); 5274484Sbinkertn@umich.edu 5284484Sbinkertn@umich.edu /* 5294484Sbinkertn@umich.edu * If the section has a `rawdata' descriptor, and the section 5304484Sbinkertn@umich.edu * contents have not been modified, use its contents directly. 5314484Sbinkertn@umich.edu * The `s_rawoff' member contains the offset into the original 5324484Sbinkertn@umich.edu * file, while `s_offset' contains its new location in the 5334484Sbinkertn@umich.edu * destination. 5344484Sbinkertn@umich.edu */ 5354484Sbinkertn@umich.edu 5364484Sbinkertn@umich.edu if (STAILQ_EMPTY(&s->s_data)) { 5374484Sbinkertn@umich.edu 5384484Sbinkertn@umich.edu if ((d = elf_rawdata(s, NULL)) == NULL) 5394484Sbinkertn@umich.edu return ((off_t) -1); 5404484Sbinkertn@umich.edu 5414484Sbinkertn@umich.edu STAILQ_FOREACH(d, &s->s_rawdata, d_next) { 5424484Sbinkertn@umich.edu if ((uint64_t) rc < sh_off + d->d_off) 5434484Sbinkertn@umich.edu (void) memset(nf + rc, 5444484Sbinkertn@umich.edu LIBELF_PRIVATE(fillchar), sh_off + 5454484Sbinkertn@umich.edu d->d_off - rc); 5464484Sbinkertn@umich.edu rc = sh_off + d->d_off; 5474484Sbinkertn@umich.edu 5484484Sbinkertn@umich.edu assert(d->d_buf != NULL); 5494484Sbinkertn@umich.edu assert(d->d_type == ELF_T_BYTE); 5504484Sbinkertn@umich.edu assert(d->d_version == e->e_version); 5514484Sbinkertn@umich.edu 5524484Sbinkertn@umich.edu (void) memcpy(nf + rc, 5534484Sbinkertn@umich.edu e->e_rawfile + s->s_rawoff + d->d_off, d->d_size); 5544484Sbinkertn@umich.edu 5554484Sbinkertn@umich.edu rc += d->d_size; 5564484Sbinkertn@umich.edu } 5574484Sbinkertn@umich.edu 5584484Sbinkertn@umich.edu return (rc); 5594484Sbinkertn@umich.edu } 5604484Sbinkertn@umich.edu 5614484Sbinkertn@umich.edu /* 5624484Sbinkertn@umich.edu * Iterate over the set of data descriptors for this section. 5634484Sbinkertn@umich.edu * The prior call to _libelf_resync_elf() would have setup the 5644484Sbinkertn@umich.edu * descriptors for this step. 5654484Sbinkertn@umich.edu */ 5664484Sbinkertn@umich.edu 5674484Sbinkertn@umich.edu dst.d_version = e->e_version; 5684484Sbinkertn@umich.edu 5694484Sbinkertn@umich.edu STAILQ_FOREACH(d, &s->s_data, d_next) { 5704484Sbinkertn@umich.edu 5714484Sbinkertn@umich.edu if ((uint64_t) rc < sh_off + d->d_off) 5724484Sbinkertn@umich.edu (void) memset(nf + rc, 5734484Sbinkertn@umich.edu LIBELF_PRIVATE(fillchar), sh_off + d->d_off - rc); 5744484Sbinkertn@umich.edu 5754484Sbinkertn@umich.edu rc = sh_off + d->d_off; 5764484Sbinkertn@umich.edu 5774484Sbinkertn@umich.edu assert(d->d_buf != NULL); 5784484Sbinkertn@umich.edu assert(d->d_type == (Elf_Type) elftype); 5794484Sbinkertn@umich.edu assert(d->d_version == e->e_version); 5804484Sbinkertn@umich.edu assert(d->d_size % msz == 0); 5814484Sbinkertn@umich.edu 5824484Sbinkertn@umich.edu nobjects = d->d_size / msz; 5834484Sbinkertn@umich.edu 5844484Sbinkertn@umich.edu fsz = _libelf_fsize(elftype, ec, e->e_version, nobjects); 5854484Sbinkertn@umich.edu 5864484Sbinkertn@umich.edu dst.d_buf = nf + rc; 5874484Sbinkertn@umich.edu dst.d_size = fsz; 5884484Sbinkertn@umich.edu 5894484Sbinkertn@umich.edu if (_libelf_xlate(&dst, d, e->e_byteorder, ec, ELF_TOFILE) == 5904484Sbinkertn@umich.edu NULL) 5914484Sbinkertn@umich.edu return ((off_t) -1); 5924484Sbinkertn@umich.edu 5934484Sbinkertn@umich.edu rc += fsz; 5944484Sbinkertn@umich.edu } 5954484Sbinkertn@umich.edu 5964484Sbinkertn@umich.edu return ((off_t) rc); 5974484Sbinkertn@umich.edu} 5984484Sbinkertn@umich.edu 5994484Sbinkertn@umich.edu/* 6004484Sbinkertn@umich.edu * Write out the file image. 6014484Sbinkertn@umich.edu * 6024484Sbinkertn@umich.edu * The original file could have been mapped in with an ELF_C_RDWR 6034484Sbinkertn@umich.edu * command and the application could have added new content or 6044484Sbinkertn@umich.edu * re-arranged its sections before calling elf_update(). Consequently 6054484Sbinkertn@umich.edu * its not safe to work `in place' on the original file. So we 6064484Sbinkertn@umich.edu * malloc() the required space for the updated ELF object and build 6074484Sbinkertn@umich.edu * the object there and write it out to the underlying file at the 6084484Sbinkertn@umich.edu * end. Note that the application may have opened the underlying file 6094484Sbinkertn@umich.edu * in ELF_C_RDWR and only retrieved/modified a few sections. We take 6104484Sbinkertn@umich.edu * care to avoid translating file sections unnecessarily. 6114484Sbinkertn@umich.edu * 6124484Sbinkertn@umich.edu * Gaps in the coverage of the file by the file's sections will be 6134484Sbinkertn@umich.edu * filled with the fill character set by elf_fill(3). 6144484Sbinkertn@umich.edu */ 6154484Sbinkertn@umich.edu 6164484Sbinkertn@umich.edustatic off_t 6174484Sbinkertn@umich.edu_libelf_write_elf(Elf *e, off_t newsize) 6184484Sbinkertn@umich.edu{ 6194484Sbinkertn@umich.edu int ec; 6204484Sbinkertn@umich.edu off_t rc; 6214484Sbinkertn@umich.edu size_t fsz, msz, phnum, shnum; 6224484Sbinkertn@umich.edu uint64_t phoff, shoff; 6234484Sbinkertn@umich.edu void *ehdr; 6244484Sbinkertn@umich.edu char *newfile; 6254484Sbinkertn@umich.edu Elf_Data dst, src; 6264484Sbinkertn@umich.edu Elf_Scn *scn, *tscn; 6274484Sbinkertn@umich.edu Elf32_Ehdr *eh32; 6284484Sbinkertn@umich.edu Elf64_Ehdr *eh64; 6294484Sbinkertn@umich.edu 6304484Sbinkertn@umich.edu assert(e->e_kind == ELF_K_ELF); 6314484Sbinkertn@umich.edu assert(e->e_cmd != ELF_C_READ); 6324484Sbinkertn@umich.edu assert(e->e_fd >= 0); 6334484Sbinkertn@umich.edu 6344484Sbinkertn@umich.edu if ((newfile = malloc((size_t) newsize)) == NULL) { 6354484Sbinkertn@umich.edu LIBELF_SET_ERROR(RESOURCE, errno); 6364484Sbinkertn@umich.edu return ((off_t) -1); 6374484Sbinkertn@umich.edu } 6384484Sbinkertn@umich.edu 6394484Sbinkertn@umich.edu ec = e->e_class; 6404484Sbinkertn@umich.edu 6414484Sbinkertn@umich.edu ehdr = _libelf_ehdr(e, ec, 0); 6424484Sbinkertn@umich.edu assert(ehdr != NULL); 6434484Sbinkertn@umich.edu 6444484Sbinkertn@umich.edu phnum = e->e_u.e_elf.e_nphdr; 6454484Sbinkertn@umich.edu 6464484Sbinkertn@umich.edu if (ec == ELFCLASS32) { 6474484Sbinkertn@umich.edu eh32 = (Elf32_Ehdr *) ehdr; 6484484Sbinkertn@umich.edu 6494484Sbinkertn@umich.edu phoff = (uint64_t) eh32->e_phoff; 6504484Sbinkertn@umich.edu shnum = eh32->e_shnum; 6514484Sbinkertn@umich.edu shoff = (uint64_t) eh32->e_shoff; 6524484Sbinkertn@umich.edu } else { 6534484Sbinkertn@umich.edu eh64 = (Elf64_Ehdr *) ehdr; 6544484Sbinkertn@umich.edu 6554484Sbinkertn@umich.edu phoff = eh64->e_phoff; 6564484Sbinkertn@umich.edu shnum = eh64->e_shnum; 6574484Sbinkertn@umich.edu shoff = eh64->e_shoff; 6584484Sbinkertn@umich.edu } 6594484Sbinkertn@umich.edu 6604484Sbinkertn@umich.edu fsz = _libelf_fsize(ELF_T_EHDR, ec, e->e_version, (size_t) 1); 6614484Sbinkertn@umich.edu msz = _libelf_msize(ELF_T_EHDR, ec, e->e_version); 6624484Sbinkertn@umich.edu 6634484Sbinkertn@umich.edu (void) memset(&dst, 0, sizeof(dst)); 6644484Sbinkertn@umich.edu (void) memset(&src, 0, sizeof(src)); 6654484Sbinkertn@umich.edu 6664484Sbinkertn@umich.edu src.d_buf = ehdr; 6674484Sbinkertn@umich.edu src.d_size = msz; 6684484Sbinkertn@umich.edu src.d_type = ELF_T_EHDR; 6694484Sbinkertn@umich.edu src.d_version = dst.d_version = e->e_version; 6704484Sbinkertn@umich.edu 6714484Sbinkertn@umich.edu rc = 0; 6724484Sbinkertn@umich.edu 6734484Sbinkertn@umich.edu dst.d_buf = newfile + rc; 6744484Sbinkertn@umich.edu dst.d_size = fsz; 6754484Sbinkertn@umich.edu 6764484Sbinkertn@umich.edu if (_libelf_xlate(&dst, &src, e->e_byteorder, ec, ELF_TOFILE) == 6774484Sbinkertn@umich.edu NULL) 6784484Sbinkertn@umich.edu goto error; 6794484Sbinkertn@umich.edu 6804484Sbinkertn@umich.edu rc += fsz; 6814484Sbinkertn@umich.edu 6824484Sbinkertn@umich.edu /* 6834484Sbinkertn@umich.edu * Write the program header table if present. 6844484Sbinkertn@umich.edu */ 6854484Sbinkertn@umich.edu 6864484Sbinkertn@umich.edu if (phnum != 0 && phoff != 0) { 6874484Sbinkertn@umich.edu assert((unsigned) rc <= phoff); 6884484Sbinkertn@umich.edu 6894484Sbinkertn@umich.edu fsz = _libelf_fsize(ELF_T_PHDR, ec, e->e_version, phnum); 6904484Sbinkertn@umich.edu 6914484Sbinkertn@umich.edu assert(phoff % _libelf_falign(ELF_T_PHDR, ec) == 0); 6924484Sbinkertn@umich.edu assert(fsz > 0); 6934484Sbinkertn@umich.edu 6944484Sbinkertn@umich.edu src.d_version = dst.d_version = e->e_version; 6954484Sbinkertn@umich.edu src.d_type = ELF_T_PHDR; 6964484Sbinkertn@umich.edu 6974484Sbinkertn@umich.edu if (ec == ELFCLASS32) 6984484Sbinkertn@umich.edu src.d_buf = e->e_u.e_elf.e_phdr.e_phdr32; 6994484Sbinkertn@umich.edu else 7004484Sbinkertn@umich.edu src.d_buf = e->e_u.e_elf.e_phdr.e_phdr64; 7014484Sbinkertn@umich.edu 7024484Sbinkertn@umich.edu src.d_size = phnum * _libelf_msize(ELF_T_PHDR, ec, 7034484Sbinkertn@umich.edu e->e_version); 7044484Sbinkertn@umich.edu 7054484Sbinkertn@umich.edu dst.d_size = fsz; 7064484Sbinkertn@umich.edu 7074484Sbinkertn@umich.edu if ((uint64_t) rc < phoff) 7084484Sbinkertn@umich.edu (void) memset(newfile + rc, 7094484Sbinkertn@umich.edu LIBELF_PRIVATE(fillchar), phoff - rc); 7104484Sbinkertn@umich.edu 7114484Sbinkertn@umich.edu dst.d_buf = newfile + rc; 7124484Sbinkertn@umich.edu 7134484Sbinkertn@umich.edu if (_libelf_xlate(&dst, &src, e->e_byteorder, ec, ELF_TOFILE) == 7144484Sbinkertn@umich.edu NULL) 7154484Sbinkertn@umich.edu goto error; 7164484Sbinkertn@umich.edu 7174484Sbinkertn@umich.edu rc = phoff + fsz; 7184484Sbinkertn@umich.edu } 7194484Sbinkertn@umich.edu 7204484Sbinkertn@umich.edu /* 7214484Sbinkertn@umich.edu * Write out individual sections. 7224484Sbinkertn@umich.edu */ 7234484Sbinkertn@umich.edu 7244484Sbinkertn@umich.edu STAILQ_FOREACH(scn, &e->e_u.e_elf.e_scn, s_next) 7254484Sbinkertn@umich.edu if ((rc = _libelf_write_scn(e, newfile, scn, rc)) < 0) 7264484Sbinkertn@umich.edu goto error; 7274484Sbinkertn@umich.edu 7284484Sbinkertn@umich.edu /* 7294484Sbinkertn@umich.edu * Write out the section header table, if required. 7304484Sbinkertn@umich.edu */ 7314484Sbinkertn@umich.edu 7324484Sbinkertn@umich.edu if (shnum != 0 && shoff != 0) { 7334484Sbinkertn@umich.edu assert((unsigned) rc <= shoff); 7344484Sbinkertn@umich.edu 7354484Sbinkertn@umich.edu if ((uint64_t) rc < shoff) 7364484Sbinkertn@umich.edu (void) memset(newfile + rc, 7374484Sbinkertn@umich.edu LIBELF_PRIVATE(fillchar), shoff - rc); 7384484Sbinkertn@umich.edu 7394484Sbinkertn@umich.edu rc = shoff; 7404484Sbinkertn@umich.edu 7414484Sbinkertn@umich.edu assert(rc % _libelf_falign(ELF_T_SHDR, ec) == 0); 7424484Sbinkertn@umich.edu 7434484Sbinkertn@umich.edu src.d_type = ELF_T_SHDR; 7444484Sbinkertn@umich.edu src.d_size = _libelf_msize(ELF_T_SHDR, ec, e->e_version); 7454484Sbinkertn@umich.edu src.d_version = dst.d_version = e->e_version; 7464484Sbinkertn@umich.edu 7474484Sbinkertn@umich.edu fsz = _libelf_fsize(ELF_T_SHDR, ec, e->e_version, (size_t) 1); 7484484Sbinkertn@umich.edu 7494484Sbinkertn@umich.edu STAILQ_FOREACH(scn, &e->e_u.e_elf.e_scn, s_next) { 7504484Sbinkertn@umich.edu if (ec == ELFCLASS32) 7514484Sbinkertn@umich.edu src.d_buf = &scn->s_shdr.s_shdr32; 7524484Sbinkertn@umich.edu else 7534484Sbinkertn@umich.edu src.d_buf = &scn->s_shdr.s_shdr64; 7544484Sbinkertn@umich.edu 7554484Sbinkertn@umich.edu dst.d_size = fsz; 7564484Sbinkertn@umich.edu dst.d_buf = newfile + rc; 7574484Sbinkertn@umich.edu 7584484Sbinkertn@umich.edu if (_libelf_xlate(&dst, &src, e->e_byteorder, ec, 7594484Sbinkertn@umich.edu ELF_TOFILE) != &dst) 7604484Sbinkertn@umich.edu goto error; 7614484Sbinkertn@umich.edu 7624484Sbinkertn@umich.edu rc += fsz; 7634484Sbinkertn@umich.edu } 7644484Sbinkertn@umich.edu } 7654484Sbinkertn@umich.edu 7664484Sbinkertn@umich.edu /* 7674484Sbinkertn@umich.edu */ 7684484Sbinkertn@umich.edu 7694484Sbinkertn@umich.edu assert(rc == newsize); 7704484Sbinkertn@umich.edu 7714484Sbinkertn@umich.edu /* 7724484Sbinkertn@umich.edu * Write out the constructed contents and remap the file in 7734484Sbinkertn@umich.edu * read-only. 7744484Sbinkertn@umich.edu */ 7754484Sbinkertn@umich.edu 7764484Sbinkertn@umich.edu if (e->e_rawfile && munmap(e->e_rawfile, e->e_rawsize) < 0) { 7774484Sbinkertn@umich.edu LIBELF_SET_ERROR(IO, errno); 7784484Sbinkertn@umich.edu goto error; 7794484Sbinkertn@umich.edu } 7804484Sbinkertn@umich.edu 7814484Sbinkertn@umich.edu if (write(e->e_fd, newfile, (size_t) newsize) != newsize || 7824484Sbinkertn@umich.edu lseek(e->e_fd, (off_t) 0, SEEK_SET) < 0) { 7834484Sbinkertn@umich.edu LIBELF_SET_ERROR(IO, errno); 7844484Sbinkertn@umich.edu goto error; 7854484Sbinkertn@umich.edu } 7864484Sbinkertn@umich.edu 7874484Sbinkertn@umich.edu if (e->e_cmd != ELF_C_WRITE) { 7884484Sbinkertn@umich.edu if ((e->e_rawfile = mmap(NULL, (size_t) newsize, PROT_READ, 7894484Sbinkertn@umich.edu MAP_PRIVATE, e->e_fd, (off_t) 0)) == MAP_FAILED) { 7904484Sbinkertn@umich.edu LIBELF_SET_ERROR(IO, errno); 7914484Sbinkertn@umich.edu goto error; 7924484Sbinkertn@umich.edu } 7934484Sbinkertn@umich.edu e->e_rawsize = newsize; 7944484Sbinkertn@umich.edu } 7954484Sbinkertn@umich.edu 7964484Sbinkertn@umich.edu /* 7974484Sbinkertn@umich.edu * Reset flags, remove existing section descriptors and 7984484Sbinkertn@umich.edu * {E,P}HDR pointers so that a subsequent elf_get{e,p}hdr() 7994484Sbinkertn@umich.edu * and elf_getscn() will function correctly. 8004484Sbinkertn@umich.edu */ 8014484Sbinkertn@umich.edu 8024484Sbinkertn@umich.edu e->e_flags &= ~ELF_F_DIRTY; 8034484Sbinkertn@umich.edu 8044484Sbinkertn@umich.edu STAILQ_FOREACH_SAFE(scn, &e->e_u.e_elf.e_scn, s_next, tscn) 8054484Sbinkertn@umich.edu _libelf_release_scn(scn); 8064484Sbinkertn@umich.edu 8074484Sbinkertn@umich.edu if (ec == ELFCLASS32) { 8084484Sbinkertn@umich.edu free(e->e_u.e_elf.e_ehdr.e_ehdr32); 8094484Sbinkertn@umich.edu if (e->e_u.e_elf.e_phdr.e_phdr32) 8104484Sbinkertn@umich.edu free(e->e_u.e_elf.e_phdr.e_phdr32); 8114484Sbinkertn@umich.edu 8124484Sbinkertn@umich.edu e->e_u.e_elf.e_ehdr.e_ehdr32 = NULL; 8134484Sbinkertn@umich.edu e->e_u.e_elf.e_phdr.e_phdr32 = NULL; 8144484Sbinkertn@umich.edu } else { 8154484Sbinkertn@umich.edu free(e->e_u.e_elf.e_ehdr.e_ehdr64); 8164484Sbinkertn@umich.edu if (e->e_u.e_elf.e_phdr.e_phdr64) 8174484Sbinkertn@umich.edu free(e->e_u.e_elf.e_phdr.e_phdr64); 8184484Sbinkertn@umich.edu 8194484Sbinkertn@umich.edu e->e_u.e_elf.e_ehdr.e_ehdr64 = NULL; 8204484Sbinkertn@umich.edu e->e_u.e_elf.e_phdr.e_phdr64 = NULL; 8214484Sbinkertn@umich.edu } 8224484Sbinkertn@umich.edu 8234484Sbinkertn@umich.edu return (rc); 8244484Sbinkertn@umich.edu 8254484Sbinkertn@umich.edu error: 8264484Sbinkertn@umich.edu if (newfile) 8274484Sbinkertn@umich.edu free(newfile); 8284484Sbinkertn@umich.edu return ((off_t) -1); 8294484Sbinkertn@umich.edu} 8304484Sbinkertn@umich.edu 8314484Sbinkertn@umich.eduoff_t 8324484Sbinkertn@umich.eduelf_update(Elf *e, Elf_Cmd c) 8334484Sbinkertn@umich.edu{ 8344484Sbinkertn@umich.edu int ec; 8354484Sbinkertn@umich.edu off_t rc; 8364484Sbinkertn@umich.edu 8374484Sbinkertn@umich.edu rc = (off_t) -1; 8384484Sbinkertn@umich.edu 8394484Sbinkertn@umich.edu if (e == NULL || e->e_kind != ELF_K_ELF || 8404484Sbinkertn@umich.edu (c != ELF_C_NULL && c != ELF_C_WRITE)) { 8414484Sbinkertn@umich.edu LIBELF_SET_ERROR(ARGUMENT, 0); 8424484Sbinkertn@umich.edu return (rc); 8434484Sbinkertn@umich.edu } 8444484Sbinkertn@umich.edu 8454484Sbinkertn@umich.edu if ((ec = e->e_class) != ELFCLASS32 && ec != ELFCLASS64) { 8464484Sbinkertn@umich.edu LIBELF_SET_ERROR(CLASS, 0); 8474484Sbinkertn@umich.edu return (rc); 8484484Sbinkertn@umich.edu } 8494484Sbinkertn@umich.edu 8504484Sbinkertn@umich.edu if (e->e_version == EV_NONE) 8514484Sbinkertn@umich.edu e->e_version = EV_CURRENT; 8524484Sbinkertn@umich.edu 8534484Sbinkertn@umich.edu if (c == ELF_C_WRITE && e->e_cmd == ELF_C_READ) { 8544484Sbinkertn@umich.edu LIBELF_SET_ERROR(MODE, 0); 8554484Sbinkertn@umich.edu return (rc); 8564484Sbinkertn@umich.edu } 8574484Sbinkertn@umich.edu 8584484Sbinkertn@umich.edu if ((rc = _libelf_resync_elf(e)) < 0) 8594484Sbinkertn@umich.edu return (rc); 8604484Sbinkertn@umich.edu 8614484Sbinkertn@umich.edu if (c == ELF_C_NULL) 8624484Sbinkertn@umich.edu return (rc); 8634484Sbinkertn@umich.edu 8644484Sbinkertn@umich.edu if (e->e_cmd == ELF_C_READ) { 8654484Sbinkertn@umich.edu /* 8664484Sbinkertn@umich.edu * This descriptor was opened in read-only mode or by 8674484Sbinkertn@umich.edu * elf_memory(). 8684484Sbinkertn@umich.edu */ 8694484Sbinkertn@umich.edu if (e->e_fd) 8704484Sbinkertn@umich.edu LIBELF_SET_ERROR(MODE, 0); 8714484Sbinkertn@umich.edu else 8724484Sbinkertn@umich.edu LIBELF_SET_ERROR(ARGUMENT, 0); 8734484Sbinkertn@umich.edu return ((off_t) -1); 8744484Sbinkertn@umich.edu } 8754484Sbinkertn@umich.edu 8764484Sbinkertn@umich.edu if (e->e_fd < 0) { 8774484Sbinkertn@umich.edu LIBELF_SET_ERROR(SEQUENCE, 0); 8784484Sbinkertn@umich.edu return ((off_t) -1); 8794484Sbinkertn@umich.edu } 8804484Sbinkertn@umich.edu 8814484Sbinkertn@umich.edu return (_libelf_write_elf(e, rc)); 8824484Sbinkertn@umich.edu} 883