1 /* Finalize operations on the assembler context, free all resources.
2 Copyright (C) 2002, 2003 Red Hat, Inc.
3 Written by Ulrich Drepper <drepper@redhat.com>, 2002.
4
5 This program is Open Source software; you can redistribute it and/or
6 modify it under the terms of the Open Software License version 1.0 as
7 published by the Open Source Initiative.
8
9 You should have received a copy of the Open Software License along
10 with this program; if not, you may obtain a copy of the Open Software
11 License version 1.0 from http://www.opensource.org/licenses/osl.php or
12 by writing the Open Source Initiative c/o Lawrence Rosen, Esq.,
13 3001 King Ranch Road, Ukiah, CA 95482. */
14
15 #ifdef HAVE_CONFIG_H
16 # include <config.h>
17 #endif
18
19 #include <assert.h>
20 #include <error.h>
21 #include <libintl.h>
22 #include <stdio.h>
23 #include <stdlib.h>
24 #include <string.h>
25 #include <unistd.h>
26 #include <sys/stat.h>
27
28 #include <libasmP.h>
29 #include <libelf.h>
30 #include <system.h>
31
32
33 static int
text_end(AsmCtx_t * ctx)34 text_end (AsmCtx_t *ctx)
35 {
36 // XXX Does anything have to be done?
37 return 0;
38 }
39
40
41 static int
binary_end(AsmCtx_t * ctx)42 binary_end (AsmCtx_t *ctx)
43 {
44 void *symtab = NULL;
45 struct Ebl_Strent *symscn_strent = NULL;
46 struct Ebl_Strent *strscn_strent = NULL;
47 struct Ebl_Strent *xndxscn_strent = NULL;
48 Elf_Scn *shstrscn;
49 struct Ebl_Strent *shstrscn_strent;
50 size_t shstrscnndx;
51 size_t symscnndx = 0;
52 size_t strscnndx = 0;
53 size_t xndxscnndx = 0;
54 Elf_Data *data;
55 Elf_Data *shstrtabdata;
56 Elf_Data *strtabdata = NULL;
57 Elf_Data *xndxdata = NULL;
58 GElf_Shdr shdr_mem;
59 GElf_Shdr *shdr;
60 GElf_Ehdr ehdr_mem;
61 GElf_Ehdr *ehdr;
62 AsmScn_t *asmscn;
63 int result = 0;
64
65 /* Iterate over the created sections and compute the offsets of the
66 various subsections and fill in the content. */
67 for (asmscn = ctx->section_list; asmscn != NULL; asmscn = asmscn->allnext)
68 {
69 #if 0
70 Elf_Scn *scn = elf_getscn (ctx->out.elf, asmscn->data.main.scnndx);
71 #else
72 Elf_Scn *scn = asmscn->data.main.scn;
73 #endif
74 off_t offset = 0;
75 AsmScn_t *asmsubscn = asmscn;
76
77 do
78 {
79 struct AsmData *content = asmsubscn->content;
80 bool first = true;
81
82 offset = ((offset + asmsubscn->max_align - 1)
83 & ~(asmsubscn->max_align - 1));
84
85 /* Update the offset for this subsection. This field now
86 stores the offset of the first by in this subsection. */
87 asmsubscn->offset = offset;
88
89 /* Note that the content list is circular. */
90 if (content != NULL)
91 do
92 {
93 Elf_Data *newdata = elf_newdata (scn);
94
95 if (newdata == NULL)
96 error (EXIT_FAILURE, 0,
97 _("cannot create section for output file: %s"),
98 elf_errmsg (-1));
99
100 newdata->d_buf = content->data;
101 newdata->d_type = ELF_T_BYTE;
102 newdata->d_size = content->len;
103 newdata->d_off = offset;
104 newdata->d_align = first ? asmsubscn->max_align : 1;
105
106 offset += content->len;
107 }
108 while ((content = content->next) != asmsubscn->content);
109 }
110 while ((asmsubscn = asmsubscn->subnext) != NULL);
111 }
112
113
114 /* Create the symbol table if necessary. */
115 if (ctx->nsymbol_tab > 0)
116 {
117 Elf_Scn *symscn;
118 Elf_Scn *strscn;
119 AsmSym_t *sym;
120 int ptr_local;
121 int ptr_nonlocal;
122 GElf_Sym syment;
123 uint32_t *xshndx = NULL;
124 void *runp;
125
126 /* Create the symbol table and string table section names. */
127 symscn_strent = ebl_strtabadd (ctx->section_strtab, ".symtab", 8);
128 strscn_strent = ebl_strtabadd (ctx->section_strtab, ".strtab", 8);
129
130 /* Create the symbol string table section. */
131 strscn = elf_newscn (ctx->out.elf);
132 strtabdata = elf_newdata (strscn);
133 shdr = gelf_getshdr (strscn, &shdr_mem);
134 if (strtabdata == NULL || shdr == NULL)
135 error (EXIT_FAILURE, 0, _("cannot create section for output file: %s"),
136 elf_errmsg (-1));
137 strscnndx = elf_ndxscn (strscn);
138
139 ebl_strtabfinalize (ctx->symbol_strtab, strtabdata);
140
141 shdr->sh_type = SHT_STRTAB;
142 assert (shdr->sh_entsize == 0);
143
144 (void) gelf_update_shdr (strscn, shdr);
145
146 /* Create the symbol table section. */
147 symscn = elf_newscn (ctx->out.elf);
148 data = elf_newdata (symscn);
149 shdr = gelf_getshdr (symscn, &shdr_mem);
150 if (data == NULL || shdr == NULL)
151 error (EXIT_FAILURE, 0, _("cannot create section for output file: %s"),
152 elf_errmsg (-1));
153 symscnndx = elf_ndxscn (symscn);
154
155 /* We know how many symbols there will be in the symbol table. */
156 data->d_size = gelf_fsize (ctx->out.elf, ELF_T_SYM,
157 ctx->nsymbol_tab + 1, EV_CURRENT);
158 symtab = malloc (data->d_size);
159 if (symtab == NULL)
160 return -1;
161 data->d_buf = symtab;
162 data->d_type = ELF_T_SYM;
163 data->d_off = 0;
164
165 /* Clear the first entry. */
166 memset (&syment, '\0', sizeof (syment));
167 (void) gelf_update_sym (data, 0, &syment);
168
169 /* Iterate over the symbol table. */
170 runp = NULL;
171 ptr_local = 1; /* Start with index 1; zero remains unused. */
172 ptr_nonlocal = ctx->nsymbol_tab;
173 while ((sym = asm_symbol_tab_iterate (&ctx->symbol_tab, &runp)) != NULL)
174 if (asm_emit_symbol_p (ebl_string (sym->strent)))
175 {
176 int ptr;
177 Elf32_Word ndx;
178 Elf_Scn *scn;
179
180 assert (ptr_local <= ptr_nonlocal);
181
182 syment.st_name = ebl_strtaboffset (sym->strent);
183 syment.st_info = GELF_ST_INFO (sym->binding, sym->type);
184 syment.st_other = 0;
185 syment.st_value = sym->scn->offset + sym->offset;
186 syment.st_size = sym->size;
187
188 /* Add local symbols at the beginning, the other from
189 the end. */
190 ptr = sym->binding == STB_LOCAL ? ptr_local++ : ptr_nonlocal--;
191
192 /* Determine the section index. We have to handle the
193 overflow correctly. */
194 scn = (sym->scn->subsection_id == 0
195 ? sym->scn->data.main.scn
196 : sym->scn->data.up->data.main.scn);
197
198 if (unlikely (scn == ASM_ABS_SCN))
199 ndx = SHN_ABS;
200 else if (unlikely (scn == ASM_COM_SCN))
201 ndx = SHN_COMMON;
202 else if (unlikely ((ndx = elf_ndxscn (scn)) >= SHN_LORESERVE))
203 {
204 if (unlikely (xshndx == NULL))
205 {
206 /* The extended section index section does not yet
207 exist. */
208 Elf_Scn *xndxscn;
209 size_t symscnndx = elf_ndxscn (symscn);
210
211 xndxscn = elf_newscn (ctx->out.elf);
212 xndxdata = elf_newdata (xndxscn);
213 shdr = gelf_getshdr (xndxscn, &shdr_mem);
214 if (xndxdata == NULL || shdr == NULL)
215 error (EXIT_FAILURE, 0, _("\
216 cannot create extended section index table: %s"),
217 elf_errmsg (-1));
218 xndxscnndx = elf_ndxscn (xndxscn);
219
220 shdr->sh_type = SHT_SYMTAB_SHNDX;
221 shdr->sh_entsize = sizeof (Elf32_Word);
222 shdr->sh_addralign = sizeof (Elf32_Word);
223 shdr->sh_link = symscnndx;
224
225 (void) gelf_update_shdr (xndxscn, shdr);
226
227 xndxscn_strent = ebl_strtabadd (ctx->section_strtab,
228 ".symtab_shndx", 14);
229
230 /* Note that using 'elf32_fsize' instead of
231 'gelf_fsize' here is correct. */
232 xndxdata->d_size = elf32_fsize (ELF_T_WORD,
233 ctx->nsymbol_tab + 1,
234 EV_CURRENT);
235 xshndx = xndxdata->d_buf = calloc (1, xndxdata->d_size);
236 if (xshndx == NULL)
237 return -1;
238 /* Using ELF_T_WORD here relies on the fact that the
239 32- and 64-bit types are the same size. */
240 xndxdata->d_type = ELF_T_WORD;
241 xndxdata->d_off = 0;
242 }
243
244 /* Store the real section index in the extended setion
245 index table. */
246 assert ((size_t) ptr < ctx->nsymbol_tab + 1);
247 xshndx[ptr] = ndx;
248
249 /* And signal that this happened. */
250 ndx = SHN_XINDEX;
251 }
252 syment.st_shndx = ndx;
253
254 /* Remember where we put the symbol. */
255 sym->symidx = ptr;
256
257 (void) gelf_update_sym (data, ptr, &syment);
258 }
259
260 assert (ptr_local == ptr_nonlocal + 1);
261
262 shdr->sh_type = SHT_SYMTAB;
263 shdr->sh_link = strscnndx;
264 shdr->sh_info = ptr_local;
265 shdr->sh_entsize = gelf_fsize (ctx->out.elf, ELF_T_SYM, 1, EV_CURRENT);
266 shdr->sh_addralign = gelf_fsize (ctx->out.elf, ELF_T_ADDR, 1,
267 EV_CURRENT);
268
269 (void) gelf_update_shdr (symscn, shdr);
270 }
271
272
273 /* Create the section header string table section and fill in the
274 references in the section headers. */
275 shstrscn = elf_newscn (ctx->out.elf);
276 shstrtabdata = elf_newdata (shstrscn);
277 shdr = gelf_getshdr (shstrscn, &shdr_mem);
278 if (shstrscn == NULL || shstrtabdata == NULL || shdr == NULL)
279 error (EXIT_FAILURE, 0, _("cannot create section for output file: %s"),
280 elf_errmsg (-1));
281
282
283 /* Add the name of the section header string table. */
284 shstrscn_strent = ebl_strtabadd (ctx->section_strtab, ".shstrtab", 10);
285
286 ebl_strtabfinalize (ctx->section_strtab, shstrtabdata);
287
288 shdr->sh_type = SHT_STRTAB;
289 assert (shdr->sh_entsize == 0);
290 shdr->sh_name = ebl_strtaboffset (shstrscn_strent);
291
292 (void) gelf_update_shdr (shstrscn, shdr);
293
294
295 /* Create the section groups. */
296 if (ctx->groups != NULL)
297 {
298 AsmScnGrp_t *runp = ctx->groups->next;
299
300 do
301 {
302 Elf_Scn *scn;
303 GElf_Shdr shdr_mem;
304 GElf_Shdr *shdr;
305 Elf_Data *data;
306 Elf32_Word *grpdata;
307
308 scn = runp->scn;
309 assert (scn != NULL);
310 shdr = gelf_getshdr (scn, &shdr_mem);
311 assert (shdr != NULL);
312
313 data = elf_newdata (scn);
314 if (data == NULL)
315 error (EXIT_FAILURE, 0,
316 _("cannot create section group for output file: %s"),
317 elf_errmsg (-1));
318
319 /* It is correct to use 'elf32_fsize' instead of 'gelf_fsize'
320 here. */
321 data->d_size = elf32_fsize (ELF_T_WORD, runp->nmembers + 1,
322 EV_CURRENT);
323 grpdata = data->d_buf = malloc (data->d_size);
324 if (grpdata == NULL)
325 return -1;
326 data->d_type = ELF_T_WORD;
327 data->d_off = 0;
328 data->d_align = elf32_fsize (ELF_T_WORD, 1, EV_CURRENT);
329
330 /* The first word of the section is filled with the flag word. */
331 *grpdata++ = runp->flags;
332
333 if (runp->members != NULL)
334 {
335 AsmScn_t *member = runp->members->data.main.next_in_group;
336
337 do
338 {
339 /* Only sections, not subsections, can be registered
340 as member of a group. The subsections get
341 automatically included. */
342 assert (member->subsection_id == 0);
343
344 *grpdata++ = elf_ndxscn (member->data.main.scn);
345 }
346 while ((member = member->data.main.next_in_group)
347 != runp->members->data.main.next_in_group);
348 }
349
350 /* Construct the section header. */
351 shdr->sh_name = ebl_strtaboffset (runp->strent);
352 shdr->sh_type = SHT_GROUP;
353 shdr->sh_flags = 0;
354 shdr->sh_link = symscnndx;
355 /* If the user did not specify a signature we use the initial
356 empty symbol in the symbol table as the signature. */
357 shdr->sh_info = (runp->signature != NULL
358 ? runp->signature->symidx : 0);
359
360 (void) gelf_update_shdr (scn, shdr);
361 }
362 while ((runp = runp->next) != ctx->groups->next);
363 }
364
365
366 /* Add the name to the symbol section. */
367 if (likely (symscnndx != 0))
368 {
369 Elf_Scn *scn = elf_getscn (ctx->out.elf, symscnndx);
370
371 shdr = gelf_getshdr (scn, &shdr_mem);
372
373 shdr->sh_name = ebl_strtaboffset (symscn_strent);
374
375 (void) gelf_update_shdr (scn, shdr);
376
377
378 /* Add the name to the string section. */
379 assert (strscnndx != 0);
380 scn = elf_getscn (ctx->out.elf, strscnndx);
381
382 shdr = gelf_getshdr (scn, &shdr_mem);
383
384 shdr->sh_name = ebl_strtaboffset (strscn_strent);
385
386 (void) gelf_update_shdr (scn, shdr);
387
388
389 /* Add the name to the extended symbol index section. */
390 if (xndxscnndx != 0)
391 {
392 scn = elf_getscn (ctx->out.elf, xndxscnndx);
393
394 shdr = gelf_getshdr (scn, &shdr_mem);
395
396 shdr->sh_name = ebl_strtaboffset (xndxscn_strent);
397
398 (void) gelf_update_shdr (scn, shdr);
399 }
400 }
401
402
403 /* Iterate over the created sections and fill in the names. */
404 for (asmscn = ctx->section_list; asmscn != NULL; asmscn = asmscn->allnext)
405 {
406 shdr = gelf_getshdr (asmscn->data.main.scn, &shdr_mem);
407 /* This better should not fail. */
408 assert (shdr != NULL);
409
410 shdr->sh_name = ebl_strtaboffset (asmscn->data.main.strent);
411
412 /* We now know the maximum alignment. */
413 shdr->sh_addralign = asmscn->max_align;
414
415 (void) gelf_update_shdr (asmscn->data.main.scn, shdr);
416 }
417
418 /* Put the reference to the section header string table in the ELF
419 header. */
420 ehdr = gelf_getehdr (ctx->out.elf, &ehdr_mem);
421 assert (ehdr != NULL);
422
423 shstrscnndx = elf_ndxscn (shstrscn);
424 if (unlikely (shstrscnndx > SHN_HIRESERVE)
425 || unlikely (shstrscnndx == SHN_XINDEX))
426 {
427 /* The index of the section header string sectio is too large. */
428 Elf_Scn *scn = elf_getscn (ctx->out.elf, 0);
429
430 /* Get the header for the zeroth section. */
431 shdr = gelf_getshdr (scn, &shdr_mem);
432 /* This better does not fail. */
433 assert (shdr != NULL);
434
435 /* The sh_link field of the zeroth section header contains the value. */
436 shdr->sh_link = shstrscnndx;
437
438 (void) gelf_update_shdr (scn, shdr);
439
440 /* This is the sign for the overflow. */
441 ehdr->e_shstrndx = SHN_XINDEX;
442 }
443 else
444 ehdr->e_shstrndx = elf_ndxscn (shstrscn);
445
446 gelf_update_ehdr (ctx->out.elf, ehdr);
447
448 /* Write out the ELF file. */
449 if (unlikely (elf_update (ctx->out.elf, ELF_C_WRITE_MMAP)) < 0)
450 {
451 __libasm_seterrno (ASM_E_LIBELF);
452 result = -1;
453 }
454
455 /* We do not need the section header and symbol string tables anymore. */
456 free (shstrtabdata->d_buf);
457 if (strtabdata != NULL)
458 free (strtabdata->d_buf);
459 /* We might have allocated the extended symbol table index. */
460 if (xndxdata != NULL)
461 free (xndxdata->d_buf);
462
463 /* Free section groups memory. */
464 AsmScnGrp_t *scngrp = ctx->groups;
465 if (scngrp != NULL)
466 do
467 free (elf_getdata (scngrp->scn, NULL)->d_buf);
468 while ((scngrp = scngrp->next) != ctx->groups);
469
470 /* Finalize the ELF handling. */
471 if (unlikely (elf_end (ctx->out.elf)) != 0)
472 {
473 __libasm_seterrno (ASM_E_LIBELF);
474 result = -1;
475 }
476
477 /* Free the temporary resources. */
478 free (symtab);
479
480 return result;
481 }
482
483
484 int
asm_end(ctx)485 asm_end (ctx)
486 AsmCtx_t *ctx;
487 {
488 int result;
489
490 if (ctx == NULL)
491 /* Something went wrong earlier. */
492 return -1;
493
494 result = unlikely (ctx->textp) ? text_end (ctx) : binary_end (ctx);
495 if (result != 0)
496 return result;
497
498 /* Make the new file globally readable and user/group-writable. */
499 if (fchmod (ctx->fd, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH) != 0)
500 {
501 __libasm_seterrno (ASM_E_CANNOT_CHMOD);
502 return -1;
503 }
504
505 /* Rename output file. */
506 if (rename (ctx->tmp_fname, ctx->fname) != 0)
507 {
508 __libasm_seterrno (ASM_E_CANNOT_RENAME);
509 return -1;
510 }
511
512 /* Free the resources. */
513 __libasm_finictx (ctx);
514
515 return 0;
516 }
517
518
519 static void
free_section(AsmScn_t * scnp)520 free_section (AsmScn_t *scnp)
521 {
522 void *oldp;
523
524 if (scnp->subnext != NULL)
525 free_section (scnp->subnext);
526
527 struct AsmData *data = scnp->content;
528 if (data != NULL)
529 do
530 {
531 oldp = data;
532 data = data->next;
533 free (oldp);
534 }
535 while (oldp != scnp->content);
536
537 free (scnp);
538 }
539
540
541 void
__libasm_finictx(ctx)542 __libasm_finictx (ctx)
543 AsmCtx_t *ctx;
544 {
545 /* Iterate through section table and free individual entries. */
546 AsmScn_t *scn = ctx->section_list;
547 while (scn != NULL)
548 {
549 AsmScn_t *oldp = scn;
550 scn = scn->allnext;
551 free_section (oldp);
552 }
553
554 /* Free the resources of the symbol table. */
555 void *runp = NULL;
556 AsmSym_t *sym;
557 while ((sym = asm_symbol_tab_iterate (&ctx->symbol_tab, &runp)) != NULL)
558 free (sym);
559 asm_symbol_tab_free (&ctx->symbol_tab);
560
561
562 /* Free section groups. */
563 AsmScnGrp_t *scngrp = ctx->groups;
564 if (scngrp != NULL)
565 do
566 {
567 AsmScnGrp_t *oldp = scngrp;
568
569 scngrp = scngrp->next;
570 free (oldp);
571 }
572 while (scngrp != ctx->groups);
573
574
575 if (unlikely (ctx->textp))
576 {
577 /* Close the stream. */
578 fclose (ctx->out.file);
579 }
580 else
581 {
582 /* Close the output file. */
583 /* XXX We should test for errors here but what would we do if we'd
584 find any. */
585 (void) close (ctx->fd);
586
587 /* And the string tables. */
588 ebl_strtabfree (ctx->section_strtab);
589 ebl_strtabfree (ctx->symbol_strtab);
590 }
591
592 /* Initialize the lock. */
593 rwlock_fini (ctx->lock);
594
595 /* Finally free the data structure. */
596 free (ctx);
597 }
598