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