1da0c48c4Sopenharmony_ci/* Update data structures for changes. 2da0c48c4Sopenharmony_ci Copyright (C) 2000-2010, 2015, 2016 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 <libelf.h> 36da0c48c4Sopenharmony_ci#include <stdbool.h> 37da0c48c4Sopenharmony_ci#include <string.h> 38da0c48c4Sopenharmony_ci 39da0c48c4Sopenharmony_ci#include "libelfP.h" 40da0c48c4Sopenharmony_ci#include "elf-knowledge.h" 41da0c48c4Sopenharmony_ci 42da0c48c4Sopenharmony_ci#ifndef LIBELFBITS 43da0c48c4Sopenharmony_ci# define LIBELFBITS 32 44da0c48c4Sopenharmony_ci#endif 45da0c48c4Sopenharmony_ci 46da0c48c4Sopenharmony_ci/* Some fields contain 32/64 sizes. We cannot use Elf32/64_Word for those, 47da0c48c4Sopenharmony_ci since those are both 32bits. Elf32/64_Xword is always 64bits. */ 48da0c48c4Sopenharmony_ci#define Elf32_SizeWord Elf32_Word 49da0c48c4Sopenharmony_ci#define Elf64_SizeWord Elf64_Xword 50da0c48c4Sopenharmony_ci 51da0c48c4Sopenharmony_ci 52da0c48c4Sopenharmony_cistatic int 53da0c48c4Sopenharmony_ciELFW(default_ehdr,LIBELFBITS) (Elf *elf, ElfW2(LIBELFBITS,Ehdr) *ehdr, 54da0c48c4Sopenharmony_ci size_t shnum, int *change_bop) 55da0c48c4Sopenharmony_ci{ 56da0c48c4Sopenharmony_ci /* Always write the magic bytes. */ 57da0c48c4Sopenharmony_ci if (memcmp (&ehdr->e_ident[EI_MAG0], ELFMAG, SELFMAG) != 0) 58da0c48c4Sopenharmony_ci { 59da0c48c4Sopenharmony_ci memcpy (&ehdr->e_ident[EI_MAG0], ELFMAG, SELFMAG); 60da0c48c4Sopenharmony_ci elf->state.ELFW(elf,LIBELFBITS).ehdr_flags |= ELF_F_DIRTY; 61da0c48c4Sopenharmony_ci } 62da0c48c4Sopenharmony_ci 63da0c48c4Sopenharmony_ci /* Always set the file class. */ 64da0c48c4Sopenharmony_ci update_if_changed (ehdr->e_ident[EI_CLASS], ELFW(ELFCLASS,LIBELFBITS), 65da0c48c4Sopenharmony_ci elf->state.ELFW(elf,LIBELFBITS).ehdr_flags); 66da0c48c4Sopenharmony_ci 67da0c48c4Sopenharmony_ci /* Set the data encoding if necessary. */ 68da0c48c4Sopenharmony_ci if (unlikely (ehdr->e_ident[EI_DATA] == ELFDATANONE)) 69da0c48c4Sopenharmony_ci { 70da0c48c4Sopenharmony_ci ehdr->e_ident[EI_DATA] = 71da0c48c4Sopenharmony_ci BYTE_ORDER == BIG_ENDIAN ? ELFDATA2MSB : ELFDATA2LSB; 72da0c48c4Sopenharmony_ci elf->state.ELFW(elf,LIBELFBITS).ehdr_flags |= ELF_F_DIRTY; 73da0c48c4Sopenharmony_ci } 74da0c48c4Sopenharmony_ci else if (unlikely (ehdr->e_ident[EI_DATA] >= ELFDATANUM)) 75da0c48c4Sopenharmony_ci { 76da0c48c4Sopenharmony_ci __libelf_seterrno (ELF_E_DATA_ENCODING); 77da0c48c4Sopenharmony_ci return 1; 78da0c48c4Sopenharmony_ci } 79da0c48c4Sopenharmony_ci else 80da0c48c4Sopenharmony_ci *change_bop = ((BYTE_ORDER == LITTLE_ENDIAN 81da0c48c4Sopenharmony_ci && ehdr->e_ident[EI_DATA] != ELFDATA2LSB) 82da0c48c4Sopenharmony_ci || (BYTE_ORDER == BIG_ENDIAN 83da0c48c4Sopenharmony_ci && ehdr->e_ident[EI_DATA] != ELFDATA2MSB)); 84da0c48c4Sopenharmony_ci 85da0c48c4Sopenharmony_ci /* Unconditionally overwrite the ELF version. */ 86da0c48c4Sopenharmony_ci update_if_changed (ehdr->e_ident[EI_VERSION], EV_CURRENT, 87da0c48c4Sopenharmony_ci elf->state.ELFW(elf,LIBELFBITS).ehdr_flags); 88da0c48c4Sopenharmony_ci 89da0c48c4Sopenharmony_ci if (unlikely (ehdr->e_version == EV_NONE)) 90da0c48c4Sopenharmony_ci { 91da0c48c4Sopenharmony_ci ehdr->e_version = EV_CURRENT; 92da0c48c4Sopenharmony_ci elf->state.ELFW(elf,LIBELFBITS).ehdr_flags |= ELF_F_DIRTY; 93da0c48c4Sopenharmony_ci } 94da0c48c4Sopenharmony_ci else if (unlikely (ehdr->e_version != EV_CURRENT)) 95da0c48c4Sopenharmony_ci { 96da0c48c4Sopenharmony_ci __libelf_seterrno (ELF_E_UNKNOWN_VERSION); 97da0c48c4Sopenharmony_ci return 1; 98da0c48c4Sopenharmony_ci } 99da0c48c4Sopenharmony_ci 100da0c48c4Sopenharmony_ci if (unlikely (shnum >= SHN_LORESERVE)) 101da0c48c4Sopenharmony_ci { 102da0c48c4Sopenharmony_ci update_if_changed (ehdr->e_shnum, 0, 103da0c48c4Sopenharmony_ci elf->state.ELFW(elf,LIBELFBITS).ehdr_flags); 104da0c48c4Sopenharmony_ci } 105da0c48c4Sopenharmony_ci else 106da0c48c4Sopenharmony_ci update_if_changed (ehdr->e_shnum, shnum, 107da0c48c4Sopenharmony_ci elf->state.ELFW(elf,LIBELFBITS).ehdr_flags); 108da0c48c4Sopenharmony_ci 109da0c48c4Sopenharmony_ci if (unlikely (ehdr->e_ehsize != elf_typesize (LIBELFBITS, ELF_T_EHDR, 1))) 110da0c48c4Sopenharmony_ci { 111da0c48c4Sopenharmony_ci ehdr->e_ehsize = elf_typesize (LIBELFBITS, ELF_T_EHDR, 1); 112da0c48c4Sopenharmony_ci elf->state.ELFW(elf,LIBELFBITS).ehdr_flags |= ELF_F_DIRTY; 113da0c48c4Sopenharmony_ci } 114da0c48c4Sopenharmony_ci 115da0c48c4Sopenharmony_ci /* If phnum is zero make sure e_phoff is also zero and not some random 116da0c48c4Sopenharmony_ci value. That would cause trouble in update_file. */ 117da0c48c4Sopenharmony_ci if (ehdr->e_phnum == 0 && ehdr->e_phoff != 0) 118da0c48c4Sopenharmony_ci { 119da0c48c4Sopenharmony_ci ehdr->e_phoff = 0; 120da0c48c4Sopenharmony_ci elf->state.ELFW(elf,LIBELFBITS).ehdr_flags |= ELF_F_DIRTY; 121da0c48c4Sopenharmony_ci } 122da0c48c4Sopenharmony_ci 123da0c48c4Sopenharmony_ci return 0; 124da0c48c4Sopenharmony_ci} 125da0c48c4Sopenharmony_ci 126da0c48c4Sopenharmony_ci 127da0c48c4Sopenharmony_ciint64_t 128da0c48c4Sopenharmony_ciinternal_function 129da0c48c4Sopenharmony_ci__elfw2(LIBELFBITS,updatenull_wrlock) (Elf *elf, int *change_bop, size_t shnum) 130da0c48c4Sopenharmony_ci{ 131da0c48c4Sopenharmony_ci ElfW2(LIBELFBITS,Ehdr) *ehdr; 132da0c48c4Sopenharmony_ci int changed = 0; 133da0c48c4Sopenharmony_ci int ehdr_flags = 0; 134da0c48c4Sopenharmony_ci 135da0c48c4Sopenharmony_ci ehdr = __elfw2(LIBELFBITS,getehdr_wrlock) (elf); 136da0c48c4Sopenharmony_ci 137da0c48c4Sopenharmony_ci /* Set the default values. */ 138da0c48c4Sopenharmony_ci if (ELFW(default_ehdr,LIBELFBITS) (elf, ehdr, shnum, change_bop) != 0) 139da0c48c4Sopenharmony_ci return -1; 140da0c48c4Sopenharmony_ci 141da0c48c4Sopenharmony_ci /* At least the ELF header is there. */ 142da0c48c4Sopenharmony_ci ElfW2(LIBELFBITS,SizeWord) size = elf_typesize (LIBELFBITS, ELF_T_EHDR, 1); 143da0c48c4Sopenharmony_ci 144da0c48c4Sopenharmony_ci /* Set the program header position. */ 145da0c48c4Sopenharmony_ci if (elf->state.ELFW(elf,LIBELFBITS).phdr == NULL) 146da0c48c4Sopenharmony_ci (void) __elfw2(LIBELFBITS,getphdr_wrlock) (elf); 147da0c48c4Sopenharmony_ci if (elf->state.ELFW(elf,LIBELFBITS).phdr != NULL) 148da0c48c4Sopenharmony_ci { 149da0c48c4Sopenharmony_ci size_t phnum; 150da0c48c4Sopenharmony_ci if (unlikely (__elf_getphdrnum_rdlock (elf, &phnum) != 0)) 151da0c48c4Sopenharmony_ci return -1; 152da0c48c4Sopenharmony_ci 153da0c48c4Sopenharmony_ci if (elf->flags & ELF_F_LAYOUT) 154da0c48c4Sopenharmony_ci { 155da0c48c4Sopenharmony_ci /* The user is supposed to fill out e_phoff. Use it and 156da0c48c4Sopenharmony_ci e_phnum to determine the maximum extend. */ 157da0c48c4Sopenharmony_ci size = MAX (size, 158da0c48c4Sopenharmony_ci ehdr->e_phoff 159da0c48c4Sopenharmony_ci + elf_typesize (LIBELFBITS, ELF_T_PHDR, phnum)); 160da0c48c4Sopenharmony_ci } 161da0c48c4Sopenharmony_ci else 162da0c48c4Sopenharmony_ci { 163da0c48c4Sopenharmony_ci update_if_changed (ehdr->e_phoff, 164da0c48c4Sopenharmony_ci elf_typesize (LIBELFBITS, ELF_T_EHDR, 1), 165da0c48c4Sopenharmony_ci ehdr_flags); 166da0c48c4Sopenharmony_ci 167da0c48c4Sopenharmony_ci /* We need no alignment here. */ 168da0c48c4Sopenharmony_ci size += elf_typesize (LIBELFBITS, ELF_T_PHDR, phnum); 169da0c48c4Sopenharmony_ci } 170da0c48c4Sopenharmony_ci } 171da0c48c4Sopenharmony_ci 172da0c48c4Sopenharmony_ci if (shnum > 0) 173da0c48c4Sopenharmony_ci { 174da0c48c4Sopenharmony_ci struct Elf_Scn *scn1 = NULL; 175da0c48c4Sopenharmony_ci Elf_ScnList *list; 176da0c48c4Sopenharmony_ci bool first = true; 177da0c48c4Sopenharmony_ci 178da0c48c4Sopenharmony_ci assert (elf->state.ELFW(elf,LIBELFBITS).scns.cnt > 0); 179da0c48c4Sopenharmony_ci 180da0c48c4Sopenharmony_ci if (shnum >= SHN_LORESERVE) 181da0c48c4Sopenharmony_ci { 182da0c48c4Sopenharmony_ci /* We have to fill in the number of sections in the header 183da0c48c4Sopenharmony_ci of the zeroth section. */ 184da0c48c4Sopenharmony_ci Elf_Scn *scn0 = &elf->state.ELFW(elf,LIBELFBITS).scns.data[0]; 185da0c48c4Sopenharmony_ci 186da0c48c4Sopenharmony_ci update_if_changed (scn0->shdr.ELFW(e,LIBELFBITS)->sh_size, 187da0c48c4Sopenharmony_ci shnum, scn0->shdr_flags); 188da0c48c4Sopenharmony_ci } 189da0c48c4Sopenharmony_ci 190da0c48c4Sopenharmony_ci /* Go over all sections and find out how large they are. */ 191da0c48c4Sopenharmony_ci list = &elf->state.ELFW(elf,LIBELFBITS).scns; 192da0c48c4Sopenharmony_ci 193da0c48c4Sopenharmony_ci /* Find the first section. */ 194da0c48c4Sopenharmony_ci if (list->cnt > 1) 195da0c48c4Sopenharmony_ci scn1 = &list->data[1]; 196da0c48c4Sopenharmony_ci else if (list->next != NULL) 197da0c48c4Sopenharmony_ci scn1 = &list->next->data[0]; 198da0c48c4Sopenharmony_ci 199da0c48c4Sopenharmony_ci /* Load the section headers if necessary. This loads the 200da0c48c4Sopenharmony_ci headers for all sections. */ 201da0c48c4Sopenharmony_ci if (scn1 != NULL && scn1->shdr.ELFW(e,LIBELFBITS) == NULL) 202da0c48c4Sopenharmony_ci (void) __elfw2(LIBELFBITS,getshdr_wrlock) (scn1); 203da0c48c4Sopenharmony_ci 204da0c48c4Sopenharmony_ci do 205da0c48c4Sopenharmony_ci { 206da0c48c4Sopenharmony_ci for (size_t cnt = first == true; cnt < list->cnt; ++cnt) 207da0c48c4Sopenharmony_ci { 208da0c48c4Sopenharmony_ci Elf_Scn *scn = &list->data[cnt]; 209da0c48c4Sopenharmony_ci ElfW2(LIBELFBITS,Shdr) *shdr = scn->shdr.ELFW(e,LIBELFBITS); 210da0c48c4Sopenharmony_ci int64_t offset = 0; 211da0c48c4Sopenharmony_ci 212da0c48c4Sopenharmony_ci assert (shdr != NULL); 213da0c48c4Sopenharmony_ci ElfW2(LIBELFBITS,SizeWord) sh_entsize = shdr->sh_entsize; 214da0c48c4Sopenharmony_ci ElfW2(LIBELFBITS,SizeWord) sh_align = shdr->sh_addralign ?: 1; 215da0c48c4Sopenharmony_ci if (unlikely (! powerof2 (sh_align))) 216da0c48c4Sopenharmony_ci { 217da0c48c4Sopenharmony_ci __libelf_seterrno (ELF_E_INVALID_ALIGN); 218da0c48c4Sopenharmony_ci return -1; 219da0c48c4Sopenharmony_ci } 220da0c48c4Sopenharmony_ci 221da0c48c4Sopenharmony_ci /* Set the sh_entsize value if we can reliably detect it. */ 222da0c48c4Sopenharmony_ci switch (shdr->sh_type) 223da0c48c4Sopenharmony_ci { 224da0c48c4Sopenharmony_ci case SHT_SYMTAB: 225da0c48c4Sopenharmony_ci sh_entsize = elf_typesize (LIBELFBITS, ELF_T_SYM, 1); 226da0c48c4Sopenharmony_ci break; 227da0c48c4Sopenharmony_ci case SHT_RELA: 228da0c48c4Sopenharmony_ci sh_entsize = elf_typesize (LIBELFBITS, ELF_T_RELA, 1); 229da0c48c4Sopenharmony_ci break; 230da0c48c4Sopenharmony_ci case SHT_GROUP: 231da0c48c4Sopenharmony_ci /* Only relocatable files can contain section groups. */ 232da0c48c4Sopenharmony_ci if (ehdr->e_type != ET_REL) 233da0c48c4Sopenharmony_ci { 234da0c48c4Sopenharmony_ci __libelf_seterrno (ELF_E_GROUP_NOT_REL); 235da0c48c4Sopenharmony_ci return -1; 236da0c48c4Sopenharmony_ci } 237da0c48c4Sopenharmony_ci FALLTHROUGH; 238da0c48c4Sopenharmony_ci case SHT_SYMTAB_SHNDX: 239da0c48c4Sopenharmony_ci sh_entsize = elf_typesize (32, ELF_T_WORD, 1); 240da0c48c4Sopenharmony_ci break; 241da0c48c4Sopenharmony_ci case SHT_HASH: 242da0c48c4Sopenharmony_ci sh_entsize = SH_ENTSIZE_HASH (ehdr); 243da0c48c4Sopenharmony_ci break; 244da0c48c4Sopenharmony_ci case SHT_DYNAMIC: 245da0c48c4Sopenharmony_ci sh_entsize = elf_typesize (LIBELFBITS, ELF_T_DYN, 1); 246da0c48c4Sopenharmony_ci break; 247da0c48c4Sopenharmony_ci case SHT_REL: 248da0c48c4Sopenharmony_ci sh_entsize = elf_typesize (LIBELFBITS, ELF_T_REL, 1); 249da0c48c4Sopenharmony_ci break; 250da0c48c4Sopenharmony_ci case SHT_DYNSYM: 251da0c48c4Sopenharmony_ci sh_entsize = elf_typesize (LIBELFBITS, ELF_T_SYM, 1); 252da0c48c4Sopenharmony_ci break; 253da0c48c4Sopenharmony_ci case SHT_SUNW_move: 254da0c48c4Sopenharmony_ci sh_entsize = elf_typesize (LIBELFBITS, ELF_T_MOVE, 1); 255da0c48c4Sopenharmony_ci break; 256da0c48c4Sopenharmony_ci case SHT_SUNW_syminfo: 257da0c48c4Sopenharmony_ci sh_entsize = elf_typesize (LIBELFBITS, ELF_T_SYMINFO, 1); 258da0c48c4Sopenharmony_ci break; 259da0c48c4Sopenharmony_ci default: 260da0c48c4Sopenharmony_ci break; 261da0c48c4Sopenharmony_ci } 262da0c48c4Sopenharmony_ci 263da0c48c4Sopenharmony_ci /* If the section header contained the wrong entry size 264da0c48c4Sopenharmony_ci correct it and mark the header as modified. */ 265da0c48c4Sopenharmony_ci update_if_changed (shdr->sh_entsize, sh_entsize, 266da0c48c4Sopenharmony_ci scn->shdr_flags); 267da0c48c4Sopenharmony_ci 268da0c48c4Sopenharmony_ci /* Likewise for the alignment of a compressed section. 269da0c48c4Sopenharmony_ci For a SHF_COMPRESSED section set the correct 270da0c48c4Sopenharmony_ci sh_addralign value, which must match the d_align of 271da0c48c4Sopenharmony_ci the data (see __libelf_set_rawdata in elf_getdata.c). */ 272da0c48c4Sopenharmony_ci if ((shdr->sh_flags & SHF_COMPRESSED) != 0) 273da0c48c4Sopenharmony_ci { 274da0c48c4Sopenharmony_ci sh_align = __libelf_type_align (ELFW(ELFCLASS,LIBELFBITS), 275da0c48c4Sopenharmony_ci ELF_T_CHDR); 276da0c48c4Sopenharmony_ci update_if_changed (shdr->sh_addralign, sh_align, 277da0c48c4Sopenharmony_ci scn->shdr_flags); 278da0c48c4Sopenharmony_ci } 279da0c48c4Sopenharmony_ci 280da0c48c4Sopenharmony_ci if (scn->data_read == 0 281da0c48c4Sopenharmony_ci && __libelf_set_rawdata_wrlock (scn) != 0) 282da0c48c4Sopenharmony_ci /* Something went wrong. The error value is already set. */ 283da0c48c4Sopenharmony_ci return -1; 284da0c48c4Sopenharmony_ci 285da0c48c4Sopenharmony_ci /* Iterate over all data blocks. */ 286da0c48c4Sopenharmony_ci if (list->data[cnt].data_list_rear != NULL) 287da0c48c4Sopenharmony_ci { 288da0c48c4Sopenharmony_ci Elf_Data_List *dl = &scn->data_list; 289da0c48c4Sopenharmony_ci 290da0c48c4Sopenharmony_ci while (dl != NULL) 291da0c48c4Sopenharmony_ci { 292da0c48c4Sopenharmony_ci Elf_Data *data = &dl->data.d; 293da0c48c4Sopenharmony_ci if (dl == &scn->data_list && data->d_buf == NULL 294da0c48c4Sopenharmony_ci && scn->rawdata.d.d_buf != NULL) 295da0c48c4Sopenharmony_ci data = &scn->rawdata.d; 296da0c48c4Sopenharmony_ci 297da0c48c4Sopenharmony_ci if (unlikely (data->d_version != EV_CURRENT)) 298da0c48c4Sopenharmony_ci { 299da0c48c4Sopenharmony_ci __libelf_seterrno (ELF_E_UNKNOWN_VERSION); 300da0c48c4Sopenharmony_ci return -1; 301da0c48c4Sopenharmony_ci } 302da0c48c4Sopenharmony_ci 303da0c48c4Sopenharmony_ci if (unlikely (! powerof2 (data->d_align))) 304da0c48c4Sopenharmony_ci { 305da0c48c4Sopenharmony_ci __libelf_seterrno (ELF_E_INVALID_ALIGN); 306da0c48c4Sopenharmony_ci return -1; 307da0c48c4Sopenharmony_ci } 308da0c48c4Sopenharmony_ci 309da0c48c4Sopenharmony_ci sh_align = MAX (sh_align, data->d_align); 310da0c48c4Sopenharmony_ci 311da0c48c4Sopenharmony_ci if (elf->flags & ELF_F_LAYOUT) 312da0c48c4Sopenharmony_ci { 313da0c48c4Sopenharmony_ci /* The user specified the offset and the size. 314da0c48c4Sopenharmony_ci All we have to do is check whether this block 315da0c48c4Sopenharmony_ci fits in the size specified for the section. */ 316da0c48c4Sopenharmony_ci if (unlikely ((ElfW2(LIBELFBITS,SizeWord)) 317da0c48c4Sopenharmony_ci (data->d_off + data->d_size) 318da0c48c4Sopenharmony_ci > shdr->sh_size)) 319da0c48c4Sopenharmony_ci { 320da0c48c4Sopenharmony_ci __libelf_seterrno (ELF_E_SECTION_TOO_SMALL); 321da0c48c4Sopenharmony_ci return -1; 322da0c48c4Sopenharmony_ci } 323da0c48c4Sopenharmony_ci } 324da0c48c4Sopenharmony_ci else 325da0c48c4Sopenharmony_ci { 326da0c48c4Sopenharmony_ci /* Determine the padding. */ 327da0c48c4Sopenharmony_ci offset = ((offset + data->d_align - 1) 328da0c48c4Sopenharmony_ci & ~(data->d_align - 1)); 329da0c48c4Sopenharmony_ci 330da0c48c4Sopenharmony_ci update_if_changed (data->d_off, offset, changed); 331da0c48c4Sopenharmony_ci 332da0c48c4Sopenharmony_ci offset += data->d_size; 333da0c48c4Sopenharmony_ci } 334da0c48c4Sopenharmony_ci 335da0c48c4Sopenharmony_ci /* Next data block. */ 336da0c48c4Sopenharmony_ci dl = dl->next; 337da0c48c4Sopenharmony_ci } 338da0c48c4Sopenharmony_ci } 339da0c48c4Sopenharmony_ci else 340da0c48c4Sopenharmony_ci /* Get the size of the section from the raw data. If 341da0c48c4Sopenharmony_ci none is available the value is zero. */ 342da0c48c4Sopenharmony_ci offset += scn->rawdata.d.d_size; 343da0c48c4Sopenharmony_ci 344da0c48c4Sopenharmony_ci if (elf->flags & ELF_F_LAYOUT) 345da0c48c4Sopenharmony_ci { 346da0c48c4Sopenharmony_ci size = MAX (size, 347da0c48c4Sopenharmony_ci (shdr->sh_type != SHT_NOBITS 348da0c48c4Sopenharmony_ci ? shdr->sh_offset + shdr->sh_size : 0)); 349da0c48c4Sopenharmony_ci 350da0c48c4Sopenharmony_ci /* The alignment must be a power of two. This is a 351da0c48c4Sopenharmony_ci requirement from the ELF specification. Additionally 352da0c48c4Sopenharmony_ci we test for the alignment of the section being large 353da0c48c4Sopenharmony_ci enough for the largest alignment required by a data 354da0c48c4Sopenharmony_ci block. */ 355da0c48c4Sopenharmony_ci if (unlikely (! powerof2 (shdr->sh_addralign)) 356da0c48c4Sopenharmony_ci || unlikely ((shdr->sh_addralign ?: 1) < sh_align)) 357da0c48c4Sopenharmony_ci { 358da0c48c4Sopenharmony_ci __libelf_seterrno (ELF_E_INVALID_ALIGN); 359da0c48c4Sopenharmony_ci return -1; 360da0c48c4Sopenharmony_ci } 361da0c48c4Sopenharmony_ci } 362da0c48c4Sopenharmony_ci else 363da0c48c4Sopenharmony_ci { 364da0c48c4Sopenharmony_ci /* How much alignment do we need for this section. */ 365da0c48c4Sopenharmony_ci update_if_changed (shdr->sh_addralign, sh_align, 366da0c48c4Sopenharmony_ci scn->shdr_flags); 367da0c48c4Sopenharmony_ci 368da0c48c4Sopenharmony_ci size = (size + sh_align - 1) & ~(sh_align - 1); 369da0c48c4Sopenharmony_ci int offset_changed = 0; 370da0c48c4Sopenharmony_ci update_if_changed (shdr->sh_offset, size, offset_changed); 371da0c48c4Sopenharmony_ci changed |= offset_changed; 372da0c48c4Sopenharmony_ci 373da0c48c4Sopenharmony_ci if (offset_changed && scn->data_list_rear == NULL) 374da0c48c4Sopenharmony_ci { 375da0c48c4Sopenharmony_ci /* The position of the section in the file 376da0c48c4Sopenharmony_ci changed. Create the section data list. */ 377da0c48c4Sopenharmony_ci if (__elf_getdata_rdlock (scn, NULL) == NULL) 378da0c48c4Sopenharmony_ci return -1; 379da0c48c4Sopenharmony_ci } 380da0c48c4Sopenharmony_ci 381da0c48c4Sopenharmony_ci /* See whether the section size is correct. */ 382da0c48c4Sopenharmony_ci int size_changed = 0; 383da0c48c4Sopenharmony_ci update_if_changed (shdr->sh_size, 384da0c48c4Sopenharmony_ci (ElfW2(LIBELFBITS,SizeWord)) offset, 385da0c48c4Sopenharmony_ci size_changed); 386da0c48c4Sopenharmony_ci changed |= size_changed; 387da0c48c4Sopenharmony_ci 388da0c48c4Sopenharmony_ci if (shdr->sh_type != SHT_NOBITS) 389da0c48c4Sopenharmony_ci size += offset; 390da0c48c4Sopenharmony_ci 391da0c48c4Sopenharmony_ci scn->shdr_flags |= (offset_changed | size_changed); 392da0c48c4Sopenharmony_ci scn->flags |= changed; 393da0c48c4Sopenharmony_ci } 394da0c48c4Sopenharmony_ci 395da0c48c4Sopenharmony_ci /* Check that the section size is actually a multiple of 396da0c48c4Sopenharmony_ci the entry size. */ 397da0c48c4Sopenharmony_ci if (shdr->sh_entsize != 0 && shdr->sh_entsize != 1 398da0c48c4Sopenharmony_ci && (elf->flags & ELF_F_PERMISSIVE) == 0) 399da0c48c4Sopenharmony_ci { 400da0c48c4Sopenharmony_ci /* For compressed sections check the uncompressed size. */ 401da0c48c4Sopenharmony_ci ElfW2(LIBELFBITS,SizeWord) sh_size; 402da0c48c4Sopenharmony_ci if ((shdr->sh_flags & SHF_COMPRESSED) == 0) 403da0c48c4Sopenharmony_ci sh_size = shdr->sh_size; 404da0c48c4Sopenharmony_ci else 405da0c48c4Sopenharmony_ci { 406da0c48c4Sopenharmony_ci ElfW2(LIBELFBITS,Chdr) *chdr; 407da0c48c4Sopenharmony_ci chdr = elfw2(LIBELFBITS,getchdr) (scn); 408da0c48c4Sopenharmony_ci if (unlikely (chdr == NULL)) 409da0c48c4Sopenharmony_ci return -1; 410da0c48c4Sopenharmony_ci sh_size = chdr->ch_size; 411da0c48c4Sopenharmony_ci } 412da0c48c4Sopenharmony_ci 413da0c48c4Sopenharmony_ci if (unlikely (sh_size % shdr->sh_entsize != 0)) 414da0c48c4Sopenharmony_ci { 415da0c48c4Sopenharmony_ci __libelf_seterrno (ELF_E_INVALID_SHENTSIZE); 416da0c48c4Sopenharmony_ci return -1; 417da0c48c4Sopenharmony_ci } 418da0c48c4Sopenharmony_ci } 419da0c48c4Sopenharmony_ci } 420da0c48c4Sopenharmony_ci 421da0c48c4Sopenharmony_ci assert (list->next == NULL || list->cnt == list->max); 422da0c48c4Sopenharmony_ci 423da0c48c4Sopenharmony_ci first = false; 424da0c48c4Sopenharmony_ci } 425da0c48c4Sopenharmony_ci while ((list = list->next) != NULL); 426da0c48c4Sopenharmony_ci 427da0c48c4Sopenharmony_ci /* Store section information. */ 428da0c48c4Sopenharmony_ci update_if_changed (ehdr->e_shentsize, 429da0c48c4Sopenharmony_ci elf_typesize (LIBELFBITS, ELF_T_SHDR, 1), ehdr_flags); 430da0c48c4Sopenharmony_ci if (elf->flags & ELF_F_LAYOUT) 431da0c48c4Sopenharmony_ci { 432da0c48c4Sopenharmony_ci /* The user is supposed to fill out e_shoff. Use it and 433da0c48c4Sopenharmony_ci e_shnum (or sh_size of the dummy, first section header) 434da0c48c4Sopenharmony_ci to determine the maximum extend. */ 435da0c48c4Sopenharmony_ci size = MAX (size, 436da0c48c4Sopenharmony_ci (ehdr->e_shoff 437da0c48c4Sopenharmony_ci + (elf_typesize (LIBELFBITS, ELF_T_SHDR, shnum)))); 438da0c48c4Sopenharmony_ci } 439da0c48c4Sopenharmony_ci else 440da0c48c4Sopenharmony_ci { 441da0c48c4Sopenharmony_ci /* Align for section header table. 442da0c48c4Sopenharmony_ci 443da0c48c4Sopenharmony_ci Yes, we use `sizeof' and not `__alignof__' since we do not 444da0c48c4Sopenharmony_ci want to be surprised by architectures with less strict 445da0c48c4Sopenharmony_ci alignment rules. */ 446da0c48c4Sopenharmony_ci#define SHDR_ALIGN sizeof (ElfW2(LIBELFBITS,Off)) 447da0c48c4Sopenharmony_ci size = (size + SHDR_ALIGN - 1) & ~(SHDR_ALIGN - 1); 448da0c48c4Sopenharmony_ci 449da0c48c4Sopenharmony_ci update_if_changed (ehdr->e_shoff, size, elf->flags); 450da0c48c4Sopenharmony_ci 451da0c48c4Sopenharmony_ci /* Account for the section header size. */ 452da0c48c4Sopenharmony_ci size += elf_typesize (LIBELFBITS, ELF_T_SHDR, shnum); 453da0c48c4Sopenharmony_ci } 454da0c48c4Sopenharmony_ci } 455da0c48c4Sopenharmony_ci 456da0c48c4Sopenharmony_ci elf->state.ELFW(elf,LIBELFBITS).ehdr_flags |= ehdr_flags; 457da0c48c4Sopenharmony_ci 458da0c48c4Sopenharmony_ci return size; 459da0c48c4Sopenharmony_ci} 460