Line data Source code
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 <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 :
48 : static int
49 0 : text_end (AsmCtx_t *ctx __attribute__ ((unused)))
50 : {
51 0 : if (fclose (ctx->out.file) != 0)
52 : {
53 0 : __libasm_seterrno (ASM_E_IOERROR);
54 0 : return -1;
55 : }
56 :
57 : return 0;
58 : }
59 :
60 :
61 : static int
62 9 : binary_end (AsmCtx_t *ctx)
63 : {
64 9 : void *symtab = NULL;
65 9 : Dwelf_Strent *symscn_strent = NULL;
66 9 : Dwelf_Strent *strscn_strent = NULL;
67 9 : Dwelf_Strent *xndxscn_strent = NULL;
68 : Elf_Scn *shstrscn;
69 : Dwelf_Strent *shstrscn_strent;
70 : size_t shstrscnndx;
71 9 : size_t symscnndx = 0;
72 9 : size_t strscnndx = 0;
73 9 : size_t xndxscnndx = 0;
74 : Elf_Data *data;
75 : Elf_Data *shstrtabdata;
76 9 : Elf_Data *strtabdata = NULL;
77 9 : 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 9 : 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 176014 : 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 176005 : Elf_Scn *scn = asmscn->data.main.scn;
93 : #endif
94 176005 : off_t offset = 0;
95 176005 : AsmScn_t *asmsubscn = asmscn;
96 :
97 : do
98 : {
99 176007 : struct AsmData *content = asmsubscn->content;
100 176007 : bool first = true;
101 :
102 352014 : offset = ((offset + asmsubscn->max_align - 1)
103 176007 : & ~(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 176007 : asmsubscn->offset = offset;
108 :
109 : /* Note that the content list is circular. */
110 176007 : if (content != NULL)
111 : do
112 : {
113 176005 : Elf_Data *newdata = elf_newdata (scn);
114 :
115 176005 : if (newdata == NULL)
116 : {
117 0 : __libasm_seterrno (ASM_E_LIBELF);
118 0 : return -1;
119 : }
120 :
121 176005 : newdata->d_buf = content->data;
122 176005 : newdata->d_type = ELF_T_BYTE;
123 176005 : newdata->d_size = content->len;
124 176005 : newdata->d_off = offset;
125 176005 : newdata->d_align = first ? asmsubscn->max_align : 1;
126 :
127 176005 : offset += content->len;
128 : }
129 176005 : while ((content = content->next) != asmsubscn->content);
130 : }
131 176007 : while ((asmsubscn = asmsubscn->subnext) != NULL);
132 : }
133 :
134 :
135 : /* Create the symbol table if necessary. */
136 9 : if (ctx->nsymbol_tab > 0)
137 : {
138 : /* Create the symbol table and string table section names. */
139 5 : symscn_strent = dwelf_strtab_add_len (ctx->section_strtab, ".symtab", 8);
140 5 : strscn_strent = dwelf_strtab_add_len (ctx->section_strtab, ".strtab", 8);
141 :
142 : /* Create the symbol string table section. */
143 5 : Elf_Scn *strscn = elf_newscn (ctx->out.elf);
144 5 : strtabdata = elf_newdata (strscn);
145 5 : shdr = gelf_getshdr (strscn, &shdr_mem);
146 5 : if (strtabdata == NULL || shdr == NULL)
147 : {
148 0 : __libasm_seterrno (ASM_E_LIBELF);
149 0 : return -1;
150 : }
151 5 : strscnndx = elf_ndxscn (strscn);
152 :
153 5 : dwelf_strtab_finalize (ctx->symbol_strtab, strtabdata);
154 :
155 5 : shdr->sh_type = SHT_STRTAB;
156 5 : assert (shdr->sh_entsize == 0);
157 :
158 5 : (void) gelf_update_shdr (strscn, shdr);
159 :
160 : /* Create the symbol table section. */
161 5 : Elf_Scn *symscn = elf_newscn (ctx->out.elf);
162 5 : data = elf_newdata (symscn);
163 5 : shdr = gelf_getshdr (symscn, &shdr_mem);
164 5 : if (data == NULL || shdr == NULL)
165 : {
166 0 : __libasm_seterrno (ASM_E_LIBELF);
167 0 : return -1;
168 : }
169 5 : symscnndx = elf_ndxscn (symscn);
170 :
171 : /* We know how many symbols there will be in the symbol table. */
172 5 : data->d_size = gelf_fsize (ctx->out.elf, ELF_T_SYM,
173 5 : ctx->nsymbol_tab + 1, EV_CURRENT);
174 5 : symtab = malloc (data->d_size);
175 5 : if (symtab == NULL)
176 : return -1;
177 5 : data->d_buf = symtab;
178 5 : data->d_type = ELF_T_SYM;
179 5 : data->d_off = 0;
180 :
181 : /* Clear the first entry. */
182 : GElf_Sym syment;
183 5 : memset (&syment, '\0', sizeof (syment));
184 5 : (void) gelf_update_sym (data, 0, &syment);
185 :
186 : /* Iterate over the symbol table. */
187 5 : void *runp = NULL;
188 5 : int ptr_local = 1; /* Start with index 1; zero remains unused. */
189 5 : int ptr_nonlocal = ctx->nsymbol_tab;
190 5 : uint32_t *xshndx = NULL;
191 : AsmSym_t *sym;
192 88015 : while ((sym = asm_symbol_tab_iterate (&ctx->symbol_tab, &runp)) != NULL)
193 88005 : if (asm_emit_symbol_p (dwelf_strent_str (sym->strent)))
194 : {
195 88005 : assert (ptr_local <= ptr_nonlocal);
196 :
197 88005 : syment.st_name = dwelf_strent_off (sym->strent);
198 88005 : syment.st_info = GELF_ST_INFO (sym->binding, sym->type);
199 88005 : syment.st_other = 0;
200 88005 : syment.st_value = sym->scn->offset + sym->offset;
201 88005 : syment.st_size = sym->size;
202 :
203 : /* Add local symbols at the beginning, the other from
204 : the end. */
205 88005 : 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 176010 : Elf_Scn *scn = (sym->scn->subsection_id == 0
210 : ? sym->scn->data.main.scn
211 88005 : : sym->scn->data.up->data.main.scn);
212 :
213 : Elf32_Word ndx;
214 88005 : if (unlikely (scn == ASM_ABS_SCN))
215 : ndx = SHN_ABS;
216 88004 : else if (unlikely (scn == ASM_COM_SCN))
217 : ndx = SHN_COMMON;
218 88003 : else if (unlikely ((ndx = elf_ndxscn (scn)) >= SHN_LORESERVE))
219 : {
220 961 : if (unlikely (xshndx == NULL))
221 : {
222 : /* The extended section index section does not yet
223 : exist. */
224 : Elf_Scn *xndxscn;
225 :
226 2 : xndxscn = elf_newscn (ctx->out.elf);
227 2 : xndxdata = elf_newdata (xndxscn);
228 2 : shdr = gelf_getshdr (xndxscn, &shdr_mem);
229 2 : if (xndxdata == NULL || shdr == NULL)
230 : {
231 0 : __libasm_seterrno (ASM_E_LIBELF);
232 0 : return -1;
233 : }
234 2 : xndxscnndx = elf_ndxscn (xndxscn);
235 :
236 2 : shdr->sh_type = SHT_SYMTAB_SHNDX;
237 2 : shdr->sh_entsize = sizeof (Elf32_Word);
238 2 : shdr->sh_addralign = sizeof (Elf32_Word);
239 2 : shdr->sh_link = symscnndx;
240 :
241 2 : (void) gelf_update_shdr (xndxscn, shdr);
242 :
243 2 : 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 2 : xndxdata->d_size = elf32_fsize (ELF_T_WORD,
250 2 : ctx->nsymbol_tab + 1,
251 : EV_CURRENT);
252 2 : xshndx = xndxdata->d_buf = calloc (1, xndxdata->d_size);
253 2 : 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 2 : xndxdata->d_type = ELF_T_WORD;
258 2 : xndxdata->d_off = 0;
259 : }
260 :
261 : /* Store the real section index in the extended setion
262 : index table. */
263 961 : assert ((size_t) ptr < ctx->nsymbol_tab + 1);
264 961 : xshndx[ptr] = ndx;
265 :
266 : /* And signal that this happened. */
267 961 : ndx = SHN_XINDEX;
268 : }
269 88005 : syment.st_shndx = ndx;
270 :
271 : /* Remember where we put the symbol. */
272 88005 : sym->symidx = ptr;
273 :
274 88005 : (void) gelf_update_sym (data, ptr, &syment);
275 : }
276 :
277 5 : assert (ptr_local == ptr_nonlocal + 1);
278 :
279 5 : shdr->sh_type = SHT_SYMTAB;
280 5 : shdr->sh_link = strscnndx;
281 5 : shdr->sh_info = ptr_local;
282 5 : shdr->sh_entsize = gelf_fsize (ctx->out.elf, ELF_T_SYM, 1, EV_CURRENT);
283 5 : shdr->sh_addralign = gelf_fsize (ctx->out.elf, ELF_T_ADDR, 1,
284 : EV_CURRENT);
285 :
286 5 : (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 9 : shstrscn = elf_newscn (ctx->out.elf);
293 9 : shstrtabdata = elf_newdata (shstrscn);
294 9 : shdr = gelf_getshdr (shstrscn, &shdr_mem);
295 9 : if (shstrscn == NULL || shstrtabdata == NULL || shdr == NULL)
296 : {
297 0 : __libasm_seterrno (ASM_E_LIBELF);
298 0 : return -1;
299 : }
300 :
301 :
302 : /* Add the name of the section header string table. */
303 9 : shstrscn_strent = dwelf_strtab_add_len (ctx->section_strtab,
304 : ".shstrtab", 10);
305 :
306 9 : dwelf_strtab_finalize (ctx->section_strtab, shstrtabdata);
307 :
308 9 : shdr->sh_type = SHT_STRTAB;
309 9 : assert (shdr->sh_entsize == 0);
310 9 : shdr->sh_name = dwelf_strent_off (shstrscn_strent);
311 :
312 9 : (void) gelf_update_shdr (shstrscn, shdr);
313 :
314 :
315 : /* Create the section groups. */
316 9 : if (ctx->groups != NULL)
317 : {
318 1 : AsmScnGrp_t *runp = ctx->groups->next;
319 :
320 : do
321 : {
322 : Elf_Scn *scn;
323 : Elf32_Word *grpdata;
324 :
325 22000 : scn = runp->scn;
326 22000 : assert (scn != NULL);
327 22000 : shdr = gelf_getshdr (scn, &shdr_mem);
328 22000 : assert (shdr != NULL);
329 :
330 22000 : data = elf_newdata (scn);
331 22000 : if (data == NULL)
332 : {
333 0 : __libasm_seterrno (ASM_E_LIBELF);
334 0 : return -1;
335 : }
336 :
337 : /* It is correct to use 'elf32_fsize' instead of 'gelf_fsize'
338 : here. */
339 22000 : data->d_size = elf32_fsize (ELF_T_WORD, runp->nmembers + 1,
340 : EV_CURRENT);
341 22000 : grpdata = data->d_buf = malloc (data->d_size);
342 22000 : if (grpdata == NULL)
343 : return -1;
344 22000 : data->d_type = ELF_T_WORD;
345 22000 : data->d_off = 0;
346 22000 : 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 22000 : *grpdata++ = runp->flags;
350 :
351 22000 : if (runp->members != NULL)
352 : {
353 22000 : 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 44000 : assert (member->subsection_id == 0);
361 :
362 44000 : *grpdata++ = elf_ndxscn (member->data.main.scn);
363 : }
364 44000 : while ((member = member->data.main.next_in_group)
365 44000 : != runp->members->data.main.next_in_group);
366 : }
367 :
368 : /* Construct the section header. */
369 22000 : shdr->sh_name = dwelf_strent_off (runp->strent);
370 22000 : shdr->sh_type = SHT_GROUP;
371 22000 : shdr->sh_flags = 0;
372 22000 : 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 44000 : shdr->sh_info = (runp->signature != NULL
376 22000 : ? runp->signature->symidx : 0);
377 :
378 22000 : (void) gelf_update_shdr (scn, shdr);
379 : }
380 22000 : while ((runp = runp->next) != ctx->groups->next);
381 : }
382 :
383 :
384 : /* Add the name to the symbol section. */
385 9 : if (likely (symscnndx != 0))
386 : {
387 5 : Elf_Scn *scn = elf_getscn (ctx->out.elf, symscnndx);
388 :
389 5 : shdr = gelf_getshdr (scn, &shdr_mem);
390 :
391 5 : shdr->sh_name = dwelf_strent_off (symscn_strent);
392 :
393 5 : (void) gelf_update_shdr (scn, shdr);
394 :
395 :
396 : /* Add the name to the string section. */
397 5 : assert (strscnndx != 0);
398 5 : scn = elf_getscn (ctx->out.elf, strscnndx);
399 :
400 5 : shdr = gelf_getshdr (scn, &shdr_mem);
401 :
402 5 : shdr->sh_name = dwelf_strent_off (strscn_strent);
403 :
404 5 : (void) gelf_update_shdr (scn, shdr);
405 :
406 :
407 : /* Add the name to the extended symbol index section. */
408 5 : if (xndxscnndx != 0)
409 : {
410 2 : scn = elf_getscn (ctx->out.elf, xndxscnndx);
411 :
412 2 : shdr = gelf_getshdr (scn, &shdr_mem);
413 :
414 2 : shdr->sh_name = dwelf_strent_off (xndxscn_strent);
415 :
416 2 : (void) gelf_update_shdr (scn, shdr);
417 : }
418 : }
419 :
420 :
421 : /* Iterate over the created sections and fill in the names. */
422 176014 : for (asmscn = ctx->section_list; asmscn != NULL; asmscn = asmscn->allnext)
423 : {
424 176005 : shdr = gelf_getshdr (asmscn->data.main.scn, &shdr_mem);
425 : /* This better should not fail. */
426 176005 : assert (shdr != NULL);
427 :
428 176005 : shdr->sh_name = dwelf_strent_off (asmscn->data.main.strent);
429 :
430 : /* We now know the maximum alignment. */
431 176005 : shdr->sh_addralign = asmscn->max_align;
432 :
433 176005 : (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 9 : ehdr = gelf_getehdr (ctx->out.elf, &ehdr_mem);
439 9 : assert (ehdr != NULL);
440 :
441 9 : shstrscnndx = elf_ndxscn (shstrscn);
442 9 : if (unlikely (shstrscnndx > SHN_HIRESERVE)
443 6 : || unlikely (shstrscnndx == SHN_XINDEX))
444 3 : {
445 : /* The index of the section header string sectio is too large. */
446 3 : Elf_Scn *scn = elf_getscn (ctx->out.elf, 0);
447 :
448 : /* Get the header for the zeroth section. */
449 3 : shdr = gelf_getshdr (scn, &shdr_mem);
450 : /* This better does not fail. */
451 3 : assert (shdr != NULL);
452 :
453 : /* The sh_link field of the zeroth section header contains the value. */
454 3 : shdr->sh_link = shstrscnndx;
455 :
456 3 : (void) gelf_update_shdr (scn, shdr);
457 :
458 : /* This is the sign for the overflow. */
459 3 : ehdr->e_shstrndx = SHN_XINDEX;
460 : }
461 : else
462 6 : ehdr->e_shstrndx = elf_ndxscn (shstrscn);
463 :
464 9 : gelf_update_ehdr (ctx->out.elf, ehdr);
465 :
466 : /* Write out the ELF file. */
467 9 : if (unlikely (elf_update (ctx->out.elf, ELF_C_WRITE_MMAP) < 0))
468 : {
469 0 : __libasm_seterrno (ASM_E_LIBELF);
470 0 : result = -1;
471 : }
472 :
473 : /* We do not need the section header and symbol string tables anymore. */
474 9 : free (shstrtabdata->d_buf);
475 9 : if (strtabdata != NULL)
476 5 : free (strtabdata->d_buf);
477 : /* We might have allocated the extended symbol table index. */
478 9 : if (xndxdata != NULL)
479 2 : free (xndxdata->d_buf);
480 :
481 : /* Free section groups memory. */
482 9 : AsmScnGrp_t *scngrp = ctx->groups;
483 9 : if (scngrp != NULL)
484 : do
485 22000 : free (elf_getdata (scngrp->scn, NULL)->d_buf);
486 22000 : while ((scngrp = scngrp->next) != ctx->groups);
487 :
488 : /* Finalize the ELF handling. */
489 9 : if (unlikely (elf_end (ctx->out.elf)) != 0)
490 : {
491 0 : __libasm_seterrno (ASM_E_LIBELF);
492 0 : result = -1;
493 : }
494 :
495 : /* Free the temporary resources. */
496 9 : free (symtab);
497 :
498 9 : return result;
499 : }
500 :
501 :
502 : int
503 9 : asm_end (AsmCtx_t *ctx)
504 : {
505 : int result;
506 :
507 9 : if (ctx == NULL)
508 : /* Something went wrong earlier. */
509 : return -1;
510 :
511 9 : result = unlikely (ctx->textp) ? text_end (ctx) : binary_end (ctx);
512 9 : if (result != 0)
513 : return result;
514 :
515 : /* Make the new file globally readable and user/group-writable. */
516 9 : if (fchmod (ctx->fd, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH) != 0)
517 : {
518 0 : __libasm_seterrno (ASM_E_CANNOT_CHMOD);
519 0 : return -1;
520 : }
521 :
522 : /* Rename output file. */
523 9 : if (rename (ctx->tmp_fname, ctx->fname) != 0)
524 : {
525 0 : __libasm_seterrno (ASM_E_CANNOT_RENAME);
526 0 : return -1;
527 : }
528 :
529 : /* Free the resources. */
530 9 : __libasm_finictx (ctx);
531 :
532 9 : return 0;
533 : }
534 :
535 :
536 : static void
537 176007 : free_section (AsmScn_t *scnp)
538 : {
539 : void *oldp;
540 :
541 176007 : if (scnp->subnext != NULL)
542 2 : free_section (scnp->subnext);
543 :
544 176007 : struct AsmData *data = scnp->content;
545 176007 : if (data != NULL)
546 : do
547 : {
548 176005 : oldp = data;
549 176005 : data = data->next;
550 176005 : free (oldp);
551 : }
552 176005 : while (oldp != scnp->content);
553 :
554 176007 : free (scnp);
555 176007 : }
556 :
557 :
558 : void
559 : internal_function
560 9 : __libasm_finictx (AsmCtx_t *ctx)
561 : {
562 : /* Iterate through section table and free individual entries. */
563 9 : AsmScn_t *scn = ctx->section_list;
564 176023 : while (scn != NULL)
565 : {
566 176005 : AsmScn_t *oldp = scn;
567 176005 : scn = scn->allnext;
568 176005 : free_section (oldp);
569 : }
570 :
571 : /* Free the resources of the symbol table. */
572 9 : void *runp = NULL;
573 : AsmSym_t *sym;
574 88023 : while ((sym = asm_symbol_tab_iterate (&ctx->symbol_tab, &runp)) != NULL)
575 88005 : free (sym);
576 9 : asm_symbol_tab_free (&ctx->symbol_tab);
577 :
578 :
579 : /* Free section groups. */
580 9 : AsmScnGrp_t *scngrp = ctx->groups;
581 9 : if (scngrp != NULL)
582 : do
583 : {
584 22000 : AsmScnGrp_t *oldp = scngrp;
585 :
586 22000 : scngrp = scngrp->next;
587 22000 : free (oldp);
588 : }
589 22000 : while (scngrp != ctx->groups);
590 :
591 :
592 9 : if (unlikely (ctx->textp))
593 : {
594 : /* Close the stream. */
595 0 : 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 9 : (void) close (ctx->fd);
603 :
604 : /* And the string tables. */
605 9 : dwelf_strtab_free (ctx->section_strtab);
606 9 : 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 9 : free (ctx);
614 9 : }
|