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