Blame libasm/asm_end.c

Packit 032894
/* Finalize operations on the assembler context, free all resources.
Packit 032894
   Copyright (C) 2002, 2003, 2005, 2016 Red Hat, Inc.
Packit 032894
   This file is part of elfutils.
Packit 032894
   Written by Ulrich Drepper <drepper@redhat.com>, 2002.
Packit 032894
Packit 032894
   This file is free software; you can redistribute it and/or modify
Packit 032894
   it under the terms of either
Packit 032894
Packit 032894
     * the GNU Lesser General Public License as published by the Free
Packit 032894
       Software Foundation; either version 3 of the License, or (at
Packit 032894
       your option) any later version
Packit 032894
Packit 032894
   or
Packit 032894
Packit 032894
     * the GNU General Public License as published by the Free
Packit 032894
       Software Foundation; either version 2 of the License, or (at
Packit 032894
       your option) any later version
Packit 032894
Packit 032894
   or both in parallel, as here.
Packit 032894
Packit 032894
   elfutils is distributed in the hope that it will be useful, but
Packit 032894
   WITHOUT ANY WARRANTY; without even the implied warranty of
Packit 032894
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Packit 032894
   General Public License for more details.
Packit 032894
Packit 032894
   You should have received copies of the GNU General Public License and
Packit 032894
   the GNU Lesser General Public License along with this program.  If
Packit 032894
   not, see <http://www.gnu.org/licenses/>.  */
