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