Home | History | Annotate | Download | only in elf
      1 /*
      2  * ELF object format
      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 #include <util.h>
     28 
     29 /* Notes
     30  *
     31  * elf-objfmt uses the "linking" view of an ELF file:
     32  * ELF header, an optional program header table, several sections,
     33  * and a section header table
     34  *
     35  * The ELF header tells us some overall program information,
     36  *   where to find the PHT (if it exists) with phnum and phentsize,
     37  *   and where to find the SHT with shnum and shentsize
     38  *
     39  * The PHT doesn't seem to be generated by NASM for elftest.asm
     40  *
     41  * The SHT
     42  *
     43  * Each Section is spatially disjoint, and has exactly one SHT entry.
     44  */
     45 
     46 #include <libyasm.h>
     47 
     48 #include "elf.h"
     49 #include "elf-machine.h"
     50 
     51 typedef struct yasm_objfmt_elf {
     52     yasm_objfmt_base objfmt;            /* base structure */
     53 
     54     elf_symtab_head* elf_symtab;        /* symbol table of indexed syms */
     55     elf_strtab_head* shstrtab;          /* section name strtab */
     56     elf_strtab_head* strtab;            /* strtab entries */
     57 
     58     elf_strtab_entry *file_strtab_entry;/* .file symbol associated string */
     59     yasm_symrec *dotdotsym;             /* ..sym symbol */
     60 } yasm_objfmt_elf;
     61 
     62 typedef struct {
     63     yasm_objfmt_elf *objfmt_elf;
     64     yasm_errwarns *errwarns;
     65     FILE *f;
     66     elf_secthead *shead;
     67     yasm_section *sect;
     68     yasm_object *object;
     69     unsigned long sindex;
     70     yasm_symrec *GOT_sym;
     71 } elf_objfmt_output_info;
     72 
     73 typedef struct {
     74     yasm_object *object;
     75     yasm_objfmt_elf *objfmt_elf;
     76     yasm_errwarns *errwarns;
     77     int local_names;
     78 } build_symtab_info;
     79 
     80 yasm_objfmt_module yasm_elf_LTX_objfmt;
     81 yasm_objfmt_module yasm_elf32_LTX_objfmt;
     82 yasm_objfmt_module yasm_elf64_LTX_objfmt;
     83 
     84 
     85 static elf_symtab_entry *
     86 elf_objfmt_symtab_append(yasm_objfmt_elf *objfmt_elf, yasm_symrec *sym,
     87                          elf_section_index sectidx, elf_symbol_binding bind,
     88                          elf_symbol_type type, elf_symbol_vis vis,
     89                          yasm_expr *size, elf_address *value,
     90                          yasm_object *object)
     91 {
     92     elf_symtab_entry *entry = yasm_symrec_get_data(sym, &elf_symrec_data);
     93 
     94     if (!entry) {
     95         /*@only@*/ char *symname = yasm_symrec_get_global_name(sym, object);
     96         elf_strtab_entry *name =
     97             elf_strtab_append_str(objfmt_elf->strtab, symname);
     98         yasm_xfree(symname);
     99         entry = elf_symtab_entry_create(name, sym);
    100         yasm_symrec_add_data(sym, &elf_symrec_data, entry);
    101     }
    102 
    103     /* Only append to table if not already appended */
    104     if (!elf_sym_in_table(entry))
    105         elf_symtab_append_entry(objfmt_elf->elf_symtab, entry);
    106 
    107     elf_symtab_set_nonzero(entry, NULL, sectidx, bind, type, size, value);
    108     elf_sym_set_visibility(entry, vis);
    109 
    110     return entry;
    111 }
    112 
    113 static elf_symtab_entry *
    114 build_extern(yasm_objfmt_elf *objfmt_elf, yasm_symrec *sym, yasm_object *object)
    115 {
    116     yasm_valparamhead *objext_valparams =
    117         yasm_symrec_get_objext_valparams(sym);
    118 
    119     if (objext_valparams) {
    120         yasm_valparam *vp = yasm_vps_first(objext_valparams);
    121         for (; vp; vp = yasm_vps_next(vp)) {
    122             if (yasm_vp_string(vp))
    123                 yasm_error_set(YASM_ERROR_TYPE,
    124                                N_("unrecognized symbol type `%s'"),
    125                                yasm_vp_string(vp));
    126         }
    127     }
    128 
    129     return elf_objfmt_symtab_append(objfmt_elf, sym, SHN_UNDEF, STB_GLOBAL, 0,
    130                                     STV_DEFAULT, NULL, NULL, object);
    131 }
    132 
    133 struct elf_build_global_data {
    134     yasm_expr *size;
    135     unsigned long type; /* elf_symbol_type */
    136     elf_symbol_vis vis;
    137     unsigned int vis_overrides;
    138 };
    139 
    140 static int
    141 elf_global_helper_valparam(void *obj, yasm_valparam *vp, unsigned long line,
    142                            void *d)
    143 
    144 {
    145     struct elf_build_global_data *data = (struct elf_build_global_data *)d;
    146     const char *s;
    147 
    148     if (!vp->val && (s = yasm_vp_id(vp))) {
    149         yasm_error_set(YASM_ERROR_TYPE, N_("unrecognized symbol type `%s'"),
    150                        s);
    151         return -1;
    152     } else if (!vp->val && vp->type == YASM_PARAM_EXPR && !data->size) {
    153         data->size = yasm_expr_copy(vp->param.e);
    154         return 0;
    155     } else
    156         return yasm_dir_helper_valparam_warn(obj, vp, line, d);
    157 }
    158 
    159 static int
    160 elf_global_helper_vis(void *obj, yasm_valparam *vp, unsigned long line,
    161                       void *d, uintptr_t vis)
    162 {
    163     struct elf_build_global_data *data = (struct elf_build_global_data *)d;
    164     data->vis = vis;
    165     data->vis_overrides++;
    166     return 0;
    167 }
    168 
    169 
    170 static elf_symtab_entry *
    171 build_global(yasm_objfmt_elf *objfmt_elf, yasm_symrec *sym, yasm_object *object)
    172 {
    173     yasm_valparamhead *objext_valparams =
    174         yasm_symrec_get_objext_valparams(sym);
    175 
    176     struct elf_build_global_data data;
    177 
    178     static const yasm_dir_help help[] = {
    179         { "function", 0, yasm_dir_helper_flag_set,
    180           offsetof(struct elf_build_global_data, type), STT_FUNC },
    181         { "data", 0, yasm_dir_helper_flag_set,
    182           offsetof(struct elf_build_global_data, type), STT_OBJECT },
    183         { "object", 0, yasm_dir_helper_flag_set,
    184           offsetof(struct elf_build_global_data, type), STT_OBJECT },
    185         { "internal", 0, elf_global_helper_vis, 0, STV_INTERNAL },
    186         { "hidden", 0, elf_global_helper_vis, 0, STV_HIDDEN },
    187         { "protected", 0, elf_global_helper_vis, 0, STV_PROTECTED },
    188     };
    189 
    190     data.size = NULL;
    191     data.type = 0;
    192     data.vis = STV_DEFAULT;
    193     data.vis_overrides = 0;
    194 
    195     if (objext_valparams)
    196         yasm_dir_helper(sym, yasm_vps_first(objext_valparams),
    197                         yasm_symrec_get_decl_line(sym), help, NELEMS(help),
    198                         &data, elf_global_helper_valparam);
    199 
    200     if (data.vis_overrides > 1) {
    201         yasm_warn_set(YASM_WARN_GENERAL,
    202             N_("More than one symbol visibility provided; using last"));
    203     }
    204 
    205     return elf_objfmt_symtab_append(objfmt_elf, sym, SHN_UNDEF, STB_GLOBAL,
    206                                     data.type, data.vis, data.size, NULL,
    207                                     object);
    208 }
    209 
    210 static /*@null@*/ elf_symtab_entry *
    211 build_common(yasm_objfmt_elf *objfmt_elf, yasm_symrec *sym, yasm_object *object)
    212 {
    213     yasm_expr **size = yasm_symrec_get_common_size(sym);
    214     yasm_valparamhead *objext_valparams =
    215         yasm_symrec_get_objext_valparams(sym);
    216     unsigned long addralign = 0;
    217 
    218     if (objext_valparams) {
    219         yasm_valparam *vp = yasm_vps_first(objext_valparams);
    220         for (; vp; vp = yasm_vps_next(vp)) {
    221             if (!vp->val) {
    222                 /*@only@*/ /*@null@*/ yasm_expr *align_expr;
    223                 /*@dependent@*/ /*@null@*/ const yasm_intnum *align_intn;
    224 
    225                 if (!(align_expr = yasm_vp_expr(vp, object->symtab,
    226                                                 yasm_symrec_get_def_line(sym)))
    227                     || !(align_intn = yasm_expr_get_intnum(&align_expr, 0))) {
    228                     yasm_error_set(YASM_ERROR_VALUE,
    229                         N_("alignment constraint is not an integer"));
    230                     if (align_expr)
    231                         yasm_expr_destroy(align_expr);
    232                     return NULL;
    233                 }
    234                 addralign = yasm_intnum_get_uint(align_intn);
    235                 yasm_expr_destroy(align_expr);
    236 
    237                 /* Alignments must be a power of two. */
    238                 if (!is_exp2(addralign)) {
    239                     yasm_error_set(YASM_ERROR_VALUE,
    240                         N_("alignment constraint is not a power of two"));
    241                     return NULL;
    242                 }
    243             } else
    244                 yasm_warn_set(YASM_WARN_GENERAL,
    245                               N_("Unrecognized qualifier `%s'"), vp->val);
    246         }
    247     }
    248 
    249     return elf_objfmt_symtab_append(objfmt_elf, sym, SHN_COMMON, STB_GLOBAL,
    250                                     0, STV_DEFAULT, *size, &addralign, object);
    251 }
    252 
    253 static int
    254 elf_objfmt_build_symtab(yasm_symrec *sym, /*@null@*/ void *d)
    255 {
    256     build_symtab_info *info = (build_symtab_info *)d;
    257     yasm_sym_vis vis = yasm_symrec_get_visibility(sym);
    258     yasm_sym_status status = yasm_symrec_get_status(sym);
    259     elf_symtab_entry *entry = yasm_symrec_get_data(sym, &elf_symrec_data);
    260     elf_address value=0;
    261     yasm_section *sect=NULL;
    262     yasm_bytecode *precbc=NULL;
    263 
    264     assert(info != NULL);
    265 
    266     if (vis & YASM_SYM_EXTERN) {
    267         entry = build_extern(info->objfmt_elf, sym, info->object);
    268         yasm_errwarn_propagate(info->errwarns,
    269                                yasm_symrec_get_decl_line(sym));
    270         return 0;
    271     }
    272 
    273     if (vis & YASM_SYM_COMMON) {
    274         entry = build_common(info->objfmt_elf, sym, info->object);
    275         yasm_errwarn_propagate(info->errwarns,
    276                                yasm_symrec_get_decl_line(sym));
    277         /* If the COMMON variable was actually defined, fall through. */
    278         if (!(status & YASM_SYM_DEFINED))
    279             return 0;
    280     }
    281 
    282     /* Ignore any undefined at this point. */
    283     if (!(status & YASM_SYM_DEFINED))
    284         return 0;
    285 
    286     if (!yasm_symrec_get_label(sym, &precbc)) {
    287         if (!yasm_symrec_get_equ(sym) && !yasm_symrec_is_abs(sym))
    288             return 0;
    289         precbc = NULL;
    290     }
    291 
    292     if (precbc)
    293         sect = yasm_bc_get_section(precbc);
    294 
    295     if (entry && elf_sym_in_table(entry))
    296         ;
    297     else if (vis & YASM_SYM_GLOBAL) {
    298         entry = build_global(info->objfmt_elf, sym, info->object);
    299         yasm_errwarn_propagate(info->errwarns, yasm_symrec_get_decl_line(sym));
    300     } else {
    301         int is_sect = 0;
    302 
    303         /* Locals (except when debugging) do not need to be
    304          * in the symbol table, unless they're a section.
    305          */
    306         if (sect &&
    307             strcmp(yasm_symrec_get_name(sym), yasm_section_get_name(sect))==0)
    308             is_sect = 1;
    309 #if 0
    310         /* FIXME: to enable this we must have handling in place for special
    311          * symbols.
    312          */
    313         if (!info->local_names && !is_sect)
    314             return 0;
    315 #else
    316         if (yasm_symrec_get_equ(sym) && !yasm_symrec_is_abs(sym))
    317             return 0;
    318 #endif
    319         entry = yasm_symrec_get_data(sym, &elf_symrec_data);
    320         if (!entry) {
    321             /*@only@*/ char *symname =
    322                 yasm_symrec_get_global_name(sym, info->object);
    323             elf_strtab_entry *name = !info->local_names || is_sect ? NULL :
    324                 elf_strtab_append_str(info->objfmt_elf->strtab, symname);
    325             yasm_xfree(symname);
    326             entry = elf_symtab_entry_create(name, sym);
    327             yasm_symrec_add_data(sym, &elf_symrec_data, entry);
    328         }
    329 
    330         if (!elf_sym_in_table(entry))
    331             elf_symtab_insert_local_sym(info->objfmt_elf->elf_symtab, entry);
    332 
    333         elf_symtab_set_nonzero(entry, sect, 0, STB_LOCAL,
    334                                is_sect ? STT_SECTION : 0, NULL, 0);
    335 
    336         if (is_sect)
    337             return 0;
    338     }
    339 
    340     if (precbc)
    341         value = yasm_bc_next_offset(precbc);
    342     elf_symtab_set_nonzero(entry, sect, 0, 0, 0, NULL, &value);
    343 
    344     return 0;
    345 }
    346 
    347 static yasm_objfmt *
    348 elf_objfmt_create_common(yasm_object *object, yasm_objfmt_module *module,
    349                          int bits_pref,
    350                          const elf_machine_handler **elf_march_out)
    351 {
    352     yasm_objfmt_elf *objfmt_elf = yasm_xmalloc(sizeof(yasm_objfmt_elf));
    353     yasm_symrec *filesym;
    354     elf_symtab_entry *entry;
    355     const elf_machine_handler *elf_march;
    356 
    357     objfmt_elf->objfmt.module = module;
    358     elf_march = elf_set_arch(object->arch, object->symtab, bits_pref);
    359     if (!elf_march) {
    360         yasm_xfree(objfmt_elf);
    361         return NULL;
    362     }
    363     if (elf_march_out)
    364         *elf_march_out = elf_march;
    365 
    366     objfmt_elf->shstrtab = elf_strtab_create();
    367     objfmt_elf->strtab = elf_strtab_create();
    368     objfmt_elf->elf_symtab = elf_symtab_create();
    369 
    370     /* FIXME: misuse of NULL bytecode here; it works, but only barely. */
    371     filesym = yasm_symtab_define_label(object->symtab, ".file", NULL, 0, 0);
    372     /* Put in current input filename; we'll replace it in output() */
    373     objfmt_elf->file_strtab_entry =
    374         elf_strtab_append_str(objfmt_elf->strtab, object->src_filename);
    375     entry = elf_symtab_entry_create(objfmt_elf->file_strtab_entry, filesym);
    376     yasm_symrec_add_data(filesym, &elf_symrec_data, entry);
    377     elf_symtab_set_nonzero(entry, NULL, SHN_ABS, STB_LOCAL, STT_FILE, NULL,
    378                            NULL);
    379     elf_symtab_append_entry(objfmt_elf->elf_symtab, entry);
    380 
    381     /* FIXME: misuse of NULL bytecode */
    382     objfmt_elf->dotdotsym =
    383         yasm_symtab_define_label(object->symtab, "..sym", NULL, 0, 0);
    384 
    385     return (yasm_objfmt *)objfmt_elf;
    386 }
    387 
    388 static yasm_objfmt *
    389 elf_objfmt_create(yasm_object *object)
    390 {
    391     const elf_machine_handler *elf_march;
    392     yasm_objfmt *objfmt;
    393     yasm_objfmt_elf *objfmt_elf;
    394 
    395     objfmt = elf_objfmt_create_common(object, &yasm_elf_LTX_objfmt, 0,
    396                                       &elf_march);
    397     if (objfmt) {
    398         objfmt_elf = (yasm_objfmt_elf *)objfmt;
    399         /* Figure out which bitness of object format to use */
    400         if (elf_march->bits == 32)
    401             objfmt_elf->objfmt.module = &yasm_elf32_LTX_objfmt;
    402         else if (elf_march->bits == 64)
    403             objfmt_elf->objfmt.module = &yasm_elf64_LTX_objfmt;
    404     }
    405     return objfmt;
    406 }
    407 
    408 static yasm_objfmt *
    409 elf32_objfmt_create(yasm_object *object)
    410 {
    411     return elf_objfmt_create_common(object, &yasm_elf32_LTX_objfmt, 32, NULL);
    412 }
    413 
    414 static yasm_objfmt *
    415 elf64_objfmt_create(yasm_object *object)
    416 {
    417     return elf_objfmt_create_common(object, &yasm_elf64_LTX_objfmt, 64, NULL);
    418 }
    419 
    420 static long
    421 elf_objfmt_output_align(FILE *f, unsigned int align)
    422 {
    423     long pos;
    424     unsigned long delta;
    425     if (!is_exp2(align))
    426         yasm_internal_error("requested alignment not a power of two");
    427 
    428     pos = ftell(f);
    429     if (pos == -1) {
    430         yasm_error_set(YASM_ERROR_IO,
    431                        N_("could not get file position on output file"));
    432         return -1;
    433     }
    434     delta = align - (pos & (align-1));
    435     if (delta != align) {
    436         pos += delta;
    437         if (fseek(f, pos, SEEK_SET) < 0) {
    438             yasm_error_set(YASM_ERROR_IO,
    439                            N_("could not set file position on output file"));
    440             return -1;
    441         }
    442     }
    443     return pos;
    444 }
    445 
    446 static int
    447 elf_objfmt_output_reloc(yasm_symrec *sym, yasm_bytecode *bc,
    448                         unsigned char *buf, unsigned int destsize,
    449                         unsigned int valsize, int warn, void *d)
    450 {
    451     elf_reloc_entry *reloc;
    452     elf_objfmt_output_info *info = d;
    453     yasm_intnum *zero;
    454     int retval;
    455 
    456     reloc = elf_reloc_entry_create(sym, NULL,
    457         yasm_intnum_create_uint(bc->offset), 0, valsize, 0);
    458     if (reloc == NULL) {
    459         yasm_error_set(YASM_ERROR_TYPE, N_("elf: invalid relocation size"));
    460         return 1;
    461     }
    462     /* allocate .rel[a] sections on a need-basis */
    463     elf_secthead_append_reloc(info->sect, info->shead, reloc);
    464 
    465     zero = yasm_intnum_create_uint(0);
    466     elf_handle_reloc_addend(zero, reloc, 0);
    467     retval = yasm_arch_intnum_tobytes(info->object->arch, zero, buf, destsize,
    468                                       valsize, 0, bc, warn);
    469     yasm_intnum_destroy(zero);
    470     return retval;
    471 }
    472 
    473 static int
    474 elf_objfmt_output_value(yasm_value *value, unsigned char *buf,
    475                         unsigned int destsize, unsigned long offset,
    476                         yasm_bytecode *bc, int warn, /*@null@*/ void *d)
    477 {
    478     /*@null@*/ elf_objfmt_output_info *info = (elf_objfmt_output_info *)d;
    479     /*@dependent@*/ /*@null@*/ yasm_intnum *intn;
    480     unsigned long intn_val;
    481     /*@null@*/ elf_reloc_entry *reloc = NULL;
    482     int retval;
    483     unsigned int valsize = value->size;
    484 
    485     if (info == NULL)
    486         yasm_internal_error("null info struct");
    487 
    488     if (value->abs)
    489         value->abs = yasm_expr_simplify(value->abs, 1);
    490 
    491     /* Try to output constant and PC-relative section-local first.
    492      * Note this does NOT output any value with a SEG, WRT, external,
    493      * cross-section, or non-PC-relative reference (those are handled below).
    494      */
    495     switch (yasm_value_output_basic(value, buf, destsize, bc, warn,
    496                                     info->object->arch)) {
    497         case -1:
    498             return 1;
    499         case 0:
    500             break;
    501         default:
    502             return 0;
    503     }
    504 
    505     /* Handle other expressions, with relocation if necessary */
    506     if (value->seg_of || value->section_rel || value->rshift > 0) {
    507         yasm_error_set(YASM_ERROR_TOO_COMPLEX,
    508                        N_("elf: relocation too complex"));
    509         return 1;
    510     }
    511 
    512     intn_val = 0;
    513     if (value->rel) {
    514         yasm_sym_vis vis = yasm_symrec_get_visibility(value->rel);
    515         /*@dependent@*/ /*@null@*/ yasm_symrec *sym = value->rel;
    516         /*@dependent@*/ /*@null@*/ yasm_symrec *wrt = value->wrt;
    517 
    518         if (wrt == info->objfmt_elf->dotdotsym)
    519             wrt = NULL;
    520         else if (wrt && elf_is_wrt_sym_relative(wrt))
    521             ;
    522         else if (wrt && elf_is_wrt_pos_adjusted(wrt))
    523             intn_val = offset + bc->offset;
    524         else if (vis == YASM_SYM_LOCAL) {
    525             yasm_bytecode *sym_precbc;
    526             /* Local symbols need relocation to their section's start, and
    527              * add in the offset of the bytecode (within the target section)
    528              * into the abs portion.
    529              *
    530              * This is only done if the symbol is relocated against the
    531              * section instead of the symbol itself.
    532              */
    533             if (yasm_symrec_get_label(sym, &sym_precbc)) {
    534                 /* Relocate to section start */
    535                 yasm_section *sym_sect = yasm_bc_get_section(sym_precbc);
    536                 /*@null@*/ elf_secthead *sym_shead;
    537                 sym_shead = yasm_section_get_data(sym_sect, &elf_section_data);
    538                 assert(sym_shead != NULL);
    539                 sym = elf_secthead_get_sym(sym_shead);
    540 
    541                 intn_val = yasm_bc_next_offset(sym_precbc);
    542             }
    543         }
    544 
    545         /* For PC-relative, need to add offset of expression within bc. */
    546         if (value->curpos_rel)
    547             intn_val += offset;
    548 
    549         /* Check for _GLOBAL_OFFSET_TABLE_ symbol reference */
    550         reloc = elf_reloc_entry_create(sym, wrt,
    551             yasm_intnum_create_uint(bc->offset + offset), value->curpos_rel,
    552             valsize, sym == info->GOT_sym);
    553         if (reloc == NULL) {
    554             yasm_error_set(YASM_ERROR_TYPE,
    555                            N_("elf: invalid relocation (WRT or size)"));
    556             return 1;
    557         }
    558         /* allocate .rel[a] sections on a need-basis */
    559         elf_secthead_append_reloc(info->sect, info->shead, reloc);
    560     }
    561 
    562     intn = yasm_intnum_create_uint(intn_val);
    563 
    564     if (value->abs) {
    565         yasm_intnum *intn2 = yasm_expr_get_intnum(&value->abs, 0);
    566         if (!intn2) {
    567             yasm_error_set(YASM_ERROR_TOO_COMPLEX,
    568                            N_("elf: relocation too complex"));
    569             yasm_intnum_destroy(intn);
    570             return 1;
    571         }
    572         yasm_intnum_calc(intn, YASM_EXPR_ADD, intn2);
    573     }
    574 
    575     if (reloc)
    576         elf_handle_reloc_addend(intn, reloc, offset);
    577     retval = yasm_arch_intnum_tobytes(info->object->arch, intn, buf, destsize,
    578                                       valsize, 0, bc, warn);
    579     yasm_intnum_destroy(intn);
    580     return retval;
    581 }
    582 
    583 static int
    584 elf_objfmt_output_bytecode(yasm_bytecode *bc, /*@null@*/ void *d)
    585 {
    586     /*@null@*/ elf_objfmt_output_info *info = (elf_objfmt_output_info *)d;
    587     unsigned char buf[256];
    588     /*@null@*/ /*@only@*/ unsigned char *bigbuf;
    589     unsigned long size = 256;
    590     int gap;
    591 
    592     if (info == NULL)
    593         yasm_internal_error("null info struct");
    594 
    595     bigbuf = yasm_bc_tobytes(bc, buf, &size, &gap, info,
    596                              elf_objfmt_output_value, elf_objfmt_output_reloc);
    597 
    598     /* Don't bother doing anything else if size ended up being 0. */
    599     if (size == 0) {
    600         if (bigbuf)
    601             yasm_xfree(bigbuf);
    602         return 0;
    603     }
    604     else {
    605         yasm_intnum *bcsize = yasm_intnum_create_uint(size);
    606         elf_secthead_add_size(info->shead, bcsize);
    607         yasm_intnum_destroy(bcsize);
    608     }
    609 
    610     /* Warn that gaps are converted to 0 and write out the 0's. */
    611     if (gap) {
    612         unsigned long left;
    613         yasm_warn_set(YASM_WARN_UNINIT_CONTENTS,
    614             N_("uninitialized space declared in code/data section: zeroing"));
    615         /* Write out in chunks */
    616         memset(buf, 0, 256);
    617         left = size;
    618         while (left > 256) {
    619             fwrite(buf, 256, 1, info->f);
    620             left -= 256;
    621         }
    622         fwrite(buf, left, 1, info->f);
    623     } else {
    624         /* Output buf (or bigbuf if non-NULL) to file */
    625         fwrite(bigbuf ? bigbuf : buf, (size_t)size, 1, info->f);
    626     }
    627 
    628     /* If bigbuf was allocated, free it */
    629     if (bigbuf)
    630         yasm_xfree(bigbuf);
    631 
    632     return 0;
    633 }
    634 
    635 static int
    636 elf_objfmt_output_section(yasm_section *sect, /*@null@*/ void *d)
    637 {
    638     /*@null@*/ elf_objfmt_output_info *info = (elf_objfmt_output_info *)d;
    639     /*@dependent@*/ /*@null@*/ elf_secthead *shead;
    640     long pos;
    641     char *relname;
    642     const char *sectname;
    643 
    644     if (info == NULL)
    645         yasm_internal_error("null info struct");
    646     shead = yasm_section_get_data(sect, &elf_section_data);
    647     if (shead == NULL)
    648         yasm_internal_error("no associated data");
    649 
    650     if (elf_secthead_get_align(shead) == 0)
    651         elf_secthead_set_align(shead, yasm_section_get_align(sect));
    652 
    653     /* don't output header-only sections */
    654     if ((elf_secthead_get_type(shead) & SHT_NOBITS) == SHT_NOBITS)
    655     {
    656         yasm_bytecode *last = yasm_section_bcs_last(sect);
    657         if (last) {
    658             yasm_intnum *sectsize;
    659             sectsize = yasm_intnum_create_uint(yasm_bc_next_offset(last));
    660             elf_secthead_add_size(shead, sectsize);
    661             yasm_intnum_destroy(sectsize);
    662         }
    663         elf_secthead_set_index(shead, ++info->sindex);
    664         return 0;
    665     }
    666 
    667     if ((pos = ftell(info->f)) == -1) {
    668         yasm_error_set(YASM_ERROR_IO,
    669                        N_("couldn't read position on output stream"));
    670         yasm_errwarn_propagate(info->errwarns, 0);
    671     }
    672     pos = elf_secthead_set_file_offset(shead, pos);
    673     if (fseek(info->f, pos, SEEK_SET) < 0) {
    674         yasm_error_set(YASM_ERROR_IO, N_("couldn't seek on output stream"));
    675         yasm_errwarn_propagate(info->errwarns, 0);
    676     }
    677 
    678     info->sect = sect;
    679     info->shead = shead;
    680     yasm_section_bcs_traverse(sect, info->errwarns, info,
    681                               elf_objfmt_output_bytecode);
    682 
    683     elf_secthead_set_index(shead, ++info->sindex);
    684 
    685     /* No relocations to output?  Go on to next section */
    686     if (elf_secthead_write_relocs_to_file(info->f, sect, shead,
    687                                           info->errwarns) == 0)
    688         return 0;
    689     elf_secthead_set_rel_index(shead, ++info->sindex);
    690 
    691     /* name the relocation section .rel[a].foo */
    692     sectname = yasm_section_get_name(sect);
    693     relname = elf_secthead_name_reloc_section(sectname);
    694     elf_secthead_set_rel_name(shead,
    695         elf_strtab_append_str(info->objfmt_elf->shstrtab, relname));
    696     yasm_xfree(relname);
    697 
    698     return 0;
    699 }
    700 
    701 static int
    702 elf_objfmt_output_secthead(yasm_section *sect, /*@null@*/ void *d)
    703 {
    704     /*@null@*/ elf_objfmt_output_info *info = (elf_objfmt_output_info *)d;
    705     /*@dependent@*/ /*@null@*/ elf_secthead *shead;
    706 
    707     if (info == NULL)
    708         yasm_internal_error("null info struct");
    709     shead = yasm_section_get_data(sect, &elf_section_data);
    710     if (shead == NULL)
    711         yasm_internal_error("no section header attached to section");
    712 
    713     if(elf_secthead_write_to_file(info->f, shead, info->sindex+1))
    714         info->sindex++;
    715 
    716     /* output strtab headers here? */
    717 
    718     /* relocation entries for .foo are stored in section .rel[a].foo */
    719     if(elf_secthead_write_rel_to_file(info->f, 3, sect, shead,
    720                                       info->sindex+1))
    721         info->sindex++;
    722 
    723     return 0;
    724 }
    725 
    726 static void
    727 elf_objfmt_output(yasm_object *object, FILE *f, int all_syms,
    728                   yasm_errwarns *errwarns)
    729 {
    730     yasm_objfmt_elf *objfmt_elf = (yasm_objfmt_elf *)object->objfmt;
    731     elf_objfmt_output_info info;
    732     build_symtab_info buildsym_info;
    733     long pos;
    734     unsigned long elf_shead_addr;
    735     elf_secthead *esdn;
    736     unsigned long elf_strtab_offset, elf_shstrtab_offset, elf_symtab_offset;
    737     unsigned long elf_strtab_size, elf_shstrtab_size, elf_symtab_size;
    738     elf_strtab_entry *elf_strtab_name, *elf_shstrtab_name, *elf_symtab_name;
    739     unsigned long elf_symtab_nlocal;
    740 
    741     info.object = object;
    742     info.objfmt_elf = objfmt_elf;
    743     info.errwarns = errwarns;
    744     info.f = f;
    745     info.GOT_sym = yasm_symtab_get(object->symtab, "_GLOBAL_OFFSET_TABLE_");
    746 
    747     /* Update filename strtab */
    748     elf_strtab_entry_set_str(objfmt_elf->file_strtab_entry,
    749                              object->src_filename);
    750 
    751     /* Allocate space for Ehdr by seeking forward */
    752     if (fseek(f, (long)(elf_proghead_get_size()), SEEK_SET) < 0) {
    753         yasm_error_set(YASM_ERROR_IO, N_("could not seek on output file"));
    754         yasm_errwarn_propagate(errwarns, 0);
    755         return;
    756     }
    757 
    758     /* add all (local) syms to symtab because relocation needs a symtab index
    759      * if all_syms, register them by name.  if not, use strtab entry 0 */
    760     buildsym_info.object = object;
    761     buildsym_info.objfmt_elf = objfmt_elf;
    762     buildsym_info.errwarns = errwarns;
    763     buildsym_info.local_names = all_syms;
    764     yasm_symtab_traverse(object->symtab, &buildsym_info,
    765                          elf_objfmt_build_symtab);
    766     elf_symtab_nlocal = elf_symtab_assign_indices(objfmt_elf->elf_symtab);
    767 
    768     /* output known sections - includes reloc sections which aren't in yasm's
    769      * list.  Assign indices as we go. */
    770     info.sindex = 3;
    771     if (yasm_object_sections_traverse(object, &info,
    772                                       elf_objfmt_output_section))
    773         return;
    774 
    775     /* add final sections to the shstrtab */
    776     elf_strtab_name = elf_strtab_append_str(objfmt_elf->shstrtab, ".strtab");
    777     elf_symtab_name = elf_strtab_append_str(objfmt_elf->shstrtab, ".symtab");
    778     elf_shstrtab_name = elf_strtab_append_str(objfmt_elf->shstrtab,
    779                                               ".shstrtab");
    780 
    781     /* output .shstrtab */
    782     if ((pos = elf_objfmt_output_align(f, 4)) == -1) {
    783         yasm_errwarn_propagate(errwarns, 0);
    784         return;
    785     }
    786     elf_shstrtab_offset = (unsigned long) pos;
    787     elf_shstrtab_size = elf_strtab_output_to_file(f, objfmt_elf->shstrtab);
    788 
    789     /* output .strtab */
    790     if ((pos = elf_objfmt_output_align(f, 4)) == -1) {
    791         yasm_errwarn_propagate(errwarns, 0);
    792         return;
    793     }
    794     elf_strtab_offset = (unsigned long) pos;
    795     elf_strtab_size = elf_strtab_output_to_file(f, objfmt_elf->strtab);
    796 
    797     /* output .symtab - last section so all others have indexes */
    798     if ((pos = elf_objfmt_output_align(f, 4)) == -1) {
    799         yasm_errwarn_propagate(errwarns, 0);
    800         return;
    801     }
    802     elf_symtab_offset = (unsigned long) pos;
    803     elf_symtab_size = elf_symtab_write_to_file(f, objfmt_elf->elf_symtab,
    804                                                errwarns);
    805 
    806     /* output section header table */
    807     if ((pos = elf_objfmt_output_align(f, 16)) == -1) {
    808         yasm_errwarn_propagate(errwarns, 0);
    809         return;
    810     }
    811     elf_shead_addr = (unsigned long) pos;
    812 
    813     /* stabs debugging support */
    814     if (strcmp(yasm_dbgfmt_keyword(object->dbgfmt), "stabs")==0) {
    815         yasm_section *stabsect = yasm_object_find_general(object, ".stab");
    816         yasm_section *stabstrsect =
    817             yasm_object_find_general(object, ".stabstr");
    818         if (stabsect && stabstrsect) {
    819             elf_secthead *stab =
    820                 yasm_section_get_data(stabsect, &elf_section_data);
    821             elf_secthead *stabstr =
    822                 yasm_section_get_data(stabstrsect, &elf_section_data);
    823             if (stab && stabstr) {
    824                 elf_secthead_set_link(stab, elf_secthead_get_index(stabstr));
    825             }
    826             else
    827                 yasm_internal_error(N_("missing .stab or .stabstr section/data"));
    828         }
    829     }
    830 
    831     /* output dummy section header - 0 */
    832     info.sindex = 0;
    833 
    834     esdn = elf_secthead_create(NULL, SHT_NULL, 0, 0, 0);
    835     elf_secthead_set_index(esdn, 0);
    836     elf_secthead_write_to_file(f, esdn, 0);
    837     elf_secthead_destroy(esdn);
    838 
    839     esdn = elf_secthead_create(elf_shstrtab_name, SHT_STRTAB, 0,
    840                                elf_shstrtab_offset, elf_shstrtab_size);
    841     elf_secthead_set_index(esdn, 1);
    842     elf_secthead_write_to_file(f, esdn, 1);
    843     elf_secthead_destroy(esdn);
    844 
    845     esdn = elf_secthead_create(elf_strtab_name, SHT_STRTAB, 0,
    846                                elf_strtab_offset, elf_strtab_size);
    847     elf_secthead_set_index(esdn, 2);
    848     elf_secthead_write_to_file(f, esdn, 2);
    849     elf_secthead_destroy(esdn);
    850 
    851     esdn = elf_secthead_create(elf_symtab_name, SHT_SYMTAB, 0,
    852                                elf_symtab_offset, elf_symtab_size);
    853     elf_secthead_set_index(esdn, 3);
    854     elf_secthead_set_info(esdn, elf_symtab_nlocal);
    855     elf_secthead_set_link(esdn, 2);     /* for .strtab, which is index 2 */
    856     elf_secthead_write_to_file(f, esdn, 3);
    857     elf_secthead_destroy(esdn);
    858 
    859     info.sindex = 3;
    860     /* output remaining section headers */
    861     yasm_object_sections_traverse(object, &info, elf_objfmt_output_secthead);
    862 
    863     /* output Ehdr */
    864     if (fseek(f, 0, SEEK_SET) < 0) {
    865         yasm_error_set(YASM_ERROR_IO, N_("could not seek on output file"));
    866         yasm_errwarn_propagate(errwarns, 0);
    867         return;
    868     }
    869 
    870     elf_proghead_write_to_file(f, elf_shead_addr, info.sindex+1, 1);
    871 }
    872 
    873 static void
    874 elf_objfmt_destroy(yasm_objfmt *objfmt)
    875 {
    876     yasm_objfmt_elf *objfmt_elf = (yasm_objfmt_elf *)objfmt;
    877     elf_symtab_destroy(objfmt_elf->elf_symtab);
    878     elf_strtab_destroy(objfmt_elf->shstrtab);
    879     elf_strtab_destroy(objfmt_elf->strtab);
    880     yasm_xfree(objfmt);
    881 }
    882 
    883 static void
    884 elf_objfmt_init_new_section(yasm_section *sect, unsigned long line)
    885 {
    886     yasm_object *object = yasm_section_get_object(sect);
    887     const char *sectname = yasm_section_get_name(sect);
    888     yasm_objfmt_elf *objfmt_elf = (yasm_objfmt_elf *)object->objfmt;
    889     elf_secthead *esd;
    890     yasm_symrec *sym;
    891     elf_strtab_entry *name = elf_strtab_append_str(objfmt_elf->shstrtab,
    892                                                    sectname);
    893 
    894     elf_section_type type=SHT_PROGBITS;
    895     elf_size entsize=0;
    896 
    897     if (yasm__strcasecmp(sectname, ".stab")==0) {
    898         entsize = 12;
    899     } else if (yasm__strcasecmp(sectname, ".stabstr")==0) {
    900         type = SHT_STRTAB;
    901     }
    902 
    903     esd = elf_secthead_create(name, type, 0, 0, 0);
    904     elf_secthead_set_entsize(esd, entsize);
    905     yasm_section_add_data(sect, &elf_section_data, esd);
    906     sym = yasm_symtab_define_label(object->symtab, sectname,
    907                                    yasm_section_bcs_first(sect), 1, line);
    908 
    909     elf_secthead_set_sym(esd, sym);
    910 }
    911 
    912 static yasm_section *
    913 elf_objfmt_add_default_section(yasm_object *object)
    914 {
    915     yasm_section *retval;
    916     int isnew;
    917 
    918     retval = yasm_object_get_general(object, ".text", 16, 1, 0, &isnew, 0);
    919     if (isnew)
    920     {
    921         elf_secthead *esd = yasm_section_get_data(retval, &elf_section_data);
    922         elf_secthead_set_typeflags(esd, SHT_PROGBITS,
    923                                    SHF_ALLOC + SHF_EXECINSTR);
    924         yasm_section_set_default(retval, 1);
    925     }
    926     return retval;
    927 }
    928 
    929 struct elf_section_switch_data {
    930     /*@only@*/ /*@null@*/ yasm_intnum *align_intn;
    931     unsigned long flags;
    932     unsigned long type;
    933     int gasflags;
    934     int stdsect;
    935 };
    936 
    937 /* GAS-style flags */
    938 static int
    939 elf_helper_gasflags(void *obj, yasm_valparam *vp, unsigned long line, void *d,
    940                     /*@unused@*/ uintptr_t arg)
    941 {
    942     struct elf_section_switch_data *data = (struct elf_section_switch_data *)d;
    943     const char *s = yasm_vp_string(vp);
    944     size_t i;
    945 
    946     if (!s) {
    947         yasm_error_set(YASM_ERROR_VALUE,
    948                        N_("non-string section attribute"));
    949         return -1;
    950     }
    951 
    952     if (data->stdsect && strlen(s) == 0) {
    953         data->gasflags = 1;
    954         return 0;
    955     }
    956 
    957     data->flags = 0;
    958     for (i=0; i<strlen(s); i++) {
    959         switch (s[i]) {
    960             case 'a':
    961                 data->flags |= SHF_ALLOC;
    962                 break;
    963             case 'w':
    964                 data->flags |= SHF_WRITE;
    965                 break;
    966             case 'x':
    967                 data->flags |= SHF_EXECINSTR;
    968                 break;
    969             case 'M':
    970                 data->flags |= SHF_MERGE;
    971                 break;
    972             case 'S':
    973                 data->flags |= SHF_STRINGS;
    974                 break;
    975             case 'G':
    976                 data->flags |= SHF_GROUP;
    977                 break;
    978             case 'T':
    979                 data->flags |= SHF_TLS;
    980                 break;
    981             default:
    982                 yasm_warn_set(YASM_WARN_GENERAL,
    983                               N_("unrecognized section attribute: `%c'"),
    984                               s[i]);
    985         }
    986     }
    987 
    988     data->gasflags = 1;
    989     return 0;
    990 }
    991 
    992 static /*@observer@*/ /*@null@*/ yasm_section *
    993 elf_objfmt_section_switch(yasm_object *object, yasm_valparamhead *valparams,
    994                           /*@null@*/ yasm_valparamhead *objext_valparams,
    995                           unsigned long line)
    996 {
    997     yasm_valparam *vp;
    998     yasm_section *retval;
    999     int isnew;
   1000     unsigned long align = 4;
   1001     int flags_override = 0;
   1002     const char *sectname;
   1003     int resonly = 0;
   1004 
   1005     struct elf_section_switch_data data;
   1006 
   1007     static const yasm_dir_help help[] = {
   1008         { "alloc", 0, yasm_dir_helper_flag_or,
   1009           offsetof(struct elf_section_switch_data, flags), SHF_ALLOC },
   1010         { "exec", 0, yasm_dir_helper_flag_or,
   1011           offsetof(struct elf_section_switch_data, flags), SHF_EXECINSTR },
   1012         { "write", 0, yasm_dir_helper_flag_or,
   1013           offsetof(struct elf_section_switch_data, flags), SHF_WRITE },
   1014         { "tls", 0, yasm_dir_helper_flag_or,
   1015           offsetof(struct elf_section_switch_data, flags), SHF_TLS },
   1016         { "progbits", 0, yasm_dir_helper_flag_set,
   1017           offsetof(struct elf_section_switch_data, type), SHT_PROGBITS },
   1018         { "noalloc", 0, yasm_dir_helper_flag_and,
   1019           offsetof(struct elf_section_switch_data, flags), SHF_ALLOC },
   1020         { "noexec", 0, yasm_dir_helper_flag_and,
   1021           offsetof(struct elf_section_switch_data, flags), SHF_EXECINSTR },
   1022         { "nowrite",  0, yasm_dir_helper_flag_and,
   1023           offsetof(struct elf_section_switch_data, flags), SHF_WRITE },
   1024         { "notls",  0, yasm_dir_helper_flag_and,
   1025           offsetof(struct elf_section_switch_data, flags), SHF_TLS },
   1026         { "noprogbits", 0, yasm_dir_helper_flag_set,
   1027           offsetof(struct elf_section_switch_data, type), SHT_NOBITS },
   1028         { "nobits", 0, yasm_dir_helper_flag_set,
   1029           offsetof(struct elf_section_switch_data, type), SHT_NOBITS },
   1030         { "gasflags", 1, elf_helper_gasflags, 0, 0 },
   1031         { "align", 1, yasm_dir_helper_intn,
   1032           offsetof(struct elf_section_switch_data, align_intn), 0 }
   1033     };
   1034     /*@only@*/ /*@null@*/ yasm_expr *merge_expr = NULL;
   1035     /*@dependent@*/ /*@null@*/ const yasm_intnum *merge_intn = NULL;
   1036     elf_secthead *esd;
   1037 
   1038     data.align_intn = NULL;
   1039     data.flags = SHF_ALLOC;
   1040     data.type = SHT_PROGBITS;
   1041     data.gasflags = 0;
   1042     data.stdsect = 1;
   1043 
   1044     vp = yasm_vps_first(valparams);
   1045     sectname = yasm_vp_string(vp);
   1046     if (!sectname)
   1047         return NULL;
   1048     vp = yasm_vps_next(vp);
   1049 
   1050     if (strcmp(sectname, ".bss") == 0) {
   1051         data.type = SHT_NOBITS;
   1052         data.flags = SHF_ALLOC + SHF_WRITE;
   1053         resonly = 1;
   1054     } else if (strcmp(sectname, ".data") == 0) {
   1055         data.type = SHT_PROGBITS;
   1056         data.flags = SHF_ALLOC + SHF_WRITE;
   1057     } else if (strcmp(sectname, ".tdata") == 0) {
   1058         data.type = SHT_PROGBITS;
   1059         data.flags = SHF_ALLOC + SHF_WRITE + SHF_TLS;
   1060     } else if (strcmp(sectname, ".rodata") == 0) {
   1061         data.type = SHT_PROGBITS;
   1062         data.flags = SHF_ALLOC;
   1063     } else if (strcmp(sectname, ".text") == 0) {
   1064         align = 16;
   1065         data.type = SHT_PROGBITS;
   1066         data.flags = SHF_ALLOC + SHF_EXECINSTR;
   1067     } else if (strcmp(sectname, ".comment") == 0) {
   1068         align = 0;
   1069         data.type = SHT_PROGBITS;
   1070         data.flags = 0;
   1071     } else {
   1072         /* Default to code */
   1073         align = 1;
   1074         data.stdsect = 0;
   1075     }
   1076 
   1077     flags_override = yasm_dir_helper(object, vp, line, help, NELEMS(help),
   1078                                      &data, yasm_dir_helper_valparam_warn);
   1079     if (flags_override < 0)
   1080         return NULL;    /* error occurred */
   1081 
   1082     if (data.align_intn) {
   1083         align = yasm_intnum_get_uint(data.align_intn);
   1084         yasm_intnum_destroy(data.align_intn);
   1085 
   1086         /* Alignments must be a power of two. */
   1087         if (!is_exp2(align)) {
   1088             yasm_error_set(YASM_ERROR_VALUE,
   1089                            N_("argument to `%s' is not a power of two"),
   1090                            "align");
   1091             return NULL;
   1092         }
   1093     }
   1094 
   1095     /* Handle merge entity size */
   1096     if (data.flags & SHF_MERGE) {
   1097         if (objext_valparams && (vp = yasm_vps_first(objext_valparams))
   1098             && !vp->val) {
   1099             if (!(merge_expr = yasm_vp_expr(vp, object->symtab, line)) ||
   1100                 !(merge_intn = yasm_expr_get_intnum(&merge_expr, 0)))
   1101                 yasm_warn_set(YASM_WARN_GENERAL,
   1102                               N_("invalid merge entity size"));
   1103         } else {
   1104             yasm_warn_set(YASM_WARN_GENERAL,
   1105                           N_("entity size for SHF_MERGE not specified"));
   1106             data.flags &= ~SHF_MERGE;
   1107         }
   1108     }
   1109 
   1110     retval = yasm_object_get_general(object, sectname, align,
   1111                                      (data.flags & SHF_EXECINSTR) != 0,
   1112                                      resonly, &isnew, line);
   1113 
   1114     esd = yasm_section_get_data(retval, &elf_section_data);
   1115 
   1116     if (isnew || yasm_section_is_default(retval)) {
   1117         yasm_section_set_default(retval, 0);
   1118         elf_secthead_set_typeflags(esd, data.type, data.flags);
   1119         if (merge_intn)
   1120             elf_secthead_set_entsize(esd, yasm_intnum_get_uint(merge_intn));
   1121         yasm_section_set_align(retval, align, line);
   1122     } else if (flags_override && !data.gasflags)
   1123         yasm_warn_set(YASM_WARN_GENERAL,
   1124                       N_("section flags ignored on section redeclaration"));
   1125     if (merge_expr)
   1126         yasm_expr_destroy(merge_expr);
   1127     return retval;
   1128 }
   1129 
   1130 static /*@observer@*/ /*@null@*/ yasm_symrec *
   1131 elf_objfmt_get_special_sym(yasm_object *object, const char *name,
   1132                            const char *parser)
   1133 {
   1134     if (yasm__strcasecmp(name, "sym") == 0) {
   1135         yasm_objfmt_elf *objfmt_elf = (yasm_objfmt_elf *)object->objfmt;
   1136         return objfmt_elf->dotdotsym;
   1137     }
   1138     return elf_get_special_sym(name, parser);
   1139 }
   1140 
   1141 static void
   1142 dir_type(yasm_object *object, yasm_valparamhead *valparams,
   1143          yasm_valparamhead *objext_valparams, unsigned long line)
   1144 {
   1145     yasm_objfmt_elf *objfmt_elf = (yasm_objfmt_elf *)object->objfmt;
   1146     yasm_valparam *vp = yasm_vps_first(valparams);
   1147     const char *symname = yasm_vp_id(vp);
   1148     /* Get symbol elf data */
   1149     yasm_symrec *sym = yasm_symtab_use(object->symtab, symname, line);
   1150     elf_symtab_entry *entry = yasm_symrec_get_data(sym, &elf_symrec_data);
   1151     /*@null@*/ const char *type;
   1152 
   1153     /* Create entry if necessary */
   1154     if (!entry) {
   1155         entry = elf_symtab_entry_create(
   1156             elf_strtab_append_str(objfmt_elf->strtab, symname), sym);
   1157         yasm_symrec_add_data(sym, &elf_symrec_data, entry);
   1158     }
   1159 
   1160     /* Pull new type from param */
   1161     vp = yasm_vps_next(vp);
   1162     if (vp && !vp->val && (type = yasm_vp_id(vp))) {
   1163         if (yasm__strcasecmp(type, "function") == 0)
   1164             elf_sym_set_type(entry, STT_FUNC);
   1165         else if (yasm__strcasecmp(type, "object") == 0)
   1166             elf_sym_set_type(entry, STT_OBJECT);
   1167         else if (yasm__strcasecmp(type, "tls_object") == 0)
   1168             elf_sym_set_type(entry, STT_TLS);
   1169         else if (yasm__strcasecmp(type, "notype") == 0)
   1170             elf_sym_set_type(entry, STT_NOTYPE);
   1171         else
   1172             yasm_warn_set(YASM_WARN_GENERAL,
   1173                           N_("unrecognized symbol type `%s'"), type);
   1174     } else
   1175         yasm_error_set(YASM_ERROR_SYNTAX, N_("no type specified"));
   1176 }
   1177 
   1178 static void
   1179 dir_size(yasm_object *object, yasm_valparamhead *valparams,
   1180          yasm_valparamhead *objext_valparams, unsigned long line)
   1181 {
   1182     yasm_objfmt_elf *objfmt_elf = (yasm_objfmt_elf *)object->objfmt;
   1183     yasm_valparam *vp = yasm_vps_first(valparams);
   1184     const char *symname = yasm_vp_id(vp);
   1185     /* Get symbol elf data */
   1186     yasm_symrec *sym = yasm_symtab_use(object->symtab, symname, line);
   1187     elf_symtab_entry *entry = yasm_symrec_get_data(sym, &elf_symrec_data);
   1188     /*@only@*/ /*@null@*/ yasm_expr *size;
   1189 
   1190     /* Create entry if necessary */
   1191     if (!entry) {
   1192         entry = elf_symtab_entry_create(
   1193             elf_strtab_append_str(objfmt_elf->strtab, symname), sym);
   1194         yasm_symrec_add_data(sym, &elf_symrec_data, entry);
   1195     }
   1196 
   1197     /* Pull new size from param */
   1198     vp = yasm_vps_next(vp);
   1199     if (vp && !vp->val && (size = yasm_vp_expr(vp, object->symtab, line)))
   1200         elf_sym_set_size(entry, size);
   1201     else
   1202         yasm_error_set(YASM_ERROR_SYNTAX, N_("no size specified"));
   1203 }
   1204 
   1205 static void
   1206 dir_weak(yasm_object *object, yasm_valparamhead *valparams,
   1207          yasm_valparamhead *objext_valparams, unsigned long line)
   1208 {
   1209     yasm_objfmt_elf *objfmt_elf = (yasm_objfmt_elf *)object->objfmt;
   1210     yasm_valparam *vp = yasm_vps_first(valparams);
   1211     const char *symname = yasm_vp_id(vp);
   1212     yasm_symrec *sym = yasm_symtab_declare(object->symtab, symname,
   1213                                            YASM_SYM_GLOBAL, line);
   1214     elf_objfmt_symtab_append(objfmt_elf, sym, SHN_UNDEF, STB_WEAK, 0,
   1215                              STV_DEFAULT, NULL, NULL, object);
   1216 }
   1217 
   1218 static void
   1219 dir_ident(yasm_object *object, yasm_valparamhead *valparams,
   1220           yasm_valparamhead *objext_valparams, unsigned long line)
   1221 {
   1222     yasm_valparamhead sect_vps;
   1223     yasm_datavalhead dvs;
   1224     yasm_section *comment;
   1225     yasm_valparam *vp;
   1226     yasm_valparam *vp2;
   1227 
   1228     /* Accept, but do nothing with empty ident */
   1229     if (!valparams)
   1230         return;
   1231     vp = yasm_vps_first(valparams);
   1232     if (!vp)
   1233         return;
   1234 
   1235     /* Put ident data into .comment section */
   1236     yasm_vps_initialize(&sect_vps);
   1237     vp2 = yasm_vp_create_string(NULL, yasm__xstrdup(".comment"));
   1238     yasm_vps_append(&sect_vps, vp2);
   1239     comment = elf_objfmt_section_switch(object, &sect_vps, NULL, line);
   1240     yasm_vps_delete(&sect_vps);
   1241 
   1242     /* To match GAS output, if the comment section is empty, put an
   1243      * initial 0 byte in the section.
   1244      */
   1245     if (yasm_section_bcs_first(comment) == yasm_section_bcs_last(comment)) {
   1246         yasm_dvs_initialize(&dvs);
   1247         yasm_dvs_append(&dvs, yasm_dv_create_expr(
   1248             yasm_expr_create_ident(
   1249                 yasm_expr_int(yasm_intnum_create_uint(0)), line)));
   1250         yasm_section_bcs_append(comment,
   1251             yasm_bc_create_data(&dvs, 1, 0, object->arch, line));
   1252     }
   1253 
   1254     yasm_dvs_initialize(&dvs);
   1255     do {
   1256         const char *s = yasm_vp_string(vp);
   1257         if (!s) {
   1258             yasm_error_set(YASM_ERROR_VALUE,
   1259                            N_(".comment requires string parameters"));
   1260             yasm_dvs_delete(&dvs);
   1261             return;
   1262         }
   1263         yasm_dvs_append(&dvs,
   1264                         yasm_dv_create_string(yasm__xstrdup(s), strlen(s)));
   1265     } while ((vp = yasm_vps_next(vp)));
   1266 
   1267     yasm_section_bcs_append(comment,
   1268         yasm_bc_create_data(&dvs, 1, 1, object->arch, line));
   1269 }
   1270 
   1271 /* Define valid debug formats to use with this object format */
   1272 static const char *elf_objfmt_dbgfmt_keywords[] = {
   1273     "null",
   1274     "stabs",
   1275     "dwarf2",
   1276     NULL
   1277 };
   1278 
   1279 static const yasm_directive elf_objfmt_directives[] = {
   1280     { ".type",          "gas",  dir_type,       YASM_DIR_ID_REQUIRED },
   1281     { ".size",          "gas",  dir_size,       YASM_DIR_ID_REQUIRED },
   1282     { ".weak",          "gas",  dir_weak,       YASM_DIR_ID_REQUIRED },
   1283     { ".ident",         "gas",  dir_ident,      YASM_DIR_ANY },
   1284     { "type",           "nasm", dir_type,       YASM_DIR_ID_REQUIRED },
   1285     { "size",           "nasm", dir_size,       YASM_DIR_ID_REQUIRED },
   1286     { "weak",           "nasm", dir_weak,       YASM_DIR_ID_REQUIRED },
   1287     { "ident",          "nasm", dir_ident,      YASM_DIR_ANY },
   1288     { NULL, NULL, NULL, 0 }
   1289 };
   1290 
   1291 static const char *elf_nasm_stdmac[] = {
   1292     "%imacro type 1+.nolist",
   1293     "[type %1]",
   1294     "%endmacro",
   1295     "%imacro size 1+.nolist",
   1296     "[size %1]",
   1297     "%endmacro",
   1298     "%imacro weak 1+.nolist",
   1299     "[weak %1]",
   1300     "%endmacro",
   1301     NULL
   1302 };
   1303 
   1304 static const yasm_stdmac elf_objfmt_stdmacs[] = {
   1305     { "nasm", "nasm", elf_nasm_stdmac },
   1306     { NULL, NULL, NULL }
   1307 };
   1308 
   1309 /* Define objfmt structure -- see objfmt.h for details */
   1310 yasm_objfmt_module yasm_elf_LTX_objfmt = {
   1311     "ELF",
   1312     "elf",
   1313     "o",
   1314     32,
   1315     0,
   1316     elf_objfmt_dbgfmt_keywords,
   1317     "null",
   1318     elf_objfmt_directives,
   1319     elf_objfmt_stdmacs,
   1320     elf_objfmt_create,
   1321     elf_objfmt_output,
   1322     elf_objfmt_destroy,
   1323     elf_objfmt_add_default_section,
   1324     elf_objfmt_init_new_section,
   1325     elf_objfmt_section_switch,
   1326     elf_objfmt_get_special_sym
   1327 };
   1328 
   1329 yasm_objfmt_module yasm_elf32_LTX_objfmt = {
   1330     "ELF (32-bit)",
   1331     "elf32",
   1332     "o",
   1333     32,
   1334     0,
   1335     elf_objfmt_dbgfmt_keywords,
   1336     "null",
   1337     elf_objfmt_directives,
   1338     elf_objfmt_stdmacs,
   1339     elf32_objfmt_create,
   1340     elf_objfmt_output,
   1341     elf_objfmt_destroy,
   1342     elf_objfmt_add_default_section,
   1343     elf_objfmt_init_new_section,
   1344     elf_objfmt_section_switch,
   1345     elf_objfmt_get_special_sym
   1346 };
   1347 
   1348 yasm_objfmt_module yasm_elf64_LTX_objfmt = {
   1349     "ELF (64-bit)",
   1350     "elf64",
   1351     "o",
   1352     64,
   1353     0,
   1354     elf_objfmt_dbgfmt_keywords,
   1355     "null",
   1356     elf_objfmt_directives,
   1357     elf_objfmt_stdmacs,
   1358     elf64_objfmt_create,
   1359     elf_objfmt_output,
   1360     elf_objfmt_destroy,
   1361     elf_objfmt_add_default_section,
   1362     elf_objfmt_init_new_section,
   1363     elf_objfmt_section_switch,
   1364     elf_objfmt_get_special_sym
   1365 };
   1366