Packit 032894
Packit 032894
#ifdef HAVE_CONFIG_H
Packit 032894
# include <config.h>
Packit 032894
#endif
Packit 032894
Packit 032894
#include <assert.h>
Packit 032894
#include <libintl.h>
Packit 032894
#include <stdio.h>
Packit 032894
#include <stdlib.h>
Packit 032894
#include <string.h>
Packit 032894
#include <unistd.h>
Packit 032894
#include <sys/stat.h>
Packit 032894
Packit 032894
#include <libasmP.h>
Packit 032894
#include <libelf.h>
Packit 032894
#include <system.h>
Packit 032894
Packit 032894
Packit 032894
static int
Packit 032894
text_end (AsmCtx_t *ctx __attribute__ ((unused)))
Packit 032894
{
Packit Service 35cfd5
  if (fflush (ctx->out.file) != 0)
Packit 032894
    {
Packit 032894
      __libasm_seterrno (ASM_E_IOERROR);
Packit 032894
      return -1;
Packit 032894
    }
Packit 032894
Packit 032894
  return 0;
Packit 032894
}
Packit 032894
Packit 032894
Packit 032894
static int
Packit 032894
binary_end (AsmCtx_t *ctx)
Packit 032894
{
Packit 032894
  void *symtab = NULL;
Packit 032894
  Dwelf_Strent *symscn_strent = NULL;
Packit 032894
  Dwelf_Strent *strscn_strent = NULL;
Packit 032894
  Dwelf_Strent *xndxscn_strent = NULL;
Packit 032894
  Elf_Scn *shstrscn;
Packit 032894
  Dwelf_Strent *shstrscn_strent;
Packit 032894
  size_t shstrscnndx;
Packit 032894
  size_t symscnndx = 0;
Packit 032894
  size_t strscnndx = 0;
Packit 032894
  size_t xndxscnndx = 0;
Packit 032894
  Elf_Data *data;
Packit 032894
  Elf_Data *shstrtabdata;
Packit 032894
  Elf_Data *strtabdata = NULL;
Packit 032894
  Elf_Data *xndxdata = NULL;
Packit 032894
  GElf_Shdr shdr_mem;
Packit 032894
  GElf_Shdr *shdr;
Packit 032894
  GElf_Ehdr ehdr_mem;
Packit 032894
  GElf_Ehdr *ehdr;
Packit 032894
  AsmScn_t *asmscn;
Packit 032894
  int result = 0;
Packit 032894
Packit 032894
  /* Iterate over the created sections and compute the offsets of the
Packit 032894
     various subsections and fill in the content.  */
Packit 032894
  for (asmscn = ctx->section_list; asmscn != NULL; asmscn = asmscn->allnext)
Packit 032894
    {
Packit 032894
#if 0
Packit 032894
      Elf_Scn *scn = elf_getscn (ctx->out.elf, asmscn->data.main.scnndx);
Packit 032894
#else
Packit 032894
      Elf_Scn *scn = asmscn->data.main.scn;
Packit 032894
#endif
Packit 032894
      off_t offset = 0;
Packit 032894
      AsmScn_t *asmsubscn = asmscn;
Packit 032894
Packit 032894
      do
Packit 032894
	{
Packit 032894
	  struct AsmData *content = asmsubscn->content;
Packit 032894
	  bool first = true;
Packit 032894
Packit 032894
	  offset = ((offset + asmsubscn->max_align - 1)
Packit 032894
		    & ~(asmsubscn->max_align - 1));
Packit 032894
Packit 032894
	  /* Update the offset for this subsection.  This field now
Packit 032894
	     stores the offset of the first by in this subsection.  */
Packit 032894
	  asmsubscn->offset = offset;
Packit 032894
Packit 032894
	  /* Note that the content list is circular.  */
Packit 032894
	  if (content != NULL)
Packit 032894
	    do
Packit 032894
	      {
Packit 032894
		Elf_Data *newdata = elf_newdata (scn);
Packit 032894
Packit 032894
		if (newdata == NULL)
Packit 032894
		  {
Packit 032894
		    __libasm_seterrno (ASM_E_LIBELF);
Packit 032894
		    return -1;
Packit 032894
		  }
Packit 032894
Packit 032894
		newdata->d_buf = content->data;
Packit 032894
		newdata->d_type = ELF_T_BYTE;
Packit 032894
		newdata->d_size = content->len;
Packit 032894
		newdata->d_off = offset;
Packit 032894
		newdata->d_align = first ? asmsubscn->max_align : 1;
Packit 032894
Packit 032894
		offset += content->len;
Packit 032894
	      }
Packit 032894
	    while ((content = content->next) != asmsubscn->content);
Packit 032894
	}
Packit 032894
      while ((asmsubscn = asmsubscn->subnext) != NULL);
Packit 032894
    }
Packit 032894
Packit 032894
Packit 032894
  /* Create the symbol table if necessary.  */
Packit 032894
  if (ctx->nsymbol_tab > 0)
Packit 032894
    {
Packit 032894
      /* Create the symbol table and string table section names.  */
Packit 032894
      symscn_strent = dwelf_strtab_add_len (ctx->section_strtab, ".symtab", 8);
Packit 032894
      strscn_strent = dwelf_strtab_add_len (ctx->section_strtab, ".strtab", 8);
Packit 032894
Packit 032894
      /* Create the symbol string table section.  */
Packit 032894
      Elf_Scn *strscn = elf_newscn (ctx->out.elf);
Packit 032894
      strtabdata = elf_newdata (strscn);
Packit 032894
      shdr = gelf_getshdr (strscn, &shdr_mem);
Packit 032894
      if (strtabdata == NULL || shdr == NULL)
Packit 032894
	{
Packit 032894
	  __libasm_seterrno (ASM_E_LIBELF);
Packit 032894
	  return -1;
Packit 032894
	}
Packit 032894
      strscnndx = elf_ndxscn (strscn);
Packit 032894
Packit 032894
      dwelf_strtab_finalize (ctx->symbol_strtab, strtabdata);
Packit 032894
Packit 032894
      shdr->sh_type = SHT_STRTAB;
Packit 032894
      assert (shdr->sh_entsize == 0);
Packit 032894
Packit 032894
      (void) gelf_update_shdr (strscn, shdr);
Packit 032894
Packit 032894
      /* Create the symbol table section.  */
Packit 032894
      Elf_Scn *symscn = elf_newscn (ctx->out.elf);
Packit 032894
      data = elf_newdata (symscn);
Packit 032894
      shdr = gelf_getshdr (symscn, &shdr_mem);
Packit 032894
      if (data == NULL || shdr == NULL)
Packit 032894
	{
Packit 032894
	  __libasm_seterrno (ASM_E_LIBELF);
Packit 032894
	  return -1;
Packit 032894
	}
Packit 032894
      symscnndx = elf_ndxscn (symscn);
Packit 032894
Packit 032894
      /* We know how many symbols there will be in the symbol table.  */
Packit 032894
      data->d_size = gelf_fsize (ctx->out.elf, ELF_T_SYM,
Packit 032894
				 ctx->nsymbol_tab + 1, EV_CURRENT);
Packit 032894
      symtab = malloc (data->d_size);
Packit 032894
      if (symtab == NULL)
Packit 032894
	return -1;
Packit 032894
      data->d_buf = symtab;
Packit 032894
      data->d_type = ELF_T_SYM;
Packit 032894
      data->d_off = 0;
Packit 032894
Packit 032894
      /* Clear the first entry.  */
Packit 032894
      GElf_Sym syment;
Packit 032894
      memset (&syment, '\0', sizeof (syment));
Packit 032894
      (void) gelf_update_sym (data, 0, &syment);
Packit 032894
Packit 032894
      /* Iterate over the symbol table.  */
Packit 032894
      void *runp = NULL;
Packit 032894
      int ptr_local = 1;	/* Start with index 1; zero remains unused.  */
Packit 032894
      int ptr_nonlocal = ctx->nsymbol_tab;
Packit 032894
      uint32_t *xshndx = NULL;
Packit 032894
      AsmSym_t *sym;
Packit 032894
      while ((sym = asm_symbol_tab_iterate (&ctx->symbol_tab, &runp)) != NULL)
Packit 032894
	if (asm_emit_symbol_p (dwelf_strent_str (sym->strent)))
Packit 032894
	  {
Packit 032894
	    assert (ptr_local <= ptr_nonlocal);
Packit 032894
Packit 032894
	    syment.st_name = dwelf_strent_off (sym->strent);
Packit 032894
	    syment.st_info = GELF_ST_INFO (sym->binding, sym->type);
Packit 032894
	    syment.st_other = 0;
Packit 032894
	    syment.st_value = sym->scn->offset + sym->offset;
Packit 032894
	    syment.st_size = sym->size;
Packit 032894
Packit 032894
	    /* Add local symbols at the beginning, the other from
Packit 032894
	       the end.  */
Packit 032894
	    int ptr = sym->binding == STB_LOCAL ? ptr_local++ : ptr_nonlocal--;
Packit 032894
Packit 032894
	    /* Determine the section index.  We have to handle the
Packit 032894
	       overflow correctly.  */
Packit 032894
	    Elf_Scn *scn = (sym->scn->subsection_id == 0
Packit 032894
			    ? sym->scn->data.main.scn
Packit 032894
			    : sym->scn->data.up->data.main.scn);
Packit 032894
Packit 032894
	    Elf32_Word ndx;
Packit 032894
	    if (unlikely (scn == ASM_ABS_SCN))
Packit 032894
	      ndx = SHN_ABS;
Packit 032894
	    else if (unlikely (scn == ASM_COM_SCN))
Packit 032894
	      ndx = SHN_COMMON;
Packit 032894
	    else if (unlikely ((ndx = elf_ndxscn (scn)) >= SHN_LORESERVE))
Packit 032894
	      {
Packit 032894
		if (unlikely (xshndx == NULL))
Packit 032894
		  {
Packit 032894
		    /* The extended section index section does not yet
Packit 032894
		       exist.  */
Packit 032894
		    Elf_Scn *xndxscn;
Packit 032894
Packit 032894
		    xndxscn = elf_newscn (ctx->out.elf);
Packit 032894
		    xndxdata = elf_newdata (xndxscn);
Packit 032894
		    shdr = gelf_getshdr (xndxscn, &shdr_mem);
Packit 032894
		    if (xndxdata == NULL || shdr == NULL)
Packit 032894
		      {
Packit 032894
			__libasm_seterrno (ASM_E_LIBELF);
Packit 032894
			return -1;
Packit 032894
		      }
Packit 032894
		    xndxscnndx = elf_ndxscn (xndxscn);
Packit 032894
Packit 032894
		    shdr->sh_type = SHT_SYMTAB_SHNDX;
Packit 032894
		    shdr->sh_entsize = sizeof (Elf32_Word);
Packit 032894
		    shdr->sh_addralign = sizeof (Elf32_Word);
Packit 032894
		    shdr->sh_link = symscnndx;
Packit 032894
Packit 032894
		    (void) gelf_update_shdr (xndxscn, shdr);
Packit 032894
Packit 032894
		    xndxscn_strent = dwelf_strtab_add_len (ctx->section_strtab,
Packit 032894
							   ".symtab_shndx",
Packit 032894
							   14);
Packit 032894
Packit 032894
		    /* Note that using 'elf32_fsize' instead of
Packit 032894
		       'gelf_fsize' here is correct.  */
Packit 032894
		    xndxdata->d_size = elf32_fsize (ELF_T_WORD,
Packit 032894
						    ctx->nsymbol_tab + 1,
Packit 032894
						    EV_CURRENT);
Packit 032894
		    xshndx = xndxdata->d_buf = calloc (1, xndxdata->d_size);
Packit 032894
		    if (xshndx == NULL)
Packit 032894
		      return -1;
Packit 032894
		    /* Using ELF_T_WORD here relies on the fact that the
Packit 032894
		       32- and 64-bit types are the same size.  */
Packit 032894
		    xndxdata->d_type = ELF_T_WORD;
Packit 032894
		    xndxdata->d_off = 0;
Packit 032894
		  }
Packit 032894
Packit 032894
		/* Store the real section index in the extended setion
Packit 032894
		   index table.  */
Packit 032894
		assert ((size_t) ptr < ctx->nsymbol_tab + 1);
Packit 032894
		xshndx[ptr] = ndx;
Packit 032894
Packit 032894
		/* And signal that this happened.  */
Packit 032894
		ndx = SHN_XINDEX;
Packit 032894
	      }
Packit 032894
	    syment.st_shndx = ndx;
Packit 032894
Packit 032894
	    /* Remember where we put the symbol.  */
Packit 032894
	    sym->symidx = ptr;
Packit 032894
Packit 032894
	    (void) gelf_update_sym (data, ptr, &syment);
Packit 032894
	  }
Packit 032894
Packit 032894
      assert (ptr_local == ptr_nonlocal + 1);
Packit 032894
Packit 032894
      shdr->sh_type = SHT_SYMTAB;
Packit 032894
      shdr->sh_link = strscnndx;
Packit 032894
      shdr->sh_info = ptr_local;
Packit 032894
      shdr->sh_entsize = gelf_fsize (ctx->out.elf, ELF_T_SYM, 1, EV_CURRENT);
Packit 032894
      shdr->sh_addralign = gelf_fsize (ctx->out.elf, ELF_T_ADDR, 1,
Packit 032894
				       EV_CURRENT);
Packit 032894
Packit 032894
      (void) gelf_update_shdr (symscn, shdr);
Packit 032894
    }
Packit 032894
Packit 032894
Packit 032894
  /* Create the section header string table section and fill in the
Packit 032894
     references in the section headers.  */
Packit 032894
  shstrscn = elf_newscn (ctx->out.elf);
Packit 032894
  shstrtabdata = elf_newdata (shstrscn);
Packit 032894
  shdr = gelf_getshdr (shstrscn, &shdr_mem);
Packit 032894
  if (shstrscn == NULL || shstrtabdata == NULL || shdr == NULL)
Packit 032894
    {
Packit 032894
      __libasm_seterrno (ASM_E_LIBELF);
Packit 032894
      return -1;
Packit 032894
    }
Packit 032894
Packit 032894
Packit 032894
  /* Add the name of the section header string table.  */
Packit 032894
  shstrscn_strent = dwelf_strtab_add_len (ctx->section_strtab,
Packit 032894
					  ".shstrtab", 10);
Packit 032894
Packit 032894
  dwelf_strtab_finalize (ctx->section_strtab, shstrtabdata);
Packit 032894
Packit 032894
  shdr->sh_type = SHT_STRTAB;
Packit 032894
  assert (shdr->sh_entsize == 0);
Packit 032894
  shdr->sh_name = dwelf_strent_off (shstrscn_strent);
Packit 032894
Packit 032894
  (void) gelf_update_shdr (shstrscn, shdr);
Packit 032894
Packit 032894
Packit 032894
  /* Create the section groups.  */
Packit 032894
  if (ctx->groups != NULL)
Packit 032894
    {
Packit 032894
      AsmScnGrp_t *runp = ctx->groups->next;
Packit 032894
Packit 032894
      do
Packit 032894
	{
Packit 032894
	  Elf_Scn *scn;
Packit 032894
	  Elf32_Word *grpdata;
Packit 032894
Packit 032894
	  scn = runp->scn;
Packit 032894
	  assert (scn != NULL);
Packit 032894
	  shdr = gelf_getshdr (scn, &shdr_mem);
Packit 032894
	  assert (shdr != NULL);
Packit 032894
Packit 032894
	  data = elf_newdata (scn);
Packit 032894
	  if (data == NULL)
Packit 032894
	    {
Packit 032894
	      __libasm_seterrno (ASM_E_LIBELF);
Packit 032894
	      return -1;
Packit 032894
	    }
Packit 032894
Packit 032894
	  /* It is correct to use 'elf32_fsize' instead of 'gelf_fsize'
Packit 032894
	     here.  */
Packit 032894
	  data->d_size = elf32_fsize (ELF_T_WORD, runp->nmembers + 1,
Packit 032894
				      EV_CURRENT);
Packit 032894
	  grpdata = data->d_buf = malloc (data->d_size);
Packit 032894
	  if (grpdata == NULL)
Packit 032894
	    return -1;
Packit 032894
	  data->d_type = ELF_T_WORD;
Packit 032894
	  data->d_off = 0;
Packit 032894
	  data->d_align = elf32_fsize (ELF_T_WORD, 1, EV_CURRENT);
Packit 032894
Packit 032894
	  /* The first word of the section is filled with the flag word.  */
Packit 032894
	  *grpdata++ = runp->flags;
Packit 032894
Packit 032894
	  if (runp->members != NULL)
Packit 032894
	    {
Packit 032894
	      AsmScn_t *member = runp->members->data.main.next_in_group;
Packit 032894
Packit 032894
	      do
Packit 032894
		{
Packit 032894
		  /* Only sections, not subsections, can be registered
Packit 032894
		     as member of a group.  The subsections get
Packit 032894
		     automatically included.  */
Packit 032894
		  assert (member->subsection_id == 0);
Packit 032894
Packit 032894
		  *grpdata++ = elf_ndxscn (member->data.main.scn);
Packit 032894
		}
Packit 032894
	      while ((member = member->data.main.next_in_group)
Packit 032894
		     != runp->members->data.main.next_in_group);
Packit 032894
	    }
Packit 032894
Packit 032894
	  /* Construct the section header.  */
Packit 032894
	  shdr->sh_name = dwelf_strent_off (runp->strent);
Packit 032894
	  shdr->sh_type = SHT_GROUP;
Packit 032894
	  shdr->sh_flags = 0;
Packit 032894
	  shdr->sh_link = symscnndx;
Packit 032894
	  /* If the user did not specify a signature we use the initial
Packit 032894
	     empty symbol in the symbol table as the signature.  */
Packit 032894
	  shdr->sh_info = (runp->signature != NULL
Packit 032894
			   ? runp->signature->symidx : 0);
Packit 032894
Packit 032894
	  (void) gelf_update_shdr (scn, shdr);
Packit 032894
	}
Packit 032894
      while ((runp = runp->next) != ctx->groups->next);
Packit 032894
    }
Packit 032894
Packit 032894
Packit 032894
  /* Add the name to the symbol section.  */
Packit 032894
  if (likely (symscnndx != 0))
Packit 032894
    {
Packit 032894
      Elf_Scn *scn = elf_getscn (ctx->out.elf, symscnndx);
Packit 032894
Packit 032894
      shdr = gelf_getshdr (scn, &shdr_mem);
Packit 032894
Packit 032894
      shdr->sh_name = dwelf_strent_off (symscn_strent);
Packit 032894
Packit 032894
      (void) gelf_update_shdr (scn, shdr);
Packit 032894
Packit 032894
Packit 032894
      /* Add the name to the string section.  */
Packit 032894
      assert (strscnndx != 0);
Packit 032894
      scn = elf_getscn (ctx->out.elf, strscnndx);
Packit 032894
Packit 032894
      shdr = gelf_getshdr (scn, &shdr_mem);
Packit 032894
Packit 032894
      shdr->sh_name = dwelf_strent_off (strscn_strent);
Packit 032894
Packit 032894
      (void) gelf_update_shdr (scn, shdr);
Packit 032894
Packit 032894
Packit 032894
      /* Add the name to the extended symbol index section.  */
Packit 032894
      if (xndxscnndx != 0)
Packit 032894
	{
Packit 032894
	  scn = elf_getscn (ctx->out.elf, xndxscnndx);
Packit 032894
Packit 032894
	  shdr = gelf_getshdr (scn, &shdr_mem);
Packit 032894
Packit 032894
	  shdr->sh_name = dwelf_strent_off (xndxscn_strent);
Packit 032894
Packit 032894
	  (void) gelf_update_shdr (scn, shdr);
Packit 032894
	}
Packit 032894
    }
Packit 032894
Packit 032894
Packit 032894
  /* Iterate over the created sections and fill in the names.  */
Packit 032894
  for (asmscn = ctx->section_list; asmscn != NULL; asmscn = asmscn->allnext)
Packit 032894
    {
Packit 032894
      shdr = gelf_getshdr (asmscn->data.main.scn, &shdr_mem);
Packit 032894
      /* This better should not fail.  */
Packit 032894
      assert (shdr != NULL);
Packit 032894
Packit 032894
      shdr->sh_name = dwelf_strent_off (asmscn->data.main.strent);
Packit 032894
Packit 032894
      /* We now know the maximum alignment.  */
Packit 032894
      shdr->sh_addralign = asmscn->max_align;
Packit 032894
Packit 032894
      (void) gelf_update_shdr (asmscn->data.main.scn, shdr);
Packit 032894
    }
Packit 032894
Packit 032894
  /* Put the reference to the section header string table in the ELF
Packit 032894
     header.  */
Packit 032894
  ehdr = gelf_getehdr (ctx->out.elf, &ehdr_mem);
Packit 032894
  assert (ehdr != NULL);
Packit 032894
Packit 032894
  shstrscnndx = elf_ndxscn (shstrscn);
Packit 032894
  if (unlikely (shstrscnndx > SHN_HIRESERVE)
Packit 032894
      || unlikely (shstrscnndx == SHN_XINDEX))
Packit 032894
    {
Packit 032894
      /* The index of the section header string sectio is too large.  */
Packit 032894
      Elf_Scn *scn = elf_getscn (ctx->out.elf, 0);
Packit 032894
Packit 032894
      /* Get the header for the zeroth section.  */
Packit 032894
      shdr = gelf_getshdr (scn, &shdr_mem);
Packit 032894
      /* This better does not fail.  */
Packit 032894
      assert (shdr != NULL);
Packit 032894
Packit 032894
      /* The sh_link field of the zeroth section header contains the value.  */
Packit 032894
      shdr->sh_link = shstrscnndx;
Packit 032894
Packit 032894
      (void) gelf_update_shdr (scn, shdr);
Packit 032894
Packit 032894
      /* This is the sign for the overflow.  */
Packit 032894
      ehdr->e_shstrndx = SHN_XINDEX;
Packit 032894
    }
Packit 032894
  else
Packit 032894
    ehdr->e_shstrndx = elf_ndxscn (shstrscn);
Packit 032894
Packit 032894
  if (unlikely (gelf_update_ehdr (ctx->out.elf, ehdr) == 0))
Packit 032894
    {
Packit 032894
      __libasm_seterrno (ASM_E_LIBELF);
Packit 032894
      result = -1;
Packit 032894
    }
Packit 032894
Packit 032894
  /* Write out the ELF file.  */
Packit 032894
  if (unlikely (elf_update (ctx->out.elf, ELF_C_WRITE_MMAP) < 0))
Packit 032894
    {
Packit 032894
      __libasm_seterrno (ASM_E_LIBELF);
Packit 032894
      result = -1;
Packit 032894
    }
Packit 032894
Packit 032894
  /* We do not need the section header and symbol string tables anymore.  */
Packit 032894
  free (shstrtabdata->d_buf);
Packit 032894
  if (strtabdata != NULL)
Packit 032894
    free (strtabdata->d_buf);
Packit 032894
  /* We might have allocated the extended symbol table index.  */
Packit 032894
  if (xndxdata != NULL)
Packit 032894
    free (xndxdata->d_buf);
Packit 032894
Packit 032894
  /* Free section groups memory.  */
Packit 032894
  AsmScnGrp_t *scngrp = ctx->groups;
Packit 032894
  if (scngrp != NULL)
Packit 032894
    do
Packit 032894
      free (elf_getdata (scngrp->scn, NULL)->d_buf);
Packit 032894
    while ((scngrp = scngrp->next) != ctx->groups);
Packit 032894
Packit 032894
  /* Finalize the ELF handling.  */
Packit 032894
  if (unlikely (elf_end (ctx->out.elf)) != 0)
Packit 032894
    {
Packit 032894
      __libasm_seterrno (ASM_E_LIBELF);
Packit 032894
      result = -1;
Packit 032894
    }
Packit 032894
Packit 032894
  /* Free the temporary resources.  */
Packit 032894
  free (symtab);
Packit 032894
Packit 032894
  return result;
Packit 032894
}
Packit 032894
Packit 032894
Packit 032894
int
Packit 032894
asm_end (AsmCtx_t *ctx)
Packit 032894
{
Packit 032894
  int result;
Packit 032894
Packit 032894
  if (ctx == NULL)
Packit 032894
    /* Something went wrong earlier.  */
Packit 032894
    return -1;
Packit 032894
Packit 032894
  result = unlikely (ctx->textp) ? text_end (ctx) : binary_end (ctx);
Packit 032894
  if (result != 0)
Packit 032894
    return result;
Packit 032894
Packit 032894
  /* Make the new file globally readable and user/group-writable.  */
Packit 032894
  if (fchmod (ctx->fd, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH) != 0)
Packit 032894
    {
Packit 032894
      __libasm_seterrno (ASM_E_CANNOT_CHMOD);
Packit 032894
      return -1;
Packit 032894
    }
Packit 032894
Packit 032894
  /* Rename output file.  */
Packit 032894
  if (rename (ctx->tmp_fname, ctx->fname) != 0)
Packit 032894
    {
Packit 032894
      __libasm_seterrno (ASM_E_CANNOT_RENAME);
Packit 032894
      return -1;
Packit 032894
    }
Packit 032894
Packit 032894
  /* Free the resources.  */
Packit 032894
  __libasm_finictx (ctx);
Packit 032894
Packit 032894
  return 0;
Packit 032894
}
Packit 032894
Packit 032894
Packit 032894
static void
Packit 032894
free_section (AsmScn_t *scnp)
Packit 032894
{
Packit 032894
  void *oldp;
Packit 032894
Packit 032894
  if (scnp->subnext != NULL)
Packit 032894
    free_section (scnp->subnext);
Packit 032894
Packit 032894
  struct AsmData *data = scnp->content;
Packit 032894
  if (data != NULL)
Packit 032894
    do
Packit 032894
      {
Packit 032894
	oldp = data;
Packit 032894
	data = data->next;
Packit 032894
	free (oldp);
Packit 032894
      }
Packit 032894
    while (oldp != scnp->content);
Packit 032894
Packit 032894
  free (scnp);
Packit 032894
}
Packit 032894
Packit 032894
Packit 032894
void
Packit 032894
internal_function
Packit 032894
__libasm_finictx (AsmCtx_t *ctx)
Packit 032894
{
Packit 032894
  /* Iterate through section table and free individual entries.  */
Packit 032894
  AsmScn_t *scn = ctx->section_list;
Packit 032894
  while (scn != NULL)
Packit 032894
    {
Packit 032894
      AsmScn_t *oldp = scn;
Packit 032894
      scn = scn->allnext;
Packit 032894
      free_section (oldp);
Packit 032894
    }
Packit 032894
Packit 032894
  /* Free the resources of the symbol table.  */
Packit 032894
  void *runp = NULL;
Packit 032894
  AsmSym_t *sym;
Packit 032894
  while ((sym = asm_symbol_tab_iterate (&ctx->symbol_tab, &runp)) != NULL)
Packit 032894
    free (sym);
Packit 032894
  asm_symbol_tab_free (&ctx->symbol_tab);
Packit 032894
Packit 032894
Packit 032894
  /* Free section groups.  */
Packit 032894
  AsmScnGrp_t *scngrp = ctx->groups;
Packit 032894
  if (scngrp != NULL)
Packit 032894
    do
Packit 032894
      {
Packit 032894
	AsmScnGrp_t *oldp = scngrp;
Packit 032894
Packit 032894
	scngrp = scngrp->next;
Packit 032894
	free (oldp);
Packit 032894
      }
Packit 032894
    while (scngrp != ctx->groups);
Packit 032894
Packit 032894
Packit 032894
  if (unlikely (ctx->textp))
Packit 032894
    {
Packit 032894
      /* Close the stream.  */
Packit 032894
      fclose (ctx->out.file);
Packit 032894
    }
Packit 032894
  else
Packit 032894
    {
Packit 032894
      /* Close the output file.  */
Packit 032894
      /* XXX We should test for errors here but what would we do if we'd
Packit 032894
	 find any.  */
Packit 032894
      (void) close (ctx->fd);
Packit 032894
Packit 032894
      /* And the string tables.  */
Packit 032894
      dwelf_strtab_free (ctx->section_strtab);
Packit 032894
      dwelf_strtab_free (ctx->symbol_strtab);
Packit 032894
    }
Packit 032894
Packit 032894
  /* Initialize the lock.  */
Packit 032894
  rwlock_fini (ctx->lock);
Packit 032894
Packit 032894
  /* Finally free the data structure.   */
Packit 032894
  free (ctx);
Packit 032894
}