• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 *
elf_objfmt_symtab_append(yasm_objfmt_elf * objfmt_elf,yasm_symrec * sym,elf_section_index sectidx,elf_symbol_binding bind,elf_symbol_type type,elf_symbol_vis vis,yasm_expr * size,elf_address * value,yasm_object * object)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 *
build_extern(yasm_objfmt_elf * objfmt_elf,yasm_symrec * sym,yasm_object * object)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
elf_global_helper_valparam(void * obj,yasm_valparam * vp,unsigned long line,void * d)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
elf_global_helper_vis(void * obj,yasm_valparam * vp,unsigned long line,void * d,uintptr_t vis)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 *
build_global(yasm_objfmt_elf * objfmt_elf,yasm_symrec * sym,yasm_object * object)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 *
build_common(yasm_objfmt_elf * objfmt_elf,yasm_symrec * sym,yasm_object * object)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
elf_objfmt_build_symtab(yasm_symrec * sym,void * d)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 *
elf_objfmt_create_common(yasm_object * object,yasm_objfmt_module * module,int bits_pref,const elf_machine_handler ** elf_march_out)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 *
elf_objfmt_create(yasm_object * object)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 *
elf32_objfmt_create(yasm_object * object)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 *
elf64_objfmt_create(yasm_object * object)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
elf_objfmt_output_align(FILE * f,unsigned int align)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
elf_objfmt_output_reloc(yasm_symrec * sym,yasm_bytecode * bc,unsigned char * buf,unsigned int destsize,unsigned int valsize,int warn,void * d)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
elf_objfmt_output_value(yasm_value * value,unsigned char * buf,unsigned int destsize,unsigned long offset,yasm_bytecode * bc,int warn,void * d)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
elf_objfmt_output_bytecode(yasm_bytecode * bc,void * d)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
elf_objfmt_output_section(yasm_section * sect,void * d)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
elf_objfmt_output_secthead(yasm_section * sect,void * d)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
elf_objfmt_output(yasm_object * object,FILE * f,int all_syms,yasm_errwarns * errwarns)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
elf_objfmt_destroy(yasm_objfmt * objfmt)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
elf_objfmt_init_new_section(yasm_section * sect,unsigned long line)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 *
elf_objfmt_add_default_section(yasm_object * object)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
elf_helper_gasflags(void * obj,yasm_valparam * vp,unsigned long line,void * d,uintptr_t arg)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 *
elf_objfmt_section_switch(yasm_object * object,yasm_valparamhead * valparams,yasm_valparamhead * objext_valparams,unsigned long line)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 *
elf_objfmt_get_special_sym(yasm_object * object,const char * name,const char * parser)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
dir_type(yasm_object * object,yasm_valparamhead * valparams,yasm_valparamhead * objext_valparams,unsigned long line)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
dir_size(yasm_object * object,yasm_valparamhead * valparams,yasm_valparamhead * objext_valparams,unsigned long line)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
dir_weak(yasm_object * object,yasm_valparamhead * valparams,yasm_valparamhead * objext_valparams,unsigned long line)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
dir_ident(yasm_object * object,yasm_valparamhead * valparams,yasm_valparamhead * objext_valparams,unsigned long line)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