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