• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * ELF object format helpers
3  *
4  *  Copyright (C) 2003-2007  Michael Urman
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  *
15  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND OTHER CONTRIBUTORS ``AS IS''
16  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR OTHER CONTRIBUTORS BE
19  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
20  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
21  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
22  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
23  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
24  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
25  * POSSIBILITY OF SUCH DAMAGE.
26  */
27 
28 #include <util.h>
29 
30 #include <libyasm.h>
31 #define YASM_OBJFMT_ELF_INTERNAL
32 #include "elf.h"
33 #include "elf-machine.h"
34 
35 static void elf_section_data_destroy(void *data);
36 static void elf_secthead_print(void *data, FILE *f, int indent_level);
37 
38 const yasm_assoc_data_callback elf_section_data = {
39     elf_section_data_destroy,
40     elf_secthead_print
41 };
42 
43 static void elf_symrec_data_destroy(/*@only@*/ void *d);
44 static void elf_symtab_entry_print(void *data, FILE *f, int indent_level);
45 static void elf_ssym_symtab_entry_print(void *data, FILE *f, int indent_level);
46 
47 const yasm_assoc_data_callback elf_symrec_data = {
48     elf_symrec_data_destroy,
49     elf_symtab_entry_print
50 };
51 
52 const yasm_assoc_data_callback elf_ssym_symrec_data = {
53     elf_symrec_data_destroy,
54     elf_ssym_symtab_entry_print
55 };
56 
57 extern elf_machine_handler
58     elf_machine_handler_x86_x86,
59     elf_machine_handler_x86_amd64;
60 
61 static const elf_machine_handler *elf_machine_handlers[] =
62 {
63     &elf_machine_handler_x86_x86,
64     &elf_machine_handler_x86_amd64,
65     NULL
66 };
67 static const elf_machine_handler elf_null_machine = {0, 0, 0, 0, 0, 0, 0, 0,
68                                                      0, 0, 0, 0, 0, 0, 0, 0,
69                                                      0, 0, 0};
70 static elf_machine_handler const *elf_march = &elf_null_machine;
71 static yasm_symrec **elf_ssyms;
72 
73 const elf_machine_handler *
elf_set_arch(yasm_arch * arch,yasm_symtab * symtab,int bits_pref)74 elf_set_arch(yasm_arch *arch, yasm_symtab *symtab, int bits_pref)
75 {
76     const char *machine = yasm_arch_get_machine(arch);
77     int i;
78 
79     for (i=0, elf_march = elf_machine_handlers[0];
80          elf_march != NULL;
81          elf_march = elf_machine_handlers[++i])
82     {
83         if (yasm__strcasecmp(yasm_arch_keyword(arch), elf_march->arch)==0)
84             if (yasm__strcasecmp(machine, elf_march->machine)==0)
85                 if (bits_pref == 0 || bits_pref == elf_march->bits)
86                     break;
87     }
88 
89     if (elf_march && elf_march->num_ssyms > 0)
90     {
91         /* Allocate "special" syms */
92         elf_ssyms =
93             yasm_xmalloc(elf_march->num_ssyms * sizeof(yasm_symrec *));
94         for (i=0; (unsigned int)i<elf_march->num_ssyms; i++)
95         {
96             /* FIXME: misuse of NULL bytecode */
97             elf_ssyms[i] = yasm_symtab_define_label(symtab,
98                                                     elf_march->ssyms[i].name,
99                                                     NULL, 0, 0);
100             yasm_symrec_add_data(elf_ssyms[i], &elf_ssym_symrec_data,
101                                  (void*)&elf_march->ssyms[i]);
102         }
103     }
104 
105     return elf_march;
106 }
107 
108 yasm_symrec *
elf_get_special_sym(const char * name,const char * parser)109 elf_get_special_sym(const char *name, const char *parser)
110 {
111     int i;
112     for (i=0; (unsigned int)i<elf_march->num_ssyms; i++) {
113         if (yasm__strcasecmp(name, elf_march->ssyms[i].name) == 0)
114             return elf_ssyms[i];
115     }
116     return NULL;
117 }
118 
119 /* reloc functions */
120 int elf_ssym_has_flag(yasm_symrec *wrt, int flag);
121 
122 int
elf_is_wrt_sym_relative(yasm_symrec * wrt)123 elf_is_wrt_sym_relative(yasm_symrec *wrt)
124 {
125     return elf_ssym_has_flag(wrt, ELF_SSYM_SYM_RELATIVE);
126 }
127 
128 int
elf_is_wrt_pos_adjusted(yasm_symrec * wrt)129 elf_is_wrt_pos_adjusted(yasm_symrec *wrt)
130 {
131     return elf_ssym_has_flag(wrt, ELF_SSYM_CURPOS_ADJUST);
132 }
133 
134 int
elf_ssym_has_flag(yasm_symrec * wrt,int flag)135 elf_ssym_has_flag(yasm_symrec *wrt, int flag)
136 {
137     int i;
138     for (i=0; (unsigned int)i<elf_march->num_ssyms; i++) {
139         if (elf_ssyms[i] == wrt)
140             return (elf_march->ssyms[i].sym_rel & flag) != 0;
141     }
142     return 0;
143 }
144 
145 /* takes ownership of addr */
146 elf_reloc_entry *
elf_reloc_entry_create(yasm_symrec * sym,yasm_symrec * wrt,yasm_intnum * addr,int rel,size_t valsize,int is_GOT_sym)147 elf_reloc_entry_create(yasm_symrec *sym,
148                        yasm_symrec *wrt,
149                        yasm_intnum *addr,
150                        int rel,
151                        size_t valsize,
152                        int is_GOT_sym)
153 {
154     elf_reloc_entry *entry;
155 
156     if (!elf_march->accepts_reloc)
157         yasm_internal_error(N_("Unsupported machine for ELF output"));
158 
159     if (!elf_march->accepts_reloc(valsize, wrt))
160     {
161         if (addr)
162             yasm_intnum_destroy(addr);
163         return NULL;
164     }
165 
166     if (sym == NULL)
167         yasm_internal_error("sym is null");
168 
169     entry = yasm_xmalloc(sizeof(elf_reloc_entry));
170     entry->reloc.sym = sym;
171     entry->reloc.addr = addr;
172     entry->rtype_rel = rel;
173     entry->valsize = valsize;
174     entry->addend = NULL;
175     entry->wrt = wrt;
176     entry->is_GOT_sym = is_GOT_sym;
177 
178     return entry;
179 }
180 
181 void
elf_reloc_entry_destroy(void * entry)182 elf_reloc_entry_destroy(void *entry)
183 {
184     if (((elf_reloc_entry*)entry)->addend)
185         yasm_intnum_destroy(((elf_reloc_entry*)entry)->addend);
186     yasm_xfree(entry);
187 }
188 
189 /* strtab functions */
190 elf_strtab_entry *
elf_strtab_entry_create(const char * str)191 elf_strtab_entry_create(const char *str)
192 {
193     elf_strtab_entry *entry = yasm_xmalloc(sizeof(elf_strtab_entry));
194     entry->str = yasm__xstrdup(str);
195     entry->index = 0;
196     return entry;
197 }
198 
199 void
elf_strtab_entry_set_str(elf_strtab_entry * entry,const char * str)200 elf_strtab_entry_set_str(elf_strtab_entry *entry, const char *str)
201 {
202     elf_strtab_entry *last;
203     if (entry->str)
204         yasm_xfree(entry->str);
205     entry->str = yasm__xstrdup(str);
206 
207     /* Update all following indices since string length probably changes */
208     last = entry;
209     entry = STAILQ_NEXT(last, qlink);
210     while (entry) {
211         entry->index = last->index + (unsigned long)strlen(last->str) + 1;
212         last = entry;
213         entry = STAILQ_NEXT(last, qlink);
214     }
215 }
216 
217 elf_strtab_head *
elf_strtab_create()218 elf_strtab_create()
219 {
220     elf_strtab_head *strtab = yasm_xmalloc(sizeof(elf_strtab_head));
221     elf_strtab_entry *entry = yasm_xmalloc(sizeof(elf_strtab_entry));
222 
223     STAILQ_INIT(strtab);
224     entry->index = 0;
225     entry->str = yasm__xstrdup("");
226 
227     STAILQ_INSERT_TAIL(strtab, entry, qlink);
228     return strtab;
229 }
230 
231 elf_strtab_entry *
elf_strtab_append_str(elf_strtab_head * strtab,const char * str)232 elf_strtab_append_str(elf_strtab_head *strtab, const char *str)
233 {
234     elf_strtab_entry *last, *entry;
235 
236     if (strtab == NULL)
237         yasm_internal_error("strtab is null");
238     if (STAILQ_EMPTY(strtab))
239         yasm_internal_error("strtab is missing initial dummy entry");
240 
241     last = STAILQ_LAST(strtab, elf_strtab_entry, qlink);
242 
243     entry = elf_strtab_entry_create(str);
244     entry->index = last->index + (unsigned long)strlen(last->str) + 1;
245 
246     STAILQ_INSERT_TAIL(strtab, entry, qlink);
247     return entry;
248 }
249 
250 void
elf_strtab_destroy(elf_strtab_head * strtab)251 elf_strtab_destroy(elf_strtab_head *strtab)
252 {
253     elf_strtab_entry *s1, *s2;
254 
255     if (strtab == NULL)
256         yasm_internal_error("strtab is null");
257     if (STAILQ_EMPTY(strtab))
258         yasm_internal_error("strtab is missing initial dummy entry");
259 
260     s1 = STAILQ_FIRST(strtab);
261     while (s1 != NULL) {
262         s2 = STAILQ_NEXT(s1, qlink);
263         yasm_xfree(s1->str);
264         yasm_xfree(s1);
265         s1 = s2;
266     }
267     yasm_xfree(strtab);
268 }
269 
270 unsigned long
elf_strtab_output_to_file(FILE * f,elf_strtab_head * strtab)271 elf_strtab_output_to_file(FILE *f, elf_strtab_head *strtab)
272 {
273     unsigned long size = 0;
274     elf_strtab_entry *entry;
275 
276     if (strtab == NULL)
277         yasm_internal_error("strtab is null");
278 
279     /* consider optimizing tables here */
280     STAILQ_FOREACH(entry, strtab, qlink) {
281         size_t len = 1 + strlen(entry->str);
282         fwrite(entry->str, len, 1, f);
283         size += (unsigned long)len;
284     }
285     return size;
286 }
287 
288 
289 
290 /* symtab functions */
291 elf_symtab_entry *
elf_symtab_entry_create(elf_strtab_entry * name,yasm_symrec * sym)292 elf_symtab_entry_create(elf_strtab_entry *name,
293                         yasm_symrec *sym)
294 {
295     elf_symtab_entry *entry = yasm_xmalloc(sizeof(elf_symtab_entry));
296     entry->in_table = 0;
297     entry->sym = sym;
298     entry->sect = NULL;
299     entry->name = name;
300     entry->value = 0;
301 
302     entry->xsize = NULL;
303     entry->size = 0;
304     entry->index = 0;
305     entry->bind = 0;
306     entry->type = STT_NOTYPE;
307     entry->vis = STV_DEFAULT;
308 
309     return entry;
310 }
311 
312 static void
elf_symtab_entry_destroy(elf_symtab_entry * entry)313 elf_symtab_entry_destroy(elf_symtab_entry *entry)
314 {
315     if (entry == NULL)
316         yasm_internal_error("symtab entry is null");
317 
318     yasm_xfree(entry);
319 }
320 
321 static void
elf_symrec_data_destroy(void * data)322 elf_symrec_data_destroy(void *data)
323 {
324     /* do nothing, as this stuff is in the symtab anyway...  this speaks of bad
325      * design/use or this stuff, i fear */
326 
327     /* watch for double-free here ... */
328     /*elf_symtab_entry_destroy((elf_symtab_entry *)data);*/
329 }
330 
331 static void
elf_symtab_entry_print(void * data,FILE * f,int indent_level)332 elf_symtab_entry_print(void *data, FILE *f, int indent_level)
333 {
334     elf_symtab_entry *entry = data;
335     if (entry == NULL)
336         yasm_internal_error("symtab entry is null");
337 
338     fprintf(f, "%*sbind=", indent_level, "");
339     switch (entry->bind) {
340         case STB_LOCAL:         fprintf(f, "local\n");  break;
341         case STB_GLOBAL:        fprintf(f, "global\n"); break;
342         case STB_WEAK:          fprintf(f, "weak\n");   break;
343         default:                fprintf(f, "undef\n");  break;
344     }
345     fprintf(f, "%*stype=", indent_level, "");
346     switch (entry->type) {
347         case STT_NOTYPE:        fprintf(f, "notype\n"); break;
348         case STT_OBJECT:        fprintf(f, "object\n"); break;
349         case STT_FUNC:          fprintf(f, "func\n");   break;
350         case STT_SECTION:       fprintf(f, "section\n");break;
351         case STT_FILE:          fprintf(f, "file\n");   break;
352         default:                fprintf(f, "undef\n");  break;
353     }
354     fprintf(f, "%*ssize=", indent_level, "");
355     if (entry->xsize)
356         yasm_expr_print(entry->xsize, f);
357     else
358         fprintf(f, "%ld", entry->size);
359     fprintf(f, "\n");
360 }
361 
362 static void
elf_ssym_symtab_entry_print(void * data,FILE * f,int indent_level)363 elf_ssym_symtab_entry_print(void *data, FILE *f, int indent_level)
364 {
365     /* TODO */
366 }
367 
368 elf_symtab_head *
elf_symtab_create()369 elf_symtab_create()
370 {
371     elf_symtab_head *symtab = yasm_xmalloc(sizeof(elf_symtab_head));
372     elf_symtab_entry *entry = yasm_xmalloc(sizeof(elf_symtab_entry));
373 
374     STAILQ_INIT(symtab);
375     entry->in_table = 1;
376     entry->sym = NULL;
377     entry->sect = NULL;
378     entry->name = NULL;
379     entry->value = 0;
380     entry->xsize = NULL;
381     entry->size = 0;
382     entry->index = SHN_UNDEF;
383     entry->bind = STB_LOCAL;
384     entry->type = STT_NOTYPE;
385     entry->vis = STV_DEFAULT;
386     entry->symindex = 0;
387     STAILQ_INSERT_TAIL(symtab, entry, qlink);
388     return symtab;
389 }
390 
391 void
elf_symtab_append_entry(elf_symtab_head * symtab,elf_symtab_entry * entry)392 elf_symtab_append_entry(elf_symtab_head *symtab, elf_symtab_entry *entry)
393 {
394     if (symtab == NULL)
395         yasm_internal_error("symtab is null");
396     if (entry == NULL)
397         yasm_internal_error("symtab entry is null");
398     if (STAILQ_EMPTY(symtab))
399         yasm_internal_error(N_("symtab is missing initial dummy entry"));
400 
401     STAILQ_INSERT_TAIL(symtab, entry, qlink);
402     entry->in_table = 1;
403 }
404 
405 void
elf_symtab_insert_local_sym(elf_symtab_head * symtab,elf_symtab_entry * entry)406 elf_symtab_insert_local_sym(elf_symtab_head *symtab, elf_symtab_entry *entry)
407 {
408     elf_symtab_entry *after = STAILQ_FIRST(symtab);
409     elf_symtab_entry *before = NULL;
410 
411     while (after && (after->bind == STB_LOCAL)) {
412         before = after;
413         if (before->type == STT_FILE) break;
414         after = STAILQ_NEXT(after, qlink);
415     }
416     STAILQ_INSERT_AFTER(symtab, before, entry, qlink);
417     entry->in_table = 1;
418 }
419 
420 void
elf_symtab_destroy(elf_symtab_head * symtab)421 elf_symtab_destroy(elf_symtab_head *symtab)
422 {
423     elf_symtab_entry *s1, *s2;
424 
425     if (symtab == NULL)
426         yasm_internal_error("symtab is null");
427     if (STAILQ_EMPTY(symtab))
428         yasm_internal_error(N_("symtab is missing initial dummy entry"));
429 
430     s1 = STAILQ_FIRST(symtab);
431     while (s1 != NULL) {
432         s2 = STAILQ_NEXT(s1, qlink);
433         elf_symtab_entry_destroy(s1);
434         s1 = s2;
435     }
436     yasm_xfree(symtab);
437 }
438 
439 unsigned long
elf_symtab_assign_indices(elf_symtab_head * symtab)440 elf_symtab_assign_indices(elf_symtab_head *symtab)
441 {
442     elf_symtab_entry *entry, *prev=NULL;
443     unsigned long last_local=0;
444 
445     if (symtab == NULL)
446         yasm_internal_error("symtab is null");
447     if (STAILQ_EMPTY(symtab))
448         yasm_internal_error(N_("symtab is missing initial dummy entry"));
449 
450     STAILQ_FOREACH(entry, symtab, qlink) {
451         if (prev)
452             entry->symindex = prev->symindex + 1;
453         if (entry->bind == STB_LOCAL)
454             last_local = entry->symindex;
455         prev = entry;
456     }
457     return last_local + 1;
458 }
459 
460 unsigned long
elf_symtab_write_to_file(FILE * f,elf_symtab_head * symtab,yasm_errwarns * errwarns)461 elf_symtab_write_to_file(FILE *f, elf_symtab_head *symtab,
462                          yasm_errwarns *errwarns)
463 {
464     unsigned char buf[SYMTAB_MAXSIZE], *bufp;
465     elf_symtab_entry *entry, *prev;
466     unsigned long size = 0;
467 
468     if (!symtab)
469         yasm_internal_error(N_("symtab is null"));
470 
471     prev = NULL;
472     STAILQ_FOREACH(entry, symtab, qlink) {
473 
474         yasm_intnum *size_intn=NULL, *value_intn=NULL;
475         bufp = buf;
476 
477         /* get size (if specified); expr overrides stored integer */
478         if (entry->xsize) {
479             size_intn = yasm_intnum_copy(
480                 yasm_expr_get_intnum(&entry->xsize, 1));
481             if (!size_intn) {
482                 yasm_error_set(YASM_ERROR_VALUE,
483                                N_("size specifier not an integer expression"));
484                 yasm_errwarn_propagate(errwarns, entry->xsize->line);
485             }
486         }
487         else
488             size_intn = yasm_intnum_create_uint(entry->size);
489 
490         /* get EQU value for constants */
491         if (entry->sym) {
492             const yasm_expr *equ_expr_c;
493             equ_expr_c = yasm_symrec_get_equ(entry->sym);
494 
495             if (equ_expr_c != NULL) {
496                 const yasm_intnum *equ_intn;
497                 yasm_expr *equ_expr = yasm_expr_copy(equ_expr_c);
498                 equ_intn = yasm_expr_get_intnum(&equ_expr, 1);
499 
500                 if (equ_intn == NULL) {
501                     yasm_error_set(YASM_ERROR_VALUE,
502                                    N_("EQU value not an integer expression"));
503                     yasm_errwarn_propagate(errwarns, equ_expr->line);
504                 } else
505                     value_intn = yasm_intnum_copy(equ_intn);
506                 entry->index = SHN_ABS;
507                 yasm_expr_destroy(equ_expr);
508             }
509         }
510         if (value_intn == NULL)
511             value_intn = yasm_intnum_create_uint(entry->value);
512 
513         /* If symbol is in a TLS section, force its type to TLS. */
514         if (entry->sym) {
515             yasm_bytecode *precbc;
516             yasm_section *sect;
517             elf_secthead *shead;
518             if (yasm_symrec_get_label(entry->sym, &precbc) &&
519                 (sect = yasm_bc_get_section(precbc)) &&
520                 (shead = yasm_section_get_data(sect, &elf_section_data)) &&
521                 shead->flags & SHF_TLS) {
522                 entry->type = STT_TLS;
523             }
524         }
525 
526         if (!elf_march->write_symtab_entry || !elf_march->symtab_entry_size)
527             yasm_internal_error(N_("Unsupported machine for ELF output"));
528         elf_march->write_symtab_entry(bufp, entry, value_intn, size_intn);
529         fwrite(buf, elf_march->symtab_entry_size, 1, f);
530         size += elf_march->symtab_entry_size;
531 
532         yasm_intnum_destroy(size_intn);
533         yasm_intnum_destroy(value_intn);
534 
535         prev = entry;
536     }
537     return size;
538 }
539 
elf_symtab_set_nonzero(elf_symtab_entry * entry,yasm_section * sect,elf_section_index sectidx,elf_symbol_binding bind,elf_symbol_type type,yasm_expr * xsize,elf_address * value)540 void elf_symtab_set_nonzero(elf_symtab_entry *entry,
541                             yasm_section *sect,
542                             elf_section_index sectidx,
543                             elf_symbol_binding bind,
544                             elf_symbol_type type,
545                             yasm_expr *xsize,
546                             elf_address *value)
547 {
548     if (!entry)
549         yasm_internal_error("NULL entry");
550     if (sect) entry->sect = sect;
551     if (sectidx) entry->index = sectidx;
552     if (bind) entry->bind = bind;
553     if (type) entry->type = type;
554     if (xsize) entry->xsize = xsize;
555     if (value) entry->value = *value;
556 }
557 
558 void
elf_sym_set_visibility(elf_symtab_entry * entry,elf_symbol_vis vis)559 elf_sym_set_visibility(elf_symtab_entry *entry,
560                        elf_symbol_vis    vis)
561 {
562     entry->vis = ELF_ST_VISIBILITY(vis);
563 }
564 
565 void
elf_sym_set_type(elf_symtab_entry * entry,elf_symbol_type type)566 elf_sym_set_type(elf_symtab_entry *entry,
567                  elf_symbol_type   type)
568 {
569     entry->type = type;
570 }
571 
572 void
elf_sym_set_size(elf_symtab_entry * entry,struct yasm_expr * size)573 elf_sym_set_size(elf_symtab_entry *entry,
574                  struct yasm_expr *size)
575 {
576     if (entry->xsize)
577         yasm_expr_destroy(entry->xsize);
578     entry->xsize = size;
579 }
580 
581 int
elf_sym_in_table(elf_symtab_entry * entry)582 elf_sym_in_table(elf_symtab_entry *entry)
583 {
584     return entry->in_table;
585 }
586 
587 elf_secthead *
elf_secthead_create(elf_strtab_entry * name,elf_section_type type,elf_section_flags flags,elf_address offset,elf_size size)588 elf_secthead_create(elf_strtab_entry    *name,
589                     elf_section_type     type,
590                     elf_section_flags    flags,
591                     elf_address          offset,
592                     elf_size             size)
593 {
594     elf_secthead *esd = yasm_xmalloc(sizeof(elf_secthead));
595 
596     esd->type = type;
597     esd->flags = flags;
598     esd->offset = offset;
599     esd->size = yasm_intnum_create_uint(size);
600     esd->link = 0;
601     esd->info = 0;
602     esd->align = 0;
603     esd->entsize = 0;
604     esd->index = 0;
605 
606     esd->sym = NULL;
607     esd->name = name;
608     esd->index = 0;
609     esd->rel_name = NULL;
610     esd->rel_index = 0;
611     esd->rel_offset = 0;
612     esd->nreloc = 0;
613 
614     if (name && (strcmp(name->str, ".symtab") == 0)) {
615         if (!elf_march->symtab_entry_size || !elf_march->symtab_entry_align)
616             yasm_internal_error(N_("unsupported ELF format"));
617         esd->entsize = elf_march->symtab_entry_size;
618         esd->align = elf_march->symtab_entry_align;
619     }
620 
621     return esd;
622 }
623 
624 void
elf_secthead_destroy(elf_secthead * shead)625 elf_secthead_destroy(elf_secthead *shead)
626 {
627     if (shead == NULL)
628         yasm_internal_error(N_("shead is null"));
629 
630     yasm_intnum_destroy(shead->size);
631 
632     yasm_xfree(shead);
633 }
634 
635 static void
elf_section_data_destroy(void * data)636 elf_section_data_destroy(void *data)
637 {
638     elf_secthead_destroy((elf_secthead *)data);
639 }
640 
641 static void
elf_secthead_print(void * data,FILE * f,int indent_level)642 elf_secthead_print(void *data, FILE *f, int indent_level)
643 {
644     elf_secthead *sect = data;
645     fprintf(f, "%*sname=%s\n", indent_level, "",
646             sect->name ? sect->name->str : "<undef>");
647     fprintf(f, "%*ssym=\n", indent_level, "");
648     yasm_symrec_print(sect->sym, f, indent_level+1);
649     fprintf(f, "%*sindex=0x%x\n", indent_level, "", sect->index);
650     fprintf(f, "%*sflags=", indent_level, "");
651     if (sect->flags & SHF_WRITE)
652         fprintf(f, "WRITE ");
653     if (sect->flags & SHF_ALLOC)
654         fprintf(f, "ALLOC ");
655     if (sect->flags & SHF_EXECINSTR)
656         fprintf(f, "EXEC ");
657     /*if (sect->flags & SHF_MASKPROC)
658         fprintf(f, "PROC-SPECIFIC"); */
659     fprintf(f, "%*soffset=0x%lx\n", indent_level, "", sect->offset);
660     fprintf(f, "%*ssize=0x%lx\n", indent_level, "",
661             yasm_intnum_get_uint(sect->size));
662     fprintf(f, "%*slink=0x%x\n", indent_level, "", sect->link);
663     fprintf(f, "%*salign=%lu\n", indent_level, "", sect->align);
664     fprintf(f, "%*snreloc=%ld\n", indent_level, "", sect->nreloc);
665 }
666 
667 unsigned long
elf_secthead_write_to_file(FILE * f,elf_secthead * shead,elf_section_index sindex)668 elf_secthead_write_to_file(FILE *f, elf_secthead *shead,
669                            elf_section_index sindex)
670 {
671     unsigned char buf[SHDR_MAXSIZE], *bufp = buf;
672     shead->index = sindex;
673 
674     if (shead == NULL)
675         yasm_internal_error("shead is null");
676 
677     if (!elf_march->write_secthead || !elf_march->secthead_size)
678         yasm_internal_error(N_("Unsupported machine for ELF output"));
679     elf_march->write_secthead(bufp, shead);
680     if (fwrite(buf, elf_march->secthead_size, 1, f))
681         return elf_march->secthead_size;
682     yasm_internal_error(N_("Failed to write an elf section header"));
683     return 0;
684 }
685 
686 void
elf_secthead_append_reloc(yasm_section * sect,elf_secthead * shead,elf_reloc_entry * reloc)687 elf_secthead_append_reloc(yasm_section *sect, elf_secthead *shead,
688                           elf_reloc_entry *reloc)
689 {
690     if (sect == NULL)
691         yasm_internal_error("sect is null");
692     if (shead == NULL)
693         yasm_internal_error("shead is null");
694     if (reloc == NULL)
695         yasm_internal_error("reloc is null");
696 
697     shead->nreloc++;
698     yasm_section_add_reloc(sect, (yasm_reloc *)reloc, elf_reloc_entry_destroy);
699 }
700 
701 char *
elf_secthead_name_reloc_section(const char * basesect)702 elf_secthead_name_reloc_section(const char *basesect)
703 {
704     if (!elf_march->reloc_section_prefix)
705     {
706         yasm_internal_error(N_("Unsupported machine for ELF output"));
707         return NULL;
708     }
709     else
710     {
711         size_t prepend_length = strlen(elf_march->reloc_section_prefix);
712         char *sectname = yasm_xmalloc(prepend_length + strlen(basesect) + 1);
713         strcpy(sectname, elf_march->reloc_section_prefix);
714         strcat(sectname, basesect);
715         return sectname;
716     }
717 }
718 
719 void
elf_handle_reloc_addend(yasm_intnum * intn,elf_reloc_entry * reloc,unsigned long offset)720 elf_handle_reloc_addend(yasm_intnum *intn,
721                         elf_reloc_entry *reloc,
722                         unsigned long offset)
723 {
724     if (!elf_march->handle_reloc_addend)
725         yasm_internal_error(N_("Unsupported machine for ELF output"));
726     elf_march->handle_reloc_addend(intn, reloc, offset);
727 }
728 
729 unsigned long
elf_secthead_write_rel_to_file(FILE * f,elf_section_index symtab_idx,yasm_section * sect,elf_secthead * shead,elf_section_index sindex)730 elf_secthead_write_rel_to_file(FILE *f, elf_section_index symtab_idx,
731                                yasm_section *sect, elf_secthead *shead,
732                                elf_section_index sindex)
733 {
734     unsigned char buf[SHDR_MAXSIZE], *bufp = buf;
735 
736     if (shead == NULL)
737         yasm_internal_error("shead is null");
738 
739     if (!yasm_section_relocs_first(sect))
740         return 0;       /* no relocations, no .rel.* section header */
741 
742     shead->rel_index = sindex;
743 
744     if (!elf_march->write_secthead_rel || !elf_march->secthead_size)
745         yasm_internal_error(N_("Unsupported machine for ELF output"));
746     elf_march->write_secthead_rel(bufp, shead, symtab_idx, sindex);
747     if (fwrite(buf, elf_march->secthead_size, 1, f))
748         return elf_march->secthead_size;
749     yasm_internal_error(N_("Failed to write an elf section header"));
750     return 0;
751 }
752 
753 unsigned long
elf_secthead_write_relocs_to_file(FILE * f,yasm_section * sect,elf_secthead * shead,yasm_errwarns * errwarns)754 elf_secthead_write_relocs_to_file(FILE *f, yasm_section *sect,
755                                   elf_secthead *shead, yasm_errwarns *errwarns)
756 {
757     elf_reloc_entry *reloc;
758     unsigned char buf[RELOC_MAXSIZE], *bufp;
759     unsigned long size = 0;
760     long pos;
761 
762     if (shead == NULL)
763         yasm_internal_error("shead is null");
764 
765     reloc = (elf_reloc_entry *)yasm_section_relocs_first(sect);
766     if (!reloc)
767         return 0;
768 
769     /* first align section to multiple of 4 */
770     pos = ftell(f);
771     if (pos == -1) {
772         yasm_error_set(YASM_ERROR_IO,
773                        N_("couldn't read position on output stream"));
774         yasm_errwarn_propagate(errwarns, 0);
775     }
776     pos = (pos + 3) & ~3;
777     if (fseek(f, pos, SEEK_SET) < 0) {
778         yasm_error_set(YASM_ERROR_IO, N_("couldn't seek on output stream"));
779         yasm_errwarn_propagate(errwarns, 0);
780     }
781     shead->rel_offset = (unsigned long)pos;
782 
783 
784     while (reloc) {
785         yasm_sym_vis vis;
786         unsigned int r_type=0, r_sym;
787         elf_symtab_entry *esym;
788 
789         esym = yasm_symrec_get_data(reloc->reloc.sym, &elf_symrec_data);
790         if (esym)
791             r_sym = esym->symindex;
792         else
793             r_sym = STN_UNDEF;
794 
795         vis = yasm_symrec_get_visibility(reloc->reloc.sym);
796         if (!elf_march->map_reloc_info_to_type)
797             yasm_internal_error(N_("Unsupported arch/machine for elf output"));
798         r_type = elf_march->map_reloc_info_to_type(reloc);
799 
800         bufp = buf;
801         if (!elf_march->write_reloc || !elf_march->reloc_entry_size)
802             yasm_internal_error(N_("Unsupported arch/machine for elf output"));
803         elf_march->write_reloc(bufp, reloc, r_type, r_sym);
804         fwrite(buf, elf_march->reloc_entry_size, 1, f);
805         size += elf_march->reloc_entry_size;
806 
807         reloc = (elf_reloc_entry *)
808             yasm_section_reloc_next((yasm_reloc *)reloc);
809     }
810     return size;
811 }
812 
813 elf_section_type
elf_secthead_get_type(elf_secthead * shead)814 elf_secthead_get_type(elf_secthead *shead)
815 {
816     return shead->type;
817 }
818 
819 void
elf_secthead_set_typeflags(elf_secthead * shead,elf_section_type type,elf_section_flags flags)820 elf_secthead_set_typeflags(elf_secthead *shead, elf_section_type type,
821                            elf_section_flags flags)
822 {
823     shead->type = type;
824     shead->flags = flags;
825 }
826 
827 int
elf_secthead_is_empty(elf_secthead * shead)828 elf_secthead_is_empty(elf_secthead *shead)
829 {
830     return yasm_intnum_is_zero(shead->size);
831 }
832 
833 yasm_symrec *
elf_secthead_get_sym(elf_secthead * shead)834 elf_secthead_get_sym(elf_secthead *shead)
835 {
836     return shead->sym;
837 }
838 
839 elf_section_index
elf_secthead_get_index(elf_secthead * shead)840 elf_secthead_get_index(elf_secthead *shead)
841 {
842     return shead->index;
843 }
844 
845 unsigned long
elf_secthead_get_align(const elf_secthead * shead)846 elf_secthead_get_align(const elf_secthead *shead)
847 {
848     return shead->align;
849 }
850 
851 unsigned long
elf_secthead_set_align(elf_secthead * shead,unsigned long align)852 elf_secthead_set_align(elf_secthead *shead, unsigned long align)
853 {
854     return shead->align = align;
855 }
856 
857 elf_section_info
elf_secthead_set_info(elf_secthead * shead,elf_section_info info)858 elf_secthead_set_info(elf_secthead *shead, elf_section_info info)
859 {
860     return shead->info = info;
861 }
862 
863 elf_section_index
elf_secthead_set_index(elf_secthead * shead,elf_section_index sectidx)864 elf_secthead_set_index(elf_secthead *shead, elf_section_index sectidx)
865 {
866     return shead->index = sectidx;
867 }
868 
869 elf_section_index
elf_secthead_set_link(elf_secthead * shead,elf_section_index link)870 elf_secthead_set_link(elf_secthead *shead, elf_section_index link)
871 {
872     return shead->link = link;
873 }
874 
875 elf_section_index
elf_secthead_set_rel_index(elf_secthead * shead,elf_section_index sectidx)876 elf_secthead_set_rel_index(elf_secthead *shead, elf_section_index sectidx)
877 {
878     return shead->rel_index = sectidx;
879 }
880 
881 elf_strtab_entry *
elf_secthead_set_rel_name(elf_secthead * shead,elf_strtab_entry * entry)882 elf_secthead_set_rel_name(elf_secthead *shead, elf_strtab_entry *entry)
883 {
884     return shead->rel_name = entry;
885 }
886 
887 elf_size
elf_secthead_set_entsize(elf_secthead * shead,elf_size size)888 elf_secthead_set_entsize(elf_secthead *shead, elf_size size)
889 {
890     return shead->entsize = size;
891 }
892 
893 yasm_symrec *
elf_secthead_set_sym(elf_secthead * shead,yasm_symrec * sym)894 elf_secthead_set_sym(elf_secthead *shead, yasm_symrec *sym)
895 {
896     return shead->sym = sym;
897 }
898 
899 void
elf_secthead_add_size(elf_secthead * shead,yasm_intnum * size)900 elf_secthead_add_size(elf_secthead *shead, yasm_intnum *size)
901 {
902     if (size) {
903         yasm_intnum_calc(shead->size, YASM_EXPR_ADD, size);
904     }
905 }
906 
907 long
elf_secthead_set_file_offset(elf_secthead * shead,long pos)908 elf_secthead_set_file_offset(elf_secthead *shead, long pos)
909 {
910     unsigned long align = shead->align;
911 
912     if (align == 0 || align == 1) {
913         shead->offset = (unsigned long)pos;
914         return pos;
915     }
916     else if (align & (align - 1))
917         yasm_internal_error(
918             N_("alignment %d for section `%s' is not a power of 2"));
919             /*, align, sect->name->str);*/
920 
921     shead->offset = (unsigned long)((pos + align - 1) & ~(align - 1));
922     return (long)shead->offset;
923 }
924 
925 unsigned long
elf_proghead_get_size(void)926 elf_proghead_get_size(void)
927 {
928     if (!elf_march->proghead_size)
929         yasm_internal_error(N_("Unsupported ELF format for output"));
930     return elf_march->proghead_size;
931 }
932 
933 unsigned long
elf_proghead_write_to_file(FILE * f,elf_offset secthead_addr,unsigned long secthead_count,elf_section_index shstrtab_index)934 elf_proghead_write_to_file(FILE *f,
935                            elf_offset secthead_addr,
936                            unsigned long secthead_count,
937                            elf_section_index shstrtab_index)
938 {
939     unsigned char buf[EHDR_MAXSIZE], *bufp = buf;
940 
941     YASM_WRITE_8(bufp, ELFMAG0);                /* ELF magic number */
942     YASM_WRITE_8(bufp, ELFMAG1);
943     YASM_WRITE_8(bufp, ELFMAG2);
944     YASM_WRITE_8(bufp, ELFMAG3);
945 
946     if (!elf_march->write_proghead || !elf_march->proghead_size)
947         yasm_internal_error(N_("Unsupported ELF format for output"));
948     elf_march->write_proghead(&bufp, secthead_addr, secthead_count, shstrtab_index);
949 
950     if (((unsigned)(bufp - buf)) != elf_march->proghead_size)
951         yasm_internal_error(N_("ELF program header is not proper length"));
952 
953     if (fwrite(buf, elf_march->proghead_size, 1, f))
954         return elf_march->proghead_size;
955 
956     yasm_internal_error(N_("Failed to write ELF program header"));
957     return 0;
958 }
959