1164190Sjkoshy/*- 2176758Sjkoshy * Copyright (c) 2006-2008 Joseph Koshy 3164190Sjkoshy * All rights reserved. 4164190Sjkoshy * 5164190Sjkoshy * Redistribution and use in source and binary forms, with or without 6164190Sjkoshy * modification, are permitted provided that the following conditions 7164190Sjkoshy * are met: 8164190Sjkoshy * 1. Redistributions of source code must retain the above copyright 9164190Sjkoshy * notice, this list of conditions and the following disclaimer. 10164190Sjkoshy * 2. Redistributions in binary form must reproduce the above copyright 11164190Sjkoshy * notice, this list of conditions and the following disclaimer in the 12164190Sjkoshy * documentation and/or other materials provided with the distribution. 13164190Sjkoshy * 14164190Sjkoshy * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15164190Sjkoshy * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16164190Sjkoshy * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17164190Sjkoshy * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18164190Sjkoshy * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19164190Sjkoshy * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20164190Sjkoshy * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21164190Sjkoshy * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22164190Sjkoshy * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23164190Sjkoshy * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24164190Sjkoshy * SUCH DAMAGE. 25164190Sjkoshy */ 26164190Sjkoshy 27164190Sjkoshy#include <sys/cdefs.h> 28164190Sjkoshy__FBSDID("$FreeBSD$"); 29164190Sjkoshy 30164190Sjkoshy#include <sys/mman.h> 31164190Sjkoshy#include <sys/param.h> 32164190Sjkoshy 33164190Sjkoshy#include <assert.h> 34164190Sjkoshy#include <errno.h> 35164190Sjkoshy#include <gelf.h> 36164190Sjkoshy#include <libelf.h> 37164190Sjkoshy#include <stdlib.h> 38164190Sjkoshy#include <string.h> 39164190Sjkoshy#include <unistd.h> 40164190Sjkoshy 41164190Sjkoshy#include "_libelf.h" 42164190Sjkoshy 43164190Sjkoshy/* 44247221Smarkj * Layout strategy: 45164190Sjkoshy * 46247221Smarkj * - Case 1: ELF_F_LAYOUT is asserted 47247221Smarkj * In this case the application has full control over where the 48247221Smarkj * section header table, program header table, and section data 49247221Smarkj * will reside. The library only perform error checks. 50164190Sjkoshy * 51247221Smarkj * - Case 2: ELF_F_LAYOUT is not asserted 52164190Sjkoshy * 53247221Smarkj * The library will do the object layout using the following 54247221Smarkj * ordering: 55247221Smarkj * - The executable header is placed first, are required by the 56247221Smarkj * ELF specification. 57247221Smarkj * - The program header table is placed immediately following the 58247221Smarkj * executable header. 59247221Smarkj * - Section data, if any, is placed after the program header 60247221Smarkj * table, aligned appropriately. 61247221Smarkj * - The section header table, if needed, is placed last. 62164190Sjkoshy * 63247221Smarkj * There are two sub-cases to be taken care of: 64164190Sjkoshy * 65247221Smarkj * - Case 2a: e->e_cmd == ELF_C_READ or ELF_C_RDWR 66247221Smarkj * 67247221Smarkj * In this sub-case, the underlying ELF object may already have 68247221Smarkj * content in it, which the application may have modified. The 69247221Smarkj * library will retrieve content from the existing object as 70247221Smarkj * needed. 71247221Smarkj * 72247221Smarkj * - Case 2b: e->e_cmd == ELF_C_WRITE 73247221Smarkj * 74247221Smarkj * The ELF object is being created afresh in this sub-case; 75247221Smarkj * there is no pre-existing content in the underlying ELF 76247221Smarkj * object. 77164190Sjkoshy */ 78164190Sjkoshy 79164190Sjkoshy/* 80172088Sjkoshy * Compute the extents of a section, by looking at the data 81247221Smarkj * descriptors associated with it. The function returns 1 if 82247221Smarkj * successful, or zero if an error was detected. 83164190Sjkoshy */ 84164190Sjkoshystatic int 85247221Smarkj_libelf_compute_section_extents(Elf *e, Elf_Scn *s, off_t rc) 86164190Sjkoshy{ 87164190Sjkoshy int ec; 88247221Smarkj size_t fsz, msz; 89247221Smarkj Elf_Data *d; 90247221Smarkj Elf32_Shdr *shdr32; 91247221Smarkj Elf64_Shdr *shdr64; 92164190Sjkoshy unsigned int elftype; 93164190Sjkoshy uint32_t sh_type; 94164190Sjkoshy uint64_t d_align; 95164190Sjkoshy uint64_t sh_align, sh_entsize, sh_offset, sh_size; 96164190Sjkoshy uint64_t scn_size, scn_alignment; 97164190Sjkoshy 98164190Sjkoshy ec = e->e_class; 99164190Sjkoshy 100247221Smarkj shdr32 = &s->s_shdr.s_shdr32; 101247221Smarkj shdr64 = &s->s_shdr.s_shdr64; 102164190Sjkoshy if (ec == ELFCLASS32) { 103247221Smarkj sh_type = shdr32->sh_type; 104247221Smarkj sh_align = (uint64_t) shdr32->sh_addralign; 105247221Smarkj sh_entsize = (uint64_t) shdr32->sh_entsize; 106247221Smarkj sh_offset = (uint64_t) shdr32->sh_offset; 107247221Smarkj sh_size = (uint64_t) shdr32->sh_size; 108164190Sjkoshy } else { 109247221Smarkj sh_type = shdr64->sh_type; 110247221Smarkj sh_align = shdr64->sh_addralign; 111247221Smarkj sh_entsize = shdr64->sh_entsize; 112247221Smarkj sh_offset = shdr64->sh_offset; 113247221Smarkj sh_size = shdr64->sh_size; 114164190Sjkoshy } 115164190Sjkoshy 116247221Smarkj assert(sh_type != SHT_NULL && sh_type != SHT_NOBITS); 117164190Sjkoshy 118164190Sjkoshy elftype = _libelf_xlate_shtype(sh_type); 119164190Sjkoshy if (elftype > ELF_T_LAST) { 120164190Sjkoshy LIBELF_SET_ERROR(SECTION, 0); 121164190Sjkoshy return (0); 122164190Sjkoshy } 123164190Sjkoshy 124164190Sjkoshy if (sh_align == 0) 125164190Sjkoshy sh_align = _libelf_falign(elftype, ec); 126164190Sjkoshy 127247221Smarkj /* 128247221Smarkj * Check the section's data buffers for sanity and compute the 129247221Smarkj * section's alignment. 130247221Smarkj * Compute the section's size and alignment using the data 131247221Smarkj * descriptors associated with the section. 132247221Smarkj */ 133247221Smarkj if (STAILQ_EMPTY(&s->s_data)) { 134247221Smarkj /* 135247221Smarkj * The section's content (if any) has not been read in 136247221Smarkj * yet. If section is not dirty marked dirty, we can 137247221Smarkj * reuse the values in the 'sh_size' and 'sh_offset' 138247221Smarkj * fields of the section header. 139247221Smarkj */ 140247221Smarkj if ((s->s_flags & ELF_F_DIRTY) == 0) { 141247221Smarkj /* 142247221Smarkj * If the library is doing the layout, then we 143247221Smarkj * compute the new start offset for the 144247221Smarkj * section based on the current offset and the 145247221Smarkj * section's alignment needs. 146247221Smarkj * 147247221Smarkj * If the application is doing the layout, we 148247221Smarkj * can use the value in the 'sh_offset' field 149247221Smarkj * in the section header directly. 150247221Smarkj */ 151247221Smarkj if (e->e_flags & ELF_F_LAYOUT) 152247221Smarkj goto updatedescriptor; 153247221Smarkj else 154247221Smarkj goto computeoffset; 155247221Smarkj } 156247221Smarkj 157247221Smarkj /* 158247221Smarkj * Otherwise, we need to bring in the section's data 159247221Smarkj * from the underlying ELF object. 160247221Smarkj */ 161247221Smarkj if (e->e_cmd != ELF_C_WRITE && elf_getdata(s, NULL) == NULL) 162247221Smarkj return (0); 163247221Smarkj } 164247221Smarkj 165247221Smarkj /* 166247221Smarkj * Loop through the section's data descriptors. 167247221Smarkj */ 168247221Smarkj scn_size = 0L; 169247221Smarkj scn_alignment = 0L; 170164190Sjkoshy STAILQ_FOREACH(d, &s->s_data, d_next) { 171212373Skaiw if (d->d_type > ELF_T_LAST) { 172164190Sjkoshy LIBELF_SET_ERROR(DATA, 0); 173164190Sjkoshy return (0); 174164190Sjkoshy } 175164190Sjkoshy if (d->d_version != e->e_version) { 176164190Sjkoshy LIBELF_SET_ERROR(VERSION, 0); 177164190Sjkoshy return (0); 178164190Sjkoshy } 179212373Skaiw if ((d_align = d->d_align) == 0 || (d_align & (d_align - 1))) { 180164190Sjkoshy LIBELF_SET_ERROR(DATA, 0); 181164190Sjkoshy return (0); 182164190Sjkoshy } 183164190Sjkoshy 184247221Smarkj /* 185247221Smarkj * The buffer's size should be a multiple of the 186247221Smarkj * memory size of the underlying type. 187247221Smarkj */ 188247221Smarkj msz = _libelf_msize(d->d_type, ec, e->e_version); 189247221Smarkj if (d->d_size % msz) { 190247221Smarkj LIBELF_SET_ERROR(DATA, 0); 191247221Smarkj return (0); 192247221Smarkj } 193164190Sjkoshy 194247221Smarkj /* 195247221Smarkj * Compute the section's size. 196247221Smarkj */ 197164190Sjkoshy if (e->e_flags & ELF_F_LAYOUT) { 198164190Sjkoshy if ((uint64_t) d->d_off + d->d_size > scn_size) 199164190Sjkoshy scn_size = d->d_off + d->d_size; 200164190Sjkoshy } else { 201212373Skaiw scn_size = roundup2(scn_size, d->d_align); 202164190Sjkoshy d->d_off = scn_size; 203247221Smarkj fsz = _libelf_fsize(d->d_type, ec, d->d_version, 204247221Smarkj d->d_size / msz); 205247221Smarkj scn_size += fsz; 206164190Sjkoshy } 207247221Smarkj 208247221Smarkj /* 209247221Smarkj * The section's alignment is the maximum alignment 210247221Smarkj * needed for its data buffers. 211247221Smarkj */ 212247221Smarkj if (d_align > scn_alignment) 213247221Smarkj scn_alignment = d_align; 214164190Sjkoshy } 215164190Sjkoshy 216247221Smarkj 217164190Sjkoshy /* 218164190Sjkoshy * If the application is requesting full control over the layout 219164190Sjkoshy * of the section, check its values for sanity. 220164190Sjkoshy */ 221164190Sjkoshy if (e->e_flags & ELF_F_LAYOUT) { 222164190Sjkoshy if (scn_alignment > sh_align || sh_offset % sh_align || 223164190Sjkoshy sh_size < scn_size) { 224164190Sjkoshy LIBELF_SET_ERROR(LAYOUT, 0); 225164190Sjkoshy return (0); 226164190Sjkoshy } 227247221Smarkj goto updatedescriptor; 228247221Smarkj } 229164190Sjkoshy 230247221Smarkj /* 231247221Smarkj * Otherwise compute the values in the section header. 232247221Smarkj * 233247221Smarkj * The section alignment is the maximum alignment for any of 234247221Smarkj * its contained data descriptors. 235247221Smarkj */ 236247221Smarkj if (scn_alignment > sh_align) 237247221Smarkj sh_align = scn_alignment; 238164190Sjkoshy 239247221Smarkj /* 240247221Smarkj * If the section entry size is zero, try and fill in an 241247221Smarkj * appropriate entry size. Per the elf(5) manual page 242247221Smarkj * sections without fixed-size entries should have their 243247221Smarkj * 'sh_entsize' field set to zero. 244247221Smarkj */ 245247221Smarkj if (sh_entsize == 0 && 246247221Smarkj (sh_entsize = _libelf_fsize(elftype, ec, e->e_version, 247247221Smarkj (size_t) 1)) == 1) 248247221Smarkj sh_entsize = 0; 249164190Sjkoshy 250247221Smarkj sh_size = scn_size; 251164190Sjkoshy 252247221Smarkjcomputeoffset: 253247221Smarkj /* 254247221Smarkj * Compute the new offset for the section based on 255247221Smarkj * the section's alignment needs. 256247221Smarkj */ 257247221Smarkj sh_offset = roundup(rc, sh_align); 258247221Smarkj 259247221Smarkj /* 260247221Smarkj * Update the section header. 261247221Smarkj */ 262247221Smarkj if (ec == ELFCLASS32) { 263247221Smarkj shdr32->sh_addralign = (uint32_t) sh_align; 264247221Smarkj shdr32->sh_entsize = (uint32_t) sh_entsize; 265247221Smarkj shdr32->sh_offset = (uint32_t) sh_offset; 266247221Smarkj shdr32->sh_size = (uint32_t) sh_size; 267247221Smarkj } else { 268247221Smarkj shdr64->sh_addralign = sh_align; 269247221Smarkj shdr64->sh_entsize = sh_entsize; 270247221Smarkj shdr64->sh_offset = sh_offset; 271247221Smarkj shdr64->sh_size = sh_size; 272164190Sjkoshy } 273164190Sjkoshy 274247221Smarkjupdatedescriptor: 275247221Smarkj /* 276247221Smarkj * Update the section descriptor. 277247221Smarkj */ 278164190Sjkoshy s->s_size = sh_size; 279164190Sjkoshy s->s_offset = sh_offset; 280247221Smarkj 281164190Sjkoshy return (1); 282164190Sjkoshy} 283164190Sjkoshy 284164190Sjkoshy 285164190Sjkoshy/* 286164190Sjkoshy * Insert a section in ascending order in the list 287164190Sjkoshy */ 288164190Sjkoshy 289164190Sjkoshystatic int 290164190Sjkoshy_libelf_insert_section(Elf *e, Elf_Scn *s) 291164190Sjkoshy{ 292164190Sjkoshy Elf_Scn *t, *prevt; 293164190Sjkoshy uint64_t smax, smin, tmax, tmin; 294164190Sjkoshy 295164190Sjkoshy smin = s->s_offset; 296164190Sjkoshy smax = smin + s->s_size; 297164190Sjkoshy 298164190Sjkoshy prevt = NULL; 299164190Sjkoshy STAILQ_FOREACH(t, &e->e_u.e_elf.e_scn, s_next) { 300164190Sjkoshy tmin = t->s_offset; 301164190Sjkoshy tmax = tmin + t->s_size; 302164190Sjkoshy 303176758Sjkoshy if (tmax <= smin) { 304176758Sjkoshy /* 305176758Sjkoshy * 't' lies entirely before 's': ...| t |...| s |... 306176758Sjkoshy */ 307164190Sjkoshy prevt = t; 308164190Sjkoshy continue; 309176758Sjkoshy } else if (smax <= tmin) 310176758Sjkoshy /* 311176758Sjkoshy * 's' lies entirely before 't', and after 'prevt': 312176758Sjkoshy * ...| prevt |...| s |...| t |... 313176758Sjkoshy */ 314164190Sjkoshy break; 315176758Sjkoshy else { /* 's' and 't' overlap. */ 316164190Sjkoshy LIBELF_SET_ERROR(LAYOUT, 0); 317164190Sjkoshy return (0); 318164190Sjkoshy } 319164190Sjkoshy } 320164190Sjkoshy 321164190Sjkoshy if (prevt) 322164190Sjkoshy STAILQ_INSERT_AFTER(&e->e_u.e_elf.e_scn, prevt, s, s_next); 323164190Sjkoshy else 324164190Sjkoshy STAILQ_INSERT_HEAD(&e->e_u.e_elf.e_scn, s, s_next); 325164190Sjkoshy return (1); 326164190Sjkoshy} 327164190Sjkoshy 328247221Smarkj/* 329247221Smarkj * Recompute section layout. 330247221Smarkj */ 331247221Smarkj 332164190Sjkoshystatic off_t 333164190Sjkoshy_libelf_resync_sections(Elf *e, off_t rc) 334164190Sjkoshy{ 335164190Sjkoshy int ec; 336247221Smarkj Elf_Scn *s; 337172088Sjkoshy size_t sh_type, shdr_start, shdr_end; 338164190Sjkoshy 339164190Sjkoshy ec = e->e_class; 340164190Sjkoshy 341164190Sjkoshy /* 342164190Sjkoshy * Make a pass through sections, computing the extent of each 343164190Sjkoshy * section. Order in increasing order of addresses. 344164190Sjkoshy */ 345247221Smarkj STAILQ_FOREACH(s, &e->e_u.e_elf.e_scn, s_next) { 346164190Sjkoshy if (ec == ELFCLASS32) 347164190Sjkoshy sh_type = s->s_shdr.s_shdr32.sh_type; 348164190Sjkoshy else 349164190Sjkoshy sh_type = s->s_shdr.s_shdr64.sh_type; 350164190Sjkoshy 351164190Sjkoshy if (sh_type == SHT_NOBITS || sh_type == SHT_NULL) 352164190Sjkoshy continue; 353164190Sjkoshy 354247221Smarkj if (_libelf_compute_section_extents(e, s, rc) == 0) 355247221Smarkj return ((off_t) -1); 356247221Smarkj 357247221Smarkj if (s->s_size == 0) 358247221Smarkj continue; 359247221Smarkj 360247221Smarkj if (s->s_offset + s->s_size < (size_t) rc) { 361247221Smarkj /* 362247221Smarkj * Try insert this section in the 363247221Smarkj * correct place in the list, 364247221Smarkj * detecting overlaps if any. 365247221Smarkj */ 366247221Smarkj STAILQ_REMOVE(&e->e_u.e_elf.e_scn, s, _Elf_Scn, 367247221Smarkj s_next); 368247221Smarkj if (_libelf_insert_section(e, s) == 0) 369164190Sjkoshy return ((off_t) -1); 370164190Sjkoshy } else 371164190Sjkoshy rc = s->s_offset + s->s_size; 372164190Sjkoshy } 373164190Sjkoshy 374172088Sjkoshy /* 375172088Sjkoshy * If the application is controlling file layout, check for an 376172088Sjkoshy * overlap between this section's extents and the SHDR table. 377172088Sjkoshy */ 378172088Sjkoshy if (e->e_flags & ELF_F_LAYOUT) { 379172088Sjkoshy 380172088Sjkoshy if (e->e_class == ELFCLASS32) 381172088Sjkoshy shdr_start = e->e_u.e_elf.e_ehdr.e_ehdr32->e_shoff; 382172088Sjkoshy else 383172088Sjkoshy shdr_start = e->e_u.e_elf.e_ehdr.e_ehdr64->e_shoff; 384172088Sjkoshy 385172088Sjkoshy shdr_end = shdr_start + _libelf_fsize(ELF_T_SHDR, e->e_class, 386172088Sjkoshy e->e_version, e->e_u.e_elf.e_nscn); 387172088Sjkoshy 388172088Sjkoshy STAILQ_FOREACH(s, &e->e_u.e_elf.e_scn, s_next) { 389172088Sjkoshy if (s->s_offset >= shdr_end || 390172088Sjkoshy s->s_offset + s->s_size <= shdr_start) 391172088Sjkoshy continue; 392172088Sjkoshy LIBELF_SET_ERROR(LAYOUT, 0); 393172088Sjkoshy return ((off_t) -1); 394172088Sjkoshy } 395172088Sjkoshy } 396172088Sjkoshy 397164190Sjkoshy return (rc); 398164190Sjkoshy} 399164190Sjkoshy 400164190Sjkoshystatic off_t 401164190Sjkoshy_libelf_resync_elf(Elf *e) 402164190Sjkoshy{ 403164190Sjkoshy int ec, eh_class, eh_type; 404164190Sjkoshy unsigned int eh_byteorder, eh_version; 405164190Sjkoshy size_t align, fsz; 406164190Sjkoshy size_t phnum, shnum; 407164190Sjkoshy off_t rc, phoff, shoff; 408164190Sjkoshy void *ehdr; 409164190Sjkoshy Elf32_Ehdr *eh32; 410164190Sjkoshy Elf64_Ehdr *eh64; 411164190Sjkoshy 412164190Sjkoshy rc = 0; 413164190Sjkoshy 414164190Sjkoshy ec = e->e_class; 415164190Sjkoshy 416164190Sjkoshy assert(ec == ELFCLASS32 || ec == ELFCLASS64); 417164190Sjkoshy 418164190Sjkoshy /* 419164190Sjkoshy * Prepare the EHDR. 420164190Sjkoshy */ 421164190Sjkoshy if ((ehdr = _libelf_ehdr(e, ec, 0)) == NULL) 422164190Sjkoshy return ((off_t) -1); 423164190Sjkoshy 424164190Sjkoshy eh32 = ehdr; 425164190Sjkoshy eh64 = ehdr; 426164190Sjkoshy 427164190Sjkoshy if (ec == ELFCLASS32) { 428164190Sjkoshy eh_byteorder = eh32->e_ident[EI_DATA]; 429164190Sjkoshy eh_class = eh32->e_ident[EI_CLASS]; 430164190Sjkoshy phoff = (uint64_t) eh32->e_phoff; 431164190Sjkoshy shoff = (uint64_t) eh32->e_shoff; 432164190Sjkoshy eh_type = eh32->e_type; 433164190Sjkoshy eh_version = eh32->e_version; 434164190Sjkoshy } else { 435164190Sjkoshy eh_byteorder = eh64->e_ident[EI_DATA]; 436164190Sjkoshy eh_class = eh64->e_ident[EI_CLASS]; 437164190Sjkoshy phoff = eh64->e_phoff; 438164190Sjkoshy shoff = eh64->e_shoff; 439164190Sjkoshy eh_type = eh64->e_type; 440164190Sjkoshy eh_version = eh64->e_version; 441164190Sjkoshy } 442164190Sjkoshy 443164190Sjkoshy if (eh_version == EV_NONE) 444164190Sjkoshy eh_version = EV_CURRENT; 445164190Sjkoshy 446164190Sjkoshy if (eh_version != e->e_version) { /* always EV_CURRENT */ 447164190Sjkoshy LIBELF_SET_ERROR(VERSION, 0); 448164190Sjkoshy return ((off_t) -1); 449164190Sjkoshy } 450164190Sjkoshy 451164190Sjkoshy if (eh_class != e->e_class) { 452164190Sjkoshy LIBELF_SET_ERROR(CLASS, 0); 453164190Sjkoshy return ((off_t) -1); 454164190Sjkoshy } 455164190Sjkoshy 456164190Sjkoshy if (e->e_cmd != ELF_C_WRITE && eh_byteorder != e->e_byteorder) { 457164190Sjkoshy LIBELF_SET_ERROR(HEADER, 0); 458164190Sjkoshy return ((off_t) -1); 459164190Sjkoshy } 460164190Sjkoshy 461165535Sjkoshy shnum = e->e_u.e_elf.e_nscn; 462165535Sjkoshy phnum = e->e_u.e_elf.e_nphdr; 463164190Sjkoshy 464164190Sjkoshy e->e_byteorder = eh_byteorder; 465164190Sjkoshy 466164190Sjkoshy#define INITIALIZE_EHDR(E,EC,V) do { \ 467164190Sjkoshy (E)->e_ident[EI_MAG0] = ELFMAG0; \ 468164190Sjkoshy (E)->e_ident[EI_MAG1] = ELFMAG1; \ 469164190Sjkoshy (E)->e_ident[EI_MAG2] = ELFMAG2; \ 470164190Sjkoshy (E)->e_ident[EI_MAG3] = ELFMAG3; \ 471164190Sjkoshy (E)->e_ident[EI_CLASS] = (EC); \ 472164190Sjkoshy (E)->e_ident[EI_VERSION] = (V); \ 473164190Sjkoshy (E)->e_ehsize = _libelf_fsize(ELF_T_EHDR, (EC), (V), \ 474164190Sjkoshy (size_t) 1); \ 475210326Skaiw (E)->e_phentsize = (phnum == 0) ? 0 : _libelf_fsize( \ 476210326Skaiw ELF_T_PHDR, (EC), (V), (size_t) 1); \ 477164190Sjkoshy (E)->e_shentsize = _libelf_fsize(ELF_T_SHDR, (EC), (V), \ 478164190Sjkoshy (size_t) 1); \ 479164190Sjkoshy } while (0) 480164190Sjkoshy 481164190Sjkoshy if (ec == ELFCLASS32) 482164190Sjkoshy INITIALIZE_EHDR(eh32, ec, eh_version); 483164190Sjkoshy else 484164190Sjkoshy INITIALIZE_EHDR(eh64, ec, eh_version); 485164190Sjkoshy 486164190Sjkoshy (void) elf_flagehdr(e, ELF_C_SET, ELF_F_DIRTY); 487164190Sjkoshy 488164190Sjkoshy rc += _libelf_fsize(ELF_T_EHDR, ec, eh_version, (size_t) 1); 489164190Sjkoshy 490164190Sjkoshy /* 491164190Sjkoshy * Compute the layout the program header table, if one is 492164190Sjkoshy * present. The program header table needs to be aligned to a 493164190Sjkoshy * `natural' boundary. 494164190Sjkoshy */ 495164190Sjkoshy if (phnum) { 496164190Sjkoshy fsz = _libelf_fsize(ELF_T_PHDR, ec, eh_version, phnum); 497164190Sjkoshy align = _libelf_falign(ELF_T_PHDR, ec); 498164190Sjkoshy 499164190Sjkoshy if (e->e_flags & ELF_F_LAYOUT) { 500164190Sjkoshy /* 501164190Sjkoshy * Check offsets for sanity. 502164190Sjkoshy */ 503164190Sjkoshy if (rc > phoff) { 504164190Sjkoshy LIBELF_SET_ERROR(HEADER, 0); 505164190Sjkoshy return ((off_t) -1); 506164190Sjkoshy } 507164190Sjkoshy 508164190Sjkoshy if (phoff % align) { 509164190Sjkoshy LIBELF_SET_ERROR(LAYOUT, 0); 510164190Sjkoshy return ((off_t) -1); 511164190Sjkoshy } 512164190Sjkoshy 513164190Sjkoshy } else 514164190Sjkoshy phoff = roundup(rc, align); 515164190Sjkoshy 516164190Sjkoshy rc = phoff + fsz; 517164190Sjkoshy } else 518164190Sjkoshy phoff = 0; 519164190Sjkoshy 520164190Sjkoshy /* 521164190Sjkoshy * Compute the layout of the sections associated with the 522164190Sjkoshy * file. 523164190Sjkoshy */ 524164190Sjkoshy 525210330Skaiw if (e->e_cmd != ELF_C_WRITE && 526210330Skaiw (e->e_flags & LIBELF_F_SHDRS_LOADED) == 0 && 527210330Skaiw _libelf_load_scn(e, ehdr) == 0) 528210330Skaiw return ((off_t) -1); 529210330Skaiw 530164190Sjkoshy if ((rc = _libelf_resync_sections(e, rc)) < 0) 531164190Sjkoshy return ((off_t) -1); 532164190Sjkoshy 533164190Sjkoshy /* 534164190Sjkoshy * Compute the space taken up by the section header table, if 535172088Sjkoshy * one is needed. If ELF_F_LAYOUT is asserted, the 536172088Sjkoshy * application may have placed the section header table in 537172088Sjkoshy * between existing sections, so the net size of the file need 538172088Sjkoshy * not increase due to the presence of the section header 539172088Sjkoshy * table. 540164190Sjkoshy */ 541164190Sjkoshy if (shnum) { 542164190Sjkoshy fsz = _libelf_fsize(ELF_T_SHDR, ec, eh_version, (size_t) 1); 543164190Sjkoshy align = _libelf_falign(ELF_T_SHDR, ec); 544164190Sjkoshy 545164190Sjkoshy if (e->e_flags & ELF_F_LAYOUT) { 546164190Sjkoshy if (shoff % align) { 547164190Sjkoshy LIBELF_SET_ERROR(LAYOUT, 0); 548164190Sjkoshy return ((off_t) -1); 549164190Sjkoshy } 550164190Sjkoshy } else 551164190Sjkoshy shoff = roundup(rc, align); 552164190Sjkoshy 553172088Sjkoshy if (shoff + fsz * shnum > (size_t) rc) 554172088Sjkoshy rc = shoff + fsz * shnum; 555164190Sjkoshy } else 556164190Sjkoshy shoff = 0; 557164190Sjkoshy 558164190Sjkoshy /* 559165535Sjkoshy * Set the fields of the Executable Header that could potentially use 560165535Sjkoshy * extended numbering. 561165535Sjkoshy */ 562165535Sjkoshy _libelf_setphnum(e, ehdr, ec, phnum); 563165535Sjkoshy _libelf_setshnum(e, ehdr, ec, shnum); 564165535Sjkoshy 565165535Sjkoshy /* 566164190Sjkoshy * Update the `e_phoff' and `e_shoff' fields if the library is 567164190Sjkoshy * doing the layout. 568164190Sjkoshy */ 569164190Sjkoshy if ((e->e_flags & ELF_F_LAYOUT) == 0) { 570164190Sjkoshy if (ec == ELFCLASS32) { 571164190Sjkoshy eh32->e_phoff = (uint32_t) phoff; 572164190Sjkoshy eh32->e_shoff = (uint32_t) shoff; 573164190Sjkoshy } else { 574164190Sjkoshy eh64->e_phoff = (uint64_t) phoff; 575164190Sjkoshy eh64->e_shoff = (uint64_t) shoff; 576164190Sjkoshy } 577164190Sjkoshy } 578164190Sjkoshy 579164190Sjkoshy return (rc); 580164190Sjkoshy} 581164190Sjkoshy 582164190Sjkoshy/* 583164190Sjkoshy * Write out the contents of a section. 584164190Sjkoshy */ 585164190Sjkoshy 586164190Sjkoshystatic off_t 587164190Sjkoshy_libelf_write_scn(Elf *e, char *nf, Elf_Scn *s, off_t rc) 588164190Sjkoshy{ 589164190Sjkoshy int ec; 590164190Sjkoshy size_t fsz, msz, nobjects; 591164190Sjkoshy uint32_t sh_type; 592210328Skaiw uint64_t sh_off, sh_size; 593164190Sjkoshy int elftype; 594164190Sjkoshy Elf_Data *d, dst; 595164190Sjkoshy 596210328Skaiw if ((ec = e->e_class) == ELFCLASS32) { 597164190Sjkoshy sh_type = s->s_shdr.s_shdr32.sh_type; 598210328Skaiw sh_size = (uint64_t) s->s_shdr.s_shdr32.sh_size; 599210328Skaiw } else { 600164190Sjkoshy sh_type = s->s_shdr.s_shdr64.sh_type; 601210328Skaiw sh_size = s->s_shdr.s_shdr64.sh_size; 602210328Skaiw } 603164190Sjkoshy 604164190Sjkoshy /* 605164190Sjkoshy * Ignore sections that do not allocate space in the file. 606164190Sjkoshy */ 607210328Skaiw if (sh_type == SHT_NOBITS || sh_type == SHT_NULL || sh_size == 0) 608164190Sjkoshy return (rc); 609164190Sjkoshy 610164190Sjkoshy elftype = _libelf_xlate_shtype(sh_type); 611164190Sjkoshy assert(elftype >= ELF_T_FIRST && elftype <= ELF_T_LAST); 612164190Sjkoshy 613164190Sjkoshy sh_off = s->s_offset; 614164190Sjkoshy assert(sh_off % _libelf_falign(elftype, ec) == 0); 615164190Sjkoshy 616164190Sjkoshy /* 617164190Sjkoshy * If the section has a `rawdata' descriptor, and the section 618164190Sjkoshy * contents have not been modified, use its contents directly. 619164190Sjkoshy * The `s_rawoff' member contains the offset into the original 620164190Sjkoshy * file, while `s_offset' contains its new location in the 621164190Sjkoshy * destination. 622164190Sjkoshy */ 623164190Sjkoshy 624164190Sjkoshy if (STAILQ_EMPTY(&s->s_data)) { 625164190Sjkoshy 626164190Sjkoshy if ((d = elf_rawdata(s, NULL)) == NULL) 627164190Sjkoshy return ((off_t) -1); 628164190Sjkoshy 629164190Sjkoshy STAILQ_FOREACH(d, &s->s_rawdata, d_next) { 630164190Sjkoshy if ((uint64_t) rc < sh_off + d->d_off) 631164190Sjkoshy (void) memset(nf + rc, 632164190Sjkoshy LIBELF_PRIVATE(fillchar), sh_off + 633164190Sjkoshy d->d_off - rc); 634164190Sjkoshy rc = sh_off + d->d_off; 635164190Sjkoshy 636164190Sjkoshy assert(d->d_buf != NULL); 637164190Sjkoshy assert(d->d_type == ELF_T_BYTE); 638164190Sjkoshy assert(d->d_version == e->e_version); 639164190Sjkoshy 640164190Sjkoshy (void) memcpy(nf + rc, 641164190Sjkoshy e->e_rawfile + s->s_rawoff + d->d_off, d->d_size); 642164190Sjkoshy 643164190Sjkoshy rc += d->d_size; 644164190Sjkoshy } 645164190Sjkoshy 646164190Sjkoshy return (rc); 647164190Sjkoshy } 648164190Sjkoshy 649164190Sjkoshy /* 650164190Sjkoshy * Iterate over the set of data descriptors for this section. 651164190Sjkoshy * The prior call to _libelf_resync_elf() would have setup the 652164190Sjkoshy * descriptors for this step. 653164190Sjkoshy */ 654164190Sjkoshy 655164190Sjkoshy dst.d_version = e->e_version; 656164190Sjkoshy 657164190Sjkoshy STAILQ_FOREACH(d, &s->s_data, d_next) { 658164190Sjkoshy 659212373Skaiw msz = _libelf_msize(d->d_type, ec, e->e_version); 660212373Skaiw 661164190Sjkoshy if ((uint64_t) rc < sh_off + d->d_off) 662164190Sjkoshy (void) memset(nf + rc, 663164190Sjkoshy LIBELF_PRIVATE(fillchar), sh_off + d->d_off - rc); 664164190Sjkoshy 665164190Sjkoshy rc = sh_off + d->d_off; 666164190Sjkoshy 667164190Sjkoshy assert(d->d_buf != NULL); 668164190Sjkoshy assert(d->d_version == e->e_version); 669164190Sjkoshy assert(d->d_size % msz == 0); 670164190Sjkoshy 671164190Sjkoshy nobjects = d->d_size / msz; 672164190Sjkoshy 673212373Skaiw fsz = _libelf_fsize(d->d_type, ec, e->e_version, nobjects); 674164190Sjkoshy 675164190Sjkoshy dst.d_buf = nf + rc; 676164190Sjkoshy dst.d_size = fsz; 677164190Sjkoshy 678164190Sjkoshy if (_libelf_xlate(&dst, d, e->e_byteorder, ec, ELF_TOFILE) == 679164190Sjkoshy NULL) 680164190Sjkoshy return ((off_t) -1); 681164190Sjkoshy 682164190Sjkoshy rc += fsz; 683164190Sjkoshy } 684164190Sjkoshy 685164190Sjkoshy return ((off_t) rc); 686164190Sjkoshy} 687164190Sjkoshy 688164190Sjkoshy/* 689164190Sjkoshy * Write out the file image. 690164190Sjkoshy * 691164190Sjkoshy * The original file could have been mapped in with an ELF_C_RDWR 692164190Sjkoshy * command and the application could have added new content or 693164190Sjkoshy * re-arranged its sections before calling elf_update(). Consequently 694164190Sjkoshy * its not safe to work `in place' on the original file. So we 695164190Sjkoshy * malloc() the required space for the updated ELF object and build 696164190Sjkoshy * the object there and write it out to the underlying file at the 697164190Sjkoshy * end. Note that the application may have opened the underlying file 698164190Sjkoshy * in ELF_C_RDWR and only retrieved/modified a few sections. We take 699164190Sjkoshy * care to avoid translating file sections unnecessarily. 700164190Sjkoshy * 701164190Sjkoshy * Gaps in the coverage of the file by the file's sections will be 702164190Sjkoshy * filled with the fill character set by elf_fill(3). 703164190Sjkoshy */ 704164190Sjkoshy 705164190Sjkoshystatic off_t 706164190Sjkoshy_libelf_write_elf(Elf *e, off_t newsize) 707164190Sjkoshy{ 708164190Sjkoshy int ec; 709172088Sjkoshy off_t maxrc, rc; 710164190Sjkoshy size_t fsz, msz, phnum, shnum; 711164190Sjkoshy uint64_t phoff, shoff; 712164190Sjkoshy void *ehdr; 713164190Sjkoshy char *newfile; 714164190Sjkoshy Elf_Data dst, src; 715164190Sjkoshy Elf_Scn *scn, *tscn; 716164190Sjkoshy Elf32_Ehdr *eh32; 717164190Sjkoshy Elf64_Ehdr *eh64; 718164190Sjkoshy 719164190Sjkoshy assert(e->e_kind == ELF_K_ELF); 720164190Sjkoshy assert(e->e_cmd != ELF_C_READ); 721164190Sjkoshy assert(e->e_fd >= 0); 722164190Sjkoshy 723164190Sjkoshy if ((newfile = malloc((size_t) newsize)) == NULL) { 724164190Sjkoshy LIBELF_SET_ERROR(RESOURCE, errno); 725164190Sjkoshy return ((off_t) -1); 726164190Sjkoshy } 727164190Sjkoshy 728164190Sjkoshy ec = e->e_class; 729164190Sjkoshy 730164190Sjkoshy ehdr = _libelf_ehdr(e, ec, 0); 731164190Sjkoshy assert(ehdr != NULL); 732164190Sjkoshy 733165535Sjkoshy phnum = e->e_u.e_elf.e_nphdr; 734165535Sjkoshy 735164190Sjkoshy if (ec == ELFCLASS32) { 736164190Sjkoshy eh32 = (Elf32_Ehdr *) ehdr; 737164190Sjkoshy 738164190Sjkoshy phoff = (uint64_t) eh32->e_phoff; 739164190Sjkoshy shnum = eh32->e_shnum; 740164190Sjkoshy shoff = (uint64_t) eh32->e_shoff; 741164190Sjkoshy } else { 742164190Sjkoshy eh64 = (Elf64_Ehdr *) ehdr; 743164190Sjkoshy 744164190Sjkoshy phoff = eh64->e_phoff; 745164190Sjkoshy shnum = eh64->e_shnum; 746164190Sjkoshy shoff = eh64->e_shoff; 747164190Sjkoshy } 748164190Sjkoshy 749164190Sjkoshy fsz = _libelf_fsize(ELF_T_EHDR, ec, e->e_version, (size_t) 1); 750164190Sjkoshy msz = _libelf_msize(ELF_T_EHDR, ec, e->e_version); 751164190Sjkoshy 752164190Sjkoshy (void) memset(&dst, 0, sizeof(dst)); 753164190Sjkoshy (void) memset(&src, 0, sizeof(src)); 754164190Sjkoshy 755164190Sjkoshy src.d_buf = ehdr; 756164190Sjkoshy src.d_size = msz; 757164190Sjkoshy src.d_type = ELF_T_EHDR; 758164190Sjkoshy src.d_version = dst.d_version = e->e_version; 759164190Sjkoshy 760164190Sjkoshy rc = 0; 761164190Sjkoshy 762164190Sjkoshy dst.d_buf = newfile + rc; 763164190Sjkoshy dst.d_size = fsz; 764164190Sjkoshy 765164190Sjkoshy if (_libelf_xlate(&dst, &src, e->e_byteorder, ec, ELF_TOFILE) == 766164190Sjkoshy NULL) 767164190Sjkoshy goto error; 768164190Sjkoshy 769164190Sjkoshy rc += fsz; 770164190Sjkoshy 771164190Sjkoshy /* 772164190Sjkoshy * Write the program header table if present. 773164190Sjkoshy */ 774164190Sjkoshy 775164190Sjkoshy if (phnum != 0 && phoff != 0) { 776164190Sjkoshy assert((unsigned) rc <= phoff); 777164190Sjkoshy 778164190Sjkoshy fsz = _libelf_fsize(ELF_T_PHDR, ec, e->e_version, phnum); 779164190Sjkoshy 780164190Sjkoshy assert(phoff % _libelf_falign(ELF_T_PHDR, ec) == 0); 781164190Sjkoshy assert(fsz > 0); 782164190Sjkoshy 783210330Skaiw src.d_buf = _libelf_getphdr(e, ec); 784164190Sjkoshy src.d_version = dst.d_version = e->e_version; 785164190Sjkoshy src.d_type = ELF_T_PHDR; 786164190Sjkoshy src.d_size = phnum * _libelf_msize(ELF_T_PHDR, ec, 787164190Sjkoshy e->e_version); 788164190Sjkoshy 789164190Sjkoshy dst.d_size = fsz; 790164190Sjkoshy 791164190Sjkoshy if ((uint64_t) rc < phoff) 792164190Sjkoshy (void) memset(newfile + rc, 793164190Sjkoshy LIBELF_PRIVATE(fillchar), phoff - rc); 794164190Sjkoshy 795164190Sjkoshy dst.d_buf = newfile + rc; 796164190Sjkoshy 797164190Sjkoshy if (_libelf_xlate(&dst, &src, e->e_byteorder, ec, ELF_TOFILE) == 798164190Sjkoshy NULL) 799164190Sjkoshy goto error; 800164190Sjkoshy 801164190Sjkoshy rc = phoff + fsz; 802164190Sjkoshy } 803164190Sjkoshy 804164190Sjkoshy /* 805164190Sjkoshy * Write out individual sections. 806164190Sjkoshy */ 807164190Sjkoshy 808164190Sjkoshy STAILQ_FOREACH(scn, &e->e_u.e_elf.e_scn, s_next) 809164190Sjkoshy if ((rc = _libelf_write_scn(e, newfile, scn, rc)) < 0) 810164190Sjkoshy goto error; 811164190Sjkoshy 812164190Sjkoshy /* 813172088Sjkoshy * Write out the section header table, if required. Note that 814172088Sjkoshy * if flag ELF_F_LAYOUT has been set the section header table 815172088Sjkoshy * could reside in between byte ranges mapped by section 816172088Sjkoshy * descriptors. 817164190Sjkoshy */ 818164190Sjkoshy if (shnum != 0 && shoff != 0) { 819164190Sjkoshy if ((uint64_t) rc < shoff) 820164190Sjkoshy (void) memset(newfile + rc, 821164190Sjkoshy LIBELF_PRIVATE(fillchar), shoff - rc); 822164190Sjkoshy 823172088Sjkoshy maxrc = rc; 824164190Sjkoshy rc = shoff; 825164190Sjkoshy 826164190Sjkoshy assert(rc % _libelf_falign(ELF_T_SHDR, ec) == 0); 827164190Sjkoshy 828164190Sjkoshy src.d_type = ELF_T_SHDR; 829164190Sjkoshy src.d_size = _libelf_msize(ELF_T_SHDR, ec, e->e_version); 830164190Sjkoshy src.d_version = dst.d_version = e->e_version; 831164190Sjkoshy 832164190Sjkoshy fsz = _libelf_fsize(ELF_T_SHDR, ec, e->e_version, (size_t) 1); 833164190Sjkoshy 834164190Sjkoshy STAILQ_FOREACH(scn, &e->e_u.e_elf.e_scn, s_next) { 835164190Sjkoshy if (ec == ELFCLASS32) 836164190Sjkoshy src.d_buf = &scn->s_shdr.s_shdr32; 837164190Sjkoshy else 838164190Sjkoshy src.d_buf = &scn->s_shdr.s_shdr64; 839164190Sjkoshy 840164190Sjkoshy dst.d_size = fsz; 841177367Sjkoshy dst.d_buf = newfile + rc + scn->s_ndx * fsz; 842164190Sjkoshy 843164190Sjkoshy if (_libelf_xlate(&dst, &src, e->e_byteorder, ec, 844164190Sjkoshy ELF_TOFILE) != &dst) 845164190Sjkoshy goto error; 846164190Sjkoshy } 847172088Sjkoshy 848177367Sjkoshy rc += e->e_u.e_elf.e_nscn * fsz; 849172088Sjkoshy if (maxrc > rc) 850172088Sjkoshy rc = maxrc; 851164190Sjkoshy } 852164190Sjkoshy 853164190Sjkoshy assert(rc == newsize); 854164190Sjkoshy 855164190Sjkoshy /* 856164190Sjkoshy * Write out the constructed contents and remap the file in 857164190Sjkoshy * read-only. 858164190Sjkoshy */ 859164190Sjkoshy 860164190Sjkoshy if (e->e_rawfile && munmap(e->e_rawfile, e->e_rawsize) < 0) { 861164190Sjkoshy LIBELF_SET_ERROR(IO, errno); 862164190Sjkoshy goto error; 863164190Sjkoshy } 864164190Sjkoshy 865164190Sjkoshy if (write(e->e_fd, newfile, (size_t) newsize) != newsize || 866164190Sjkoshy lseek(e->e_fd, (off_t) 0, SEEK_SET) < 0) { 867164190Sjkoshy LIBELF_SET_ERROR(IO, errno); 868164190Sjkoshy goto error; 869164190Sjkoshy } 870164190Sjkoshy 871164190Sjkoshy if (e->e_cmd != ELF_C_WRITE) { 872164190Sjkoshy if ((e->e_rawfile = mmap(NULL, (size_t) newsize, PROT_READ, 873164190Sjkoshy MAP_PRIVATE, e->e_fd, (off_t) 0)) == MAP_FAILED) { 874164190Sjkoshy LIBELF_SET_ERROR(IO, errno); 875164190Sjkoshy goto error; 876164190Sjkoshy } 877164190Sjkoshy e->e_rawsize = newsize; 878164190Sjkoshy } 879164190Sjkoshy 880164190Sjkoshy /* 881164190Sjkoshy * Reset flags, remove existing section descriptors and 882164190Sjkoshy * {E,P}HDR pointers so that a subsequent elf_get{e,p}hdr() 883164190Sjkoshy * and elf_getscn() will function correctly. 884164190Sjkoshy */ 885164190Sjkoshy 886164190Sjkoshy e->e_flags &= ~ELF_F_DIRTY; 887164190Sjkoshy 888164190Sjkoshy STAILQ_FOREACH_SAFE(scn, &e->e_u.e_elf.e_scn, s_next, tscn) 889164190Sjkoshy _libelf_release_scn(scn); 890164190Sjkoshy 891164190Sjkoshy if (ec == ELFCLASS32) { 892164190Sjkoshy free(e->e_u.e_elf.e_ehdr.e_ehdr32); 893164190Sjkoshy if (e->e_u.e_elf.e_phdr.e_phdr32) 894164190Sjkoshy free(e->e_u.e_elf.e_phdr.e_phdr32); 895164190Sjkoshy 896164190Sjkoshy e->e_u.e_elf.e_ehdr.e_ehdr32 = NULL; 897164190Sjkoshy e->e_u.e_elf.e_phdr.e_phdr32 = NULL; 898164190Sjkoshy } else { 899164190Sjkoshy free(e->e_u.e_elf.e_ehdr.e_ehdr64); 900164190Sjkoshy if (e->e_u.e_elf.e_phdr.e_phdr64) 901164190Sjkoshy free(e->e_u.e_elf.e_phdr.e_phdr64); 902164190Sjkoshy 903164190Sjkoshy e->e_u.e_elf.e_ehdr.e_ehdr64 = NULL; 904164190Sjkoshy e->e_u.e_elf.e_phdr.e_phdr64 = NULL; 905164190Sjkoshy } 906164190Sjkoshy 907210347Skaiw free(newfile); 908210347Skaiw 909164190Sjkoshy return (rc); 910164190Sjkoshy 911164190Sjkoshy error: 912210347Skaiw free(newfile); 913210347Skaiw 914164190Sjkoshy return ((off_t) -1); 915164190Sjkoshy} 916164190Sjkoshy 917164190Sjkoshyoff_t 918164190Sjkoshyelf_update(Elf *e, Elf_Cmd c) 919164190Sjkoshy{ 920164190Sjkoshy int ec; 921164190Sjkoshy off_t rc; 922164190Sjkoshy 923164190Sjkoshy rc = (off_t) -1; 924164190Sjkoshy 925164190Sjkoshy if (e == NULL || e->e_kind != ELF_K_ELF || 926164190Sjkoshy (c != ELF_C_NULL && c != ELF_C_WRITE)) { 927164190Sjkoshy LIBELF_SET_ERROR(ARGUMENT, 0); 928164190Sjkoshy return (rc); 929164190Sjkoshy } 930164190Sjkoshy 931164190Sjkoshy if ((ec = e->e_class) != ELFCLASS32 && ec != ELFCLASS64) { 932164190Sjkoshy LIBELF_SET_ERROR(CLASS, 0); 933164190Sjkoshy return (rc); 934164190Sjkoshy } 935164190Sjkoshy 936164190Sjkoshy if (e->e_version == EV_NONE) 937164190Sjkoshy e->e_version = EV_CURRENT; 938164190Sjkoshy 939164190Sjkoshy if (c == ELF_C_WRITE && e->e_cmd == ELF_C_READ) { 940164190Sjkoshy LIBELF_SET_ERROR(MODE, 0); 941164190Sjkoshy return (rc); 942164190Sjkoshy } 943164190Sjkoshy 944164190Sjkoshy if ((rc = _libelf_resync_elf(e)) < 0) 945164190Sjkoshy return (rc); 946164190Sjkoshy 947164190Sjkoshy if (c == ELF_C_NULL) 948164190Sjkoshy return (rc); 949164190Sjkoshy 950164190Sjkoshy if (e->e_cmd == ELF_C_READ) { 951164190Sjkoshy /* 952164190Sjkoshy * This descriptor was opened in read-only mode or by 953164190Sjkoshy * elf_memory(). 954164190Sjkoshy */ 955164190Sjkoshy if (e->e_fd) 956164190Sjkoshy LIBELF_SET_ERROR(MODE, 0); 957164190Sjkoshy else 958164190Sjkoshy LIBELF_SET_ERROR(ARGUMENT, 0); 959164190Sjkoshy return ((off_t) -1); 960164190Sjkoshy } 961164190Sjkoshy 962164190Sjkoshy if (e->e_fd < 0) { 963164190Sjkoshy LIBELF_SET_ERROR(SEQUENCE, 0); 964164190Sjkoshy return ((off_t) -1); 965164190Sjkoshy } 966164190Sjkoshy 967164190Sjkoshy return (_libelf_write_elf(e, rc)); 968164190Sjkoshy} 969