• 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 <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 
44 static int
text_end(AsmCtx_t * ctx)45 text_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 
57 static int
binary_end(AsmCtx_t * ctx)58 binary_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 
502 int
asm_end(AsmCtx_t * ctx)503 asm_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 
536 static void
free_section(AsmScn_t * scnp)537 free_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 
558 void
559 internal_function
__libasm_finictx(AsmCtx_t * ctx)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