elf32_updatenull.c revision d56e232fb8f8cd97a336ed612c89145ec121f785
1/* Update data structures for changes. 2 Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006 Red Hat, Inc. 3 This file is part of Red Hat elfutils. 4 Written by Ulrich Drepper <drepper@redhat.com>, 2000. 5 6 Red Hat elfutils is free software; you can redistribute it and/or modify 7 it under the terms of the GNU General Public License as published by the 8 Free Software Foundation; version 2 of the License. 9 10 Red Hat elfutils is distributed in the hope that it will be useful, but 11 WITHOUT ANY WARRANTY; without even the implied warranty of 12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 General Public License for more details. 14 15 You should have received a copy of the GNU General Public License along 16 with Red Hat elfutils; if not, write to the Free Software Foundation, 17 Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301 USA. 18 19 In addition, as a special exception, Red Hat, Inc. gives You the 20 additional right to link the code of Red Hat elfutils with code licensed 21 under any Open Source Initiative certified open source license 22 (http://www.opensource.org/licenses/index.php) which requires the 23 distribution of source code with any binary distribution and to 24 distribute linked combinations of the two. Non-GPL Code permitted under 25 this exception must only link to the code of Red Hat elfutils through 26 those well defined interfaces identified in the file named EXCEPTION 27 found in the source code files (the "Approved Interfaces"). The files 28 of Non-GPL Code may instantiate templates or use macros or inline 29 functions from the Approved Interfaces without causing the resulting 30 work to be covered by the GNU General Public License. Only Red Hat, 31 Inc. may make changes or additions to the list of Approved Interfaces. 32 Red Hat's grant of this exception is conditioned upon your not adding 33 any new exceptions. If you wish to add a new Approved Interface or 34 exception, please contact Red Hat. You must obey the GNU General Public 35 License in all respects for all of the Red Hat elfutils code and other 36 code used in conjunction with Red Hat elfutils except the Non-GPL Code 37 covered by this exception. If you modify this file, you may extend this 38 exception to your version of the file, but you are not obligated to do 39 so. If you do not wish to provide this exception without modification, 40 you must delete this exception statement from your version and license 41 this file solely under the GPL without exception. 42 43 Red Hat elfutils is an included package of the Open Invention Network. 44 An included package of the Open Invention Network is a package for which 45 Open Invention Network licensees cross-license their patents. No patent 46 license is granted, either expressly or impliedly, by designation as an 47 included package. Should you wish to participate in the Open Invention 48 Network licensing program, please visit www.openinventionnetwork.com 49 <http://www.openinventionnetwork.com>. */ 50 51#ifdef HAVE_CONFIG_H 52# include <config.h> 53#endif 54 55#include <assert.h> 56#include <endian.h> 57#include <libelf.h> 58#include <stdbool.h> 59#include <string.h> 60#include <sys/param.h> 61 62#include "libelfP.h" 63#include "elf-knowledge.h" 64 65#ifndef LIBELFBITS 66# define LIBELFBITS 32 67#endif 68 69 70 71static int 72ELFW(default_ehdr,LIBELFBITS) (Elf *elf, ElfW2(LIBELFBITS,Ehdr) *ehdr, 73 size_t shnum, int *change_bop) 74{ 75 /* Always write the magic bytes. */ 76 if (memcmp (&ehdr->e_ident[EI_MAG0], ELFMAG, SELFMAG) != 0) 77 { 78 memcpy (&ehdr->e_ident[EI_MAG0], ELFMAG, SELFMAG); 79 elf->state.ELFW(elf,LIBELFBITS).ehdr_flags |= ELF_F_DIRTY; 80 } 81 82 /* Always set the file class. */ 83 update_if_changed (ehdr->e_ident[EI_CLASS], ELFW(ELFCLASS,LIBELFBITS), 84 elf->state.ELFW(elf,LIBELFBITS).ehdr_flags); 85 86 /* Set the data encoding if necessary. */ 87 if (unlikely (ehdr->e_ident[EI_DATA] == ELFDATANONE)) 88 { 89 ehdr->e_ident[EI_DATA] = 90 BYTE_ORDER == BIG_ENDIAN ? ELFDATA2MSB : ELFDATA2LSB; 91 elf->state.ELFW(elf,LIBELFBITS).ehdr_flags |= ELF_F_DIRTY; 92 } 93 else if (unlikely (ehdr->e_ident[EI_DATA] >= ELFDATANUM)) 94 { 95 __libelf_seterrno (ELF_E_DATA_ENCODING); 96 return 1; 97 } 98 else 99 *change_bop = ((BYTE_ORDER == LITTLE_ENDIAN 100 && ehdr->e_ident[EI_DATA] != ELFDATA2LSB) 101 || (BYTE_ORDER == BIG_ENDIAN 102 && ehdr->e_ident[EI_DATA] != ELFDATA2MSB)); 103 104 /* Unconditionally overwrite the ELF version. */ 105 update_if_changed (ehdr->e_ident[EI_VERSION], EV_CURRENT, 106 elf->state.ELFW(elf,LIBELFBITS).ehdr_flags); 107 108 if (unlikely (ehdr->e_version == EV_NONE) 109 || unlikely (ehdr->e_version >= EV_NUM)) 110 { 111 __libelf_seterrno (ELF_E_UNKNOWN_VERSION); 112 return 1; 113 } 114 115 if (unlikely (shnum >= SHN_LORESERVE)) 116 { 117 update_if_changed (ehdr->e_shnum, 0, 118 elf->state.ELFW(elf,LIBELFBITS).ehdr_flags); 119 } 120 else 121 update_if_changed (ehdr->e_shnum, shnum, 122 elf->state.ELFW(elf,LIBELFBITS).ehdr_flags); 123 124 if (unlikely (ehdr->e_ehsize != elf_typesize (LIBELFBITS, ELF_T_EHDR, 1))) 125 { 126 ehdr->e_ehsize = elf_typesize (LIBELFBITS, ELF_T_EHDR, 1); 127 elf->state.ELFW(elf,LIBELFBITS).ehdr_flags |= ELF_F_DIRTY; 128 } 129 130 return 0; 131} 132 133 134off_t 135internal_function 136__elfw2(LIBELFBITS,updatenull) (Elf *elf, int *change_bop, 137 size_t shnum, lockstat_t locked) 138{ 139 ElfW2(LIBELFBITS,Ehdr) *ehdr; 140 int changed = 0; 141 int ehdr_flags = 0; 142 143 ehdr = __elfw2(LIBELFBITS,getehdr_internal) (elf, locked); 144 145 /* Set the default values. */ 146 if (ELFW(default_ehdr,LIBELFBITS) (elf, ehdr, shnum, change_bop) != 0) 147 return -1; 148 149 /* At least the ELF header is there. */ 150 off_t size = elf_typesize (LIBELFBITS, ELF_T_EHDR, 1); 151 152 /* Set the program header position. */ 153 if (elf->state.ELFW(elf,LIBELFBITS).phdr == NULL 154 && (ehdr->e_type == ET_EXEC || ehdr->e_type == ET_DYN 155 || ehdr->e_type == ET_CORE)) 156 (void) __elfw2(LIBELFBITS,getphdr_internal) (elf, locked); 157 if (elf->state.ELFW(elf,LIBELFBITS).phdr != NULL) 158 { 159 /* Only executables, shared objects, and core files have a program 160 header. */ 161 if (ehdr->e_type != ET_EXEC && ehdr->e_type != ET_DYN 162 && unlikely (ehdr->e_type != ET_CORE)) 163 { 164 __libelf_seterrno (ELF_E_INVALID_PHDR); 165 return -1; 166 } 167 168 if (elf->flags & ELF_F_LAYOUT) 169 { 170 /* The user is supposed to fill out e_phoff. Use it and 171 e_phnum to determine the maximum extend. */ 172 size = MAX ((size_t) size, 173 ehdr->e_phoff 174 + elf_typesize (LIBELFBITS, ELF_T_PHDR, ehdr->e_phnum)); 175 } 176 else 177 { 178 update_if_changed (ehdr->e_phoff, 179 elf_typesize (LIBELFBITS, ELF_T_EHDR, 1), 180 ehdr_flags); 181 182 /* We need no alignment here. */ 183 size += elf_typesize (LIBELFBITS, ELF_T_PHDR, ehdr->e_phnum); 184 } 185 } 186 187 if (shnum > 0) 188 { 189 Elf_ScnList *list; 190 bool first = true; 191 192 assert (elf->state.ELFW(elf,LIBELFBITS).scns.cnt > 0); 193 194 if (shnum >= SHN_LORESERVE) 195 { 196 /* We have to fill in the number of sections in the header 197 of the zeroth section. */ 198 Elf_Scn *scn0 = &elf->state.ELFW(elf,LIBELFBITS).scns.data[0]; 199 200 update_if_changed (scn0->shdr.ELFW(e,LIBELFBITS)->sh_size, 201 shnum, scn0->shdr_flags); 202 } 203 204 /* Go over all sections and find out how large they are. */ 205 list = &elf->state.ELFW(elf,LIBELFBITS).scns; 206 207 /* Load the section headers if necessary. This loads the 208 headers for all sections. */ 209 if (list->data[1].shdr.ELFW(e,LIBELFBITS) == NULL) 210 (void) __elfw2(LIBELFBITS,getshdr_internal) (&list->data[1], locked); 211 212 do 213 { 214 for (size_t cnt = first == true; cnt < list->cnt; ++cnt) 215 { 216 Elf_Scn *scn = &list->data[cnt]; 217 ElfW2(LIBELFBITS,Shdr) *shdr = scn->shdr.ELFW(e,LIBELFBITS); 218 off_t offset = 0; 219 220 assert (shdr != NULL); 221 ElfW2(LIBELFBITS,Word) sh_entsize = shdr->sh_entsize; 222 ElfW2(LIBELFBITS,Word) sh_align = shdr->sh_addralign ?: 1; 223 224 /* Set the sh_entsize value if we can reliably detect it. */ 225 switch (shdr->sh_type) 226 { 227 case SHT_SYMTAB: 228 sh_entsize = elf_typesize (LIBELFBITS, ELF_T_SYM, 1); 229 break; 230 case SHT_RELA: 231 sh_entsize = elf_typesize (LIBELFBITS, ELF_T_RELA, 1); 232 break; 233 case SHT_GROUP: 234 /* Only relocatable files can contain section groups. */ 235 if (ehdr->e_type != ET_REL) 236 { 237 __libelf_seterrno (ELF_E_GROUP_NOT_REL); 238 return -1; 239 } 240 /* FALLTHROUGH */ 241 case SHT_SYMTAB_SHNDX: 242 sh_entsize = elf_typesize (32, ELF_T_WORD, 1); 243 break; 244 case SHT_HASH: 245 sh_entsize = SH_ENTSIZE_HASH (ehdr); 246 break; 247 case SHT_DYNAMIC: 248 sh_entsize = elf_typesize (LIBELFBITS, ELF_T_DYN, 1); 249 break; 250 case SHT_REL: 251 sh_entsize = elf_typesize (LIBELFBITS, ELF_T_REL, 1); 252 break; 253 case SHT_DYNSYM: 254 sh_entsize = elf_typesize (LIBELFBITS, ELF_T_SYM, 1); 255 break; 256 case SHT_SUNW_move: 257 sh_entsize = elf_typesize (LIBELFBITS, ELF_T_MOVE, 1); 258 break; 259 case SHT_SUNW_syminfo: 260 sh_entsize = elf_typesize (LIBELFBITS, ELF_T_SYMINFO, 1); 261 break; 262 default: 263 break; 264 } 265 266 /* If the section header contained the wrong entry size 267 correct it and mark the header as modified. */ 268 update_if_changed (shdr->sh_entsize, sh_entsize, 269 scn->shdr_flags); 270 271 if (scn->data_read == 0 272 && __libelf_set_rawdata (scn, locked) != 0) 273 /* Something went wrong. The error value is already set. */ 274 return -1; 275 276 /* Iterate over all data blocks. */ 277 if (list->data[cnt].data_list_rear != NULL) 278 { 279 Elf_Data_List *dl = &scn->data_list; 280 281 while (dl != NULL) 282 { 283 Elf_Data *data = &dl->data.d; 284 if (dl == &scn->data_list && data->d_buf == NULL 285 && scn->rawdata.d.d_buf != NULL) 286 data = &scn->rawdata.d; 287 288 if (unlikely (data->d_version == EV_NONE) 289 || unlikely (data->d_version >= EV_NUM)) 290 { 291 __libelf_seterrno (ELF_E_UNKNOWN_VERSION); 292 return -1; 293 } 294 295 if (unlikely (! powerof2 (data->d_align))) 296 { 297 __libelf_seterrno (ELF_E_INVALID_ALIGN); 298 return -1; 299 } 300 301 sh_align = MAX (sh_align, data->d_align); 302 303 if (elf->flags & ELF_F_LAYOUT) 304 { 305 /* The user specified the offset and the size. 306 All we have to do is check whether this block 307 fits in the size specified for the section. */ 308 if (unlikely ((GElf_Word) (data->d_off 309 + data->d_size) 310 > shdr->sh_size)) 311 { 312 __libelf_seterrno (ELF_E_SECTION_TOO_SMALL); 313 return -1; 314 } 315 } 316 else 317 { 318 /* Determine the padding. */ 319 offset = ((offset + data->d_align - 1) 320 & ~(data->d_align - 1)); 321 322 update_if_changed (data->d_off, offset, changed); 323 324 offset += data->d_size; 325 } 326 327 /* Next data block. */ 328 dl = dl->next; 329 } 330 } 331 else 332 /* Get the size of the section from the raw data. If 333 none is available the value is zero. */ 334 offset += scn->rawdata.d.d_size; 335 336 if (elf->flags & ELF_F_LAYOUT) 337 { 338 size = MAX ((GElf_Word) size, 339 shdr->sh_offset 340 + (shdr->sh_type != SHT_NOBITS 341 ? shdr->sh_size : 0)); 342 343 /* The alignment must be a power of two. This is a 344 requirement from the ELF specification. Additionally 345 we test for the alignment of the section being large 346 enough for the largest alignment required by a data 347 block. */ 348 if (unlikely (! powerof2 (shdr->sh_addralign)) 349 || unlikely (shdr->sh_addralign < sh_align)) 350 { 351 __libelf_seterrno (ELF_E_INVALID_ALIGN); 352 return -1; 353 } 354 } 355 else 356 { 357 /* How much alignment do we need for this section. */ 358 update_if_changed (shdr->sh_addralign, sh_align, 359 scn->shdr_flags); 360 361 size = (size + sh_align - 1) & ~(sh_align - 1); 362 int offset_changed = 0; 363 update_if_changed (shdr->sh_offset, (GElf_Word) size, 364 offset_changed); 365 changed |= offset_changed; 366 367 if (offset_changed && scn->data_list_rear == NULL) 368 { 369 /* The position of the section in the file 370 changed. Create the section data list. */ 371 if (__elf_getdata_internal (scn, NULL, locked) == NULL) 372 return -1; 373 } 374 375 /* See whether the section size is correct. */ 376 update_if_changed (shdr->sh_size, (GElf_Word) offset, 377 changed); 378 379 if (shdr->sh_type != SHT_NOBITS) 380 size += offset; 381 382 scn->flags |= changed; 383 } 384 385 /* Check that the section size is actually a multiple of 386 the entry size. */ 387 if (shdr->sh_entsize != 0 388 && unlikely (shdr->sh_size % shdr->sh_entsize != 0) 389 && (elf->flags & ELF_F_PERMISSIVE) == 0) 390 { 391 __libelf_seterrno (ELF_E_INVALID_SHENTSIZE); 392 return -1; 393 } 394 } 395 396 assert (list->next == NULL || list->cnt == list->max); 397 398 first = false; 399 } 400 while ((list = list->next) != NULL); 401 402 /* Store section information. */ 403 if (elf->flags & ELF_F_LAYOUT) 404 { 405 /* The user is supposed to fill out e_phoff. Use it and 406 e_phnum to determine the maximum extend. */ 407 size = MAX ((GElf_Word) size, 408 (ehdr->e_shoff 409 + (elf_typesize (LIBELFBITS, ELF_T_SHDR, shnum)))); 410 } 411 else 412 { 413 /* Align for section header table. 414 415 Yes, we use `sizeof' and not `__alignof__' since we do not 416 want to be surprised by architectures with less strict 417 alignment rules. */ 418#define SHDR_ALIGN sizeof (ElfW2(LIBELFBITS,Off)) 419 size = (size + SHDR_ALIGN - 1) & ~(SHDR_ALIGN - 1); 420 421 update_if_changed (ehdr->e_shoff, (GElf_Word) size, elf->flags); 422 update_if_changed (ehdr->e_shentsize, 423 elf_typesize (LIBELFBITS, ELF_T_SHDR, 1), 424 ehdr_flags); 425 426 /* Account for the section header size. */ 427 size += elf_typesize (LIBELFBITS, ELF_T_SHDR, shnum); 428 } 429 } 430 431 elf->state.ELFW(elf,LIBELFBITS).ehdr_flags |= ehdr_flags; 432 433 return size; 434} 435