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