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