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(§_vps);
1237 vp2 = yasm_vp_create_string(NULL, yasm__xstrdup(".comment"));
1238 yasm_vps_append(§_vps, vp2);
1239 comment = elf_objfmt_section_switch(object, §_vps, NULL, line);
1240 yasm_vps_delete(§_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