• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
45 static int
text_end(AsmCtx_t * ctx)46 text_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 
58 static int
binary_end(AsmCtx_t * ctx)59 binary_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 
497 int
asm_end(ctx)498 asm_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 
532 static void
free_section(AsmScn_t * scnp)533 free_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 
554 void
__libasm_finictx(ctx)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