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