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@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
48static int
49text_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
61static int
62binary_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
500int
501asm_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
534static void
535free_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
556void
557internal_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