1da0c48c4Sopenharmony_ci/* Finalize operations on the assembler context, free all resources.
2da0c48c4Sopenharmony_ci   Copyright (C) 2002, 2003, 2005, 2016 Red Hat, Inc.
3da0c48c4Sopenharmony_ci   This file is part of elfutils.
4da0c48c4Sopenharmony_ci   Written by Ulrich Drepper <drepper@redhat.com>, 2002.
5da0c48c4Sopenharmony_ci
6da0c48c4Sopenharmony_ci   This file is free software; you can redistribute it and/or modify
7da0c48c4Sopenharmony_ci   it under the terms of either
8da0c48c4Sopenharmony_ci
9da0c48c4Sopenharmony_ci     * the GNU Lesser General Public License as published by the Free
10da0c48c4Sopenharmony_ci       Software Foundation; either version 3 of the License, or (at
11da0c48c4Sopenharmony_ci       your option) any later version
12da0c48c4Sopenharmony_ci
13da0c48c4Sopenharmony_ci   or
14da0c48c4Sopenharmony_ci
15da0c48c4Sopenharmony_ci     * the GNU General Public License as published by the Free
16da0c48c4Sopenharmony_ci       Software Foundation; either version 2 of the License, or (at
17da0c48c4Sopenharmony_ci       your option) any later version
18da0c48c4Sopenharmony_ci
19da0c48c4Sopenharmony_ci   or both in parallel, as here.
20da0c48c4Sopenharmony_ci
21da0c48c4Sopenharmony_ci   elfutils is distributed in the hope that it will be useful, but
22da0c48c4Sopenharmony_ci   WITHOUT ANY WARRANTY; without even the implied warranty of
23da0c48c4Sopenharmony_ci   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
24da0c48c4Sopenharmony_ci   General Public License for more details.
25da0c48c4Sopenharmony_ci
26da0c48c4Sopenharmony_ci   You should have received copies of the GNU General Public License and
27da0c48c4Sopenharmony_ci   the GNU Lesser General Public License along with this program.  If
28da0c48c4Sopenharmony_ci   not, see <http://www.gnu.org/licenses/>.  */
29da0c48c4Sopenharmony_ci
30da0c48c4Sopenharmony_ci#ifdef HAVE_CONFIG_H
31da0c48c4Sopenharmony_ci# include <config.h>
32da0c48c4Sopenharmony_ci#endif
33da0c48c4Sopenharmony_ci
34da0c48c4Sopenharmony_ci#include <assert.h>
35da0c48c4Sopenharmony_ci#include <stdio.h>
36da0c48c4Sopenharmony_ci#include <stdlib.h>
37da0c48c4Sopenharmony_ci#include <string.h>
38da0c48c4Sopenharmony_ci#include <sys/stat.h>
39da0c48c4Sopenharmony_ci
40da0c48c4Sopenharmony_ci#include <libasmP.h>
41da0c48c4Sopenharmony_ci#include <libelf.h>
42da0c48c4Sopenharmony_ci
43da0c48c4Sopenharmony_ci
44da0c48c4Sopenharmony_cistatic int
45da0c48c4Sopenharmony_citext_end (AsmCtx_t *ctx __attribute__ ((unused)))
46da0c48c4Sopenharmony_ci{
47da0c48c4Sopenharmony_ci  if (fflush (ctx->out.file) != 0)
48da0c48c4Sopenharmony_ci    {
49da0c48c4Sopenharmony_ci      __libasm_seterrno (ASM_E_IOERROR);
50da0c48c4Sopenharmony_ci      return -1;
51da0c48c4Sopenharmony_ci    }
52da0c48c4Sopenharmony_ci
53da0c48c4Sopenharmony_ci  return 0;
54da0c48c4Sopenharmony_ci}
55da0c48c4Sopenharmony_ci
56da0c48c4Sopenharmony_ci
57da0c48c4Sopenharmony_cistatic int
58da0c48c4Sopenharmony_cibinary_end (AsmCtx_t *ctx)
59da0c48c4Sopenharmony_ci{
60da0c48c4Sopenharmony_ci  void *symtab = NULL;
61da0c48c4Sopenharmony_ci  Dwelf_Strent *symscn_strent = NULL;
62da0c48c4Sopenharmony_ci  Dwelf_Strent *strscn_strent = NULL;
63da0c48c4Sopenharmony_ci  Dwelf_Strent *xndxscn_strent = NULL;
64da0c48c4Sopenharmony_ci  Elf_Scn *shstrscn;
65da0c48c4Sopenharmony_ci  Dwelf_Strent *shstrscn_strent;
66da0c48c4Sopenharmony_ci  size_t shstrscnndx;
67da0c48c4Sopenharmony_ci  size_t symscnndx = 0;
68da0c48c4Sopenharmony_ci  size_t strscnndx = 0;
69da0c48c4Sopenharmony_ci  size_t xndxscnndx = 0;
70da0c48c4Sopenharmony_ci  Elf_Data *data;
71da0c48c4Sopenharmony_ci  Elf_Data *shstrtabdata;
72da0c48c4Sopenharmony_ci  Elf_Data *strtabdata = NULL;
73da0c48c4Sopenharmony_ci  Elf_Data *xndxdata = NULL;
74da0c48c4Sopenharmony_ci  GElf_Shdr shdr_mem;
75da0c48c4Sopenharmony_ci  GElf_Shdr *shdr;
76da0c48c4Sopenharmony_ci  GElf_Ehdr ehdr_mem;
77da0c48c4Sopenharmony_ci  GElf_Ehdr *ehdr;
78da0c48c4Sopenharmony_ci  AsmScn_t *asmscn;
79da0c48c4Sopenharmony_ci  int result = 0;
80da0c48c4Sopenharmony_ci
81da0c48c4Sopenharmony_ci  /* Iterate over the created sections and compute the offsets of the
82da0c48c4Sopenharmony_ci     various subsections and fill in the content.  */
83da0c48c4Sopenharmony_ci  for (asmscn = ctx->section_list; asmscn != NULL; asmscn = asmscn->allnext)
84da0c48c4Sopenharmony_ci    {
85da0c48c4Sopenharmony_ci#if 0
86da0c48c4Sopenharmony_ci      Elf_Scn *scn = elf_getscn (ctx->out.elf, asmscn->data.main.scnndx);
87da0c48c4Sopenharmony_ci#else
88da0c48c4Sopenharmony_ci      Elf_Scn *scn = asmscn->data.main.scn;
89da0c48c4Sopenharmony_ci#endif
90da0c48c4Sopenharmony_ci      off_t offset = 0;
91da0c48c4Sopenharmony_ci      AsmScn_t *asmsubscn = asmscn;
92da0c48c4Sopenharmony_ci
93da0c48c4Sopenharmony_ci      do
94da0c48c4Sopenharmony_ci	{
95da0c48c4Sopenharmony_ci	  struct AsmData *content = asmsubscn->content;
96da0c48c4Sopenharmony_ci	  bool first = true;
97da0c48c4Sopenharmony_ci
98da0c48c4Sopenharmony_ci	  offset = ((offset + asmsubscn->max_align - 1)
99da0c48c4Sopenharmony_ci		    & ~(asmsubscn->max_align - 1));
100da0c48c4Sopenharmony_ci
101da0c48c4Sopenharmony_ci	  /* Update the offset for this subsection.  This field now
102da0c48c4Sopenharmony_ci	     stores the offset of the first by in this subsection.  */
103da0c48c4Sopenharmony_ci	  asmsubscn->offset = offset;
104da0c48c4Sopenharmony_ci
105da0c48c4Sopenharmony_ci	  /* Note that the content list is circular.  */
106da0c48c4Sopenharmony_ci	  if (content != NULL)
107da0c48c4Sopenharmony_ci	    do
108da0c48c4Sopenharmony_ci	      {
109da0c48c4Sopenharmony_ci		Elf_Data *newdata = elf_newdata (scn);
110da0c48c4Sopenharmony_ci
111da0c48c4Sopenharmony_ci		if (newdata == NULL)
112da0c48c4Sopenharmony_ci		  {
113da0c48c4Sopenharmony_ci		    __libasm_seterrno (ASM_E_LIBELF);
114da0c48c4Sopenharmony_ci		    return -1;
115da0c48c4Sopenharmony_ci		  }
116da0c48c4Sopenharmony_ci
117da0c48c4Sopenharmony_ci		newdata->d_buf = content->data;
118da0c48c4Sopenharmony_ci		newdata->d_type = ELF_T_BYTE;
119da0c48c4Sopenharmony_ci		newdata->d_size = content->len;
120da0c48c4Sopenharmony_ci		newdata->d_off = offset;
121da0c48c4Sopenharmony_ci		newdata->d_align = first ? asmsubscn->max_align : 1;
122da0c48c4Sopenharmony_ci
123da0c48c4Sopenharmony_ci		offset += content->len;
124da0c48c4Sopenharmony_ci	      }
125da0c48c4Sopenharmony_ci	    while ((content = content->next) != asmsubscn->content);
126da0c48c4Sopenharmony_ci	}
127da0c48c4Sopenharmony_ci      while ((asmsubscn = asmsubscn->subnext) != NULL);
128da0c48c4Sopenharmony_ci    }
129da0c48c4Sopenharmony_ci
130da0c48c4Sopenharmony_ci
131da0c48c4Sopenharmony_ci  /* Create the symbol table if necessary.  */
132da0c48c4Sopenharmony_ci  if (ctx->nsymbol_tab > 0)
133da0c48c4Sopenharmony_ci    {
134da0c48c4Sopenharmony_ci      /* Create the symbol table and string table section names.  */
135da0c48c4Sopenharmony_ci      symscn_strent = dwelf_strtab_add_len (ctx->section_strtab, ".symtab", 8);
136da0c48c4Sopenharmony_ci      strscn_strent = dwelf_strtab_add_len (ctx->section_strtab, ".strtab", 8);
137da0c48c4Sopenharmony_ci
138da0c48c4Sopenharmony_ci      /* Create the symbol string table section.  */
139da0c48c4Sopenharmony_ci      Elf_Scn *strscn = elf_newscn (ctx->out.elf);
140da0c48c4Sopenharmony_ci      strtabdata = elf_newdata (strscn);
141da0c48c4Sopenharmony_ci      shdr = gelf_getshdr (strscn, &shdr_mem);
142da0c48c4Sopenharmony_ci      if (strtabdata == NULL || shdr == NULL)
143da0c48c4Sopenharmony_ci	{
144da0c48c4Sopenharmony_ci	  __libasm_seterrno (ASM_E_LIBELF);
145da0c48c4Sopenharmony_ci	  return -1;
146da0c48c4Sopenharmony_ci	}
147da0c48c4Sopenharmony_ci      strscnndx = elf_ndxscn (strscn);
148da0c48c4Sopenharmony_ci
149da0c48c4Sopenharmony_ci      dwelf_strtab_finalize (ctx->symbol_strtab, strtabdata);
150da0c48c4Sopenharmony_ci
151da0c48c4Sopenharmony_ci      shdr->sh_type = SHT_STRTAB;
152da0c48c4Sopenharmony_ci      assert (shdr->sh_entsize == 0);
153da0c48c4Sopenharmony_ci
154da0c48c4Sopenharmony_ci      (void) gelf_update_shdr (strscn, shdr);
155da0c48c4Sopenharmony_ci
156da0c48c4Sopenharmony_ci      /* Create the symbol table section.  */
157da0c48c4Sopenharmony_ci      Elf_Scn *symscn = elf_newscn (ctx->out.elf);
158da0c48c4Sopenharmony_ci      data = elf_newdata (symscn);
159da0c48c4Sopenharmony_ci      shdr = gelf_getshdr (symscn, &shdr_mem);
160da0c48c4Sopenharmony_ci      if (data == NULL || shdr == NULL)
161da0c48c4Sopenharmony_ci	{
162da0c48c4Sopenharmony_ci	  __libasm_seterrno (ASM_E_LIBELF);
163da0c48c4Sopenharmony_ci	  return -1;
164da0c48c4Sopenharmony_ci	}
165da0c48c4Sopenharmony_ci      symscnndx = elf_ndxscn (symscn);
166da0c48c4Sopenharmony_ci
167da0c48c4Sopenharmony_ci      /* We know how many symbols there will be in the symbol table.  */
168da0c48c4Sopenharmony_ci      data->d_size = gelf_fsize (ctx->out.elf, ELF_T_SYM,
169da0c48c4Sopenharmony_ci				 ctx->nsymbol_tab + 1, EV_CURRENT);
170da0c48c4Sopenharmony_ci      symtab = malloc (data->d_size);
171da0c48c4Sopenharmony_ci      if (symtab == NULL)
172da0c48c4Sopenharmony_ci	return -1;
173da0c48c4Sopenharmony_ci      data->d_buf = symtab;
174da0c48c4Sopenharmony_ci      data->d_type = ELF_T_SYM;
175da0c48c4Sopenharmony_ci      data->d_off = 0;
176da0c48c4Sopenharmony_ci
177da0c48c4Sopenharmony_ci      /* Clear the first entry.  */
178da0c48c4Sopenharmony_ci      GElf_Sym syment;
179da0c48c4Sopenharmony_ci      memset (&syment, '\0', sizeof (syment));
180da0c48c4Sopenharmony_ci      (void) gelf_update_sym (data, 0, &syment);
181da0c48c4Sopenharmony_ci
182da0c48c4Sopenharmony_ci      /* Iterate over the symbol table.  */
183da0c48c4Sopenharmony_ci      void *runp = NULL;
184da0c48c4Sopenharmony_ci      int ptr_local = 1;	/* Start with index 1; zero remains unused.  */
185da0c48c4Sopenharmony_ci      int ptr_nonlocal = ctx->nsymbol_tab;
186da0c48c4Sopenharmony_ci      uint32_t *xshndx = NULL;
187da0c48c4Sopenharmony_ci      AsmSym_t *sym;
188da0c48c4Sopenharmony_ci      while ((sym = asm_symbol_tab_iterate (&ctx->symbol_tab, &runp)) != NULL)
189da0c48c4Sopenharmony_ci	if (asm_emit_symbol_p (dwelf_strent_str (sym->strent)))
190da0c48c4Sopenharmony_ci	  {
191da0c48c4Sopenharmony_ci	    assert (ptr_local <= ptr_nonlocal);
192da0c48c4Sopenharmony_ci
193da0c48c4Sopenharmony_ci	    syment.st_name = dwelf_strent_off (sym->strent);
194da0c48c4Sopenharmony_ci	    syment.st_info = GELF_ST_INFO (sym->binding, sym->type);
195da0c48c4Sopenharmony_ci	    syment.st_other = 0;
196da0c48c4Sopenharmony_ci	    syment.st_value = sym->scn->offset + sym->offset;
197da0c48c4Sopenharmony_ci	    syment.st_size = sym->size;
198da0c48c4Sopenharmony_ci
199da0c48c4Sopenharmony_ci	    /* Add local symbols at the beginning, the other from
200da0c48c4Sopenharmony_ci	       the end.  */
201da0c48c4Sopenharmony_ci	    int ptr = sym->binding == STB_LOCAL ? ptr_local++ : ptr_nonlocal--;
202da0c48c4Sopenharmony_ci
203da0c48c4Sopenharmony_ci	    /* Determine the section index.  We have to handle the
204da0c48c4Sopenharmony_ci	       overflow correctly.  */
205da0c48c4Sopenharmony_ci	    Elf_Scn *scn = (sym->scn->subsection_id == 0
206da0c48c4Sopenharmony_ci			    ? sym->scn->data.main.scn
207da0c48c4Sopenharmony_ci			    : sym->scn->data.up->data.main.scn);
208da0c48c4Sopenharmony_ci
209da0c48c4Sopenharmony_ci	    Elf32_Word ndx;
210da0c48c4Sopenharmony_ci	    if (unlikely (scn == ASM_ABS_SCN))
211da0c48c4Sopenharmony_ci	      ndx = SHN_ABS;
212da0c48c4Sopenharmony_ci	    else if (unlikely (scn == ASM_COM_SCN))
213da0c48c4Sopenharmony_ci	      ndx = SHN_COMMON;
214da0c48c4Sopenharmony_ci	    else if (unlikely ((ndx = elf_ndxscn (scn)) >= SHN_LORESERVE))
215da0c48c4Sopenharmony_ci	      {
216da0c48c4Sopenharmony_ci		if (unlikely (xshndx == NULL))
217da0c48c4Sopenharmony_ci		  {
218da0c48c4Sopenharmony_ci		    /* The extended section index section does not yet
219da0c48c4Sopenharmony_ci		       exist.  */
220da0c48c4Sopenharmony_ci		    Elf_Scn *xndxscn;
221da0c48c4Sopenharmony_ci
222da0c48c4Sopenharmony_ci		    xndxscn = elf_newscn (ctx->out.elf);
223da0c48c4Sopenharmony_ci		    xndxdata = elf_newdata (xndxscn);
224da0c48c4Sopenharmony_ci		    shdr = gelf_getshdr (xndxscn, &shdr_mem);
225da0c48c4Sopenharmony_ci		    if (xndxdata == NULL || shdr == NULL)
226da0c48c4Sopenharmony_ci		      {
227da0c48c4Sopenharmony_ci			__libasm_seterrno (ASM_E_LIBELF);
228da0c48c4Sopenharmony_ci			return -1;
229da0c48c4Sopenharmony_ci		      }
230da0c48c4Sopenharmony_ci		    xndxscnndx = elf_ndxscn (xndxscn);
231da0c48c4Sopenharmony_ci
232da0c48c4Sopenharmony_ci		    shdr->sh_type = SHT_SYMTAB_SHNDX;
233da0c48c4Sopenharmony_ci		    shdr->sh_entsize = sizeof (Elf32_Word);
234da0c48c4Sopenharmony_ci		    shdr->sh_addralign = sizeof (Elf32_Word);
235da0c48c4Sopenharmony_ci		    shdr->sh_link = symscnndx;
236da0c48c4Sopenharmony_ci
237da0c48c4Sopenharmony_ci		    (void) gelf_update_shdr (xndxscn, shdr);
238da0c48c4Sopenharmony_ci
239da0c48c4Sopenharmony_ci		    xndxscn_strent = dwelf_strtab_add_len (ctx->section_strtab,
240da0c48c4Sopenharmony_ci							   ".symtab_shndx",
241da0c48c4Sopenharmony_ci							   14);
242da0c48c4Sopenharmony_ci
243da0c48c4Sopenharmony_ci		    /* Note that using 'elf32_fsize' instead of
244da0c48c4Sopenharmony_ci		       'gelf_fsize' here is correct.  */
245da0c48c4Sopenharmony_ci		    xndxdata->d_size = elf32_fsize (ELF_T_WORD,
246da0c48c4Sopenharmony_ci						    ctx->nsymbol_tab + 1,
247da0c48c4Sopenharmony_ci						    EV_CURRENT);
248da0c48c4Sopenharmony_ci		    xshndx = xndxdata->d_buf = calloc (1, xndxdata->d_size);
249da0c48c4Sopenharmony_ci		    if (xshndx == NULL)
250da0c48c4Sopenharmony_ci		      return -1;
251da0c48c4Sopenharmony_ci		    /* Using ELF_T_WORD here relies on the fact that the
252da0c48c4Sopenharmony_ci		       32- and 64-bit types are the same size.  */
253da0c48c4Sopenharmony_ci		    xndxdata->d_type = ELF_T_WORD;
254da0c48c4Sopenharmony_ci		    xndxdata->d_off = 0;
255da0c48c4Sopenharmony_ci		  }
256da0c48c4Sopenharmony_ci
257da0c48c4Sopenharmony_ci		/* Store the real section index in the extended section
258da0c48c4Sopenharmony_ci		   index table.  */
259da0c48c4Sopenharmony_ci		assert ((size_t) ptr < ctx->nsymbol_tab + 1);
260da0c48c4Sopenharmony_ci		xshndx[ptr] = ndx;
261da0c48c4Sopenharmony_ci
262da0c48c4Sopenharmony_ci		/* And signal that this happened.  */
263da0c48c4Sopenharmony_ci		ndx = SHN_XINDEX;
264da0c48c4Sopenharmony_ci	      }
265da0c48c4Sopenharmony_ci	    syment.st_shndx = ndx;
266da0c48c4Sopenharmony_ci
267da0c48c4Sopenharmony_ci	    /* Remember where we put the symbol.  */
268da0c48c4Sopenharmony_ci	    sym->symidx = ptr;
269da0c48c4Sopenharmony_ci
270da0c48c4Sopenharmony_ci	    (void) gelf_update_sym (data, ptr, &syment);
271da0c48c4Sopenharmony_ci	  }
272da0c48c4Sopenharmony_ci
273da0c48c4Sopenharmony_ci      assert (ptr_local == ptr_nonlocal + 1);
274da0c48c4Sopenharmony_ci
275da0c48c4Sopenharmony_ci      shdr->sh_type = SHT_SYMTAB;
276da0c48c4Sopenharmony_ci      shdr->sh_link = strscnndx;
277da0c48c4Sopenharmony_ci      shdr->sh_info = ptr_local;
278da0c48c4Sopenharmony_ci      shdr->sh_entsize = gelf_fsize (ctx->out.elf, ELF_T_SYM, 1, EV_CURRENT);
279da0c48c4Sopenharmony_ci      shdr->sh_addralign = gelf_fsize (ctx->out.elf, ELF_T_ADDR, 1,
280da0c48c4Sopenharmony_ci				       EV_CURRENT);
281da0c48c4Sopenharmony_ci
282da0c48c4Sopenharmony_ci      (void) gelf_update_shdr (symscn, shdr);
283da0c48c4Sopenharmony_ci    }
284da0c48c4Sopenharmony_ci
285da0c48c4Sopenharmony_ci
286da0c48c4Sopenharmony_ci  /* Create the section header string table section and fill in the
287da0c48c4Sopenharmony_ci     references in the section headers.  */
288da0c48c4Sopenharmony_ci  shstrscn = elf_newscn (ctx->out.elf);
289da0c48c4Sopenharmony_ci  shstrtabdata = elf_newdata (shstrscn);
290da0c48c4Sopenharmony_ci  shdr = gelf_getshdr (shstrscn, &shdr_mem);
291da0c48c4Sopenharmony_ci  if (shstrscn == NULL || shstrtabdata == NULL || shdr == NULL)
292da0c48c4Sopenharmony_ci    {
293da0c48c4Sopenharmony_ci      __libasm_seterrno (ASM_E_LIBELF);
294da0c48c4Sopenharmony_ci      return -1;
295da0c48c4Sopenharmony_ci    }
296da0c48c4Sopenharmony_ci
297da0c48c4Sopenharmony_ci
298da0c48c4Sopenharmony_ci  /* Add the name of the section header string table.  */
299da0c48c4Sopenharmony_ci  shstrscn_strent = dwelf_strtab_add_len (ctx->section_strtab,
300da0c48c4Sopenharmony_ci					  ".shstrtab", 10);
301da0c48c4Sopenharmony_ci
302da0c48c4Sopenharmony_ci  dwelf_strtab_finalize (ctx->section_strtab, shstrtabdata);
303da0c48c4Sopenharmony_ci
304da0c48c4Sopenharmony_ci  shdr->sh_type = SHT_STRTAB;
305da0c48c4Sopenharmony_ci  assert (shdr->sh_entsize == 0);
306da0c48c4Sopenharmony_ci  shdr->sh_name = dwelf_strent_off (shstrscn_strent);
307da0c48c4Sopenharmony_ci
308da0c48c4Sopenharmony_ci  (void) gelf_update_shdr (shstrscn, shdr);
309da0c48c4Sopenharmony_ci
310da0c48c4Sopenharmony_ci
311da0c48c4Sopenharmony_ci  /* Create the section groups.  */
312da0c48c4Sopenharmony_ci  if (ctx->groups != NULL)
313da0c48c4Sopenharmony_ci    {
314da0c48c4Sopenharmony_ci      AsmScnGrp_t *runp = ctx->groups->next;
315da0c48c4Sopenharmony_ci
316da0c48c4Sopenharmony_ci      do
317da0c48c4Sopenharmony_ci	{
318da0c48c4Sopenharmony_ci	  Elf_Scn *scn;
319da0c48c4Sopenharmony_ci	  Elf32_Word *grpdata;
320da0c48c4Sopenharmony_ci
321da0c48c4Sopenharmony_ci	  scn = runp->scn;
322da0c48c4Sopenharmony_ci	  assert (scn != NULL);
323da0c48c4Sopenharmony_ci	  shdr = gelf_getshdr (scn, &shdr_mem);
324da0c48c4Sopenharmony_ci	  assert (shdr != NULL);
325da0c48c4Sopenharmony_ci
326da0c48c4Sopenharmony_ci	  data = elf_newdata (scn);
327da0c48c4Sopenharmony_ci	  if (data == NULL)
328da0c48c4Sopenharmony_ci	    {
329da0c48c4Sopenharmony_ci	      __libasm_seterrno (ASM_E_LIBELF);
330da0c48c4Sopenharmony_ci	      return -1;
331da0c48c4Sopenharmony_ci	    }
332da0c48c4Sopenharmony_ci
333da0c48c4Sopenharmony_ci	  /* It is correct to use 'elf32_fsize' instead of 'gelf_fsize'
334da0c48c4Sopenharmony_ci	     here.  */
335da0c48c4Sopenharmony_ci	  data->d_size = elf32_fsize (ELF_T_WORD, runp->nmembers + 1,
336da0c48c4Sopenharmony_ci				      EV_CURRENT);
337da0c48c4Sopenharmony_ci	  grpdata = data->d_buf = malloc (data->d_size);
338da0c48c4Sopenharmony_ci	  if (grpdata == NULL)
339da0c48c4Sopenharmony_ci	    return -1;
340da0c48c4Sopenharmony_ci	  data->d_type = ELF_T_WORD;
341da0c48c4Sopenharmony_ci	  data->d_off = 0;
342da0c48c4Sopenharmony_ci	  data->d_align = elf32_fsize (ELF_T_WORD, 1, EV_CURRENT);
343da0c48c4Sopenharmony_ci
344da0c48c4Sopenharmony_ci	  /* The first word of the section is filled with the flag word.  */
345da0c48c4Sopenharmony_ci	  *grpdata++ = runp->flags;
346da0c48c4Sopenharmony_ci
347da0c48c4Sopenharmony_ci	  if (runp->members != NULL)
348da0c48c4Sopenharmony_ci	    {
349da0c48c4Sopenharmony_ci	      AsmScn_t *member = runp->members->data.main.next_in_group;
350da0c48c4Sopenharmony_ci
351da0c48c4Sopenharmony_ci	      do
352da0c48c4Sopenharmony_ci		{
353da0c48c4Sopenharmony_ci		  /* Only sections, not subsections, can be registered
354da0c48c4Sopenharmony_ci		     as member of a group.  The subsections get
355da0c48c4Sopenharmony_ci		     automatically included.  */
356da0c48c4Sopenharmony_ci		  assert (member->subsection_id == 0);
357da0c48c4Sopenharmony_ci
358da0c48c4Sopenharmony_ci		  *grpdata++ = elf_ndxscn (member->data.main.scn);
359da0c48c4Sopenharmony_ci		}
360da0c48c4Sopenharmony_ci	      while ((member = member->data.main.next_in_group)
361da0c48c4Sopenharmony_ci		     != runp->members->data.main.next_in_group);
362da0c48c4Sopenharmony_ci	    }
363da0c48c4Sopenharmony_ci
364da0c48c4Sopenharmony_ci	  /* Construct the section header.  */
365da0c48c4Sopenharmony_ci	  shdr->sh_name = dwelf_strent_off (runp->strent);
366da0c48c4Sopenharmony_ci	  shdr->sh_type = SHT_GROUP;
367da0c48c4Sopenharmony_ci	  shdr->sh_flags = 0;
368da0c48c4Sopenharmony_ci	  shdr->sh_link = symscnndx;
369da0c48c4Sopenharmony_ci	  /* If the user did not specify a signature we use the initial
370da0c48c4Sopenharmony_ci	     empty symbol in the symbol table as the signature.  */
371da0c48c4Sopenharmony_ci	  shdr->sh_info = (runp->signature != NULL
372da0c48c4Sopenharmony_ci			   ? runp->signature->symidx : 0);
373da0c48c4Sopenharmony_ci
374da0c48c4Sopenharmony_ci	  (void) gelf_update_shdr (scn, shdr);
375da0c48c4Sopenharmony_ci	}
376da0c48c4Sopenharmony_ci      while ((runp = runp->next) != ctx->groups->next);
377da0c48c4Sopenharmony_ci    }
378da0c48c4Sopenharmony_ci
379da0c48c4Sopenharmony_ci
380da0c48c4Sopenharmony_ci  /* Add the name to the symbol section.  */
381da0c48c4Sopenharmony_ci  if (likely (symscnndx != 0))
382da0c48c4Sopenharmony_ci    {
383da0c48c4Sopenharmony_ci      Elf_Scn *scn = elf_getscn (ctx->out.elf, symscnndx);
384da0c48c4Sopenharmony_ci
385da0c48c4Sopenharmony_ci      shdr = gelf_getshdr (scn, &shdr_mem);
386da0c48c4Sopenharmony_ci
387da0c48c4Sopenharmony_ci      shdr->sh_name = dwelf_strent_off (symscn_strent);
388da0c48c4Sopenharmony_ci
389da0c48c4Sopenharmony_ci      (void) gelf_update_shdr (scn, shdr);
390da0c48c4Sopenharmony_ci
391da0c48c4Sopenharmony_ci
392da0c48c4Sopenharmony_ci      /* Add the name to the string section.  */
393da0c48c4Sopenharmony_ci      assert (strscnndx != 0);
394da0c48c4Sopenharmony_ci      scn = elf_getscn (ctx->out.elf, strscnndx);
395da0c48c4Sopenharmony_ci
396da0c48c4Sopenharmony_ci      shdr = gelf_getshdr (scn, &shdr_mem);
397da0c48c4Sopenharmony_ci
398da0c48c4Sopenharmony_ci      shdr->sh_name = dwelf_strent_off (strscn_strent);
399da0c48c4Sopenharmony_ci
400da0c48c4Sopenharmony_ci      (void) gelf_update_shdr (scn, shdr);
401da0c48c4Sopenharmony_ci
402da0c48c4Sopenharmony_ci
403da0c48c4Sopenharmony_ci      /* Add the name to the extended symbol index section.  */
404da0c48c4Sopenharmony_ci      if (xndxscnndx != 0)
405da0c48c4Sopenharmony_ci	{
406da0c48c4Sopenharmony_ci	  scn = elf_getscn (ctx->out.elf, xndxscnndx);
407da0c48c4Sopenharmony_ci
408da0c48c4Sopenharmony_ci	  shdr = gelf_getshdr (scn, &shdr_mem);
409da0c48c4Sopenharmony_ci
410da0c48c4Sopenharmony_ci	  shdr->sh_name = dwelf_strent_off (xndxscn_strent);
411da0c48c4Sopenharmony_ci
412da0c48c4Sopenharmony_ci	  (void) gelf_update_shdr (scn, shdr);
413da0c48c4Sopenharmony_ci	}
414da0c48c4Sopenharmony_ci    }
415da0c48c4Sopenharmony_ci
416da0c48c4Sopenharmony_ci
417da0c48c4Sopenharmony_ci  /* Iterate over the created sections and fill in the names.  */
418da0c48c4Sopenharmony_ci  for (asmscn = ctx->section_list; asmscn != NULL; asmscn = asmscn->allnext)
419da0c48c4Sopenharmony_ci    {
420da0c48c4Sopenharmony_ci      shdr = gelf_getshdr (asmscn->data.main.scn, &shdr_mem);
421da0c48c4Sopenharmony_ci      /* This better should not fail.  */
422da0c48c4Sopenharmony_ci      assert (shdr != NULL);
423da0c48c4Sopenharmony_ci
424da0c48c4Sopenharmony_ci      shdr->sh_name = dwelf_strent_off (asmscn->data.main.strent);
425da0c48c4Sopenharmony_ci
426da0c48c4Sopenharmony_ci      /* We now know the maximum alignment.  */
427da0c48c4Sopenharmony_ci      shdr->sh_addralign = asmscn->max_align;
428da0c48c4Sopenharmony_ci
429da0c48c4Sopenharmony_ci      (void) gelf_update_shdr (asmscn->data.main.scn, shdr);
430da0c48c4Sopenharmony_ci    }
431da0c48c4Sopenharmony_ci
432da0c48c4Sopenharmony_ci  /* Put the reference to the section header string table in the ELF
433da0c48c4Sopenharmony_ci     header.  */
434da0c48c4Sopenharmony_ci  ehdr = gelf_getehdr (ctx->out.elf, &ehdr_mem);
435da0c48c4Sopenharmony_ci  assert (ehdr != NULL);
436da0c48c4Sopenharmony_ci
437da0c48c4Sopenharmony_ci  shstrscnndx = elf_ndxscn (shstrscn);
438da0c48c4Sopenharmony_ci  if (unlikely (shstrscnndx > SHN_HIRESERVE)
439da0c48c4Sopenharmony_ci      || unlikely (shstrscnndx == SHN_XINDEX))
440da0c48c4Sopenharmony_ci    {
441da0c48c4Sopenharmony_ci      /* The index of the section header string sectio is too large.  */
442da0c48c4Sopenharmony_ci      Elf_Scn *scn = elf_getscn (ctx->out.elf, 0);
443da0c48c4Sopenharmony_ci
444da0c48c4Sopenharmony_ci      /* Get the header for the zeroth section.  */
445da0c48c4Sopenharmony_ci      shdr = gelf_getshdr (scn, &shdr_mem);
446da0c48c4Sopenharmony_ci      /* This better does not fail.  */
447da0c48c4Sopenharmony_ci      assert (shdr != NULL);
448da0c48c4Sopenharmony_ci
449da0c48c4Sopenharmony_ci      /* The sh_link field of the zeroth section header contains the value.  */
450da0c48c4Sopenharmony_ci      shdr->sh_link = shstrscnndx;
451da0c48c4Sopenharmony_ci
452da0c48c4Sopenharmony_ci      (void) gelf_update_shdr (scn, shdr);
453da0c48c4Sopenharmony_ci
454da0c48c4Sopenharmony_ci      /* This is the sign for the overflow.  */
455da0c48c4Sopenharmony_ci      ehdr->e_shstrndx = SHN_XINDEX;
456da0c48c4Sopenharmony_ci    }
457da0c48c4Sopenharmony_ci  else
458da0c48c4Sopenharmony_ci    ehdr->e_shstrndx = elf_ndxscn (shstrscn);
459da0c48c4Sopenharmony_ci
460da0c48c4Sopenharmony_ci  if (unlikely (gelf_update_ehdr (ctx->out.elf, ehdr) == 0))
461da0c48c4Sopenharmony_ci    {
462da0c48c4Sopenharmony_ci      __libasm_seterrno (ASM_E_LIBELF);
463da0c48c4Sopenharmony_ci      result = -1;
464da0c48c4Sopenharmony_ci    }
465da0c48c4Sopenharmony_ci
466da0c48c4Sopenharmony_ci  /* Write out the ELF file.  */
467da0c48c4Sopenharmony_ci  if (unlikely (elf_update (ctx->out.elf, ELF_C_WRITE_MMAP) < 0))
468da0c48c4Sopenharmony_ci    {
469da0c48c4Sopenharmony_ci      __libasm_seterrno (ASM_E_LIBELF);
470da0c48c4Sopenharmony_ci      result = -1;
471da0c48c4Sopenharmony_ci    }
472da0c48c4Sopenharmony_ci
473da0c48c4Sopenharmony_ci  /* We do not need the section header and symbol string tables anymore.  */
474da0c48c4Sopenharmony_ci  free (shstrtabdata->d_buf);
475da0c48c4Sopenharmony_ci  if (strtabdata != NULL)
476da0c48c4Sopenharmony_ci    free (strtabdata->d_buf);
477da0c48c4Sopenharmony_ci  /* We might have allocated the extended symbol table index.  */
478da0c48c4Sopenharmony_ci  if (xndxdata != NULL)
479da0c48c4Sopenharmony_ci    free (xndxdata->d_buf);
480da0c48c4Sopenharmony_ci
481da0c48c4Sopenharmony_ci  /* Free section groups memory.  */
482da0c48c4Sopenharmony_ci  AsmScnGrp_t *scngrp = ctx->groups;
483da0c48c4Sopenharmony_ci  if (scngrp != NULL)
484da0c48c4Sopenharmony_ci    do
485da0c48c4Sopenharmony_ci      free (elf_getdata (scngrp->scn, NULL)->d_buf);
486da0c48c4Sopenharmony_ci    while ((scngrp = scngrp->next) != ctx->groups);
487da0c48c4Sopenharmony_ci
488da0c48c4Sopenharmony_ci  /* Finalize the ELF handling.  */
489da0c48c4Sopenharmony_ci  if (unlikely (elf_end (ctx->out.elf)) != 0)
490da0c48c4Sopenharmony_ci    {
491da0c48c4Sopenharmony_ci      __libasm_seterrno (ASM_E_LIBELF);
492da0c48c4Sopenharmony_ci      result = -1;
493da0c48c4Sopenharmony_ci    }
494da0c48c4Sopenharmony_ci
495da0c48c4Sopenharmony_ci  /* Free the temporary resources.  */
496da0c48c4Sopenharmony_ci  free (symtab);
497da0c48c4Sopenharmony_ci
498da0c48c4Sopenharmony_ci  return result;
499da0c48c4Sopenharmony_ci}
500da0c48c4Sopenharmony_ci
501da0c48c4Sopenharmony_ci
502da0c48c4Sopenharmony_ciint
503da0c48c4Sopenharmony_ciasm_end (AsmCtx_t *ctx)
504da0c48c4Sopenharmony_ci{
505da0c48c4Sopenharmony_ci  int result;
506da0c48c4Sopenharmony_ci
507da0c48c4Sopenharmony_ci  if (ctx == NULL)
508da0c48c4Sopenharmony_ci    /* Something went wrong earlier.  */
509da0c48c4Sopenharmony_ci    return -1;
510da0c48c4Sopenharmony_ci
511da0c48c4Sopenharmony_ci  result = unlikely (ctx->textp) ? text_end (ctx) : binary_end (ctx);
512da0c48c4Sopenharmony_ci  if (result != 0)
513da0c48c4Sopenharmony_ci    return result;
514da0c48c4Sopenharmony_ci
515da0c48c4Sopenharmony_ci  /* Make the new file globally readable and user/group-writable.  */
516da0c48c4Sopenharmony_ci  if (fchmod (ctx->fd, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH) != 0)
517da0c48c4Sopenharmony_ci    {
518da0c48c4Sopenharmony_ci      __libasm_seterrno (ASM_E_CANNOT_CHMOD);
519da0c48c4Sopenharmony_ci      return -1;
520da0c48c4Sopenharmony_ci    }
521da0c48c4Sopenharmony_ci
522da0c48c4Sopenharmony_ci  /* Rename output file.  */
523da0c48c4Sopenharmony_ci  if (rename (ctx->tmp_fname, ctx->fname) != 0)
524da0c48c4Sopenharmony_ci    {
525da0c48c4Sopenharmony_ci      __libasm_seterrno (ASM_E_CANNOT_RENAME);
526da0c48c4Sopenharmony_ci      return -1;
527da0c48c4Sopenharmony_ci    }
528da0c48c4Sopenharmony_ci
529da0c48c4Sopenharmony_ci  /* Free the resources.  */
530da0c48c4Sopenharmony_ci  __libasm_finictx (ctx);
531da0c48c4Sopenharmony_ci
532da0c48c4Sopenharmony_ci  return 0;
533da0c48c4Sopenharmony_ci}
534da0c48c4Sopenharmony_ci
535da0c48c4Sopenharmony_ci
536da0c48c4Sopenharmony_cistatic void
537da0c48c4Sopenharmony_cifree_section (AsmScn_t *scnp)
538da0c48c4Sopenharmony_ci{
539da0c48c4Sopenharmony_ci  void *oldp;
540da0c48c4Sopenharmony_ci
541da0c48c4Sopenharmony_ci  if (scnp->subnext != NULL)
542da0c48c4Sopenharmony_ci    free_section (scnp->subnext);
543da0c48c4Sopenharmony_ci
544da0c48c4Sopenharmony_ci  struct AsmData *data = scnp->content;
545da0c48c4Sopenharmony_ci  if (data != NULL)
546da0c48c4Sopenharmony_ci    do
547da0c48c4Sopenharmony_ci      {
548da0c48c4Sopenharmony_ci	oldp = data;
549da0c48c4Sopenharmony_ci	data = data->next;
550da0c48c4Sopenharmony_ci	free (oldp);
551da0c48c4Sopenharmony_ci      }
552da0c48c4Sopenharmony_ci    while (oldp != scnp->content);
553da0c48c4Sopenharmony_ci
554da0c48c4Sopenharmony_ci  free (scnp);
555da0c48c4Sopenharmony_ci}
556da0c48c4Sopenharmony_ci
557da0c48c4Sopenharmony_ci
558da0c48c4Sopenharmony_civoid
559da0c48c4Sopenharmony_ciinternal_function
560da0c48c4Sopenharmony_ci__libasm_finictx (AsmCtx_t *ctx)
561da0c48c4Sopenharmony_ci{
562da0c48c4Sopenharmony_ci  /* Iterate through section table and free individual entries.  */
563da0c48c4Sopenharmony_ci  AsmScn_t *scn = ctx->section_list;
564da0c48c4Sopenharmony_ci  while (scn != NULL)
565da0c48c4Sopenharmony_ci    {
566da0c48c4Sopenharmony_ci      AsmScn_t *oldp = scn;
567da0c48c4Sopenharmony_ci      scn = scn->allnext;
568da0c48c4Sopenharmony_ci      free_section (oldp);
569da0c48c4Sopenharmony_ci    }
570da0c48c4Sopenharmony_ci
571da0c48c4Sopenharmony_ci  /* Free the resources of the symbol table.  */
572da0c48c4Sopenharmony_ci  void *runp = NULL;
573da0c48c4Sopenharmony_ci  AsmSym_t *sym;
574da0c48c4Sopenharmony_ci  while ((sym = asm_symbol_tab_iterate (&ctx->symbol_tab, &runp)) != NULL)
575da0c48c4Sopenharmony_ci    free (sym);
576da0c48c4Sopenharmony_ci  asm_symbol_tab_free (&ctx->symbol_tab);
577da0c48c4Sopenharmony_ci
578da0c48c4Sopenharmony_ci
579da0c48c4Sopenharmony_ci  /* Free section groups.  */
580da0c48c4Sopenharmony_ci  AsmScnGrp_t *scngrp = ctx->groups;
581da0c48c4Sopenharmony_ci  if (scngrp != NULL)
582da0c48c4Sopenharmony_ci    do
583da0c48c4Sopenharmony_ci      {
584da0c48c4Sopenharmony_ci	AsmScnGrp_t *oldp = scngrp;
585da0c48c4Sopenharmony_ci
586da0c48c4Sopenharmony_ci	scngrp = scngrp->next;
587da0c48c4Sopenharmony_ci	free (oldp);
588da0c48c4Sopenharmony_ci      }
589da0c48c4Sopenharmony_ci    while (scngrp != ctx->groups);
590da0c48c4Sopenharmony_ci
591da0c48c4Sopenharmony_ci
592da0c48c4Sopenharmony_ci  if (unlikely (ctx->textp))
593da0c48c4Sopenharmony_ci    {
594da0c48c4Sopenharmony_ci      /* Close the stream.  */
595da0c48c4Sopenharmony_ci      fclose (ctx->out.file);
596da0c48c4Sopenharmony_ci    }
597da0c48c4Sopenharmony_ci  else
598da0c48c4Sopenharmony_ci    {
599da0c48c4Sopenharmony_ci      /* Close the output file.  */
600da0c48c4Sopenharmony_ci      /* XXX We should test for errors here but what would we do if we'd
601da0c48c4Sopenharmony_ci	 find any.  */
602da0c48c4Sopenharmony_ci      (void) close (ctx->fd);
603da0c48c4Sopenharmony_ci
604da0c48c4Sopenharmony_ci      /* And the string tables.  */
605da0c48c4Sopenharmony_ci      dwelf_strtab_free (ctx->section_strtab);
606da0c48c4Sopenharmony_ci      dwelf_strtab_free (ctx->symbol_strtab);
607da0c48c4Sopenharmony_ci    }
608da0c48c4Sopenharmony_ci
609da0c48c4Sopenharmony_ci  /* Initialize the lock.  */
610da0c48c4Sopenharmony_ci  rwlock_fini (ctx->lock);
611da0c48c4Sopenharmony_ci
612da0c48c4Sopenharmony_ci  /* Finally free the data structure.   */
613da0c48c4Sopenharmony_ci  free (ctx);
614da0c48c4Sopenharmony_ci}
615