1 /* Finalize operations on the assembler context, free all resources.
2 Copyright (C) 2002, 2003, 2005 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
text_end(AsmCtx_t * ctx)49 text_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
61 static int
binary_end(AsmCtx_t * ctx)62 binary_end (AsmCtx_t *ctx)
63 {
64 void *symtab = NULL;
65 struct Ebl_Strent *symscn_strent = NULL;
66 struct Ebl_Strent *strscn_strent = NULL;
67 struct Ebl_Strent *xndxscn_strent = NULL;
68 Elf_Scn *shstrscn;
69 struct Ebl_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 = ebl_strtabadd (ctx->section_strtab, ".symtab", 8);
140 strscn_strent = ebl_strtabadd (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 ebl_strtabfinalize (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 (ebl_string (sym->strent)))
194 {
195 assert (ptr_local <= ptr_nonlocal);
196
197 syment.st_name = ebl_strtaboffset (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 = ebl_strtabadd (ctx->section_strtab,
244 ".symtab_shndx", 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 = ebl_strtabadd (ctx->section_strtab, ".shstrtab", 10);
303
304 ebl_strtabfinalize (ctx->section_strtab, shstrtabdata);
305
306 shdr->sh_type = SHT_STRTAB;
307 assert (shdr->sh_entsize == 0);
308 shdr->sh_name = ebl_strtaboffset (shstrscn_strent);
309
310 (void) gelf_update_shdr (shstrscn, shdr);
311
312
313 /* Create the section groups. */
314 if (ctx->groups != NULL)
315 {
316 AsmScnGrp_t *runp = ctx->groups->next;
317
318 do
319 {
320 Elf_Scn *scn;
321 Elf32_Word *grpdata;
322
323 scn = runp->scn;
324 assert (scn != NULL);
325 shdr = gelf_getshdr (scn, &shdr_mem);
326 assert (shdr != NULL);
327
328 data = elf_newdata (scn);
329 if (data == NULL)
330 {
331 __libasm_seterrno (ASM_E_LIBELF);
332 return -1;
333 }
334
335 /* It is correct to use 'elf32_fsize' instead of 'gelf_fsize'
336 here. */
337 data->d_size = elf32_fsize (ELF_T_WORD, runp->nmembers + 1,
338 EV_CURRENT);
339 grpdata = data->d_buf = malloc (data->d_size);
340 if (grpdata == NULL)
341 return -1;
342 data->d_type = ELF_T_WORD;
343 data->d_off = 0;
344 data->d_align = elf32_fsize (ELF_T_WORD, 1, EV_CURRENT);
345
346 /* The first word of the section is filled with the flag word. */
347 *grpdata++ = runp->flags;
348
349 if (runp->members != NULL)
350 {
351 AsmScn_t *member = runp->members->data.main.next_in_group;
352
353 do
354 {
355 /* Only sections, not subsections, can be registered
356 as member of a group. The subsections get
357 automatically included. */
358 assert (member->subsection_id == 0);
359
360 *grpdata++ = elf_ndxscn (member->data.main.scn);
361 }
362 while ((member = member->data.main.next_in_group)
363 != runp->members->data.main.next_in_group);
364 }
365
366 /* Construct the section header. */
367 shdr->sh_name = ebl_strtaboffset (runp->strent);
368 shdr->sh_type = SHT_GROUP;
369 shdr->sh_flags = 0;
370 shdr->sh_link = symscnndx;
371 /* If the user did not specify a signature we use the initial
372 empty symbol in the symbol table as the signature. */
373 shdr->sh_info = (runp->signature != NULL
374 ? runp->signature->symidx : 0);
375
376 (void) gelf_update_shdr (scn, shdr);
377 }
378 while ((runp = runp->next) != ctx->groups->next);
379 }
380
381
382 /* Add the name to the symbol section. */
383 if (likely (symscnndx != 0))
384 {
385 Elf_Scn *scn = elf_getscn (ctx->out.elf, symscnndx);
386
387 shdr = gelf_getshdr (scn, &shdr_mem);
388
389 shdr->sh_name = ebl_strtaboffset (symscn_strent);
390
391 (void) gelf_update_shdr (scn, shdr);
392
393
394 /* Add the name to the string section. */
395 assert (strscnndx != 0);
396 scn = elf_getscn (ctx->out.elf, strscnndx);
397
398 shdr = gelf_getshdr (scn, &shdr_mem);
399
400 shdr->sh_name = ebl_strtaboffset (strscn_strent);
401
402 (void) gelf_update_shdr (scn, shdr);
403
404
405 /* Add the name to the extended symbol index section. */
406 if (xndxscnndx != 0)
407 {
408 scn = elf_getscn (ctx->out.elf, xndxscnndx);
409
410 shdr = gelf_getshdr (scn, &shdr_mem);
411
412 shdr->sh_name = ebl_strtaboffset (xndxscn_strent);
413
414 (void) gelf_update_shdr (scn, shdr);
415 }
416 }
417
418
419 /* Iterate over the created sections and fill in the names. */
420 for (asmscn = ctx->section_list; asmscn != NULL; asmscn = asmscn->allnext)
421 {
422 shdr = gelf_getshdr (asmscn->data.main.scn, &shdr_mem);
423 /* This better should not fail. */
424 assert (shdr != NULL);
425
426 shdr->sh_name = ebl_strtaboffset (asmscn->data.main.strent);
427
428 /* We now know the maximum alignment. */
429 shdr->sh_addralign = asmscn->max_align;
430
431 (void) gelf_update_shdr (asmscn->data.main.scn, shdr);
432 }
433
434 /* Put the reference to the section header string table in the ELF
435 header. */
436 ehdr = gelf_getehdr (ctx->out.elf, &ehdr_mem);
437 assert (ehdr != NULL);
438
439 shstrscnndx = elf_ndxscn (shstrscn);
440 if (unlikely (shstrscnndx > SHN_HIRESERVE)
441 || unlikely (shstrscnndx == SHN_XINDEX))
442 {
443 /* The index of the section header string sectio is too large. */
444 Elf_Scn *scn = elf_getscn (ctx->out.elf, 0);
445
446 /* Get the header for the zeroth section. */
447 shdr = gelf_getshdr (scn, &shdr_mem);
448 /* This better does not fail. */
449 assert (shdr != NULL);
450
451 /* The sh_link field of the zeroth section header contains the value. */
452 shdr->sh_link = shstrscnndx;
453
454 (void) gelf_update_shdr (scn, shdr);
455
456 /* This is the sign for the overflow. */
457 ehdr->e_shstrndx = SHN_XINDEX;
458 }
459 else
460 ehdr->e_shstrndx = elf_ndxscn (shstrscn);
461
462 gelf_update_ehdr (ctx->out.elf, ehdr);
463
464 /* Write out the ELF file. */
465 if (unlikely (elf_update (ctx->out.elf, ELF_C_WRITE_MMAP)) < 0)
466 {
467 __libasm_seterrno (ASM_E_LIBELF);
468 result = -1;
469 }
470
471 /* We do not need the section header and symbol string tables anymore. */
472 free (shstrtabdata->d_buf);
473 if (strtabdata != NULL)
474 free (strtabdata->d_buf);
475 /* We might have allocated the extended symbol table index. */
476 if (xndxdata != NULL)
477 free (xndxdata->d_buf);
478
479 /* Free section groups memory. */
480 AsmScnGrp_t *scngrp = ctx->groups;
481 if (scngrp != NULL)
482 do
483 free (elf_getdata (scngrp->scn, NULL)->d_buf);
484 while ((scngrp = scngrp->next) != ctx->groups);
485
486 /* Finalize the ELF handling. */
487 if (unlikely (elf_end (ctx->out.elf)) != 0)
488 {
489 __libasm_seterrno (ASM_E_LIBELF);
490 result = -1;
491 }
492
493 /* Free the temporary resources. */
494 free (symtab);
495
496 return result;
497 }
498
499
500 int
asm_end(ctx)501 asm_end (ctx)
502 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
__libasm_finictx(ctx)558 __libasm_finictx (ctx)
559 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 ebl_strtabfree (ctx->section_strtab);
605 ebl_strtabfree (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