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 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 <error.h>
     36 #include <libintl.h>
     37 #include <stdio.h>
     38 #include <stdlib.h>
     39 #include <string.h>
     40 #include <unistd.h>
     41 #include <sys/stat.h>
     42 
     43 #include <libasmP.h>
     44 #include <libelf.h>
     45 #include <system.h>
     46 
     47 
     48 static int
     49 text_end (AsmCtx_t *ctx __attribute__ ((unused)))
     50 {
     51   if (fclose (ctx->out.file) != 0)
     52     {
     53       __libasm_seterrno (ASM_E_IOERROR);
     54       return -1;
     55     }
     56 
     57   return 0;
     58 }
     59 
     60 
     61 static int
     62 binary_end (AsmCtx_t *ctx)
     63 {
     64   void *symtab = NULL;
     65   struct Ebl_Strent *symscn_strent = NULL;
     66   struct Ebl_Strent *strscn_strent = NULL;
     67   struct Ebl_Strent *xndxscn_strent = NULL;
     68   Elf_Scn *shstrscn;
     69   struct Ebl_Strent *shstrscn_strent;
     70   size_t shstrscnndx;
     71   size_t symscnndx = 0;
     72   size_t strscnndx = 0;
     73   size_t xndxscnndx = 0;
     74   Elf_Data *data;
     75   Elf_Data *shstrtabdata;
     76   Elf_Data *strtabdata = NULL;
     77   Elf_Data *xndxdata = NULL;
     78   GElf_Shdr shdr_mem;
     79   GElf_Shdr *shdr;
     80   GElf_Ehdr ehdr_mem;
     81   GElf_Ehdr *ehdr;
     82   AsmScn_t *asmscn;
     83   int result = 0;
     84 
     85   /* Iterate over the created sections and compute the offsets of the
     86      various subsections and fill in the content.  */
     87   for (asmscn = ctx->section_list; asmscn != NULL; asmscn = asmscn->allnext)
     88     {
     89 #if 0
     90       Elf_Scn *scn = elf_getscn (ctx->out.elf, asmscn->data.main.scnndx);
     91 #else
     92       Elf_Scn *scn = asmscn->data.main.scn;
     93 #endif
     94       off_t offset = 0;
     95       AsmScn_t *asmsubscn = asmscn;
     96 
     97       do
     98 	{
     99 	  struct AsmData *content = asmsubscn->content;
    100 	  bool first = true;
    101 
    102 	  offset = ((offset + asmsubscn->max_align - 1)
    103 		    & ~(asmsubscn->max_align - 1));
    104 
    105 	  /* Update the offset for this subsection.  This field now
    106 	     stores the offset of the first by in this subsection.  */
    107 	  asmsubscn->offset = offset;
    108 
    109 	  /* Note that the content list is circular.  */
    110 	  if (content != NULL)
    111 	    do
    112 	      {
    113 		Elf_Data *newdata = elf_newdata (scn);
    114 
    115 		if (newdata == NULL)
    116 		  {
    117 		    __libasm_seterrno (ASM_E_LIBELF);
    118 		    return -1;
    119 		  }
    120 
    121 		newdata->d_buf = content->data;
    122 		newdata->d_type = ELF_T_BYTE;
    123 		newdata->d_size = content->len;
    124 		newdata->d_off = offset;
    125 		newdata->d_align = first ? asmsubscn->max_align : 1;
    126 
    127 		offset += content->len;
    128 	      }
    129 	    while ((content = content->next) != asmsubscn->content);
    130 	}
    131       while ((asmsubscn = asmsubscn->subnext) != NULL);
    132     }
    133 
    134 
    135   /* Create the symbol table if necessary.  */
    136   if (ctx->nsymbol_tab > 0)
    137     {
    138       /* Create the symbol table and string table section names.  */
    139       symscn_strent = ebl_strtabadd (ctx->section_strtab, ".symtab", 8);
    140       strscn_strent = ebl_strtabadd (ctx->section_strtab, ".strtab", 8);
    141 
    142       /* Create the symbol string table section.  */
    143       Elf_Scn *strscn = elf_newscn (ctx->out.elf);
    144       strtabdata = elf_newdata (strscn);
    145       shdr = gelf_getshdr (strscn, &shdr_mem);
    146       if (strtabdata == NULL || shdr == NULL)
    147 	{
    148 	  __libasm_seterrno (ASM_E_LIBELF);
    149 	  return -1;
    150 	}
    151       strscnndx = elf_ndxscn (strscn);
    152 
    153       ebl_strtabfinalize (ctx->symbol_strtab, strtabdata);
    154 
    155       shdr->sh_type = SHT_STRTAB;
    156       assert (shdr->sh_entsize == 0);
    157 
    158       (void) gelf_update_shdr (strscn, shdr);
    159 
    160       /* Create the symbol table section.  */
    161       Elf_Scn *symscn = elf_newscn (ctx->out.elf);
    162       data = elf_newdata (symscn);
    163       shdr = gelf_getshdr (symscn, &shdr_mem);
    164       if (data == NULL || shdr == NULL)
    165 	{
    166 	  __libasm_seterrno (ASM_E_LIBELF);
    167 	  return -1;
    168 	}
    169       symscnndx = elf_ndxscn (symscn);
    170 
    171       /* We know how many symbols there will be in the symbol table.  */
    172       data->d_size = gelf_fsize (ctx->out.elf, ELF_T_SYM,
    173 				 ctx->nsymbol_tab + 1, EV_CURRENT);
    174       symtab = malloc (data->d_size);
    175       if (symtab == NULL)
    176 	return -1;
    177       data->d_buf = symtab;
    178       data->d_type = ELF_T_SYM;
    179       data->d_off = 0;
    180 
    181       /* Clear the first entry.  */
    182       GElf_Sym syment;
    183       memset (&syment, '\0', sizeof (syment));
    184       (void) gelf_update_sym (data, 0, &syment);
    185 
    186       /* Iterate over the symbol table.  */
    187       void *runp = NULL;
    188       int ptr_local = 1;	/* Start with index 1; zero remains unused.  */
    189       int ptr_nonlocal = ctx->nsymbol_tab;
    190       uint32_t *xshndx = NULL;
    191       AsmSym_t *sym;
    192       while ((sym = asm_symbol_tab_iterate (&ctx->symbol_tab, &runp)) != NULL)
    193 	if (asm_emit_symbol_p (ebl_string (sym->strent)))
    194 	  {
    195 	    assert (ptr_local <= ptr_nonlocal);
    196 
    197 	    syment.st_name = ebl_strtaboffset (sym->strent);
    198 	    syment.st_info = GELF_ST_INFO (sym->binding, sym->type);
    199 	    syment.st_other = 0;
    200 	    syment.st_value = sym->scn->offset + sym->offset;
    201 	    syment.st_size = sym->size;
    202 
    203 	    /* Add local symbols at the beginning, the other from
    204 	       the end.  */
    205 	    int ptr = sym->binding == STB_LOCAL ? ptr_local++ : ptr_nonlocal--;
    206 
    207 	    /* Determine the section index.  We have to handle the
    208 	       overflow correctly.  */
    209 	    Elf_Scn *scn = (sym->scn->subsection_id == 0
    210 			    ? sym->scn->data.main.scn
    211 			    : sym->scn->data.up->data.main.scn);
    212 
    213 	    Elf32_Word ndx;
    214 	    if (unlikely (scn == ASM_ABS_SCN))
    215 	      ndx = SHN_ABS;
    216 	    else if (unlikely (scn == ASM_COM_SCN))
    217 	      ndx = SHN_COMMON;
    218 	    else if (unlikely ((ndx = elf_ndxscn (scn)) >= SHN_LORESERVE))
    219 	      {
    220 		if (unlikely (xshndx == NULL))
    221 		  {
    222 		    /* The extended section index section does not yet
    223 		       exist.  */
    224 		    Elf_Scn *xndxscn;
    225 
    226 		    xndxscn = elf_newscn (ctx->out.elf);
    227 		    xndxdata = elf_newdata (xndxscn);
    228 		    shdr = gelf_getshdr (xndxscn, &shdr_mem);
    229 		    if (xndxdata == NULL || shdr == NULL)
    230 		      {
    231 			__libasm_seterrno (ASM_E_LIBELF);
    232 			return -1;
    233 		      }
    234 		    xndxscnndx = elf_ndxscn (xndxscn);
    235 
    236 		    shdr->sh_type = SHT_SYMTAB_SHNDX;
    237 		    shdr->sh_entsize = sizeof (Elf32_Word);
    238 		    shdr->sh_addralign = sizeof (Elf32_Word);
    239 		    shdr->sh_link = symscnndx;
    240 
    241 		    (void) gelf_update_shdr (xndxscn, shdr);
    242 
    243 		    xndxscn_strent = ebl_strtabadd (ctx->section_strtab,
    244 						    ".symtab_shndx", 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 = ebl_strtabadd (ctx->section_strtab, ".shstrtab", 10);
    303 
    304   ebl_strtabfinalize (ctx->section_strtab, shstrtabdata);
    305 
    306   shdr->sh_type = SHT_STRTAB;
    307   assert (shdr->sh_entsize == 0);
    308   shdr->sh_name = ebl_strtaboffset (shstrscn_strent);
    309 
    310   (void) gelf_update_shdr (shstrscn, shdr);
    311 
    312 
    313   /* Create the section groups.  */
    314   if (ctx->groups != NULL)
    315     {
    316       AsmScnGrp_t *runp = ctx->groups->next;
    317 
    318       do
    319 	{
    320 	  Elf_Scn *scn;
    321 	  Elf32_Word *grpdata;
    322 
    323 	  scn = runp->scn;
    324 	  assert (scn != NULL);
    325 	  shdr = gelf_getshdr (scn, &shdr_mem);
    326 	  assert (shdr != NULL);
    327 
    328 	  data = elf_newdata (scn);
    329 	  if (data == NULL)
    330 	    {
    331 	      __libasm_seterrno (ASM_E_LIBELF);
    332 	      return -1;
    333 	    }
    334 
    335 	  /* It is correct to use 'elf32_fsize' instead of 'gelf_fsize'
    336 	     here.  */
    337 	  data->d_size = elf32_fsize (ELF_T_WORD, runp->nmembers + 1,
    338 				      EV_CURRENT);
    339 	  grpdata = data->d_buf = malloc (data->d_size);
    340 	  if (grpdata == NULL)
    341 	    return -1;
    342 	  data->d_type = ELF_T_WORD;
    343 	  data->d_off = 0;
    344 	  data->d_align = elf32_fsize (ELF_T_WORD, 1, EV_CURRENT);
    345 
    346 	  /* The first word of the section is filled with the flag word.  */
    347 	  *grpdata++ = runp->flags;
    348 
    349 	  if (runp->members != NULL)
    350 	    {
    351 	      AsmScn_t *member = runp->members->data.main.next_in_group;
    352 
    353 	      do
    354 		{
    355 		  /* Only sections, not subsections, can be registered
    356 		     as member of a group.  The subsections get
    357 		     automatically included.  */
    358 		  assert (member->subsection_id == 0);
    359 
    360 		  *grpdata++ = elf_ndxscn (member->data.main.scn);
    361 		}
    362 	      while ((member = member->data.main.next_in_group)
    363 		     != runp->members->data.main.next_in_group);
    364 	    }
    365 
    366 	  /* Construct the section header.  */
    367 	  shdr->sh_name = ebl_strtaboffset (runp->strent);
    368 	  shdr->sh_type = SHT_GROUP;
    369 	  shdr->sh_flags = 0;
    370 	  shdr->sh_link = symscnndx;
    371 	  /* If the user did not specify a signature we use the initial
    372 	     empty symbol in the symbol table as the signature.  */
    373 	  shdr->sh_info = (runp->signature != NULL
    374 			   ? runp->signature->symidx : 0);
    375 
    376 	  (void) gelf_update_shdr (scn, shdr);
    377 	}
    378       while ((runp = runp->next) != ctx->groups->next);
    379     }
    380 
    381 
    382   /* Add the name to the symbol section.  */
    383   if (likely (symscnndx != 0))
    384     {
    385       Elf_Scn *scn = elf_getscn (ctx->out.elf, symscnndx);
    386 
    387       shdr = gelf_getshdr (scn, &shdr_mem);
    388 
    389       shdr->sh_name = ebl_strtaboffset (symscn_strent);
    390 
    391       (void) gelf_update_shdr (scn, shdr);
    392 
    393 
    394       /* Add the name to the string section.  */
    395       assert (strscnndx != 0);
    396       scn = elf_getscn (ctx->out.elf, strscnndx);
    397 
    398       shdr = gelf_getshdr (scn, &shdr_mem);
    399 
    400       shdr->sh_name = ebl_strtaboffset (strscn_strent);
    401 
    402       (void) gelf_update_shdr (scn, shdr);
    403 
    404 
    405       /* Add the name to the extended symbol index section.  */
    406       if (xndxscnndx != 0)
    407 	{
    408 	  scn = elf_getscn (ctx->out.elf, xndxscnndx);
    409 
    410 	  shdr = gelf_getshdr (scn, &shdr_mem);
    411 
    412 	  shdr->sh_name = ebl_strtaboffset (xndxscn_strent);
    413 
    414 	  (void) gelf_update_shdr (scn, shdr);
    415 	}
    416     }
    417 
    418 
    419   /* Iterate over the created sections and fill in the names.  */
    420   for (asmscn = ctx->section_list; asmscn != NULL; asmscn = asmscn->allnext)
    421     {
    422       shdr = gelf_getshdr (asmscn->data.main.scn, &shdr_mem);
    423       /* This better should not fail.  */
    424       assert (shdr != NULL);
    425 
    426       shdr->sh_name = ebl_strtaboffset (asmscn->data.main.strent);
    427 
    428       /* We now know the maximum alignment.  */
    429       shdr->sh_addralign = asmscn->max_align;
    430 
    431       (void) gelf_update_shdr (asmscn->data.main.scn, shdr);
    432     }
    433 
    434   /* Put the reference to the section header string table in the ELF
    435      header.  */
    436   ehdr = gelf_getehdr (ctx->out.elf, &ehdr_mem);
    437   assert (ehdr != NULL);
    438 
    439   shstrscnndx = elf_ndxscn (shstrscn);
    440   if (unlikely (shstrscnndx > SHN_HIRESERVE)
    441       || unlikely (shstrscnndx == SHN_XINDEX))
    442     {
    443       /* The index of the section header string sectio is too large.  */
    444       Elf_Scn *scn = elf_getscn (ctx->out.elf, 0);
    445 
    446       /* Get the header for the zeroth section.  */
    447       shdr = gelf_getshdr (scn, &shdr_mem);
    448       /* This better does not fail.  */
    449       assert (shdr != NULL);
    450 
    451       /* The sh_link field of the zeroth section header contains the value.  */
    452       shdr->sh_link = shstrscnndx;
    453 
    454       (void) gelf_update_shdr (scn, shdr);
    455 
    456       /* This is the sign for the overflow.  */
    457       ehdr->e_shstrndx = SHN_XINDEX;
    458     }
    459   else
    460     ehdr->e_shstrndx = elf_ndxscn (shstrscn);
    461 
    462   gelf_update_ehdr (ctx->out.elf, ehdr);
    463 
    464   /* Write out the ELF file.  */
    465   if (unlikely (elf_update (ctx->out.elf, ELF_C_WRITE_MMAP)) < 0)
    466     {
    467       __libasm_seterrno (ASM_E_LIBELF);
    468       result = -1;
    469     }
    470 
    471   /* We do not need the section header and symbol string tables anymore.  */
    472   free (shstrtabdata->d_buf);
    473   if (strtabdata != NULL)
    474     free (strtabdata->d_buf);
    475   /* We might have allocated the extended symbol table index.  */
    476   if (xndxdata != NULL)
    477     free (xndxdata->d_buf);
    478 
    479   /* Free section groups memory.  */
    480   AsmScnGrp_t *scngrp = ctx->groups;
    481   if (scngrp != NULL)
    482     do
    483       free (elf_getdata (scngrp->scn, NULL)->d_buf);
    484     while ((scngrp = scngrp->next) != ctx->groups);
    485 
    486   /* Finalize the ELF handling.  */
    487   if (unlikely (elf_end (ctx->out.elf)) != 0)
    488     {
    489       __libasm_seterrno (ASM_E_LIBELF);
    490       result = -1;
    491     }
    492 
    493   /* Free the temporary resources.  */
    494   free (symtab);
    495 
    496   return result;
    497 }
    498 
    499 
    500 int
    501 asm_end (ctx)
    502      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 __libasm_finictx (ctx)
    559      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       ebl_strtabfree (ctx->section_strtab);
    605       ebl_strtabfree (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