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