Imported Upstream version 0.153
[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 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
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
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
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
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
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 }