1da0c48c4Sopenharmony_ci/* Write changed data structures. 2da0c48c4Sopenharmony_ci Copyright (C) 2000-2010, 2014, 2015, 2016, 2018 Red Hat, Inc. 3da0c48c4Sopenharmony_ci This file is part of elfutils. 4da0c48c4Sopenharmony_ci Written by Ulrich Drepper <drepper@redhat.com>, 2000. 5da0c48c4Sopenharmony_ci 6da0c48c4Sopenharmony_ci This file is free software; you can redistribute it and/or modify 7da0c48c4Sopenharmony_ci it under the terms of either 8da0c48c4Sopenharmony_ci 9da0c48c4Sopenharmony_ci * the GNU Lesser General Public License as published by the Free 10da0c48c4Sopenharmony_ci Software Foundation; either version 3 of the License, or (at 11da0c48c4Sopenharmony_ci your option) any later version 12da0c48c4Sopenharmony_ci 13da0c48c4Sopenharmony_ci or 14da0c48c4Sopenharmony_ci 15da0c48c4Sopenharmony_ci * the GNU General Public License as published by the Free 16da0c48c4Sopenharmony_ci Software Foundation; either version 2 of the License, or (at 17da0c48c4Sopenharmony_ci your option) any later version 18da0c48c4Sopenharmony_ci 19da0c48c4Sopenharmony_ci or both in parallel, as here. 20da0c48c4Sopenharmony_ci 21da0c48c4Sopenharmony_ci elfutils is distributed in the hope that it will be useful, but 22da0c48c4Sopenharmony_ci WITHOUT ANY WARRANTY; without even the implied warranty of 23da0c48c4Sopenharmony_ci MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 24da0c48c4Sopenharmony_ci General Public License for more details. 25da0c48c4Sopenharmony_ci 26da0c48c4Sopenharmony_ci You should have received copies of the GNU General Public License and 27da0c48c4Sopenharmony_ci the GNU Lesser General Public License along with this program. If 28da0c48c4Sopenharmony_ci not, see <http://www.gnu.org/licenses/>. */ 29da0c48c4Sopenharmony_ci 30da0c48c4Sopenharmony_ci#ifdef HAVE_CONFIG_H 31da0c48c4Sopenharmony_ci# include <config.h> 32da0c48c4Sopenharmony_ci#endif 33da0c48c4Sopenharmony_ci 34da0c48c4Sopenharmony_ci#include <assert.h> 35da0c48c4Sopenharmony_ci#include <errno.h> 36da0c48c4Sopenharmony_ci#include <libelf.h> 37da0c48c4Sopenharmony_ci#include <stdbool.h> 38da0c48c4Sopenharmony_ci#include <stdlib.h> 39da0c48c4Sopenharmony_ci#include <string.h> 40da0c48c4Sopenharmony_ci 41da0c48c4Sopenharmony_ci#include "libelfP.h" 42da0c48c4Sopenharmony_ci 43da0c48c4Sopenharmony_ci 44da0c48c4Sopenharmony_ci#ifndef LIBELFBITS 45da0c48c4Sopenharmony_ci# define LIBELFBITS 32 46da0c48c4Sopenharmony_ci#endif 47da0c48c4Sopenharmony_ci 48da0c48c4Sopenharmony_ci 49da0c48c4Sopenharmony_cistatic int 50da0c48c4Sopenharmony_cicompare_sections (const void *a, const void *b) 51da0c48c4Sopenharmony_ci{ 52da0c48c4Sopenharmony_ci const Elf_Scn **scna = (const Elf_Scn **) a; 53da0c48c4Sopenharmony_ci const Elf_Scn **scnb = (const Elf_Scn **) b; 54da0c48c4Sopenharmony_ci 55da0c48c4Sopenharmony_ci if ((*scna)->shdr.ELFW(e,LIBELFBITS)->sh_offset 56da0c48c4Sopenharmony_ci < (*scnb)->shdr.ELFW(e,LIBELFBITS)->sh_offset) 57da0c48c4Sopenharmony_ci return -1; 58da0c48c4Sopenharmony_ci 59da0c48c4Sopenharmony_ci if ((*scna)->shdr.ELFW(e,LIBELFBITS)->sh_offset 60da0c48c4Sopenharmony_ci > (*scnb)->shdr.ELFW(e,LIBELFBITS)->sh_offset) 61da0c48c4Sopenharmony_ci return 1; 62da0c48c4Sopenharmony_ci 63da0c48c4Sopenharmony_ci if ((*scna)->shdr.ELFW(e,LIBELFBITS)->sh_size 64da0c48c4Sopenharmony_ci < (*scnb)->shdr.ELFW(e,LIBELFBITS)->sh_size) 65da0c48c4Sopenharmony_ci return -1; 66da0c48c4Sopenharmony_ci 67da0c48c4Sopenharmony_ci if ((*scna)->shdr.ELFW(e,LIBELFBITS)->sh_size 68da0c48c4Sopenharmony_ci > (*scnb)->shdr.ELFW(e,LIBELFBITS)->sh_size) 69da0c48c4Sopenharmony_ci return 1; 70da0c48c4Sopenharmony_ci 71da0c48c4Sopenharmony_ci if ((*scna)->index < (*scnb)->index) 72da0c48c4Sopenharmony_ci return -1; 73da0c48c4Sopenharmony_ci 74da0c48c4Sopenharmony_ci if ((*scna)->index > (*scnb)->index) 75da0c48c4Sopenharmony_ci return 1; 76da0c48c4Sopenharmony_ci 77da0c48c4Sopenharmony_ci return 0; 78da0c48c4Sopenharmony_ci} 79da0c48c4Sopenharmony_ci 80da0c48c4Sopenharmony_ci 81da0c48c4Sopenharmony_ci/* Insert the sections in the list into the provided array and sort 82da0c48c4Sopenharmony_ci them according to their start offsets. For sections with equal 83da0c48c4Sopenharmony_ci start offsets, the size is used; for sections with equal start 84da0c48c4Sopenharmony_ci offsets and sizes, the section index is used. Sorting by size 85da0c48c4Sopenharmony_ci ensures that zero-length sections are processed first, which 86da0c48c4Sopenharmony_ci is what we want since they do not advance our file writing position. */ 87da0c48c4Sopenharmony_cistatic void 88da0c48c4Sopenharmony_cisort_sections (Elf_Scn **scns, Elf_ScnList *list) 89da0c48c4Sopenharmony_ci{ 90da0c48c4Sopenharmony_ci Elf_Scn **scnp = scns; 91da0c48c4Sopenharmony_ci do 92da0c48c4Sopenharmony_ci for (size_t cnt = 0; cnt < list->cnt; ++cnt) 93da0c48c4Sopenharmony_ci *scnp++ = &list->data[cnt]; 94da0c48c4Sopenharmony_ci while ((list = list->next) != NULL); 95da0c48c4Sopenharmony_ci 96da0c48c4Sopenharmony_ci qsort (scns, scnp - scns, sizeof (*scns), compare_sections); 97da0c48c4Sopenharmony_ci} 98da0c48c4Sopenharmony_ci 99da0c48c4Sopenharmony_ci 100da0c48c4Sopenharmony_cistatic inline void 101da0c48c4Sopenharmony_cifill_mmap (size_t offset, char *last_position, char *scn_start, 102da0c48c4Sopenharmony_ci char *const shdr_start, char *const shdr_end) 103da0c48c4Sopenharmony_ci{ 104da0c48c4Sopenharmony_ci size_t written = 0; 105da0c48c4Sopenharmony_ci 106da0c48c4Sopenharmony_ci if (last_position < shdr_start) 107da0c48c4Sopenharmony_ci { 108da0c48c4Sopenharmony_ci written = MIN (scn_start + offset - last_position, 109da0c48c4Sopenharmony_ci shdr_start - last_position); 110da0c48c4Sopenharmony_ci 111da0c48c4Sopenharmony_ci memset (last_position, __libelf_fill_byte, written); 112da0c48c4Sopenharmony_ci } 113da0c48c4Sopenharmony_ci 114da0c48c4Sopenharmony_ci if (last_position + written != scn_start + offset 115da0c48c4Sopenharmony_ci && shdr_end < scn_start + offset) 116da0c48c4Sopenharmony_ci { 117da0c48c4Sopenharmony_ci char *fill_start = MAX (shdr_end, scn_start); 118da0c48c4Sopenharmony_ci memset (fill_start, __libelf_fill_byte, 119da0c48c4Sopenharmony_ci scn_start + offset - fill_start); 120da0c48c4Sopenharmony_ci } 121da0c48c4Sopenharmony_ci} 122da0c48c4Sopenharmony_ci 123da0c48c4Sopenharmony_ciint 124da0c48c4Sopenharmony_ciinternal_function 125da0c48c4Sopenharmony_ci__elfw2(LIBELFBITS,updatemmap) (Elf *elf, int change_bo, size_t shnum) 126da0c48c4Sopenharmony_ci{ 127da0c48c4Sopenharmony_ci bool previous_scn_changed = false; 128da0c48c4Sopenharmony_ci 129da0c48c4Sopenharmony_ci /* We need the ELF header several times. */ 130da0c48c4Sopenharmony_ci ElfW2(LIBELFBITS,Ehdr) *ehdr = elf->state.ELFW(elf,LIBELFBITS).ehdr; 131da0c48c4Sopenharmony_ci 132da0c48c4Sopenharmony_ci /* Write out the ELF header. */ 133da0c48c4Sopenharmony_ci if ((elf->state.ELFW(elf,LIBELFBITS).ehdr_flags | elf->flags) & ELF_F_DIRTY) 134da0c48c4Sopenharmony_ci { 135da0c48c4Sopenharmony_ci /* If the type sizes should be different at some time we have to 136da0c48c4Sopenharmony_ci rewrite this code. */ 137da0c48c4Sopenharmony_ci assert (sizeof (ElfW2(LIBELFBITS,Ehdr)) 138da0c48c4Sopenharmony_ci == elf_typesize (LIBELFBITS, ELF_T_EHDR, 1)); 139da0c48c4Sopenharmony_ci 140da0c48c4Sopenharmony_ci if (unlikely (change_bo)) 141da0c48c4Sopenharmony_ci { 142da0c48c4Sopenharmony_ci /* Today there is only one version of the ELF header. */ 143da0c48c4Sopenharmony_ci#undef fctp 144da0c48c4Sopenharmony_ci#define fctp __elf_xfctstom[ELFW(ELFCLASS, LIBELFBITS) - 1][ELF_T_EHDR] 145da0c48c4Sopenharmony_ci 146da0c48c4Sopenharmony_ci /* Do the real work. */ 147da0c48c4Sopenharmony_ci (*fctp) ((char *) elf->map_address + elf->start_offset, ehdr, 148da0c48c4Sopenharmony_ci sizeof (ElfW2(LIBELFBITS,Ehdr)), 1); 149da0c48c4Sopenharmony_ci } 150da0c48c4Sopenharmony_ci else if (elf->map_address + elf->start_offset != ehdr) 151da0c48c4Sopenharmony_ci memcpy (elf->map_address + elf->start_offset, ehdr, 152da0c48c4Sopenharmony_ci sizeof (ElfW2(LIBELFBITS,Ehdr))); 153da0c48c4Sopenharmony_ci 154da0c48c4Sopenharmony_ci elf->state.ELFW(elf,LIBELFBITS).ehdr_flags &= ~ELF_F_DIRTY; 155da0c48c4Sopenharmony_ci 156da0c48c4Sopenharmony_ci /* We start writing sections after the ELF header only if there is 157da0c48c4Sopenharmony_ci no program header. */ 158da0c48c4Sopenharmony_ci previous_scn_changed = elf->state.ELFW(elf,LIBELFBITS).phdr == NULL; 159da0c48c4Sopenharmony_ci } 160da0c48c4Sopenharmony_ci 161da0c48c4Sopenharmony_ci size_t phnum; 162da0c48c4Sopenharmony_ci if (unlikely (__elf_getphdrnum_rdlock (elf, &phnum) != 0)) 163da0c48c4Sopenharmony_ci return -1; 164da0c48c4Sopenharmony_ci 165da0c48c4Sopenharmony_ci /* Write out the program header table. */ 166da0c48c4Sopenharmony_ci if (elf->state.ELFW(elf,LIBELFBITS).phdr != NULL 167da0c48c4Sopenharmony_ci && ((elf->state.ELFW(elf,LIBELFBITS).phdr_flags | elf->flags) 168da0c48c4Sopenharmony_ci & ELF_F_DIRTY)) 169da0c48c4Sopenharmony_ci { 170da0c48c4Sopenharmony_ci /* If the type sizes should be different at some time we have to 171da0c48c4Sopenharmony_ci rewrite this code. */ 172da0c48c4Sopenharmony_ci assert (sizeof (ElfW2(LIBELFBITS,Phdr)) 173da0c48c4Sopenharmony_ci == elf_typesize (LIBELFBITS, ELF_T_PHDR, 1)); 174da0c48c4Sopenharmony_ci 175da0c48c4Sopenharmony_ci /* Maybe the user wants a gap between the ELF header and the program 176da0c48c4Sopenharmony_ci header. */ 177da0c48c4Sopenharmony_ci if (ehdr->e_phoff > ehdr->e_ehsize) 178da0c48c4Sopenharmony_ci memset (elf->map_address + elf->start_offset + ehdr->e_ehsize, 179da0c48c4Sopenharmony_ci __libelf_fill_byte, ehdr->e_phoff - ehdr->e_ehsize); 180da0c48c4Sopenharmony_ci 181da0c48c4Sopenharmony_ci if (unlikely (change_bo)) 182da0c48c4Sopenharmony_ci { 183da0c48c4Sopenharmony_ci /* Today there is only one version of the ELF header. */ 184da0c48c4Sopenharmony_ci#undef fctp 185da0c48c4Sopenharmony_ci#define fctp __elf_xfctstom[ELFW(ELFCLASS, LIBELFBITS) - 1][ELF_T_PHDR] 186da0c48c4Sopenharmony_ci 187da0c48c4Sopenharmony_ci /* Do the real work. */ 188da0c48c4Sopenharmony_ci (*fctp) (elf->map_address + elf->start_offset + ehdr->e_phoff, 189da0c48c4Sopenharmony_ci elf->state.ELFW(elf,LIBELFBITS).phdr, 190da0c48c4Sopenharmony_ci sizeof (ElfW2(LIBELFBITS,Phdr)) * phnum, 1); 191da0c48c4Sopenharmony_ci } 192da0c48c4Sopenharmony_ci else 193da0c48c4Sopenharmony_ci memmove (elf->map_address + elf->start_offset + ehdr->e_phoff, 194da0c48c4Sopenharmony_ci elf->state.ELFW(elf,LIBELFBITS).phdr, 195da0c48c4Sopenharmony_ci sizeof (ElfW2(LIBELFBITS,Phdr)) * phnum); 196da0c48c4Sopenharmony_ci 197da0c48c4Sopenharmony_ci elf->state.ELFW(elf,LIBELFBITS).phdr_flags &= ~ELF_F_DIRTY; 198da0c48c4Sopenharmony_ci 199da0c48c4Sopenharmony_ci /* We modified the program header. Maybe this created a gap so 200da0c48c4Sopenharmony_ci we have to write fill bytes, if necessary. */ 201da0c48c4Sopenharmony_ci previous_scn_changed = true; 202da0c48c4Sopenharmony_ci } 203da0c48c4Sopenharmony_ci 204da0c48c4Sopenharmony_ci /* From now on we have to keep track of the last position to eventually 205da0c48c4Sopenharmony_ci fill the gaps with the prescribed fill byte. */ 206da0c48c4Sopenharmony_ci char *last_position = ((char *) elf->map_address + elf->start_offset 207da0c48c4Sopenharmony_ci + MAX (elf_typesize (LIBELFBITS, ELF_T_EHDR, 1), 208da0c48c4Sopenharmony_ci ehdr->e_phoff) 209da0c48c4Sopenharmony_ci + elf_typesize (LIBELFBITS, ELF_T_PHDR, phnum)); 210da0c48c4Sopenharmony_ci 211da0c48c4Sopenharmony_ci /* Write all the sections. Well, only those which are modified. */ 212da0c48c4Sopenharmony_ci if (shnum > 0) 213da0c48c4Sopenharmony_ci { 214da0c48c4Sopenharmony_ci if (unlikely (shnum > SIZE_MAX / sizeof (Elf_Scn *))) 215da0c48c4Sopenharmony_ci return 1; 216da0c48c4Sopenharmony_ci 217da0c48c4Sopenharmony_ci Elf_ScnList *list = &elf->state.ELFW(elf,LIBELFBITS).scns; 218da0c48c4Sopenharmony_ci Elf_Scn **scns = malloc (shnum * sizeof (Elf_Scn *)); 219da0c48c4Sopenharmony_ci if (unlikely (scns == NULL)) 220da0c48c4Sopenharmony_ci { 221da0c48c4Sopenharmony_ci __libelf_seterrno (ELF_E_NOMEM); 222da0c48c4Sopenharmony_ci return -1; 223da0c48c4Sopenharmony_ci } 224da0c48c4Sopenharmony_ci char *const shdr_start = ((char *) elf->map_address + elf->start_offset 225da0c48c4Sopenharmony_ci + ehdr->e_shoff); 226da0c48c4Sopenharmony_ci char *const shdr_end = shdr_start + shnum * ehdr->e_shentsize; 227da0c48c4Sopenharmony_ci 228da0c48c4Sopenharmony_ci#undef shdr_fctp 229da0c48c4Sopenharmony_ci#define shdr_fctp __elf_xfctstom[ELFW(ELFCLASS, LIBELFBITS) - 1][ELF_T_SHDR] 230da0c48c4Sopenharmony_ci#define shdr_dest ((ElfW2(LIBELFBITS,Shdr) *) shdr_start) 231da0c48c4Sopenharmony_ci 232da0c48c4Sopenharmony_ci /* Get all sections into the array and sort them. */ 233da0c48c4Sopenharmony_ci sort_sections (scns, list); 234da0c48c4Sopenharmony_ci 235da0c48c4Sopenharmony_ci /* We possibly have to copy the section header data because moving 236da0c48c4Sopenharmony_ci the sections might overwrite the data. */ 237da0c48c4Sopenharmony_ci for (size_t cnt = 0; cnt < shnum; ++cnt) 238da0c48c4Sopenharmony_ci { 239da0c48c4Sopenharmony_ci Elf_Scn *scn = scns[cnt]; 240da0c48c4Sopenharmony_ci 241da0c48c4Sopenharmony_ci if (!elf->state.ELFW(elf,LIBELFBITS).shdr_malloced 242da0c48c4Sopenharmony_ci && (scn->shdr_flags & ELF_F_MALLOCED) == 0 243da0c48c4Sopenharmony_ci && scn->shdr.ELFW(e,LIBELFBITS) != &shdr_dest[scn->index]) 244da0c48c4Sopenharmony_ci { 245da0c48c4Sopenharmony_ci assert ((char *) elf->map_address + elf->start_offset 246da0c48c4Sopenharmony_ci < (char *) scn->shdr.ELFW(e,LIBELFBITS)); 247da0c48c4Sopenharmony_ci assert ((char *) scn->shdr.ELFW(e,LIBELFBITS) 248da0c48c4Sopenharmony_ci < ((char *) elf->map_address + elf->start_offset 249da0c48c4Sopenharmony_ci + elf->maximum_size)); 250da0c48c4Sopenharmony_ci 251da0c48c4Sopenharmony_ci void *p = malloc (sizeof (ElfW2(LIBELFBITS,Shdr))); 252da0c48c4Sopenharmony_ci if (unlikely (p == NULL)) 253da0c48c4Sopenharmony_ci { 254da0c48c4Sopenharmony_ci free (scns); 255da0c48c4Sopenharmony_ci __libelf_seterrno (ELF_E_NOMEM); 256da0c48c4Sopenharmony_ci return -1; 257da0c48c4Sopenharmony_ci } 258da0c48c4Sopenharmony_ci scn->shdr.ELFW(e,LIBELFBITS) 259da0c48c4Sopenharmony_ci = memcpy (p, scn->shdr.ELFW(e,LIBELFBITS), 260da0c48c4Sopenharmony_ci sizeof (ElfW2(LIBELFBITS,Shdr))); 261da0c48c4Sopenharmony_ci } 262da0c48c4Sopenharmony_ci 263da0c48c4Sopenharmony_ci /* If the file is mmaped and the original position of the 264da0c48c4Sopenharmony_ci section in the file is lower than the new position we 265da0c48c4Sopenharmony_ci need to save the section content since otherwise it is 266da0c48c4Sopenharmony_ci overwritten before it can be copied. If there are 267da0c48c4Sopenharmony_ci multiple data segments in the list only the first can be 268da0c48c4Sopenharmony_ci from the file. */ 269da0c48c4Sopenharmony_ci if (((char *) elf->map_address + elf->start_offset 270da0c48c4Sopenharmony_ci <= (char *) scn->data_list.data.d.d_buf) 271da0c48c4Sopenharmony_ci && ((char *) scn->data_list.data.d.d_buf 272da0c48c4Sopenharmony_ci < ((char *) elf->map_address + elf->start_offset 273da0c48c4Sopenharmony_ci + elf->maximum_size)) 274da0c48c4Sopenharmony_ci && (((char *) elf->map_address + elf->start_offset 275da0c48c4Sopenharmony_ci + scn->shdr.ELFW(e,LIBELFBITS)->sh_offset) 276da0c48c4Sopenharmony_ci > (char *) scn->data_list.data.d.d_buf)) 277da0c48c4Sopenharmony_ci { 278da0c48c4Sopenharmony_ci void *p = malloc (scn->data_list.data.d.d_size); 279da0c48c4Sopenharmony_ci if (unlikely (p == NULL)) 280da0c48c4Sopenharmony_ci { 281da0c48c4Sopenharmony_ci free (scns); 282da0c48c4Sopenharmony_ci __libelf_seterrno (ELF_E_NOMEM); 283da0c48c4Sopenharmony_ci return -1; 284da0c48c4Sopenharmony_ci } 285da0c48c4Sopenharmony_ci scn->data_list.data.d.d_buf = scn->data_base 286da0c48c4Sopenharmony_ci = memcpy (p, scn->data_list.data.d.d_buf, 287da0c48c4Sopenharmony_ci scn->data_list.data.d.d_size); 288da0c48c4Sopenharmony_ci } 289da0c48c4Sopenharmony_ci } 290da0c48c4Sopenharmony_ci 291da0c48c4Sopenharmony_ci /* Iterate over all the section in the order in which they 292da0c48c4Sopenharmony_ci appear in the output file. */ 293da0c48c4Sopenharmony_ci for (size_t cnt = 0; cnt < shnum; ++cnt) 294da0c48c4Sopenharmony_ci { 295da0c48c4Sopenharmony_ci Elf_Scn *scn = scns[cnt]; 296da0c48c4Sopenharmony_ci if (scn->index == 0) 297da0c48c4Sopenharmony_ci { 298da0c48c4Sopenharmony_ci /* The dummy section header entry. It should not be 299da0c48c4Sopenharmony_ci possible to mark this "section" as dirty. */ 300da0c48c4Sopenharmony_ci assert ((scn->flags & ELF_F_DIRTY) == 0); 301da0c48c4Sopenharmony_ci continue; 302da0c48c4Sopenharmony_ci } 303da0c48c4Sopenharmony_ci 304da0c48c4Sopenharmony_ci ElfW2(LIBELFBITS,Shdr) *shdr = scn->shdr.ELFW(e,LIBELFBITS); 305da0c48c4Sopenharmony_ci if (shdr->sh_type == SHT_NOBITS) 306da0c48c4Sopenharmony_ci goto next; 307da0c48c4Sopenharmony_ci 308da0c48c4Sopenharmony_ci char *scn_start = ((char *) elf->map_address 309da0c48c4Sopenharmony_ci + elf->start_offset + shdr->sh_offset); 310da0c48c4Sopenharmony_ci Elf_Data_List *dl = &scn->data_list; 311da0c48c4Sopenharmony_ci bool scn_changed = false; 312da0c48c4Sopenharmony_ci 313da0c48c4Sopenharmony_ci if (scn->data_list_rear != NULL) 314da0c48c4Sopenharmony_ci do 315da0c48c4Sopenharmony_ci { 316da0c48c4Sopenharmony_ci assert (dl->data.d.d_off >= 0); 317da0c48c4Sopenharmony_ci assert ((GElf_Off) dl->data.d.d_off <= shdr->sh_size); 318da0c48c4Sopenharmony_ci assert (dl->data.d.d_size <= (shdr->sh_size 319da0c48c4Sopenharmony_ci - (GElf_Off) dl->data.d.d_off)); 320da0c48c4Sopenharmony_ci 321da0c48c4Sopenharmony_ci /* If there is a gap, fill it. */ 322da0c48c4Sopenharmony_ci if (scn_start + dl->data.d.d_off > last_position 323da0c48c4Sopenharmony_ci && (dl->data.d.d_off == 0 324da0c48c4Sopenharmony_ci || ((scn->flags | dl->flags | elf->flags) 325da0c48c4Sopenharmony_ci & ELF_F_DIRTY) != 0)) 326da0c48c4Sopenharmony_ci { 327da0c48c4Sopenharmony_ci fill_mmap (dl->data.d.d_off, last_position, scn_start, 328da0c48c4Sopenharmony_ci shdr_start, shdr_end); 329da0c48c4Sopenharmony_ci } 330da0c48c4Sopenharmony_ci 331da0c48c4Sopenharmony_ci last_position = scn_start + dl->data.d.d_off; 332da0c48c4Sopenharmony_ci 333da0c48c4Sopenharmony_ci if ((scn->flags | dl->flags | elf->flags) & ELF_F_DIRTY) 334da0c48c4Sopenharmony_ci { 335da0c48c4Sopenharmony_ci /* Let it go backward if the sections use a bogus 336da0c48c4Sopenharmony_ci layout with overlaps. We'll overwrite the stupid 337da0c48c4Sopenharmony_ci user's section data with the latest one, rather than 338da0c48c4Sopenharmony_ci crashing. */ 339da0c48c4Sopenharmony_ci 340da0c48c4Sopenharmony_ci if (unlikely (change_bo 341da0c48c4Sopenharmony_ci && dl->data.d.d_size != 0 342da0c48c4Sopenharmony_ci && dl->data.d.d_type != ELF_T_BYTE)) 343da0c48c4Sopenharmony_ci { 344da0c48c4Sopenharmony_ci#undef fctp 345da0c48c4Sopenharmony_ci#define fctp __elf_xfctstom[ELFW(ELFCLASS, LIBELFBITS) - 1][dl->data.d.d_type] 346da0c48c4Sopenharmony_ci 347da0c48c4Sopenharmony_ci size_t align; 348da0c48c4Sopenharmony_ci align = __libelf_type_align (ELFW(ELFCLASS,LIBELFBITS), 349da0c48c4Sopenharmony_ci dl->data.d.d_type); 350da0c48c4Sopenharmony_ci if ((((uintptr_t) last_position) 351da0c48c4Sopenharmony_ci & (uintptr_t) (align - 1)) == 0) 352da0c48c4Sopenharmony_ci { 353da0c48c4Sopenharmony_ci /* No need to copy, we can convert directly. */ 354da0c48c4Sopenharmony_ci (*fctp) (last_position, dl->data.d.d_buf, 355da0c48c4Sopenharmony_ci dl->data.d.d_size, 1); 356da0c48c4Sopenharmony_ci } 357da0c48c4Sopenharmony_ci else 358da0c48c4Sopenharmony_ci { 359da0c48c4Sopenharmony_ci /* We have to do the conversion on properly 360da0c48c4Sopenharmony_ci aligned memory first. align is a power of 2, 361da0c48c4Sopenharmony_ci but posix_memalign only works for alignments 362da0c48c4Sopenharmony_ci which are a multiple of sizeof (void *). 363da0c48c4Sopenharmony_ci So use normal malloc for smaller alignments. */ 364da0c48c4Sopenharmony_ci size_t size = dl->data.d.d_size; 365da0c48c4Sopenharmony_ci void *converted; 366da0c48c4Sopenharmony_ci if (align < sizeof (void *)) 367da0c48c4Sopenharmony_ci converted = malloc (size); 368da0c48c4Sopenharmony_ci else 369da0c48c4Sopenharmony_ci { 370da0c48c4Sopenharmony_ci int res; 371da0c48c4Sopenharmony_ci res = posix_memalign (&converted, align, size); 372da0c48c4Sopenharmony_ci if (res != 0) 373da0c48c4Sopenharmony_ci converted = NULL; 374da0c48c4Sopenharmony_ci } 375da0c48c4Sopenharmony_ci 376da0c48c4Sopenharmony_ci if (converted == NULL) 377da0c48c4Sopenharmony_ci { 378da0c48c4Sopenharmony_ci free (scns); 379da0c48c4Sopenharmony_ci __libelf_seterrno (ELF_E_NOMEM); 380da0c48c4Sopenharmony_ci return 1; 381da0c48c4Sopenharmony_ci } 382da0c48c4Sopenharmony_ci 383da0c48c4Sopenharmony_ci (*fctp) (converted, dl->data.d.d_buf, size, 1); 384da0c48c4Sopenharmony_ci 385da0c48c4Sopenharmony_ci /* And then write it to the mmapped file. */ 386da0c48c4Sopenharmony_ci memcpy (last_position, converted, size); 387da0c48c4Sopenharmony_ci free (converted); 388da0c48c4Sopenharmony_ci } 389da0c48c4Sopenharmony_ci 390da0c48c4Sopenharmony_ci last_position += dl->data.d.d_size; 391da0c48c4Sopenharmony_ci } 392da0c48c4Sopenharmony_ci else if (dl->data.d.d_size != 0) 393da0c48c4Sopenharmony_ci { 394da0c48c4Sopenharmony_ci memmove (last_position, dl->data.d.d_buf, 395da0c48c4Sopenharmony_ci dl->data.d.d_size); 396da0c48c4Sopenharmony_ci last_position += dl->data.d.d_size; 397da0c48c4Sopenharmony_ci } 398da0c48c4Sopenharmony_ci 399da0c48c4Sopenharmony_ci scn_changed = true; 400da0c48c4Sopenharmony_ci } 401da0c48c4Sopenharmony_ci else 402da0c48c4Sopenharmony_ci last_position += dl->data.d.d_size; 403da0c48c4Sopenharmony_ci 404da0c48c4Sopenharmony_ci assert (scn_start + dl->data.d.d_off + dl->data.d.d_size 405da0c48c4Sopenharmony_ci == last_position); 406da0c48c4Sopenharmony_ci 407da0c48c4Sopenharmony_ci dl->flags &= ~ELF_F_DIRTY; 408da0c48c4Sopenharmony_ci 409da0c48c4Sopenharmony_ci dl = dl->next; 410da0c48c4Sopenharmony_ci } 411da0c48c4Sopenharmony_ci while (dl != NULL); 412da0c48c4Sopenharmony_ci else 413da0c48c4Sopenharmony_ci { 414da0c48c4Sopenharmony_ci /* If the previous section (or the ELF/program 415da0c48c4Sopenharmony_ci header) changed we might have to fill the gap. */ 416da0c48c4Sopenharmony_ci if (scn_start > last_position && previous_scn_changed) 417da0c48c4Sopenharmony_ci fill_mmap (0, last_position, scn_start, 418da0c48c4Sopenharmony_ci shdr_start, shdr_end); 419da0c48c4Sopenharmony_ci 420da0c48c4Sopenharmony_ci /* We have to trust the existing section header information. */ 421da0c48c4Sopenharmony_ci last_position = scn_start + shdr->sh_size; 422da0c48c4Sopenharmony_ci } 423da0c48c4Sopenharmony_ci 424da0c48c4Sopenharmony_ci 425da0c48c4Sopenharmony_ci previous_scn_changed = scn_changed; 426da0c48c4Sopenharmony_ci next: 427da0c48c4Sopenharmony_ci scn->flags &= ~ELF_F_DIRTY; 428da0c48c4Sopenharmony_ci } 429da0c48c4Sopenharmony_ci 430da0c48c4Sopenharmony_ci /* Fill the gap between last section and section header table if 431da0c48c4Sopenharmony_ci necessary. */ 432da0c48c4Sopenharmony_ci if ((elf->flags & ELF_F_DIRTY) 433da0c48c4Sopenharmony_ci && last_position < ((char *) elf->map_address + elf->start_offset 434da0c48c4Sopenharmony_ci + ehdr->e_shoff)) 435da0c48c4Sopenharmony_ci memset (last_position, __libelf_fill_byte, 436da0c48c4Sopenharmony_ci (char *) elf->map_address + elf->start_offset + ehdr->e_shoff 437da0c48c4Sopenharmony_ci - last_position); 438da0c48c4Sopenharmony_ci 439da0c48c4Sopenharmony_ci /* Write the section header table entry if necessary. */ 440da0c48c4Sopenharmony_ci for (size_t cnt = 0; cnt < shnum; ++cnt) 441da0c48c4Sopenharmony_ci { 442da0c48c4Sopenharmony_ci Elf_Scn *scn = scns[cnt]; 443da0c48c4Sopenharmony_ci 444da0c48c4Sopenharmony_ci if ((scn->shdr_flags | elf->flags) & ELF_F_DIRTY) 445da0c48c4Sopenharmony_ci { 446da0c48c4Sopenharmony_ci if (unlikely (change_bo)) 447da0c48c4Sopenharmony_ci (*shdr_fctp) (&shdr_dest[scn->index], 448da0c48c4Sopenharmony_ci scn->shdr.ELFW(e,LIBELFBITS), 449da0c48c4Sopenharmony_ci sizeof (ElfW2(LIBELFBITS,Shdr)), 1); 450da0c48c4Sopenharmony_ci else 451da0c48c4Sopenharmony_ci memcpy (&shdr_dest[scn->index], 452da0c48c4Sopenharmony_ci scn->shdr.ELFW(e,LIBELFBITS), 453da0c48c4Sopenharmony_ci sizeof (ElfW2(LIBELFBITS,Shdr))); 454da0c48c4Sopenharmony_ci 455da0c48c4Sopenharmony_ci /* If we previously made a copy of the section header 456da0c48c4Sopenharmony_ci entry we now have to adjust the pointer again so 457da0c48c4Sopenharmony_ci point to new place in the mapping. */ 458da0c48c4Sopenharmony_ci if (!elf->state.ELFW(elf,LIBELFBITS).shdr_malloced 459da0c48c4Sopenharmony_ci && (scn->shdr_flags & ELF_F_MALLOCED) == 0 460da0c48c4Sopenharmony_ci && scn->shdr.ELFW(e,LIBELFBITS) != &shdr_dest[scn->index]) 461da0c48c4Sopenharmony_ci { 462da0c48c4Sopenharmony_ci free (scn->shdr.ELFW(e,LIBELFBITS)); 463da0c48c4Sopenharmony_ci scn->shdr.ELFW(e,LIBELFBITS) = &shdr_dest[scn->index]; 464da0c48c4Sopenharmony_ci } 465da0c48c4Sopenharmony_ci 466da0c48c4Sopenharmony_ci scn->shdr_flags &= ~ELF_F_DIRTY; 467da0c48c4Sopenharmony_ci } 468da0c48c4Sopenharmony_ci } 469da0c48c4Sopenharmony_ci free (scns); 470da0c48c4Sopenharmony_ci } 471da0c48c4Sopenharmony_ci 472da0c48c4Sopenharmony_ci /* That was the last part. Clear the overall flag. */ 473da0c48c4Sopenharmony_ci elf->flags &= ~ELF_F_DIRTY; 474da0c48c4Sopenharmony_ci 475da0c48c4Sopenharmony_ci /* Make sure the content hits the disk. */ 476da0c48c4Sopenharmony_ci char *msync_start = ((char *) elf->map_address 477da0c48c4Sopenharmony_ci + (elf->start_offset & ~(sysconf (_SC_PAGESIZE) - 1))); 478da0c48c4Sopenharmony_ci char *msync_end = ((char *) elf->map_address 479da0c48c4Sopenharmony_ci + elf->start_offset + ehdr->e_shoff 480da0c48c4Sopenharmony_ci + ehdr->e_shentsize * shnum); 481da0c48c4Sopenharmony_ci (void) msync (msync_start, msync_end - msync_start, MS_SYNC); 482da0c48c4Sopenharmony_ci 483da0c48c4Sopenharmony_ci return 0; 484da0c48c4Sopenharmony_ci} 485da0c48c4Sopenharmony_ci 486da0c48c4Sopenharmony_ci 487da0c48c4Sopenharmony_ci/* Size of the buffer we use to generate the blocks of fill bytes. */ 488da0c48c4Sopenharmony_ci#define FILLBUFSIZE 4096 489da0c48c4Sopenharmony_ci 490da0c48c4Sopenharmony_ci/* If we have to convert the section buffer contents we have to use 491da0c48c4Sopenharmony_ci temporary buffer. Only buffers up to MAX_TMPBUF bytes are allocated 492da0c48c4Sopenharmony_ci on the stack. */ 493da0c48c4Sopenharmony_ci#define MAX_TMPBUF 32768 494da0c48c4Sopenharmony_ci 495da0c48c4Sopenharmony_ci 496da0c48c4Sopenharmony_ci/* Helper function to write out fill bytes. */ 497da0c48c4Sopenharmony_cistatic int 498da0c48c4Sopenharmony_cifill (int fd, int64_t pos, size_t len, char *fillbuf, size_t *filledp) 499da0c48c4Sopenharmony_ci{ 500da0c48c4Sopenharmony_ci size_t filled = *filledp; 501da0c48c4Sopenharmony_ci size_t fill_len = MIN (len, FILLBUFSIZE); 502da0c48c4Sopenharmony_ci 503da0c48c4Sopenharmony_ci if (unlikely (fill_len > filled) && filled < FILLBUFSIZE) 504da0c48c4Sopenharmony_ci { 505da0c48c4Sopenharmony_ci /* Initialize a few more bytes. */ 506da0c48c4Sopenharmony_ci memset (fillbuf + filled, __libelf_fill_byte, fill_len - filled); 507da0c48c4Sopenharmony_ci *filledp = filled = fill_len; 508da0c48c4Sopenharmony_ci } 509da0c48c4Sopenharmony_ci 510da0c48c4Sopenharmony_ci do 511da0c48c4Sopenharmony_ci { 512da0c48c4Sopenharmony_ci /* This many bytes we want to write in this round. */ 513da0c48c4Sopenharmony_ci size_t n = MIN (filled, len); 514da0c48c4Sopenharmony_ci 515da0c48c4Sopenharmony_ci if (unlikely ((size_t) pwrite_retry (fd, fillbuf, n, pos) != n)) 516da0c48c4Sopenharmony_ci { 517da0c48c4Sopenharmony_ci __libelf_seterrno (ELF_E_WRITE_ERROR); 518da0c48c4Sopenharmony_ci return 1; 519da0c48c4Sopenharmony_ci } 520da0c48c4Sopenharmony_ci 521da0c48c4Sopenharmony_ci pos += n; 522da0c48c4Sopenharmony_ci len -= n; 523da0c48c4Sopenharmony_ci } 524da0c48c4Sopenharmony_ci while (len > 0); 525da0c48c4Sopenharmony_ci 526da0c48c4Sopenharmony_ci return 0; 527da0c48c4Sopenharmony_ci} 528da0c48c4Sopenharmony_ci 529da0c48c4Sopenharmony_ci 530da0c48c4Sopenharmony_ciint 531da0c48c4Sopenharmony_ciinternal_function 532da0c48c4Sopenharmony_ci__elfw2(LIBELFBITS,updatefile) (Elf *elf, int change_bo, size_t shnum) 533da0c48c4Sopenharmony_ci{ 534da0c48c4Sopenharmony_ci char fillbuf[FILLBUFSIZE]; 535da0c48c4Sopenharmony_ci size_t filled = 0; 536da0c48c4Sopenharmony_ci bool previous_scn_changed = false; 537da0c48c4Sopenharmony_ci 538da0c48c4Sopenharmony_ci /* We need the ELF header several times. */ 539da0c48c4Sopenharmony_ci ElfW2(LIBELFBITS,Ehdr) *ehdr = elf->state.ELFW(elf,LIBELFBITS).ehdr; 540da0c48c4Sopenharmony_ci 541da0c48c4Sopenharmony_ci /* Write out the ELF header. */ 542da0c48c4Sopenharmony_ci if ((elf->state.ELFW(elf,LIBELFBITS).ehdr_flags | elf->flags) & ELF_F_DIRTY) 543da0c48c4Sopenharmony_ci { 544da0c48c4Sopenharmony_ci ElfW2(LIBELFBITS,Ehdr) tmp_ehdr; 545da0c48c4Sopenharmony_ci ElfW2(LIBELFBITS,Ehdr) *out_ehdr = ehdr; 546da0c48c4Sopenharmony_ci 547da0c48c4Sopenharmony_ci /* If the type sizes should be different at some time we have to 548da0c48c4Sopenharmony_ci rewrite this code. */ 549da0c48c4Sopenharmony_ci assert (sizeof (ElfW2(LIBELFBITS,Ehdr)) 550da0c48c4Sopenharmony_ci == elf_typesize (LIBELFBITS, ELF_T_EHDR, 1)); 551da0c48c4Sopenharmony_ci 552da0c48c4Sopenharmony_ci if (unlikely (change_bo)) 553da0c48c4Sopenharmony_ci { 554da0c48c4Sopenharmony_ci /* Today there is only one version of the ELF header. */ 555da0c48c4Sopenharmony_ci#undef fctp 556da0c48c4Sopenharmony_ci#define fctp __elf_xfctstom[ELFW(ELFCLASS, LIBELFBITS) - 1][ELF_T_EHDR] 557da0c48c4Sopenharmony_ci 558da0c48c4Sopenharmony_ci /* Write the converted ELF header in a temporary buffer. */ 559da0c48c4Sopenharmony_ci (*fctp) (&tmp_ehdr, ehdr, sizeof (ElfW2(LIBELFBITS,Ehdr)), 1); 560da0c48c4Sopenharmony_ci 561da0c48c4Sopenharmony_ci /* This is the buffer we want to write. */ 562da0c48c4Sopenharmony_ci out_ehdr = &tmp_ehdr; 563da0c48c4Sopenharmony_ci } 564da0c48c4Sopenharmony_ci 565da0c48c4Sopenharmony_ci /* Write out the ELF header. */ 566da0c48c4Sopenharmony_ci if (unlikely (pwrite_retry (elf->fildes, out_ehdr, 567da0c48c4Sopenharmony_ci sizeof (ElfW2(LIBELFBITS,Ehdr)), 0) 568da0c48c4Sopenharmony_ci != sizeof (ElfW2(LIBELFBITS,Ehdr)))) 569da0c48c4Sopenharmony_ci { 570da0c48c4Sopenharmony_ci __libelf_seterrno (ELF_E_WRITE_ERROR); 571da0c48c4Sopenharmony_ci return 1; 572da0c48c4Sopenharmony_ci } 573da0c48c4Sopenharmony_ci 574da0c48c4Sopenharmony_ci elf->state.ELFW(elf,LIBELFBITS).ehdr_flags &= ~ELF_F_DIRTY; 575da0c48c4Sopenharmony_ci 576da0c48c4Sopenharmony_ci /* We start writing sections after the ELF header only if there is 577da0c48c4Sopenharmony_ci no program header. */ 578da0c48c4Sopenharmony_ci previous_scn_changed = elf->state.ELFW(elf,LIBELFBITS).phdr == NULL; 579da0c48c4Sopenharmony_ci } 580da0c48c4Sopenharmony_ci 581da0c48c4Sopenharmony_ci /* If the type sizes should be different at some time we have to 582da0c48c4Sopenharmony_ci rewrite this code. */ 583da0c48c4Sopenharmony_ci assert (sizeof (ElfW2(LIBELFBITS,Phdr)) 584da0c48c4Sopenharmony_ci == elf_typesize (LIBELFBITS, ELF_T_PHDR, 1)); 585da0c48c4Sopenharmony_ci 586da0c48c4Sopenharmony_ci size_t phnum; 587da0c48c4Sopenharmony_ci if (unlikely (__elf_getphdrnum_rdlock (elf, &phnum) != 0)) 588da0c48c4Sopenharmony_ci return -1; 589da0c48c4Sopenharmony_ci 590da0c48c4Sopenharmony_ci /* Write out the program header table. */ 591da0c48c4Sopenharmony_ci if (elf->state.ELFW(elf,LIBELFBITS).phdr != NULL 592da0c48c4Sopenharmony_ci && ((elf->state.ELFW(elf,LIBELFBITS).phdr_flags | elf->flags) 593da0c48c4Sopenharmony_ci & ELF_F_DIRTY)) 594da0c48c4Sopenharmony_ci { 595da0c48c4Sopenharmony_ci ElfW2(LIBELFBITS,Phdr) *tmp_phdr = NULL; 596da0c48c4Sopenharmony_ci ElfW2(LIBELFBITS,Phdr) *out_phdr = elf->state.ELFW(elf,LIBELFBITS).phdr; 597da0c48c4Sopenharmony_ci 598da0c48c4Sopenharmony_ci /* Maybe the user wants a gap between the ELF header and the program 599da0c48c4Sopenharmony_ci header. */ 600da0c48c4Sopenharmony_ci if (ehdr->e_phoff > ehdr->e_ehsize 601da0c48c4Sopenharmony_ci && unlikely (fill (elf->fildes, ehdr->e_ehsize, 602da0c48c4Sopenharmony_ci ehdr->e_phoff - ehdr->e_ehsize, fillbuf, &filled) 603da0c48c4Sopenharmony_ci != 0)) 604da0c48c4Sopenharmony_ci return 1; 605da0c48c4Sopenharmony_ci 606da0c48c4Sopenharmony_ci if (unlikely (change_bo)) 607da0c48c4Sopenharmony_ci { 608da0c48c4Sopenharmony_ci /* Today there is only one version of the ELF header. */ 609da0c48c4Sopenharmony_ci#undef fctp 610da0c48c4Sopenharmony_ci#define fctp __elf_xfctstom[ELFW(ELFCLASS, LIBELFBITS) - 1][ELF_T_PHDR] 611da0c48c4Sopenharmony_ci 612da0c48c4Sopenharmony_ci /* Allocate sufficient memory. */ 613da0c48c4Sopenharmony_ci tmp_phdr = (ElfW2(LIBELFBITS,Phdr) *) 614da0c48c4Sopenharmony_ci malloc (sizeof (ElfW2(LIBELFBITS,Phdr)) * phnum); 615da0c48c4Sopenharmony_ci if (unlikely (tmp_phdr == NULL)) 616da0c48c4Sopenharmony_ci { 617da0c48c4Sopenharmony_ci __libelf_seterrno (ELF_E_NOMEM); 618da0c48c4Sopenharmony_ci return 1; 619da0c48c4Sopenharmony_ci } 620da0c48c4Sopenharmony_ci 621da0c48c4Sopenharmony_ci /* Write the converted ELF header in a temporary buffer. */ 622da0c48c4Sopenharmony_ci (*fctp) (tmp_phdr, elf->state.ELFW(elf,LIBELFBITS).phdr, 623da0c48c4Sopenharmony_ci sizeof (ElfW2(LIBELFBITS,Phdr)) * phnum, 1); 624da0c48c4Sopenharmony_ci 625da0c48c4Sopenharmony_ci /* This is the buffer we want to write. */ 626da0c48c4Sopenharmony_ci out_phdr = tmp_phdr; 627da0c48c4Sopenharmony_ci } 628da0c48c4Sopenharmony_ci 629da0c48c4Sopenharmony_ci /* Write out the ELF header. */ 630da0c48c4Sopenharmony_ci size_t phdr_size = sizeof (ElfW2(LIBELFBITS,Phdr)) * phnum; 631da0c48c4Sopenharmony_ci if (unlikely ((size_t) pwrite_retry (elf->fildes, out_phdr, 632da0c48c4Sopenharmony_ci phdr_size, ehdr->e_phoff) 633da0c48c4Sopenharmony_ci != phdr_size)) 634da0c48c4Sopenharmony_ci { 635da0c48c4Sopenharmony_ci __libelf_seterrno (ELF_E_WRITE_ERROR); 636da0c48c4Sopenharmony_ci return 1; 637da0c48c4Sopenharmony_ci } 638da0c48c4Sopenharmony_ci 639da0c48c4Sopenharmony_ci /* This is a no-op we we have not allocated any memory. */ 640da0c48c4Sopenharmony_ci free (tmp_phdr); 641da0c48c4Sopenharmony_ci 642da0c48c4Sopenharmony_ci elf->state.ELFW(elf,LIBELFBITS).phdr_flags &= ~ELF_F_DIRTY; 643da0c48c4Sopenharmony_ci 644da0c48c4Sopenharmony_ci /* We modified the program header. Maybe this created a gap so 645da0c48c4Sopenharmony_ci we have to write fill bytes, if necessary. */ 646da0c48c4Sopenharmony_ci previous_scn_changed = true; 647da0c48c4Sopenharmony_ci } 648da0c48c4Sopenharmony_ci 649da0c48c4Sopenharmony_ci /* From now on we have to keep track of the last position to eventually 650da0c48c4Sopenharmony_ci fill the gaps with the prescribed fill byte. */ 651da0c48c4Sopenharmony_ci int64_t last_offset; 652da0c48c4Sopenharmony_ci if (elf->state.ELFW(elf,LIBELFBITS).phdr == NULL) 653da0c48c4Sopenharmony_ci last_offset = elf_typesize (LIBELFBITS, ELF_T_EHDR, 1); 654da0c48c4Sopenharmony_ci else 655da0c48c4Sopenharmony_ci last_offset = (ehdr->e_phoff + sizeof (ElfW2(LIBELFBITS,Phdr)) * phnum); 656da0c48c4Sopenharmony_ci 657da0c48c4Sopenharmony_ci /* Write all the sections. Well, only those which are modified. */ 658da0c48c4Sopenharmony_ci if (shnum > 0) 659da0c48c4Sopenharmony_ci { 660da0c48c4Sopenharmony_ci if (unlikely (shnum > SIZE_MAX / (sizeof (Elf_Scn *) 661da0c48c4Sopenharmony_ci + sizeof (ElfW2(LIBELFBITS,Shdr))))) 662da0c48c4Sopenharmony_ci return 1; 663da0c48c4Sopenharmony_ci 664da0c48c4Sopenharmony_ci int64_t shdr_offset = elf->start_offset + ehdr->e_shoff; 665da0c48c4Sopenharmony_ci#undef shdr_fctp 666da0c48c4Sopenharmony_ci#define shdr_fctp __elf_xfctstom[ELFW(ELFCLASS, LIBELFBITS) - 1][ELF_T_SHDR] 667da0c48c4Sopenharmony_ci 668da0c48c4Sopenharmony_ci ElfW2(LIBELFBITS,Shdr) *shdr_data; 669da0c48c4Sopenharmony_ci ElfW2(LIBELFBITS,Shdr) *shdr_data_mem = NULL; 670da0c48c4Sopenharmony_ci if (change_bo || elf->state.ELFW(elf,LIBELFBITS).shdr == NULL 671da0c48c4Sopenharmony_ci || (elf->flags & ELF_F_DIRTY)) 672da0c48c4Sopenharmony_ci { 673da0c48c4Sopenharmony_ci shdr_data_mem = (ElfW2(LIBELFBITS,Shdr) *) 674da0c48c4Sopenharmony_ci malloc (shnum * sizeof (ElfW2(LIBELFBITS,Shdr))); 675da0c48c4Sopenharmony_ci if (unlikely (shdr_data_mem == NULL)) 676da0c48c4Sopenharmony_ci { 677da0c48c4Sopenharmony_ci __libelf_seterrno (ELF_E_NOMEM); 678da0c48c4Sopenharmony_ci return -1; 679da0c48c4Sopenharmony_ci } 680da0c48c4Sopenharmony_ci shdr_data = shdr_data_mem; 681da0c48c4Sopenharmony_ci } 682da0c48c4Sopenharmony_ci else 683da0c48c4Sopenharmony_ci shdr_data = elf->state.ELFW(elf,LIBELFBITS).shdr; 684da0c48c4Sopenharmony_ci int shdr_flags = elf->flags; 685da0c48c4Sopenharmony_ci 686da0c48c4Sopenharmony_ci /* Get all sections into the array and sort them. */ 687da0c48c4Sopenharmony_ci Elf_ScnList *list = &elf->state.ELFW(elf,LIBELFBITS).scns; 688da0c48c4Sopenharmony_ci Elf_Scn **scns = malloc (shnum * sizeof (Elf_Scn *)); 689da0c48c4Sopenharmony_ci if (unlikely (scns == NULL)) 690da0c48c4Sopenharmony_ci { 691da0c48c4Sopenharmony_ci free (shdr_data_mem); 692da0c48c4Sopenharmony_ci __libelf_seterrno (ELF_E_NOMEM); 693da0c48c4Sopenharmony_ci return -1; 694da0c48c4Sopenharmony_ci } 695da0c48c4Sopenharmony_ci sort_sections (scns, list); 696da0c48c4Sopenharmony_ci 697da0c48c4Sopenharmony_ci for (size_t cnt = 0; cnt < shnum; ++cnt) 698da0c48c4Sopenharmony_ci { 699da0c48c4Sopenharmony_ci Elf_Scn *scn = scns[cnt]; 700da0c48c4Sopenharmony_ci if (scn->index == 0) 701da0c48c4Sopenharmony_ci { 702da0c48c4Sopenharmony_ci /* The dummy section header entry. It should not be 703da0c48c4Sopenharmony_ci possible to mark this "section" as dirty. */ 704da0c48c4Sopenharmony_ci assert ((scn->flags & ELF_F_DIRTY) == 0); 705da0c48c4Sopenharmony_ci goto next; 706da0c48c4Sopenharmony_ci } 707da0c48c4Sopenharmony_ci 708da0c48c4Sopenharmony_ci ElfW2(LIBELFBITS,Shdr) *shdr = scn->shdr.ELFW(e,LIBELFBITS); 709da0c48c4Sopenharmony_ci if (shdr->sh_type == SHT_NOBITS) 710da0c48c4Sopenharmony_ci goto next; 711da0c48c4Sopenharmony_ci 712da0c48c4Sopenharmony_ci int64_t scn_start = elf->start_offset + shdr->sh_offset; 713da0c48c4Sopenharmony_ci Elf_Data_List *dl = &scn->data_list; 714da0c48c4Sopenharmony_ci bool scn_changed = false; 715da0c48c4Sopenharmony_ci 716da0c48c4Sopenharmony_ci if (scn->data_list_rear != NULL) 717da0c48c4Sopenharmony_ci do 718da0c48c4Sopenharmony_ci { 719da0c48c4Sopenharmony_ci /* If there is a gap, fill it. */ 720da0c48c4Sopenharmony_ci if (scn_start + dl->data.d.d_off > last_offset 721da0c48c4Sopenharmony_ci && ((previous_scn_changed && dl->data.d.d_off == 0) 722da0c48c4Sopenharmony_ci || ((scn->flags | dl->flags | elf->flags) 723da0c48c4Sopenharmony_ci & ELF_F_DIRTY) != 0)) 724da0c48c4Sopenharmony_ci { 725da0c48c4Sopenharmony_ci if (unlikely (fill (elf->fildes, last_offset, 726da0c48c4Sopenharmony_ci (scn_start + dl->data.d.d_off) 727da0c48c4Sopenharmony_ci - last_offset, fillbuf, 728da0c48c4Sopenharmony_ci &filled) != 0)) 729da0c48c4Sopenharmony_ci { 730da0c48c4Sopenharmony_ci fail_free: 731da0c48c4Sopenharmony_ci free (shdr_data_mem); 732da0c48c4Sopenharmony_ci free (scns); 733da0c48c4Sopenharmony_ci return 1; 734da0c48c4Sopenharmony_ci } 735da0c48c4Sopenharmony_ci } 736da0c48c4Sopenharmony_ci 737da0c48c4Sopenharmony_ci last_offset = scn_start + dl->data.d.d_off; 738da0c48c4Sopenharmony_ci 739da0c48c4Sopenharmony_ci if ((scn->flags | dl->flags | elf->flags) & ELF_F_DIRTY) 740da0c48c4Sopenharmony_ci { 741da0c48c4Sopenharmony_ci char tmpbuf[MAX_TMPBUF]; 742da0c48c4Sopenharmony_ci void *buf = dl->data.d.d_buf; 743da0c48c4Sopenharmony_ci 744da0c48c4Sopenharmony_ci /* Let it go backward if the sections use a bogus 745da0c48c4Sopenharmony_ci layout with overlaps. We'll overwrite the stupid 746da0c48c4Sopenharmony_ci user's section data with the latest one, rather than 747da0c48c4Sopenharmony_ci crashing. */ 748da0c48c4Sopenharmony_ci 749da0c48c4Sopenharmony_ci if (unlikely (change_bo)) 750da0c48c4Sopenharmony_ci { 751da0c48c4Sopenharmony_ci#undef fctp 752da0c48c4Sopenharmony_ci#define fctp __elf_xfctstom[ELFW(ELFCLASS, LIBELFBITS) - 1][dl->data.d.d_type] 753da0c48c4Sopenharmony_ci 754da0c48c4Sopenharmony_ci buf = tmpbuf; 755da0c48c4Sopenharmony_ci if (dl->data.d.d_size > MAX_TMPBUF) 756da0c48c4Sopenharmony_ci { 757da0c48c4Sopenharmony_ci buf = malloc (dl->data.d.d_size); 758da0c48c4Sopenharmony_ci if (unlikely (buf == NULL)) 759da0c48c4Sopenharmony_ci { 760da0c48c4Sopenharmony_ci __libelf_seterrno (ELF_E_NOMEM); 761da0c48c4Sopenharmony_ci goto fail_free; 762da0c48c4Sopenharmony_ci } 763da0c48c4Sopenharmony_ci } 764da0c48c4Sopenharmony_ci 765da0c48c4Sopenharmony_ci /* Do the real work. */ 766da0c48c4Sopenharmony_ci (*fctp) (buf, dl->data.d.d_buf, dl->data.d.d_size, 1); 767da0c48c4Sopenharmony_ci } 768da0c48c4Sopenharmony_ci 769da0c48c4Sopenharmony_ci ssize_t n = pwrite_retry (elf->fildes, buf, 770da0c48c4Sopenharmony_ci dl->data.d.d_size, 771da0c48c4Sopenharmony_ci last_offset); 772da0c48c4Sopenharmony_ci if (unlikely ((size_t) n != dl->data.d.d_size)) 773da0c48c4Sopenharmony_ci { 774da0c48c4Sopenharmony_ci if (buf != dl->data.d.d_buf && buf != tmpbuf) 775da0c48c4Sopenharmony_ci free (buf); 776da0c48c4Sopenharmony_ci 777da0c48c4Sopenharmony_ci __libelf_seterrno (ELF_E_WRITE_ERROR); 778da0c48c4Sopenharmony_ci goto fail_free; 779da0c48c4Sopenharmony_ci } 780da0c48c4Sopenharmony_ci 781da0c48c4Sopenharmony_ci if (buf != dl->data.d.d_buf && buf != tmpbuf) 782da0c48c4Sopenharmony_ci free (buf); 783da0c48c4Sopenharmony_ci 784da0c48c4Sopenharmony_ci scn_changed = true; 785da0c48c4Sopenharmony_ci } 786da0c48c4Sopenharmony_ci 787da0c48c4Sopenharmony_ci last_offset += dl->data.d.d_size; 788da0c48c4Sopenharmony_ci 789da0c48c4Sopenharmony_ci dl->flags &= ~ELF_F_DIRTY; 790da0c48c4Sopenharmony_ci 791da0c48c4Sopenharmony_ci dl = dl->next; 792da0c48c4Sopenharmony_ci } 793da0c48c4Sopenharmony_ci while (dl != NULL); 794da0c48c4Sopenharmony_ci else 795da0c48c4Sopenharmony_ci { 796da0c48c4Sopenharmony_ci /* If the previous section (or the ELF/program 797da0c48c4Sopenharmony_ci header) changed we might have to fill the gap. */ 798da0c48c4Sopenharmony_ci if (scn_start > last_offset && previous_scn_changed) 799da0c48c4Sopenharmony_ci { 800da0c48c4Sopenharmony_ci if (unlikely (fill (elf->fildes, last_offset, 801da0c48c4Sopenharmony_ci scn_start - last_offset, fillbuf, 802da0c48c4Sopenharmony_ci &filled) != 0)) 803da0c48c4Sopenharmony_ci goto fail_free; 804da0c48c4Sopenharmony_ci } 805da0c48c4Sopenharmony_ci 806da0c48c4Sopenharmony_ci last_offset = scn_start + shdr->sh_size; 807da0c48c4Sopenharmony_ci } 808da0c48c4Sopenharmony_ci 809da0c48c4Sopenharmony_ci previous_scn_changed = scn_changed; 810da0c48c4Sopenharmony_ci next: 811da0c48c4Sopenharmony_ci /* Collect the section header table information. */ 812da0c48c4Sopenharmony_ci if (unlikely (change_bo)) 813da0c48c4Sopenharmony_ci (*shdr_fctp) (&shdr_data[scn->index], 814da0c48c4Sopenharmony_ci scn->shdr.ELFW(e,LIBELFBITS), 815da0c48c4Sopenharmony_ci sizeof (ElfW2(LIBELFBITS,Shdr)), 1); 816da0c48c4Sopenharmony_ci else if (elf->state.ELFW(elf,LIBELFBITS).shdr == NULL 817da0c48c4Sopenharmony_ci || (elf->flags & ELF_F_DIRTY)) 818da0c48c4Sopenharmony_ci memcpy (&shdr_data[scn->index], scn->shdr.ELFW(e,LIBELFBITS), 819da0c48c4Sopenharmony_ci sizeof (ElfW2(LIBELFBITS,Shdr))); 820da0c48c4Sopenharmony_ci 821da0c48c4Sopenharmony_ci shdr_flags |= scn->shdr_flags; 822da0c48c4Sopenharmony_ci scn->shdr_flags &= ~ELF_F_DIRTY; 823da0c48c4Sopenharmony_ci } 824da0c48c4Sopenharmony_ci 825da0c48c4Sopenharmony_ci /* Fill the gap between last section and section header table if 826da0c48c4Sopenharmony_ci necessary. */ 827da0c48c4Sopenharmony_ci if ((elf->flags & ELF_F_DIRTY) && last_offset < shdr_offset 828da0c48c4Sopenharmony_ci && unlikely (fill (elf->fildes, last_offset, 829da0c48c4Sopenharmony_ci shdr_offset - last_offset, 830da0c48c4Sopenharmony_ci fillbuf, &filled) != 0)) 831da0c48c4Sopenharmony_ci goto fail_free; 832da0c48c4Sopenharmony_ci 833da0c48c4Sopenharmony_ci /* Write out the section header table. */ 834da0c48c4Sopenharmony_ci if (shdr_flags & ELF_F_DIRTY 835da0c48c4Sopenharmony_ci && unlikely ((size_t) pwrite_retry (elf->fildes, shdr_data, 836da0c48c4Sopenharmony_ci sizeof (ElfW2(LIBELFBITS,Shdr)) 837da0c48c4Sopenharmony_ci * shnum, shdr_offset) 838da0c48c4Sopenharmony_ci != sizeof (ElfW2(LIBELFBITS,Shdr)) * shnum)) 839da0c48c4Sopenharmony_ci { 840da0c48c4Sopenharmony_ci __libelf_seterrno (ELF_E_WRITE_ERROR); 841da0c48c4Sopenharmony_ci goto fail_free; 842da0c48c4Sopenharmony_ci } 843da0c48c4Sopenharmony_ci 844da0c48c4Sopenharmony_ci free (shdr_data_mem); 845da0c48c4Sopenharmony_ci free (scns); 846da0c48c4Sopenharmony_ci } 847da0c48c4Sopenharmony_ci 848da0c48c4Sopenharmony_ci /* That was the last part. Clear the overall flag. */ 849da0c48c4Sopenharmony_ci elf->flags &= ~ELF_F_DIRTY; 850da0c48c4Sopenharmony_ci 851da0c48c4Sopenharmony_ci return 0; 852da0c48c4Sopenharmony_ci} 853