Blame libasm/asm_end.c

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