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