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