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
51typedef 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
62typedef 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
73typedef struct {
74    yasm_object *object;
75    yasm_objfmt_elf *objfmt_elf;
76    yasm_errwarns *errwarns;
77    int local_names;
78} build_symtab_info;
79
80yasm_objfmt_module yasm_elf_LTX_objfmt;
81yasm_objfmt_module yasm_elf32_LTX_objfmt;
82yasm_objfmt_module yasm_elf64_LTX_objfmt;
83
84
85static elf_symtab_entry *
86elf_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
113static elf_symtab_entry *
114build_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
133struct 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
140static int
141elf_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
159static int
160elf_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
170static elf_symtab_entry *
171build_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
210static /*@null@*/ elf_symtab_entry *
211build_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
253static int
254elf_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
347static yasm_objfmt *
348elf_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
388static yasm_objfmt *
389elf_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
408static yasm_objfmt *
409elf32_objfmt_create(yasm_object *object)
410{
411    return elf_objfmt_create_common(object, &yasm_elf32_LTX_objfmt, 32, NULL);
412}
413
414static yasm_objfmt *
415elf64_objfmt_create(yasm_object *object)
416{
417    return elf_objfmt_create_common(object, &yasm_elf64_LTX_objfmt, 64, NULL);
418}
419
420static long
421elf_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
446static int
447elf_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
473static int
474elf_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
583static int
584elf_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
635static int
636elf_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
701static int
702elf_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
726static void
727elf_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
873static void
874elf_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
883static void
884elf_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
912static yasm_section *
913elf_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
929struct 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 */
938static int
939elf_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
992static /*@observer@*/ /*@null@*/ yasm_section *
993elf_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
1130static /*@observer@*/ /*@null@*/ yasm_symrec *
1131elf_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
1141static void
1142dir_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
1178static void
1179dir_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
1205static void
1206dir_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
1218static void
1219dir_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 */
1272static const char *elf_objfmt_dbgfmt_keywords[] = {
1273    "null",
1274    "stabs",
1275    "dwarf2",
1276    NULL
1277};
1278
1279static 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
1291static 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
1304static 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 */
1310yasm_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
1329yasm_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
1348yasm_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