1 /* Finalize operations on the assembler context, free all resources. 2 Copyright (C) 2002, 2003, 2005 Red Hat, Inc. 3 This file is part of elfutils. 4 Written by Ulrich Drepper <drepper (at) redhat.com>, 2002. 5 6 This file is free software; you can redistribute it and/or modify 7 it under the terms of either 8 9 * the GNU Lesser General Public License as published by the Free 10 Software Foundation; either version 3 of the License, or (at 11 your option) any later version 12 13 or 14 15 * the GNU General Public License as published by the Free 16 Software Foundation; either version 2 of the License, or (at 17 your option) any later version 18 19 or both in parallel, as here. 20 21 elfutils is distributed in the hope that it will be useful, but 22 WITHOUT ANY WARRANTY; without even the implied warranty of 23 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 24 General Public License for more details. 25 26 You should have received copies of the GNU General Public License and 27 the GNU Lesser General Public License along with this program. If 28 not, see <http://www.gnu.org/licenses/>. */ 29 30 #ifdef HAVE_CONFIG_H 31 # include <config.h> 32 #endif 33 34 #include <assert.h> 35 #include <error.h> 36 #include <libintl.h> 37 #include <stdio.h> 38 #include <stdlib.h> 39 #include <string.h> 40 #include <unistd.h> 41 #include <sys/stat.h> 42 43 #include <libasmP.h> 44 #include <libelf.h> 45 #include <system.h> 46 47 48 static int 49 text_end (AsmCtx_t *ctx __attribute__ ((unused))) 50 { 51 if (fclose (ctx->out.file) != 0) 52 { 53 __libasm_seterrno (ASM_E_IOERROR); 54 return -1; 55 } 56 57 return 0; 58 } 59 60 61 static int 62 binary_end (AsmCtx_t *ctx) 63 { 64 void *symtab = NULL; 65 struct Ebl_Strent *symscn_strent = NULL; 66 struct Ebl_Strent *strscn_strent = NULL; 67 struct Ebl_Strent *xndxscn_strent = NULL; 68 Elf_Scn *shstrscn; 69 struct Ebl_Strent *shstrscn_strent; 70 size_t shstrscnndx; 71 size_t symscnndx = 0; 72 size_t strscnndx = 0; 73 size_t xndxscnndx = 0; 74 Elf_Data *data; 75 Elf_Data *shstrtabdata; 76 Elf_Data *strtabdata = NULL; 77 Elf_Data *xndxdata = NULL; 78 GElf_Shdr shdr_mem; 79 GElf_Shdr *shdr; 80 GElf_Ehdr ehdr_mem; 81 GElf_Ehdr *ehdr; 82 AsmScn_t *asmscn; 83 int result = 0; 84 85 /* Iterate over the created sections and compute the offsets of the 86 various subsections and fill in the content. */ 87 for (asmscn = ctx->section_list; asmscn != NULL; asmscn = asmscn->allnext) 88 { 89 #if 0 90 Elf_Scn *scn = elf_getscn (ctx->out.elf, asmscn->data.main.scnndx); 91 #else 92 Elf_Scn *scn = asmscn->data.main.scn; 93 #endif 94 off_t offset = 0; 95 AsmScn_t *asmsubscn = asmscn; 96 97 do 98 { 99 struct AsmData *content = asmsubscn->content; 100 bool first = true; 101 102 offset = ((offset + asmsubscn->max_align - 1) 103 & ~(asmsubscn->max_align - 1)); 104 105 /* Update the offset for this subsection. This field now 106 stores the offset of the first by in this subsection. */ 107 asmsubscn->offset = offset; 108 109 /* Note that the content list is circular. */ 110 if (content != NULL) 111 do 112 { 113 Elf_Data *newdata = elf_newdata (scn); 114 115 if (newdata == NULL) 116 { 117 __libasm_seterrno (ASM_E_LIBELF); 118 return -1; 119 } 120 121 newdata->d_buf = content->data; 122 newdata->d_type = ELF_T_BYTE; 123 newdata->d_size = content->len; 124 newdata->d_off = offset; 125 newdata->d_align = first ? asmsubscn->max_align : 1; 126 127 offset += content->len; 128 } 129 while ((content = content->next) != asmsubscn->content); 130 } 131 while ((asmsubscn = asmsubscn->subnext) != NULL); 132 } 133 134 135 /* Create the symbol table if necessary. */ 136 if (ctx->nsymbol_tab > 0) 137 { 138 /* Create the symbol table and string table section names. */ 139 symscn_strent = ebl_strtabadd (ctx->section_strtab, ".symtab", 8); 140 strscn_strent = ebl_strtabadd (ctx->section_strtab, ".strtab", 8); 141 142 /* Create the symbol string table section. */ 143 Elf_Scn *strscn = elf_newscn (ctx->out.elf); 144 strtabdata = elf_newdata (strscn); 145 shdr = gelf_getshdr (strscn, &shdr_mem); 146 if (strtabdata == NULL || shdr == NULL) 147 { 148 __libasm_seterrno (ASM_E_LIBELF); 149 return -1; 150 } 151 strscnndx = elf_ndxscn (strscn); 152 153 ebl_strtabfinalize (ctx->symbol_strtab, strtabdata); 154 155 shdr->sh_type = SHT_STRTAB; 156 assert (shdr->sh_entsize == 0); 157 158 (void) gelf_update_shdr (strscn, shdr); 159 160 /* Create the symbol table section. */ 161 Elf_Scn *symscn = elf_newscn (ctx->out.elf); 162 data = elf_newdata (symscn); 163 shdr = gelf_getshdr (symscn, &shdr_mem); 164 if (data == NULL || shdr == NULL) 165 { 166 __libasm_seterrno (ASM_E_LIBELF); 167 return -1; 168 } 169 symscnndx = elf_ndxscn (symscn); 170 171 /* We know how many symbols there will be in the symbol table. */ 172 data->d_size = gelf_fsize (ctx->out.elf, ELF_T_SYM, 173 ctx->nsymbol_tab + 1, EV_CURRENT); 174 symtab = malloc (data->d_size); 175 if (symtab == NULL) 176 return -1; 177 data->d_buf = symtab; 178 data->d_type = ELF_T_SYM; 179 data->d_off = 0; 180 181 /* Clear the first entry. */ 182 GElf_Sym syment; 183 memset (&syment, '\0', sizeof (syment)); 184 (void) gelf_update_sym (data, 0, &syment); 185 186 /* Iterate over the symbol table. */ 187 void *runp = NULL; 188 int ptr_local = 1; /* Start with index 1; zero remains unused. */ 189 int ptr_nonlocal = ctx->nsymbol_tab; 190 uint32_t *xshndx = NULL; 191 AsmSym_t *sym; 192 while ((sym = asm_symbol_tab_iterate (&ctx->symbol_tab, &runp)) != NULL) 193 if (asm_emit_symbol_p (ebl_string (sym->strent))) 194 { 195 assert (ptr_local <= ptr_nonlocal); 196 197 syment.st_name = ebl_strtaboffset (sym->strent); 198 syment.st_info = GELF_ST_INFO (sym->binding, sym->type); 199 syment.st_other = 0; 200 syment.st_value = sym->scn->offset + sym->offset; 201 syment.st_size = sym->size; 202 203 /* Add local symbols at the beginning, the other from 204 the end. */ 205 int ptr = sym->binding == STB_LOCAL ? ptr_local++ : ptr_nonlocal--; 206 207 /* Determine the section index. We have to handle the 208 overflow correctly. */ 209 Elf_Scn *scn = (sym->scn->subsection_id == 0 210 ? sym->scn->data.main.scn 211 : sym->scn->data.up->data.main.scn); 212 213 Elf32_Word ndx; 214 if (unlikely (scn == ASM_ABS_SCN)) 215 ndx = SHN_ABS; 216 else if (unlikely (scn == ASM_COM_SCN)) 217 ndx = SHN_COMMON; 218 else if (unlikely ((ndx = elf_ndxscn (scn)) >= SHN_LORESERVE)) 219 { 220 if (unlikely (xshndx == NULL)) 221 { 222 /* The extended section index section does not yet 223 exist. */ 224 Elf_Scn *xndxscn; 225 226 xndxscn = elf_newscn (ctx->out.elf); 227 xndxdata = elf_newdata (xndxscn); 228 shdr = gelf_getshdr (xndxscn, &shdr_mem); 229 if (xndxdata == NULL || shdr == NULL) 230 { 231 __libasm_seterrno (ASM_E_LIBELF); 232 return -1; 233 } 234 xndxscnndx = elf_ndxscn (xndxscn); 235 236 shdr->sh_type = SHT_SYMTAB_SHNDX; 237 shdr->sh_entsize = sizeof (Elf32_Word); 238 shdr->sh_addralign = sizeof (Elf32_Word); 239 shdr->sh_link = symscnndx; 240 241 (void) gelf_update_shdr (xndxscn, shdr); 242 243 xndxscn_strent = ebl_strtabadd (ctx->section_strtab, 244 ".symtab_shndx", 14); 245 246 /* Note that using 'elf32_fsize' instead of 247 'gelf_fsize' here is correct. */ 248 xndxdata->d_size = elf32_fsize (ELF_T_WORD, 249 ctx->nsymbol_tab + 1, 250 EV_CURRENT); 251 xshndx = xndxdata->d_buf = calloc (1, xndxdata->d_size); 252 if (xshndx == NULL) 253 return -1; 254 /* Using ELF_T_WORD here relies on the fact that the 255 32- and 64-bit types are the same size. */ 256 xndxdata->d_type = ELF_T_WORD; 257 xndxdata->d_off = 0; 258 } 259 260 /* Store the real section index in the extended setion 261 index table. */ 262 assert ((size_t) ptr < ctx->nsymbol_tab + 1); 263 xshndx[ptr] = ndx; 264 265 /* And signal that this happened. */ 266 ndx = SHN_XINDEX; 267 } 268 syment.st_shndx = ndx; 269 270 /* Remember where we put the symbol. */ 271 sym->symidx = ptr; 272 273 (void) gelf_update_sym (data, ptr, &syment); 274 } 275 276 assert (ptr_local == ptr_nonlocal + 1); 277 278 shdr->sh_type = SHT_SYMTAB; 279 shdr->sh_link = strscnndx; 280 shdr->sh_info = ptr_local; 281 shdr->sh_entsize = gelf_fsize (ctx->out.elf, ELF_T_SYM, 1, EV_CURRENT); 282 shdr->sh_addralign = gelf_fsize (ctx->out.elf, ELF_T_ADDR, 1, 283 EV_CURRENT); 284 285 (void) gelf_update_shdr (symscn, shdr); 286 } 287 288 289 /* Create the section header string table section and fill in the 290 references in the section headers. */ 291 shstrscn = elf_newscn (ctx->out.elf); 292 shstrtabdata = elf_newdata (shstrscn); 293 shdr = gelf_getshdr (shstrscn, &shdr_mem); 294 if (shstrscn == NULL || shstrtabdata == NULL || shdr == NULL) 295 { 296 __libasm_seterrno (ASM_E_LIBELF); 297 return -1; 298 } 299 300 301 /* Add the name of the section header string table. */ 302 shstrscn_strent = ebl_strtabadd (ctx->section_strtab, ".shstrtab", 10); 303 304 ebl_strtabfinalize (ctx->section_strtab, shstrtabdata); 305 306 shdr->sh_type = SHT_STRTAB; 307 assert (shdr->sh_entsize == 0); 308 shdr->sh_name = ebl_strtaboffset (shstrscn_strent); 309 310 (void) gelf_update_shdr (shstrscn, shdr); 311 312 313 /* Create the section groups. */ 314 if (ctx->groups != NULL) 315 { 316 AsmScnGrp_t *runp = ctx->groups->next; 317 318 do 319 { 320 Elf_Scn *scn; 321 Elf32_Word *grpdata; 322 323 scn = runp->scn; 324 assert (scn != NULL); 325 shdr = gelf_getshdr (scn, &shdr_mem); 326 assert (shdr != NULL); 327 328 data = elf_newdata (scn); 329 if (data == NULL) 330 { 331 __libasm_seterrno (ASM_E_LIBELF); 332 return -1; 333 } 334 335 /* It is correct to use 'elf32_fsize' instead of 'gelf_fsize' 336 here. */ 337 data->d_size = elf32_fsize (ELF_T_WORD, runp->nmembers + 1, 338 EV_CURRENT); 339 grpdata = data->d_buf = malloc (data->d_size); 340 if (grpdata == NULL) 341 return -1; 342 data->d_type = ELF_T_WORD; 343 data->d_off = 0; 344 data->d_align = elf32_fsize (ELF_T_WORD, 1, EV_CURRENT); 345 346 /* The first word of the section is filled with the flag word. */ 347 *grpdata++ = runp->flags; 348 349 if (runp->members != NULL) 350 { 351 AsmScn_t *member = runp->members->data.main.next_in_group; 352 353 do 354 { 355 /* Only sections, not subsections, can be registered 356 as member of a group. The subsections get 357 automatically included. */ 358 assert (member->subsection_id == 0); 359 360 *grpdata++ = elf_ndxscn (member->data.main.scn); 361 } 362 while ((member = member->data.main.next_in_group) 363 != runp->members->data.main.next_in_group); 364 } 365 366 /* Construct the section header. */ 367 shdr->sh_name = ebl_strtaboffset (runp->strent); 368 shdr->sh_type = SHT_GROUP; 369 shdr->sh_flags = 0; 370 shdr->sh_link = symscnndx; 371 /* If the user did not specify a signature we use the initial 372 empty symbol in the symbol table as the signature. */ 373 shdr->sh_info = (runp->signature != NULL 374 ? runp->signature->symidx : 0); 375 376 (void) gelf_update_shdr (scn, shdr); 377 } 378 while ((runp = runp->next) != ctx->groups->next); 379 } 380 381 382 /* Add the name to the symbol section. */ 383 if (likely (symscnndx != 0)) 384 { 385 Elf_Scn *scn = elf_getscn (ctx->out.elf, symscnndx); 386 387 shdr = gelf_getshdr (scn, &shdr_mem); 388 389 shdr->sh_name = ebl_strtaboffset (symscn_strent); 390 391 (void) gelf_update_shdr (scn, shdr); 392 393 394 /* Add the name to the string section. */ 395 assert (strscnndx != 0); 396 scn = elf_getscn (ctx->out.elf, strscnndx); 397 398 shdr = gelf_getshdr (scn, &shdr_mem); 399 400 shdr->sh_name = ebl_strtaboffset (strscn_strent); 401 402 (void) gelf_update_shdr (scn, shdr); 403 404 405 /* Add the name to the extended symbol index section. */ 406 if (xndxscnndx != 0) 407 { 408 scn = elf_getscn (ctx->out.elf, xndxscnndx); 409 410 shdr = gelf_getshdr (scn, &shdr_mem); 411 412 shdr->sh_name = ebl_strtaboffset (xndxscn_strent); 413 414 (void) gelf_update_shdr (scn, shdr); 415 } 416 } 417 418 419 /* Iterate over the created sections and fill in the names. */ 420 for (asmscn = ctx->section_list; asmscn != NULL; asmscn = asmscn->allnext) 421 { 422 shdr = gelf_getshdr (asmscn->data.main.scn, &shdr_mem); 423 /* This better should not fail. */ 424 assert (shdr != NULL); 425 426 shdr->sh_name = ebl_strtaboffset (asmscn->data.main.strent); 427 428 /* We now know the maximum alignment. */ 429 shdr->sh_addralign = asmscn->max_align; 430 431 (void) gelf_update_shdr (asmscn->data.main.scn, shdr); 432 } 433 434 /* Put the reference to the section header string table in the ELF 435 header. */ 436 ehdr = gelf_getehdr (ctx->out.elf, &ehdr_mem); 437 assert (ehdr != NULL); 438 439 shstrscnndx = elf_ndxscn (shstrscn); 440 if (unlikely (shstrscnndx > SHN_HIRESERVE) 441 || unlikely (shstrscnndx == SHN_XINDEX)) 442 { 443 /* The index of the section header string sectio is too large. */ 444 Elf_Scn *scn = elf_getscn (ctx->out.elf, 0); 445 446 /* Get the header for the zeroth section. */ 447 shdr = gelf_getshdr (scn, &shdr_mem); 448 /* This better does not fail. */ 449 assert (shdr != NULL); 450 451 /* The sh_link field of the zeroth section header contains the value. */ 452 shdr->sh_link = shstrscnndx; 453 454 (void) gelf_update_shdr (scn, shdr); 455 456 /* This is the sign for the overflow. */ 457 ehdr->e_shstrndx = SHN_XINDEX; 458 } 459 else 460 ehdr->e_shstrndx = elf_ndxscn (shstrscn); 461 462 gelf_update_ehdr (ctx->out.elf, ehdr); 463 464 /* Write out the ELF file. */ 465 if (unlikely (elf_update (ctx->out.elf, ELF_C_WRITE_MMAP)) < 0) 466 { 467 __libasm_seterrno (ASM_E_LIBELF); 468 result = -1; 469 } 470 471 /* We do not need the section header and symbol string tables anymore. */ 472 free (shstrtabdata->d_buf); 473 if (strtabdata != NULL) 474 free (strtabdata->d_buf); 475 /* We might have allocated the extended symbol table index. */ 476 if (xndxdata != NULL) 477 free (xndxdata->d_buf); 478 479 /* Free section groups memory. */ 480 AsmScnGrp_t *scngrp = ctx->groups; 481 if (scngrp != NULL) 482 do 483 free (elf_getdata (scngrp->scn, NULL)->d_buf); 484 while ((scngrp = scngrp->next) != ctx->groups); 485 486 /* Finalize the ELF handling. */ 487 if (unlikely (elf_end (ctx->out.elf)) != 0) 488 { 489 __libasm_seterrno (ASM_E_LIBELF); 490 result = -1; 491 } 492 493 /* Free the temporary resources. */ 494 free (symtab); 495 496 return result; 497 } 498 499 500 int 501 asm_end (AsmCtx_t *ctx) 502 { 503 int result; 504 505 if (ctx == NULL) 506 /* Something went wrong earlier. */ 507 return -1; 508 509 result = unlikely (ctx->textp) ? text_end (ctx) : binary_end (ctx); 510 if (result != 0) 511 return result; 512 513 /* Make the new file globally readable and user/group-writable. */ 514 if (fchmod (ctx->fd, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH) != 0) 515 { 516 __libasm_seterrno (ASM_E_CANNOT_CHMOD); 517 return -1; 518 } 519 520 /* Rename output file. */ 521 if (rename (ctx->tmp_fname, ctx->fname) != 0) 522 { 523 __libasm_seterrno (ASM_E_CANNOT_RENAME); 524 return -1; 525 } 526 527 /* Free the resources. */ 528 __libasm_finictx (ctx); 529 530 return 0; 531 } 532 533 534 static void 535 free_section (AsmScn_t *scnp) 536 { 537 void *oldp; 538 539 if (scnp->subnext != NULL) 540 free_section (scnp->subnext); 541 542 struct AsmData *data = scnp->content; 543 if (data != NULL) 544 do 545 { 546 oldp = data; 547 data = data->next; 548 free (oldp); 549 } 550 while (oldp != scnp->content); 551 552 free (scnp); 553 } 554 555 556 void 557 internal_function 558 __libasm_finictx (AsmCtx_t *ctx) 559 { 560 /* Iterate through section table and free individual entries. */ 561 AsmScn_t *scn = ctx->section_list; 562 while (scn != NULL) 563 { 564 AsmScn_t *oldp = scn; 565 scn = scn->allnext; 566 free_section (oldp); 567 } 568 569 /* Free the resources of the symbol table. */ 570 void *runp = NULL; 571 AsmSym_t *sym; 572 while ((sym = asm_symbol_tab_iterate (&ctx->symbol_tab, &runp)) != NULL) 573 free (sym); 574 asm_symbol_tab_free (&ctx->symbol_tab); 575 576 577 /* Free section groups. */ 578 AsmScnGrp_t *scngrp = ctx->groups; 579 if (scngrp != NULL) 580 do 581 { 582 AsmScnGrp_t *oldp = scngrp; 583 584 scngrp = scngrp->next; 585 free (oldp); 586 } 587 while (scngrp != ctx->groups); 588 589 590 if (unlikely (ctx->textp)) 591 { 592 /* Close the stream. */ 593 fclose (ctx->out.file); 594 } 595 else 596 { 597 /* Close the output file. */ 598 /* XXX We should test for errors here but what would we do if we'd 599 find any. */ 600 (void) close (ctx->fd); 601 602 /* And the string tables. */ 603 ebl_strtabfree (ctx->section_strtab); 604 ebl_strtabfree (ctx->symbol_strtab); 605 } 606 607 /* Initialize the lock. */ 608 rwlock_fini (ctx->lock); 609 610 /* Finally free the data structure. */ 611 free (ctx); 612 } 613