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
text_end(AsmCtx_t * ctx)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
binary_end(AsmCtx_t * ctx)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
asm_end(AsmCtx_t * ctx)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
free_section(AsmScn_t * scnp)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
__libasm_finictx(AsmCtx_t * ctx)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 }
614