Home | History | Annotate | Download | only in libasm
      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