Imported Upstream version 0.155
[platform/upstream/elfutils.git] / libasm / asm_end.c
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
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
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
501 asm_end (ctx)
502      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
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 __libasm_finictx (ctx)
559      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       ebl_strtabfree (ctx->section_strtab);
605       ebl_strtabfree (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 }