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