blob: ced24f50b307a7adae7f8667724294091d9db3bc [file] [log] [blame]
Brian Silverman86497922018-02-10 19:28:39 -05001/* 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 <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
48static int
49text_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
61static int
62binary_end (AsmCtx_t *ctx)
63{
64 void *symtab = NULL;
65 Dwelf_Strent *symscn_strent = NULL;
66 Dwelf_Strent *strscn_strent = NULL;
67 Dwelf_Strent *xndxscn_strent = NULL;
68 Elf_Scn *shstrscn;
69 Dwelf_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 = dwelf_strtab_add_len (ctx->section_strtab, ".symtab", 8);
140 strscn_strent = dwelf_strtab_add_len (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 dwelf_strtab_finalize (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 (dwelf_strent_str (sym->strent)))
194 {
195 assert (ptr_local <= ptr_nonlocal);
196
197 syment.st_name = dwelf_strent_off (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 = dwelf_strtab_add_len (ctx->section_strtab,
244 ".symtab_shndx",
245 14);
246
247 /* Note that using 'elf32_fsize' instead of
248 'gelf_fsize' here is correct. */
249 xndxdata->d_size = elf32_fsize (ELF_T_WORD,
250 ctx->nsymbol_tab + 1,
251 EV_CURRENT);
252 xshndx = xndxdata->d_buf = calloc (1, xndxdata->d_size);
253 if (xshndx == NULL)
254 return -1;
255 /* Using ELF_T_WORD here relies on the fact that the
256 32- and 64-bit types are the same size. */
257 xndxdata->d_type = ELF_T_WORD;
258 xndxdata->d_off = 0;
259 }
260
261 /* Store the real section index in the extended setion
262 index table. */
263 assert ((size_t) ptr < ctx->nsymbol_tab + 1);
264 xshndx[ptr] = ndx;
265
266 /* And signal that this happened. */
267 ndx = SHN_XINDEX;
268 }
269 syment.st_shndx = ndx;
270
271 /* Remember where we put the symbol. */
272 sym->symidx = ptr;
273
274 (void) gelf_update_sym (data, ptr, &syment);
275 }
276
277 assert (ptr_local == ptr_nonlocal + 1);
278
279 shdr->sh_type = SHT_SYMTAB;
280 shdr->sh_link = strscnndx;
281 shdr->sh_info = ptr_local;
282 shdr->sh_entsize = gelf_fsize (ctx->out.elf, ELF_T_SYM, 1, EV_CURRENT);
283 shdr->sh_addralign = gelf_fsize (ctx->out.elf, ELF_T_ADDR, 1,
284 EV_CURRENT);
285
286 (void) gelf_update_shdr (symscn, shdr);
287 }
288
289
290 /* Create the section header string table section and fill in the
291 references in the section headers. */
292 shstrscn = elf_newscn (ctx->out.elf);
293 shstrtabdata = elf_newdata (shstrscn);
294 shdr = gelf_getshdr (shstrscn, &shdr_mem);
295 if (shstrscn == NULL || shstrtabdata == NULL || shdr == NULL)
296 {
297 __libasm_seterrno (ASM_E_LIBELF);
298 return -1;
299 }
300
301
302 /* Add the name of the section header string table. */
303 shstrscn_strent = dwelf_strtab_add_len (ctx->section_strtab,
304 ".shstrtab", 10);
305
306 dwelf_strtab_finalize (ctx->section_strtab, shstrtabdata);
307
308 shdr->sh_type = SHT_STRTAB;
309 assert (shdr->sh_entsize == 0);
310 shdr->sh_name = dwelf_strent_off (shstrscn_strent);
311
312 (void) gelf_update_shdr (shstrscn, shdr);
313
314
315 /* Create the section groups. */
316 if (ctx->groups != NULL)
317 {
318 AsmScnGrp_t *runp = ctx->groups->next;
319
320 do
321 {
322 Elf_Scn *scn;
323 Elf32_Word *grpdata;
324
325 scn = runp->scn;
326 assert (scn != NULL);
327 shdr = gelf_getshdr (scn, &shdr_mem);
328 assert (shdr != NULL);
329
330 data = elf_newdata (scn);
331 if (data == NULL)
332 {
333 __libasm_seterrno (ASM_E_LIBELF);
334 return -1;
335 }
336
337 /* It is correct to use 'elf32_fsize' instead of 'gelf_fsize'
338 here. */
339 data->d_size = elf32_fsize (ELF_T_WORD, runp->nmembers + 1,
340 EV_CURRENT);
341 grpdata = data->d_buf = malloc (data->d_size);
342 if (grpdata == NULL)
343 return -1;
344 data->d_type = ELF_T_WORD;
345 data->d_off = 0;
346 data->d_align = elf32_fsize (ELF_T_WORD, 1, EV_CURRENT);
347
348 /* The first word of the section is filled with the flag word. */
349 *grpdata++ = runp->flags;
350
351 if (runp->members != NULL)
352 {
353 AsmScn_t *member = runp->members->data.main.next_in_group;
354
355 do
356 {
357 /* Only sections, not subsections, can be registered
358 as member of a group. The subsections get
359 automatically included. */
360 assert (member->subsection_id == 0);
361
362 *grpdata++ = elf_ndxscn (member->data.main.scn);
363 }
364 while ((member = member->data.main.next_in_group)
365 != runp->members->data.main.next_in_group);
366 }
367
368 /* Construct the section header. */
369 shdr->sh_name = dwelf_strent_off (runp->strent);
370 shdr->sh_type = SHT_GROUP;
371 shdr->sh_flags = 0;
372 shdr->sh_link = symscnndx;
373 /* If the user did not specify a signature we use the initial
374 empty symbol in the symbol table as the signature. */
375 shdr->sh_info = (runp->signature != NULL
376 ? runp->signature->symidx : 0);
377
378 (void) gelf_update_shdr (scn, shdr);
379 }
380 while ((runp = runp->next) != ctx->groups->next);
381 }
382
383
384 /* Add the name to the symbol section. */
385 if (likely (symscnndx != 0))
386 {
387 Elf_Scn *scn = elf_getscn (ctx->out.elf, symscnndx);
388
389 shdr = gelf_getshdr (scn, &shdr_mem);
390
391 shdr->sh_name = dwelf_strent_off (symscn_strent);
392
393 (void) gelf_update_shdr (scn, shdr);
394
395
396 /* Add the name to the string section. */
397 assert (strscnndx != 0);
398 scn = elf_getscn (ctx->out.elf, strscnndx);
399
400 shdr = gelf_getshdr (scn, &shdr_mem);
401
402 shdr->sh_name = dwelf_strent_off (strscn_strent);
403
404 (void) gelf_update_shdr (scn, shdr);
405
406
407 /* Add the name to the extended symbol index section. */
408 if (xndxscnndx != 0)
409 {
410 scn = elf_getscn (ctx->out.elf, xndxscnndx);
411
412 shdr = gelf_getshdr (scn, &shdr_mem);
413
414 shdr->sh_name = dwelf_strent_off (xndxscn_strent);
415
416 (void) gelf_update_shdr (scn, shdr);
417 }
418 }
419
420
421 /* Iterate over the created sections and fill in the names. */
422 for (asmscn = ctx->section_list; asmscn != NULL; asmscn = asmscn->allnext)
423 {
424 shdr = gelf_getshdr (asmscn->data.main.scn, &shdr_mem);
425 /* This better should not fail. */
426 assert (shdr != NULL);
427
428 shdr->sh_name = dwelf_strent_off (asmscn->data.main.strent);
429
430 /* We now know the maximum alignment. */
431 shdr->sh_addralign = asmscn->max_align;
432
433 (void) gelf_update_shdr (asmscn->data.main.scn, shdr);
434 }
435
436 /* Put the reference to the section header string table in the ELF
437 header. */
438 ehdr = gelf_getehdr (ctx->out.elf, &ehdr_mem);
439 assert (ehdr != NULL);
440
441 shstrscnndx = elf_ndxscn (shstrscn);
442 if (unlikely (shstrscnndx > SHN_HIRESERVE)
443 || unlikely (shstrscnndx == SHN_XINDEX))
444 {
445 /* The index of the section header string sectio is too large. */
446 Elf_Scn *scn = elf_getscn (ctx->out.elf, 0);
447
448 /* Get the header for the zeroth section. */
449 shdr = gelf_getshdr (scn, &shdr_mem);
450 /* This better does not fail. */
451 assert (shdr != NULL);
452
453 /* The sh_link field of the zeroth section header contains the value. */
454 shdr->sh_link = shstrscnndx;
455
456 (void) gelf_update_shdr (scn, shdr);
457
458 /* This is the sign for the overflow. */
459 ehdr->e_shstrndx = SHN_XINDEX;
460 }
461 else
462 ehdr->e_shstrndx = elf_ndxscn (shstrscn);
463
464 gelf_update_ehdr (ctx->out.elf, ehdr);
465
466 /* Write out the ELF file. */
467 if (unlikely (elf_update (ctx->out.elf, ELF_C_WRITE_MMAP) < 0))
468 {
469 __libasm_seterrno (ASM_E_LIBELF);
470 result = -1;
471 }
472
473 /* We do not need the section header and symbol string tables anymore. */
474 free (shstrtabdata->d_buf);
475 if (strtabdata != NULL)
476 free (strtabdata->d_buf);
477 /* We might have allocated the extended symbol table index. */
478 if (xndxdata != NULL)
479 free (xndxdata->d_buf);
480
481 /* Free section groups memory. */
482 AsmScnGrp_t *scngrp = ctx->groups;
483 if (scngrp != NULL)
484 do
485 free (elf_getdata (scngrp->scn, NULL)->d_buf);
486 while ((scngrp = scngrp->next) != ctx->groups);
487
488 /* Finalize the ELF handling. */
489 if (unlikely (elf_end (ctx->out.elf)) != 0)
490 {
491 __libasm_seterrno (ASM_E_LIBELF);
492 result = -1;
493 }
494
495 /* Free the temporary resources. */
496 free (symtab);
497
498 return result;
499}
500
501
502int
503asm_end (AsmCtx_t *ctx)
504{
505 int result;
506
507 if (ctx == NULL)
508 /* Something went wrong earlier. */
509 return -1;
510
511 result = unlikely (ctx->textp) ? text_end (ctx) : binary_end (ctx);
512 if (result != 0)
513 return result;
514
515 /* Make the new file globally readable and user/group-writable. */
516 if (fchmod (ctx->fd, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH) != 0)
517 {
518 __libasm_seterrno (ASM_E_CANNOT_CHMOD);
519 return -1;
520 }
521
522 /* Rename output file. */
523 if (rename (ctx->tmp_fname, ctx->fname) != 0)
524 {
525 __libasm_seterrno (ASM_E_CANNOT_RENAME);
526 return -1;
527 }
528
529 /* Free the resources. */
530 __libasm_finictx (ctx);
531
532 return 0;
533}
534
535
536static void
537free_section (AsmScn_t *scnp)
538{
539 void *oldp;
540
541 if (scnp->subnext != NULL)
542 free_section (scnp->subnext);
543
544 struct AsmData *data = scnp->content;
545 if (data != NULL)
546 do
547 {
548 oldp = data;
549 data = data->next;
550 free (oldp);
551 }
552 while (oldp != scnp->content);
553
554 free (scnp);
555}
556
557
558void
559internal_function
560__libasm_finictx (AsmCtx_t *ctx)
561{
562 /* Iterate through section table and free individual entries. */
563 AsmScn_t *scn = ctx->section_list;
564 while (scn != NULL)
565 {
566 AsmScn_t *oldp = scn;
567 scn = scn->allnext;
568 free_section (oldp);
569 }
570
571 /* Free the resources of the symbol table. */
572 void *runp = NULL;
573 AsmSym_t *sym;
574 while ((sym = asm_symbol_tab_iterate (&ctx->symbol_tab, &runp)) != NULL)
575 free (sym);
576 asm_symbol_tab_free (&ctx->symbol_tab);
577
578
579 /* Free section groups. */
580 AsmScnGrp_t *scngrp = ctx->groups;
581 if (scngrp != NULL)
582 do
583 {
584 AsmScnGrp_t *oldp = scngrp;
585
586 scngrp = scngrp->next;
587 free (oldp);
588 }
589 while (scngrp != ctx->groups);
590
591
592 if (unlikely (ctx->textp))
593 {
594 /* Close the stream. */
595 fclose (ctx->out.file);
596 }
597 else
598 {
599 /* Close the output file. */
600 /* XXX We should test for errors here but what would we do if we'd
601 find any. */
602 (void) close (ctx->fd);
603
604 /* And the string tables. */
605 dwelf_strtab_free (ctx->section_strtab);
606 dwelf_strtab_free (ctx->symbol_strtab);
607 }
608
609 /* Initialize the lock. */
610 rwlock_fini (ctx->lock);
611
612 /* Finally free the data structure. */
613 free (ctx);
614}