Home | History | Annotate | Download | only in elf
      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 *
     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 *
    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
    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
    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
    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 *
    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
    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 *
    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
    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 *
    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 *
    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
    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
    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 *
    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
    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
    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
    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
    363 elf_ssym_symtab_entry_print(void *data, FILE *f, int indent_level)
    364 {
    365     /* TODO */
    366 }
    367 
    368 elf_symtab_head *
    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
    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
    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
    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
    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
    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 
    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
    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
    566 elf_sym_set_type(elf_symtab_entry *entry,
    567                  elf_symbol_type   type)
    568 {
    569     entry->type = type;
    570 }
    571 
    572 void
    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
    582 elf_sym_in_table(elf_symtab_entry *entry)
    583 {
    584     return entry->in_table;
    585 }
    586 
    587 elf_secthead *
    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
    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
    636 elf_section_data_destroy(void *data)
    637 {
    638     elf_secthead_destroy((elf_secthead *)data);
    639 }
    640 
    641 static void
    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
    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
    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 *
    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
    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
    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
    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
    814 elf_secthead_get_type(elf_secthead *shead)
    815 {
    816     return shead->type;
    817 }
    818 
    819 void
    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
    828 elf_secthead_is_empty(elf_secthead *shead)
    829 {
    830     return yasm_intnum_is_zero(shead->size);
    831 }
    832 
    833 yasm_symrec *
    834 elf_secthead_get_sym(elf_secthead *shead)
    835 {
    836     return shead->sym;
    837 }
    838 
    839 elf_section_index
    840 elf_secthead_get_index(elf_secthead *shead)
    841 {
    842     return shead->index;
    843 }
    844 
    845 unsigned long
    846 elf_secthead_get_align(const elf_secthead *shead)
    847 {
    848     return shead->align;
    849 }
    850 
    851 unsigned long
    852 elf_secthead_set_align(elf_secthead *shead, unsigned long align)
    853 {
    854     return shead->align = align;
    855 }
    856 
    857 elf_section_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
    864 elf_secthead_set_index(elf_secthead *shead, elf_section_index sectidx)
    865 {
    866     return shead->index = sectidx;
    867 }
    868 
    869 elf_section_index
    870 elf_secthead_set_link(elf_secthead *shead, elf_section_index link)
    871 {
    872     return shead->link = link;
    873 }
    874 
    875 elf_section_index
    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 *
    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
    888 elf_secthead_set_entsize(elf_secthead *shead, elf_size size)
    889 {
    890     return shead->entsize = size;
    891 }
    892 
    893 yasm_symrec *
    894 elf_secthead_set_sym(elf_secthead *shead, yasm_symrec *sym)
    895 {
    896     return shead->sym = sym;
    897 }
    898 
    899 void
    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
    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
    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
    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