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