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