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