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