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
35static void elf_section_data_destroy(void *data);
36static void elf_secthead_print(void *data, FILE *f, int indent_level);
37
38const yasm_assoc_data_callback elf_section_data = {
39    elf_section_data_destroy,
40    elf_secthead_print
41};
42
43static void elf_symrec_data_destroy(/*@only@*/ void *d);
44static void elf_symtab_entry_print(void *data, FILE *f, int indent_level);
45static void elf_ssym_symtab_entry_print(void *data, FILE *f, int indent_level);
46
47const yasm_assoc_data_callback elf_symrec_data = {
48    elf_symrec_data_destroy,
49    elf_symtab_entry_print
50};
51
52const yasm_assoc_data_callback elf_ssym_symrec_data = {
53    elf_symrec_data_destroy,
54    elf_ssym_symtab_entry_print
55};
56
57extern elf_machine_handler
58    elf_machine_handler_x86_x86,
59    elf_machine_handler_x86_amd64;
60
61static const elf_machine_handler *elf_machine_handlers[] =
62{
63    &elf_machine_handler_x86_x86,
64    &elf_machine_handler_x86_amd64,
65    NULL
66};
67static 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};
70static elf_machine_handler const *elf_march = &elf_null_machine;
71static yasm_symrec **elf_ssyms;
72
73const elf_machine_handler *
74elf_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
108yasm_symrec *
109elf_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 */
120int elf_ssym_has_flag(yasm_symrec *wrt, int flag);
121
122int
123elf_is_wrt_sym_relative(yasm_symrec *wrt)
124{
125    return elf_ssym_has_flag(wrt, ELF_SSYM_SYM_RELATIVE);
126}
127
128int
129elf_is_wrt_pos_adjusted(yasm_symrec *wrt)
130{
131    return elf_ssym_has_flag(wrt, ELF_SSYM_CURPOS_ADJUST);
132}
133
134int
135elf_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 */
146elf_reloc_entry *
147elf_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
181void
182elf_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 */
190elf_strtab_entry *
191elf_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
199void
200elf_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
217elf_strtab_head *
218elf_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
231elf_strtab_entry *
232elf_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
250void
251elf_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
270unsigned long
271elf_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 */
291elf_symtab_entry *
292elf_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
312static void
313elf_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
321static void
322elf_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
331static void
332elf_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
362static void
363elf_ssym_symtab_entry_print(void *data, FILE *f, int indent_level)
364{
365    /* TODO */
366}
367
368elf_symtab_head *
369elf_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
391void
392elf_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
405void
406elf_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
420void
421elf_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
439unsigned long
440elf_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
460unsigned long
461elf_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
540void 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
558void
559elf_sym_set_visibility(elf_symtab_entry *entry,
560                       elf_symbol_vis    vis)
561{
562    entry->vis = ELF_ST_VISIBILITY(vis);
563}
564
565void
566elf_sym_set_type(elf_symtab_entry *entry,
567                 elf_symbol_type   type)
568{
569    entry->type = type;
570}
571
572void
573elf_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
581int
582elf_sym_in_table(elf_symtab_entry *entry)
583{
584    return entry->in_table;
585}
586
587elf_secthead *
588elf_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
624void
625elf_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
635static void
636elf_section_data_destroy(void *data)
637{
638    elf_secthead_destroy((elf_secthead *)data);
639}
640
641static void
642elf_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
667unsigned long
668elf_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
686void
687elf_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
701char *
702elf_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
719void
720elf_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
729unsigned long
730elf_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
753unsigned long
754elf_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
813elf_section_type
814elf_secthead_get_type(elf_secthead *shead)
815{
816    return shead->type;
817}
818
819void
820elf_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
827int
828elf_secthead_is_empty(elf_secthead *shead)
829{
830    return yasm_intnum_is_zero(shead->size);
831}
832
833yasm_symrec *
834elf_secthead_get_sym(elf_secthead *shead)
835{
836    return shead->sym;
837}
838
839elf_section_index
840elf_secthead_get_index(elf_secthead *shead)
841{
842    return shead->index;
843}
844
845unsigned long
846elf_secthead_get_align(const elf_secthead *shead)
847{
848    return shead->align;
849}
850
851unsigned long
852elf_secthead_set_align(elf_secthead *shead, unsigned long align)
853{
854    return shead->align = align;
855}
856
857elf_section_info
858elf_secthead_set_info(elf_secthead *shead, elf_section_info info)
859{
860    return shead->info = info;
861}
862
863elf_section_index
864elf_secthead_set_index(elf_secthead *shead, elf_section_index sectidx)
865{
866    return shead->index = sectidx;
867}
868
869elf_section_index
870elf_secthead_set_link(elf_secthead *shead, elf_section_index link)
871{
872    return shead->link = link;
873}
874
875elf_section_index
876elf_secthead_set_rel_index(elf_secthead *shead, elf_section_index sectidx)
877{
878    return shead->rel_index = sectidx;
879}
880
881elf_strtab_entry *
882elf_secthead_set_rel_name(elf_secthead *shead, elf_strtab_entry *entry)
883{
884    return shead->rel_name = entry;
885}
886
887elf_size
888elf_secthead_set_entsize(elf_secthead *shead, elf_size size)
889{
890    return shead->entsize = size;
891}
892
893yasm_symrec *
894elf_secthead_set_sym(elf_secthead *shead, yasm_symrec *sym)
895{
896    return shead->sym = sym;
897}
898
899void
900elf_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
907long
908elf_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
925unsigned long
926elf_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
933unsigned long
934elf_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