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 (AsmCtx_t *ctx)
    502 {
    503   int result;
    504 
    505   if (ctx == NULL)
    506     /* Something went wrong earlier.  */
    507     return -1;
    508 
    509   result = unlikely (ctx->textp) ? text_end (ctx) : binary_end (ctx);
    510   if (result != 0)
    511     return result;
    512 
    513   /* Make the new file globally readable and user/group-writable.  */
    514   if (fchmod (ctx->fd, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH) != 0)
    515     {
    516       __libasm_seterrno (ASM_E_CANNOT_CHMOD);
    517       return -1;
    518     }
    519 
    520   /* Rename output file.  */
    521   if (rename (ctx->tmp_fname, ctx->fname) != 0)
    522     {
    523       __libasm_seterrno (ASM_E_CANNOT_RENAME);
    524       return -1;
    525     }
    526 
    527   /* Free the resources.  */
    528   __libasm_finictx (ctx);
    529 
    530   return 0;
    531 }
    532 
    533 
    534 static void
    535 free_section (AsmScn_t *scnp)
    536 {
    537   void *oldp;
    538 
    539   if (scnp->subnext != NULL)
    540     free_section (scnp->subnext);
    541 
    542   struct AsmData *data = scnp->content;
    543   if (data != NULL)
    544     do
    545       {
    546 	oldp = data;
    547 	data = data->next;
    548 	free (oldp);
    549       }
    550     while (oldp != scnp->content);
    551 
    552   free (scnp);
    553 }
    554 
    555 
    556 void
    557 internal_function
    558 __libasm_finictx (AsmCtx_t *ctx)
    559 {
    560   /* Iterate through section table and free individual entries.  */
    561   AsmScn_t *scn = ctx->section_list;
    562   while (scn != NULL)
    563     {
    564       AsmScn_t *oldp = scn;
    565       scn = scn->allnext;
    566       free_section (oldp);
    567     }
    568 
    569   /* Free the resources of the symbol table.  */
    570   void *runp = NULL;
    571   AsmSym_t *sym;
    572   while ((sym = asm_symbol_tab_iterate (&ctx->symbol_tab, &runp)) != NULL)
    573     free (sym);
    574   asm_symbol_tab_free (&ctx->symbol_tab);
    575 
    576 
    577   /* Free section groups.  */
    578   AsmScnGrp_t *scngrp = ctx->groups;
    579   if (scngrp != NULL)
    580     do
    581       {
    582 	AsmScnGrp_t *oldp = scngrp;
    583 
    584 	scngrp = scngrp->next;
    585 	free (oldp);
    586       }
    587     while (scngrp != ctx->groups);
    588 
    589 
    590   if (unlikely (ctx->textp))
    591     {
    592       /* Close the stream.  */
    593       fclose (ctx->out.file);
    594     }
    595   else
    596     {
    597       /* Close the output file.  */
    598       /* XXX We should test for errors here but what would we do if we'd
    599 	 find any.  */
    600       (void) close (ctx->fd);
    601 
    602       /* And the string tables.  */
    603       ebl_strtabfree (ctx->section_strtab);
    604       ebl_strtabfree (ctx->symbol_strtab);
    605     }
    606 
    607   /* Initialize the lock.  */
    608   rwlock_fini (ctx->lock);
    609 
    610   /* Finally free the data structure.   */
    611   free (ctx);
    612 }
    613