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