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