1 /* 2 * GAS-compatible parser 3 * 4 * Copyright (C) 2005-2007 Peter Johnson 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 * 3. Neither the name of the author nor the names of other contributors 15 * may be used to endorse or promote products derived from this 16 * software without specific prior written permission. 17 * 18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND OTHER CONTRIBUTORS ``AS IS'' 19 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR OTHER CONTRIBUTORS BE 22 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 23 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 24 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 25 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 26 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 27 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 28 * POSSIBILITY OF SUCH DAMAGE. 29 */ 30 #include <util.h> 31 32 #include <libyasm.h> 33 34 #include <ctype.h> 35 #include <limits.h> 36 #include <math.h> 37 38 #include "modules/parsers/gas/gas-parser.h" 39 40 typedef struct dir_lookup { 41 const char *name; 42 yasm_bytecode * (*handler) (yasm_parser_gas *, unsigned int); 43 unsigned int param; 44 enum gas_parser_state newstate; 45 } dir_lookup; 46 47 static void cpp_line_marker(yasm_parser_gas *parser_gas); 48 static void nasm_line_marker(yasm_parser_gas *parser_gas); 49 static yasm_bytecode *parse_instr(yasm_parser_gas *parser_gas); 50 static int parse_dirvals(yasm_parser_gas *parser_gas, yasm_valparamhead *vps); 51 static int parse_datavals(yasm_parser_gas *parser_gas, yasm_datavalhead *dvs); 52 static int parse_strvals(yasm_parser_gas *parser_gas, yasm_datavalhead *dvs); 53 static yasm_effaddr *parse_memaddr(yasm_parser_gas *parser_gas); 54 static yasm_insn_operand *parse_operand(yasm_parser_gas *parser_gas); 55 static yasm_expr *parse_expr(yasm_parser_gas *parser_gas); 56 static yasm_expr *parse_expr0(yasm_parser_gas *parser_gas); 57 static yasm_expr *parse_expr1(yasm_parser_gas *parser_gas); 58 static yasm_expr *parse_expr2(yasm_parser_gas *parser_gas); 59 60 static void define_label(yasm_parser_gas *parser_gas, char *name, int local); 61 static void define_lcomm(yasm_parser_gas *parser_gas, /*@only@*/ char *name, 62 yasm_expr *size, /*@null@*/ yasm_expr *align); 63 static yasm_section *gas_get_section 64 (yasm_parser_gas *parser_gas, /*@only@*/ char *name, /*@null@*/ char *flags, 65 /*@null@*/ char *type, /*@null@*/ yasm_valparamhead *objext_valparams, 66 int builtin); 67 static void gas_switch_section 68 (yasm_parser_gas *parser_gas, /*@only@*/ const char *name, 69 /*@null@*/ char *flags, /*@null@*/ char *type, 70 /*@null@*/ yasm_valparamhead *objext_valparams, int builtin); 71 static yasm_bytecode *gas_parser_align 72 (yasm_parser_gas *parser_gas, yasm_section *sect, yasm_expr *boundval, 73 /*@null@*/ yasm_expr *fillval, /*@null@*/ yasm_expr *maxskipval, 74 int power2); 75 static yasm_bytecode *gas_parser_dir_fill 76 (yasm_parser_gas *parser_gas, /*@only@*/ yasm_expr *repeat, 77 /*@only@*/ /*@null@*/ yasm_expr *size, 78 /*@only@*/ /*@null@*/ yasm_expr *value); 79 80 #define is_eol_tok(tok) ((tok) == '\n' || (tok) == ';' || (tok) == 0) 81 #define is_eol() is_eol_tok(curtok) 82 83 #define get_next_token() (curtok = gas_parser_lex(&curval, parser_gas)) 84 85 static void 86 get_peek_token(yasm_parser_gas *parser_gas) 87 { 88 char savech = parser_gas->tokch; 89 if (parser_gas->peek_token != NONE) 90 yasm_internal_error(N_("can only have one token of lookahead")); 91 parser_gas->peek_token = 92 gas_parser_lex(&parser_gas->peek_tokval, parser_gas); 93 parser_gas->peek_tokch = parser_gas->tokch; 94 parser_gas->tokch = savech; 95 } 96 97 static void 98 destroy_curtok_(yasm_parser_gas *parser_gas) 99 { 100 if (curtok < 256) 101 ; 102 else switch ((enum tokentype)curtok) { 103 case INTNUM: 104 yasm_intnum_destroy(curval.intn); 105 break; 106 case FLTNUM: 107 yasm_floatnum_destroy(curval.flt); 108 break; 109 case ID: 110 case LABEL: 111 case STRING: 112 yasm_xfree(curval.str.contents); 113 break; 114 default: 115 break; 116 } 117 curtok = NONE; /* sanity */ 118 } 119 #define destroy_curtok() destroy_curtok_(parser_gas) 120 121 /* Eat all remaining tokens to EOL, discarding all of them. If there's any 122 * intervening tokens, generates an error (junk at end of line). 123 */ 124 static void 125 demand_eol_(yasm_parser_gas *parser_gas) 126 { 127 if (is_eol()) 128 return; 129 130 yasm_error_set(YASM_ERROR_SYNTAX, 131 N_("junk at end of line, first unrecognized character is `%c'"), 132 parser_gas->tokch); 133 134 do { 135 destroy_curtok(); 136 get_next_token(); 137 } while (!is_eol()); 138 } 139 #define demand_eol() demand_eol_(parser_gas) 140 141 static int 142 expect_(yasm_parser_gas *parser_gas, int token) 143 { 144 static char strch[] = "` '"; 145 const char *str; 146 147 if (curtok == token) 148 return 1; 149 150 switch (token) { 151 case INTNUM: str = "integer"; break; 152 case FLTNUM: str = "floating point value"; break; 153 case STRING: str = "string"; break; 154 case REG: str = "register"; break; 155 case REGGROUP: str = "register group"; break; 156 case SEGREG: str = "segment register"; break; 157 case TARGETMOD: str = "target modifier"; break; 158 case LEFT_OP: str = "<<"; break; 159 case RIGHT_OP: str = ">>"; break; 160 case ID: str = "identifier"; break; 161 case LABEL: str = "label"; break; 162 default: 163 strch[1] = token; 164 str = strch; 165 break; 166 } 167 yasm_error_set(YASM_ERROR_PARSE, "expected %s", str); 168 destroy_curtok(); 169 return 0; 170 } 171 #define expect(token) expect_(parser_gas, token) 172 173 static yasm_bytecode * 174 parse_line(yasm_parser_gas *parser_gas) 175 { 176 yasm_bytecode *bc; 177 yasm_expr *e; 178 yasm_valparamhead vps; 179 char *id; 180 const dir_lookup *dir; 181 182 if (is_eol()) 183 return NULL; 184 185 bc = parse_instr(parser_gas); 186 if (bc) 187 return bc; 188 189 switch (curtok) { 190 case ID: 191 id = ID_val; 192 193 /* See if it's a gas-specific directive */ 194 dir = (const dir_lookup *)HAMT_search(parser_gas->dirs, id); 195 if (dir) { 196 parser_gas->state = dir->newstate; 197 get_next_token(); /* ID */ 198 return dir->handler(parser_gas, dir->param); 199 } 200 201 get_next_token(); /* ID */ 202 if (curtok == ':') { 203 /* Label */ 204 parser_gas->state = INITIAL; 205 get_next_token(); /* : */ 206 define_label(parser_gas, id, 0); 207 return parse_line(parser_gas); 208 } else if (curtok == '=') { 209 /* EQU */ 210 /* TODO: allow redefinition, assigning to . (same as .org) */ 211 parser_gas->state = INITIAL; 212 get_next_token(); /* = */ 213 e = parse_expr(parser_gas); 214 if (e) 215 yasm_symtab_define_equ(p_symtab, id, e, cur_line); 216 else 217 yasm_error_set(YASM_ERROR_SYNTAX, 218 N_("expression expected after `%s'"), "="); 219 yasm_xfree(id); 220 return NULL; 221 } 222 223 /* possibly a directive; try to parse it */ 224 parse_dirvals(parser_gas, &vps); 225 if (!yasm_object_directive(p_object, id, "gas", &vps, NULL, 226 cur_line)) { 227 yasm_vps_delete(&vps); 228 yasm_xfree(id); 229 return NULL; 230 } 231 yasm_vps_delete(&vps); 232 if (id[0] == '.') 233 yasm_warn_set(YASM_WARN_GENERAL, 234 N_("directive `%s' not recognized"), id); 235 else 236 yasm_error_set(YASM_ERROR_SYNTAX, 237 N_("instruction not recognized: `%s'"), id); 238 yasm_xfree(id); 239 return NULL; 240 case LABEL: 241 define_label(parser_gas, LABEL_val, 0); 242 get_next_token(); /* LABEL */ 243 return parse_line(parser_gas); 244 case CPP_LINE_MARKER: 245 get_next_token(); 246 cpp_line_marker(parser_gas); 247 return NULL; 248 case NASM_LINE_MARKER: 249 get_next_token(); 250 nasm_line_marker(parser_gas); 251 return NULL; 252 default: 253 yasm_error_set(YASM_ERROR_SYNTAX, 254 N_("label or instruction expected at start of line")); 255 return NULL; 256 } 257 } 258 259 /* 260 Handle line markers generated by cpp. 261 262 We expect a positive integer (line) followed by a string (filename). If we 263 fail to find either of these, we treat the line as a comment. There is a 264 possibility of false positives (mistaking a comment for a line marker, when 265 the comment is not intended as a line marker) but this cannot be avoided 266 without adding a filter to the input before passing it to cpp. 267 268 This function is only called if the preprocessor was 'cpp', since the 269 CPP_LINE_MARKER token isn't generated for any other preprocessor. With any 270 other preprocessor, anything after a '#' is always treated as a comment. 271 */ 272 static void 273 cpp_line_marker(yasm_parser_gas *parser_gas) 274 { 275 yasm_valparamhead vps; 276 yasm_valparam *vp; 277 unsigned long line; 278 char *filename; 279 280 /* Line number. */ 281 if (curtok != INTNUM) { 282 /* Skip over a comment. */ 283 while (curtok != '\n') 284 get_next_token(); 285 286 return; 287 } 288 289 if (yasm_intnum_sign(INTNUM_val) < 0) { 290 get_next_token(); /* INTNUM */ 291 yasm_error_set(YASM_ERROR_SYNTAX, 292 N_("line number is negative")); 293 return; 294 } 295 296 line = yasm_intnum_get_uint(INTNUM_val); 297 298 /* 299 Set to (line - 1) since the directive indicates that the *next* line 300 will have the number given. 301 302 cpp should never produce line=0, but the if keeps us safe just incase. 303 */ 304 if (line != 0) 305 line--; 306 307 yasm_intnum_destroy(INTNUM_val); 308 get_next_token(); /* INTNUM */ 309 310 /* File name, in quotes. */ 311 if (curtok != STRING) { 312 /* Skip over a comment. */ 313 while (curtok != '\n') 314 get_next_token(); 315 316 return; 317 } 318 319 filename = STRING_val.contents; 320 get_next_token(); 321 322 /* Set linemap. */ 323 yasm_linemap_set(parser_gas->linemap, filename, 0, line, 1); 324 325 /* 326 The first line marker in the file (which should be on the first line 327 of the file) will give us the name of the source file. This information 328 needs to be passed on to the debug format module. 329 */ 330 if (parser_gas->seen_line_marker == 0) { 331 parser_gas->seen_line_marker = 1; 332 333 yasm_vps_initialize(&vps); 334 vp = yasm_vp_create_string(NULL, filename); 335 yasm_vps_append(&vps, vp); 336 337 yasm_object_directive(p_object, ".file", "gas", &vps, NULL, cur_line); 338 339 yasm_vps_delete(&vps); 340 } else 341 yasm_xfree(filename); 342 343 /* Skip flags. */ 344 while (1) { 345 switch (curtok) { 346 case INTNUM: 347 break; 348 349 case '\n': 350 return; 351 352 default: 353 yasm_error_set(YASM_ERROR_SYNTAX, 354 N_("junk at end of cpp line marker")); 355 return; 356 } 357 get_next_token(); 358 } 359 } 360 361 /* 362 Handle line markers generated by the nasm preproc. 363 364 We expect a positive integer (line) followed by a plus sign, followed by 365 another positive integer, followed by a string (filename). 366 367 This function is only called if the preprocessor was 'nasm', since the 368 NASM_LINE_MARKER token isn't generated for any other preprocessor. 369 */ 370 static void 371 nasm_line_marker(yasm_parser_gas *parser_gas) 372 { 373 yasm_valparamhead vps; 374 yasm_valparam *vp; 375 unsigned long line, incr; 376 char *filename; 377 378 /* Line number. */ 379 if (!expect(INTNUM)) return; 380 381 if (yasm_intnum_sign(INTNUM_val) < 0) { 382 get_next_token(); /* INTNUM */ 383 yasm_error_set(YASM_ERROR_SYNTAX, 384 N_("line number is negative")); 385 return; 386 } 387 388 line = yasm_intnum_get_uint(INTNUM_val); 389 390 /* 391 Set to (line - 1) since the directive indicates that the *next* line 392 will have the number given. 393 394 cpp should never produce line=0, but the if keeps us safe just incase. 395 */ 396 if (line != 0) 397 line--; 398 399 yasm_intnum_destroy(INTNUM_val); 400 get_next_token(); /* INTNUM */ 401 402 if (!expect('+')) return; 403 get_next_token(); /* + */ 404 405 /* Line number increment. */ 406 if (!expect(INTNUM)) return; 407 408 if (yasm_intnum_sign(INTNUM_val) < 0) { 409 get_next_token(); /* INTNUM */ 410 yasm_error_set(YASM_ERROR_SYNTAX, 411 N_("line increment is negative")); 412 return; 413 } 414 415 incr = yasm_intnum_get_uint(INTNUM_val); 416 yasm_intnum_destroy(INTNUM_val); 417 418 /* File name is not in quotes, so need to switch to a different tokenizer 419 * state. 420 */ 421 parser_gas->state = NASM_FILENAME; 422 get_next_token(); /* INTNUM */ 423 if (!expect(STRING)) { 424 parser_gas->state = INITIAL; 425 return; 426 } 427 428 filename = STRING_val.contents; 429 430 /* Set linemap. */ 431 yasm_linemap_set(parser_gas->linemap, filename, 0, line, incr); 432 433 /* 434 The first line marker in the file (which should be on the first line 435 of the file) will give us the name of the source file. This information 436 needs to be passed on to the debug format module. 437 */ 438 if (parser_gas->seen_line_marker == 0) { 439 parser_gas->seen_line_marker = 1; 440 441 yasm_vps_initialize(&vps); 442 vp = yasm_vp_create_string(NULL, filename); 443 yasm_vps_append(&vps, vp); 444 445 yasm_object_directive(p_object, ".file", "gas", &vps, NULL, cur_line); 446 447 yasm_vps_delete(&vps); 448 } else 449 yasm_xfree(filename); 450 451 /* We need to poke back on the \n that was consumed by the tokenizer */ 452 parser_gas->peek_token = '\n'; 453 get_next_token(); 454 } 455 456 /* Line directive */ 457 static yasm_bytecode * 458 dir_line(yasm_parser_gas *parser_gas, unsigned int param) 459 { 460 if (!expect(INTNUM)) return NULL; 461 if (yasm_intnum_sign(INTNUM_val) < 0) { 462 get_next_token(); /* INTNUM */ 463 yasm_error_set(YASM_ERROR_SYNTAX, 464 N_("line number is negative")); 465 return NULL; 466 } 467 468 parser_gas->dir_line = yasm_intnum_get_uint(INTNUM_val); 469 yasm_intnum_destroy(INTNUM_val); 470 get_next_token(); /* INTNUM */ 471 472 if (parser_gas->dir_fileline == 3) { 473 /* Have both file and line */ 474 yasm_linemap_set(parser_gas->linemap, NULL, 0, 475 parser_gas->dir_line, 1); 476 } else if (parser_gas->dir_fileline == 1) { 477 /* Had previous file directive only */ 478 parser_gas->dir_fileline = 3; 479 yasm_linemap_set(parser_gas->linemap, parser_gas->dir_file, 0, 480 parser_gas->dir_line, 1); 481 } else { 482 /* Didn't see file yet */ 483 parser_gas->dir_fileline = 2; 484 } 485 return NULL; 486 } 487 488 /* Alignment directives */ 489 490 static yasm_bytecode * 491 dir_align(yasm_parser_gas *parser_gas, unsigned int param) 492 { 493 yasm_expr *bound, *fill=NULL, *maxskip=NULL; 494 495 bound = parse_expr(parser_gas); 496 if (!bound) { 497 yasm_error_set(YASM_ERROR_SYNTAX, 498 N_(".align directive must specify alignment")); 499 return NULL; 500 } 501 502 if (curtok == ',') { 503 get_next_token(); /* ',' */ 504 fill = parse_expr(parser_gas); 505 if (curtok == ',') { 506 get_next_token(); /* ',' */ 507 maxskip = parse_expr(parser_gas); 508 } 509 } 510 511 return gas_parser_align(parser_gas, cursect, bound, fill, maxskip, 512 (int)param); 513 } 514 515 static yasm_bytecode * 516 dir_org(yasm_parser_gas *parser_gas, unsigned int param) 517 { 518 yasm_intnum *start, *value=NULL; 519 yasm_bytecode *bc; 520 521 /* TODO: support expr instead of intnum */ 522 if (!expect(INTNUM)) return NULL; 523 start = INTNUM_val; 524 get_next_token(); /* INTNUM */ 525 526 if (curtok == ',') { 527 get_next_token(); /* ',' */ 528 /* TODO: support expr instead of intnum */ 529 if (!expect(INTNUM)) return NULL; 530 value = INTNUM_val; 531 get_next_token(); /* INTNUM */ 532 } 533 if (value) { 534 bc = yasm_bc_create_org(yasm_intnum_get_uint(start), 535 yasm_intnum_get_uint(value), cur_line); 536 yasm_intnum_destroy(value); 537 } else 538 bc = yasm_bc_create_org(yasm_intnum_get_uint(start), 0, 539 cur_line); 540 yasm_intnum_destroy(start); 541 return bc; 542 } 543 544 /* Data visibility directives */ 545 546 static yasm_bytecode * 547 dir_local(yasm_parser_gas *parser_gas, unsigned int param) 548 { 549 if (!expect(ID)) return NULL; 550 yasm_symtab_declare(p_symtab, ID_val, YASM_SYM_DLOCAL, cur_line); 551 yasm_xfree(ID_val); 552 get_next_token(); /* ID */ 553 return NULL; 554 } 555 556 static yasm_bytecode * 557 dir_comm(yasm_parser_gas *parser_gas, unsigned int is_lcomm) 558 { 559 yasm_expr *align = NULL; 560 /*@null@*/ /*@dependent@*/ yasm_symrec *sym; 561 char *id; 562 yasm_expr *e; 563 564 if (!expect(ID)) return NULL; 565 id = ID_val; 566 get_next_token(); /* ID */ 567 if (!expect(',')) { 568 yasm_xfree(id); 569 return NULL; 570 } 571 get_next_token(); /* , */ 572 e = parse_expr(parser_gas); 573 if (!e) { 574 yasm_error_set(YASM_ERROR_SYNTAX, N_("size expected for `%s'"), 575 ".COMM"); 576 return NULL; 577 } 578 if (curtok == ',') { 579 /* Optional alignment expression */ 580 get_next_token(); /* ',' */ 581 align = parse_expr(parser_gas); 582 } 583 /* If already explicitly declared local, treat like LCOMM */ 584 if (is_lcomm 585 || ((sym = yasm_symtab_get(p_symtab, id)) 586 && yasm_symrec_get_visibility(sym) == YASM_SYM_DLOCAL)) { 587 define_lcomm(parser_gas, id, e, align); 588 } else if (align) { 589 /* Give third parameter as objext valparam */ 590 yasm_valparamhead *extvps = yasm_vps_create(); 591 yasm_valparam *vp = yasm_vp_create_expr(NULL, align); 592 yasm_vps_append(extvps, vp); 593 594 sym = yasm_symtab_declare(p_symtab, id, YASM_SYM_COMMON, 595 cur_line); 596 yasm_symrec_set_common_size(sym, e); 597 yasm_symrec_set_objext_valparams(sym, extvps); 598 599 yasm_xfree(id); 600 } else { 601 sym = yasm_symtab_declare(p_symtab, id, YASM_SYM_COMMON, 602 cur_line); 603 yasm_symrec_set_common_size(sym, e); 604 yasm_xfree(id); 605 } 606 return NULL; 607 } 608 609 /* Integer data definition directives */ 610 611 static yasm_bytecode * 612 dir_ascii(yasm_parser_gas *parser_gas, unsigned int withzero) 613 { 614 yasm_datavalhead dvs; 615 if (!parse_strvals(parser_gas, &dvs)) 616 return NULL; 617 return yasm_bc_create_data(&dvs, 1, (int)withzero, p_object->arch, 618 cur_line); 619 } 620 621 static yasm_bytecode * 622 dir_data(yasm_parser_gas *parser_gas, unsigned int size) 623 { 624 yasm_datavalhead dvs; 625 if (!parse_datavals(parser_gas, &dvs)) 626 return NULL; 627 return yasm_bc_create_data(&dvs, size, 0, p_object->arch, cur_line); 628 } 629 630 static yasm_bytecode * 631 dir_leb128(yasm_parser_gas *parser_gas, unsigned int sign) 632 { 633 yasm_datavalhead dvs; 634 if (!parse_datavals(parser_gas, &dvs)) 635 return NULL; 636 return yasm_bc_create_leb128(&dvs, (int)sign, cur_line); 637 } 638 639 /* Empty space / fill data definition directives */ 640 641 static yasm_bytecode * 642 dir_zero(yasm_parser_gas *parser_gas, unsigned int param) 643 { 644 yasm_bytecode *bc; 645 yasm_datavalhead dvs; 646 yasm_expr *e = parse_expr(parser_gas); 647 if (!e) { 648 yasm_error_set(YASM_ERROR_SYNTAX, 649 N_("expression expected after `%s'"), ".ZERO"); 650 return NULL; 651 } 652 653 yasm_dvs_initialize(&dvs); 654 yasm_dvs_append(&dvs, yasm_dv_create_expr( 655 p_expr_new_ident(yasm_expr_int(yasm_intnum_create_uint(0))))); 656 bc = yasm_bc_create_data(&dvs, 1, 0, p_object->arch, cur_line); 657 yasm_bc_set_multiple(bc, e); 658 return bc; 659 } 660 661 static yasm_bytecode * 662 dir_skip(yasm_parser_gas *parser_gas, unsigned int param) 663 { 664 yasm_expr *e, *e_val; 665 yasm_bytecode *bc; 666 yasm_datavalhead dvs; 667 668 e = parse_expr(parser_gas); 669 if (!e) { 670 yasm_error_set(YASM_ERROR_SYNTAX, 671 N_("expression expected after `%s'"), ".SKIP"); 672 return NULL; 673 } 674 if (curtok != ',') 675 return yasm_bc_create_reserve(e, 1, cur_line); 676 get_next_token(); /* ',' */ 677 e_val = parse_expr(parser_gas); 678 yasm_dvs_initialize(&dvs); 679 yasm_dvs_append(&dvs, yasm_dv_create_expr(e_val)); 680 bc = yasm_bc_create_data(&dvs, 1, 0, p_object->arch, cur_line); 681 682 yasm_bc_set_multiple(bc, e); 683 return bc; 684 } 685 686 /* fill data definition directive */ 687 static yasm_bytecode * 688 dir_fill(yasm_parser_gas *parser_gas, unsigned int param) 689 { 690 yasm_expr *sz=NULL, *val=NULL; 691 yasm_expr *e = parse_expr(parser_gas); 692 if (!e) { 693 yasm_error_set(YASM_ERROR_SYNTAX, 694 N_("expression expected after `%s'"), ".FILL"); 695 return NULL; 696 } 697 if (curtok == ',') { 698 get_next_token(); /* ',' */ 699 sz = parse_expr(parser_gas); 700 if (curtok == ',') { 701 get_next_token(); /* ',' */ 702 val = parse_expr(parser_gas); 703 } 704 } 705 return gas_parser_dir_fill(parser_gas, e, sz, val); 706 } 707 708 /* Section directives */ 709 710 static yasm_bytecode * 711 dir_bss_section(yasm_parser_gas *parser_gas, unsigned int param) 712 { 713 gas_switch_section(parser_gas, ".bss", NULL, NULL, NULL, 1); 714 return NULL; 715 } 716 717 static yasm_bytecode * 718 dir_data_section(yasm_parser_gas *parser_gas, unsigned int param) 719 { 720 gas_switch_section(parser_gas, ".data", NULL, NULL, NULL, 1); 721 return NULL; 722 } 723 724 static yasm_bytecode * 725 dir_text_section(yasm_parser_gas *parser_gas, unsigned int param) 726 { 727 gas_switch_section(parser_gas, ".text", NULL, NULL, NULL, 1); 728 return NULL; 729 } 730 731 static yasm_bytecode * 732 dir_section(yasm_parser_gas *parser_gas, unsigned int param) 733 { 734 /* DIR_SECTION ID ',' STRING ',' '@' ID ',' dirvals */ 735 char *sectname, *flags = NULL, *type = NULL; 736 yasm_valparamhead vps; 737 int have_vps = 0; 738 739 if (!expect(ID)) return NULL; 740 sectname = ID_val; 741 get_next_token(); /* ID */ 742 743 if (curtok == ',') { 744 get_next_token(); /* ',' */ 745 if (!expect(STRING)) { 746 yasm_error_set(YASM_ERROR_SYNTAX, 747 N_("flag string expected")); 748 yasm_xfree(sectname); 749 return NULL; 750 } 751 flags = STRING_val.contents; 752 get_next_token(); /* STRING */ 753 } 754 755 if (curtok == ',') { 756 get_next_token(); /* ',' */ 757 if (!expect('@')) { 758 yasm_xfree(sectname); 759 yasm_xfree(flags); 760 return NULL; 761 } 762 get_next_token(); /* '@' */ 763 if (!expect(ID)) { 764 yasm_xfree(sectname); 765 yasm_xfree(flags); 766 return NULL; 767 } 768 type = ID_val; 769 get_next_token(); /* ID */ 770 } 771 772 if (curtok == ',') { 773 get_next_token(); /* ',' */ 774 if (parse_dirvals(parser_gas, &vps)) 775 have_vps = 1; 776 } 777 778 gas_switch_section(parser_gas, sectname, flags, type, 779 have_vps ? &vps : NULL, 0); 780 yasm_xfree(sectname); 781 yasm_xfree(flags); 782 return NULL; 783 } 784 785 /* Other directives */ 786 787 static yasm_bytecode * 788 dir_equ(yasm_parser_gas *parser_gas, unsigned int param) 789 { 790 yasm_expr *e; 791 char *id; 792 793 /* ID ',' expr */ 794 if (!expect(ID)) return NULL; 795 id = ID_val; 796 get_next_token(); /* ID */ 797 if (!expect(',')) { 798 yasm_xfree(id); 799 return NULL; 800 } 801 get_next_token(); /* ',' */ 802 e = parse_expr(parser_gas); 803 if (e) 804 yasm_symtab_define_equ(p_symtab, id, e, cur_line); 805 else 806 yasm_error_set(YASM_ERROR_SYNTAX, 807 N_("expression expected after `%s'"), ","); 808 yasm_xfree(id); 809 return NULL; 810 } 811 812 static yasm_bytecode * 813 dir_file(yasm_parser_gas *parser_gas, unsigned int param) 814 { 815 yasm_valparamhead vps; 816 yasm_valparam *vp; 817 818 if (curtok == STRING) { 819 /* No file number; this form also sets the assembler's 820 * internal line number. 821 */ 822 char *filename = STRING_val.contents; 823 824 get_next_token(); /* STRING */ 825 if (parser_gas->dir_fileline == 3) { 826 /* Have both file and line */ 827 const char *old_fn; 828 unsigned long old_line; 829 830 yasm_linemap_lookup(parser_gas->linemap, cur_line, &old_fn, 831 &old_line); 832 yasm_linemap_set(parser_gas->linemap, filename, 0, old_line, 833 1); 834 } else if (parser_gas->dir_fileline == 2) { 835 /* Had previous line directive only */ 836 parser_gas->dir_fileline = 3; 837 yasm_linemap_set(parser_gas->linemap, filename, 0, 838 parser_gas->dir_line, 1); 839 } else { 840 /* Didn't see line yet, save file */ 841 parser_gas->dir_fileline = 1; 842 if (parser_gas->dir_file) 843 yasm_xfree(parser_gas->dir_file); 844 parser_gas->dir_file = yasm__xstrdup(filename); 845 } 846 847 /* Pass change along to debug format */ 848 yasm_vps_initialize(&vps); 849 vp = yasm_vp_create_string(NULL, filename); 850 yasm_vps_append(&vps, vp); 851 852 yasm_object_directive(p_object, ".file", "gas", &vps, NULL, 853 cur_line); 854 855 yasm_vps_delete(&vps); 856 return NULL; 857 } 858 859 /* fileno filename form */ 860 yasm_vps_initialize(&vps); 861 862 if (!expect(INTNUM)) return NULL; 863 vp = yasm_vp_create_expr(NULL, 864 p_expr_new_ident(yasm_expr_int(INTNUM_val))); 865 yasm_vps_append(&vps, vp); 866 get_next_token(); /* INTNUM */ 867 868 if (!expect(STRING)) { 869 yasm_vps_delete(&vps); 870 return NULL; 871 } 872 vp = yasm_vp_create_string(NULL, STRING_val.contents); 873 yasm_vps_append(&vps, vp); 874 get_next_token(); /* STRING */ 875 876 yasm_object_directive(p_object, ".file", "gas", &vps, NULL, 877 cur_line); 878 879 yasm_vps_delete(&vps); 880 return NULL; 881 } 882 883 884 static yasm_bytecode * 885 dir_intel_syntax(yasm_parser_gas *parser_gas, unsigned int param) 886 { 887 parser_gas->intel_syntax = 1; 888 889 do { 890 destroy_curtok(); 891 get_next_token(); 892 } while (!is_eol()); 893 return NULL; 894 } 895 896 static yasm_bytecode * 897 dir_att_syntax(yasm_parser_gas *parser_gas, unsigned int param) 898 { 899 parser_gas->intel_syntax = 0; 900 return NULL; 901 } 902 903 static yasm_bytecode * 904 parse_instr(yasm_parser_gas *parser_gas) 905 { 906 yasm_bytecode *bc; 907 char *id; 908 size_t id_len; 909 uintptr_t prefix; 910 911 if (parser_gas->intel_syntax) { 912 bc = parse_instr_intel(parser_gas); 913 if (bc) { 914 yasm_warn_disable(YASM_WARN_UNREC_CHAR); 915 do { 916 destroy_curtok(); 917 get_next_token(); 918 } while (!is_eol()); 919 yasm_warn_enable(YASM_WARN_UNREC_CHAR); 920 } 921 return bc; 922 } 923 924 if (curtok != ID) 925 return NULL; 926 927 id = ID_val; 928 id_len = ID_len; 929 930 /* instructions/prefixes must start with a letter */ 931 if (!isalpha(id[0])) 932 return NULL; 933 934 /* check to be sure it's not a label or equ */ 935 get_peek_token(parser_gas); 936 if (parser_gas->peek_token == ':' || parser_gas->peek_token == '=') 937 return NULL; 938 939 switch (yasm_arch_parse_check_insnprefix 940 (p_object->arch, ID_val, ID_len, cur_line, &bc, &prefix)) { 941 case YASM_ARCH_INSN: 942 { 943 yasm_insn *insn; 944 945 /* Propagate errors in case we got a warning from the arch */ 946 yasm_errwarn_propagate(parser_gas->errwarns, cur_line); 947 948 insn = yasm_bc_get_insn(bc); 949 950 yasm_xfree(id); 951 get_next_token(); /* ID */ 952 if (is_eol()) 953 return bc; /* no operands */ 954 955 /* parse operands */ 956 for (;;) { 957 yasm_insn_operand *op = parse_operand(parser_gas); 958 if (!op) { 959 yasm_error_set(YASM_ERROR_SYNTAX, 960 N_("expression syntax error")); 961 yasm_bc_destroy(bc); 962 return NULL; 963 } 964 yasm_insn_ops_append(insn, op); 965 966 if (is_eol()) 967 break; 968 if (!expect(',')) { 969 yasm_bc_destroy(bc); 970 return NULL; 971 } 972 get_next_token(); 973 } 974 return bc; 975 } 976 case YASM_ARCH_PREFIX: 977 /* Propagate errors in case we got a warning from the arch */ 978 yasm_errwarn_propagate(parser_gas->errwarns, cur_line); 979 980 yasm_xfree(id); 981 get_next_token(); /* ID */ 982 bc = parse_instr(parser_gas); 983 if (!bc) 984 bc = yasm_arch_create_empty_insn(p_object->arch, cur_line); 985 yasm_insn_add_prefix(yasm_bc_get_insn(bc), prefix); 986 return bc; 987 default: 988 break; 989 } 990 991 /* Check for segment register used as prefix */ 992 switch (yasm_arch_parse_check_regtmod(p_object->arch, ID_val, ID_len, 993 &prefix)) { 994 case YASM_ARCH_SEGREG: 995 yasm_xfree(id); 996 get_next_token(); /* ID */ 997 bc = parse_instr(parser_gas); 998 if (!bc) 999 bc = yasm_arch_create_empty_insn(p_object->arch, cur_line); 1000 yasm_insn_add_seg_prefix(yasm_bc_get_insn(bc), prefix); 1001 return bc; 1002 default: 1003 return NULL; 1004 } 1005 } 1006 1007 static int 1008 parse_dirvals(yasm_parser_gas *parser_gas, yasm_valparamhead *vps) 1009 { 1010 yasm_valparam *vp; 1011 yasm_expr *e; 1012 int num = 0; 1013 1014 yasm_vps_initialize(vps); 1015 1016 for (;;) { 1017 switch (curtok) { 1018 case ID: 1019 get_peek_token(parser_gas); 1020 switch (parser_gas->peek_token) { 1021 case '+': case '-': 1022 case '|': case '^': case '&': case '!': 1023 case '*': case '/': case '%': case LEFT_OP: case RIGHT_OP: 1024 e = parse_expr(parser_gas); 1025 vp = yasm_vp_create_expr(NULL, e); 1026 break; 1027 default: 1028 /* Just an ID */ 1029 vp = yasm_vp_create_id(NULL, ID_val, '\0'); 1030 get_next_token(); /* ID */ 1031 break; 1032 } 1033 break; 1034 case STRING: 1035 vp = yasm_vp_create_string(NULL, STRING_val.contents); 1036 get_next_token(); /* STRING */ 1037 break; 1038 case REG: 1039 e = p_expr_new_ident(yasm_expr_reg(REG_val)); 1040 vp = yasm_vp_create_expr(NULL, e); 1041 get_next_token(); /* REG */ 1042 break; 1043 case '@': 1044 /* XXX: is throwing it away *really* the right thing? */ 1045 get_next_token(); /* @ */ 1046 continue; 1047 default: 1048 e = parse_expr(parser_gas); 1049 if (!e) 1050 return num; 1051 vp = yasm_vp_create_expr(NULL, e); 1052 break; 1053 } 1054 yasm_vps_append(vps, vp); 1055 num++; 1056 if (curtok == ',') 1057 get_next_token(); /* ',' */ 1058 } 1059 return num; 1060 } 1061 1062 static int 1063 parse_datavals(yasm_parser_gas *parser_gas, yasm_datavalhead *dvs) 1064 { 1065 yasm_expr *e; 1066 yasm_dataval *dv; 1067 int num = 0; 1068 1069 yasm_dvs_initialize(dvs); 1070 1071 for (;;) { 1072 e = parse_expr(parser_gas); 1073 if (!e) { 1074 yasm_dvs_delete(dvs); 1075 yasm_dvs_initialize(dvs); 1076 return 0; 1077 } 1078 dv = yasm_dv_create_expr(e); 1079 yasm_dvs_append(dvs, dv); 1080 num++; 1081 if (curtok != ',') 1082 break; 1083 get_next_token(); /* ',' */ 1084 } 1085 return num; 1086 } 1087 1088 static int 1089 parse_strvals(yasm_parser_gas *parser_gas, yasm_datavalhead *dvs) 1090 { 1091 yasm_dataval *dv; 1092 int num = 0; 1093 1094 yasm_dvs_initialize(dvs); 1095 1096 for (;;) { 1097 if (!expect(STRING)) { 1098 yasm_dvs_delete(dvs); 1099 yasm_dvs_initialize(dvs); 1100 return 0; 1101 } 1102 dv = yasm_dv_create_string(STRING_val.contents, STRING_val.len); 1103 yasm_dvs_append(dvs, dv); 1104 get_next_token(); /* STRING */ 1105 num++; 1106 if (curtok != ',') 1107 break; 1108 get_next_token(); /* ',' */ 1109 } 1110 return num; 1111 } 1112 1113 /* instruction operands */ 1114 /* memory addresses */ 1115 static yasm_effaddr * 1116 parse_memaddr(yasm_parser_gas *parser_gas) 1117 { 1118 yasm_effaddr *ea = NULL; 1119 yasm_expr *e1, *e2; 1120 int strong = 0; 1121 1122 if (curtok == SEGREG) { 1123 uintptr_t segreg = SEGREG_val; 1124 get_next_token(); /* SEGREG */ 1125 if (!expect(':')) return NULL; 1126 get_next_token(); /* ':' */ 1127 ea = parse_memaddr(parser_gas); 1128 if (!ea) 1129 return NULL; 1130 yasm_ea_set_segreg(ea, segreg); 1131 return ea; 1132 } 1133 1134 /* We want to parse a leading expression, except when it's actually 1135 * just a memory address (with no preceding expression) such as 1136 * (REG...) or (,...). 1137 */ 1138 get_peek_token(parser_gas); 1139 if (curtok != '(' || (parser_gas->peek_token != REG 1140 && parser_gas->peek_token != ',')) 1141 e1 = parse_expr(parser_gas); 1142 else 1143 e1 = NULL; 1144 1145 if (curtok == '(') { 1146 int havereg = 0; 1147 uintptr_t reg = 0; 1148 yasm_intnum *scale = NULL; 1149 1150 get_next_token(); /* '(' */ 1151 1152 /* base register */ 1153 if (curtok == REG) { 1154 e2 = p_expr_new_ident(yasm_expr_reg(REG_val)); 1155 get_next_token(); /* REG */ 1156 } else 1157 e2 = p_expr_new_ident(yasm_expr_int(yasm_intnum_create_uint(0))); 1158 1159 if (curtok == ')') 1160 goto done; 1161 1162 if (!expect(',')) { 1163 yasm_error_set(YASM_ERROR_SYNTAX, N_("invalid memory expression")); 1164 if (e1) yasm_expr_destroy(e1); 1165 yasm_expr_destroy(e2); 1166 return NULL; 1167 } 1168 get_next_token(); /* ',' */ 1169 1170 if (curtok == ')') 1171 goto done; 1172 1173 /* index register */ 1174 if (curtok == REG) { 1175 reg = REG_val; 1176 havereg = 1; 1177 get_next_token(); /* REG */ 1178 if (curtok != ',') { 1179 scale = yasm_intnum_create_uint(1); 1180 goto done; 1181 } 1182 get_next_token(); /* ',' */ 1183 } 1184 1185 /* scale */ 1186 if (!expect(INTNUM)) { 1187 yasm_error_set(YASM_ERROR_SYNTAX, N_("non-integer scale")); 1188 if (e1) yasm_expr_destroy(e1); 1189 yasm_expr_destroy(e2); 1190 return NULL; 1191 } 1192 scale = INTNUM_val; 1193 get_next_token(); /* INTNUM */ 1194 1195 done: 1196 if (!expect(')')) { 1197 yasm_error_set(YASM_ERROR_SYNTAX, N_("invalid memory expression")); 1198 if (scale) yasm_intnum_destroy(scale); 1199 if (e1) yasm_expr_destroy(e1); 1200 yasm_expr_destroy(e2); 1201 return NULL; 1202 } 1203 get_next_token(); /* ')' */ 1204 1205 if (scale) { 1206 if (!havereg) { 1207 if (yasm_intnum_get_uint(scale) != 1) 1208 yasm_warn_set(YASM_WARN_GENERAL, 1209 N_("scale factor of %u without an index register"), 1210 yasm_intnum_get_uint(scale)); 1211 yasm_intnum_destroy(scale); 1212 } else 1213 e2 = p_expr_new(yasm_expr_expr(e2), YASM_EXPR_ADD, 1214 yasm_expr_expr(p_expr_new(yasm_expr_reg(reg), YASM_EXPR_MUL, 1215 yasm_expr_int(scale)))); 1216 } 1217 1218 if (e1) { 1219 /* Ordering is critical here to correctly detecting presence of 1220 * RIP in RIP-relative expressions. 1221 */ 1222 e1 = p_expr_new_tree(e2, YASM_EXPR_ADD, e1); 1223 } else 1224 e1 = e2; 1225 strong = 1; 1226 } 1227 1228 if (!e1) 1229 return NULL; 1230 ea = yasm_arch_ea_create(p_object->arch, e1); 1231 if (strong) 1232 ea->strong = 1; 1233 return ea; 1234 } 1235 1236 static yasm_insn_operand * 1237 parse_operand(yasm_parser_gas *parser_gas) 1238 { 1239 yasm_effaddr *ea; 1240 yasm_insn_operand *op; 1241 uintptr_t reg; 1242 1243 switch (curtok) { 1244 case REG: 1245 reg = REG_val; 1246 get_next_token(); /* REG */ 1247 return yasm_operand_create_reg(reg); 1248 case SEGREG: 1249 /* need to see if it's really a memory address */ 1250 get_peek_token(parser_gas); 1251 if (parser_gas->peek_token == ':') { 1252 ea = parse_memaddr(parser_gas); 1253 if (!ea) 1254 return NULL; 1255 return yasm_operand_create_mem(ea); 1256 } 1257 reg = SEGREG_val; 1258 get_next_token(); /* SEGREG */ 1259 return yasm_operand_create_segreg(reg); 1260 case REGGROUP: 1261 { 1262 unsigned long regindex; 1263 reg = REGGROUP_val; 1264 get_next_token(); /* REGGROUP */ 1265 if (curtok != '(') 1266 return yasm_operand_create_reg(reg); 1267 get_next_token(); /* '(' */ 1268 if (!expect(INTNUM)) { 1269 yasm_error_set(YASM_ERROR_SYNTAX, 1270 N_("integer register index expected")); 1271 return NULL; 1272 } 1273 regindex = yasm_intnum_get_uint(INTNUM_val); 1274 get_next_token(); /* INTNUM */ 1275 if (!expect(')')) { 1276 yasm_error_set(YASM_ERROR_SYNTAX, 1277 N_("missing closing parenthesis for register index")); 1278 return NULL; 1279 } 1280 get_next_token(); /* ')' */ 1281 reg = yasm_arch_reggroup_get_reg(p_object->arch, reg, regindex); 1282 if (reg == 0) { 1283 yasm_error_set(YASM_ERROR_SYNTAX, N_("bad register index `%u'"), 1284 regindex); 1285 return NULL; 1286 } 1287 return yasm_operand_create_reg(reg); 1288 } 1289 case '$': 1290 { 1291 yasm_expr *e; 1292 get_next_token(); /* '$' */ 1293 e = parse_expr(parser_gas); 1294 if (!e) { 1295 yasm_error_set(YASM_ERROR_SYNTAX, 1296 N_("expression missing after `%s'"), "$"); 1297 return NULL; 1298 } 1299 return yasm_operand_create_imm(e); 1300 } 1301 case '*': 1302 get_next_token(); /* '*' */ 1303 if (curtok == REG) { 1304 op = yasm_operand_create_reg(REG_val); 1305 get_next_token(); /* REG */ 1306 } else { 1307 ea = parse_memaddr(parser_gas); 1308 if (!ea) { 1309 yasm_error_set(YASM_ERROR_SYNTAX, 1310 N_("expression missing after `%s'"), "*"); 1311 return NULL; 1312 } 1313 op = yasm_operand_create_mem(ea); 1314 } 1315 op->deref = 1; 1316 return op; 1317 default: 1318 ea = parse_memaddr(parser_gas); 1319 if (!ea) 1320 return NULL; 1321 return yasm_operand_create_mem(ea); 1322 } 1323 } 1324 1325 /* Expression grammar parsed is: 1326 * 1327 * expr : expr0 [ {+,-} expr0...] 1328 * expr0 : expr1 [ {|,^,&,!} expr1...] 1329 * expr1 : expr2 [ {*,/,%,<<,>>} expr2...] 1330 * expr2 : { ~,+,- } expr2 1331 * | (expr) 1332 * | symbol 1333 * | number 1334 */ 1335 1336 static yasm_expr * 1337 parse_expr(yasm_parser_gas *parser_gas) 1338 { 1339 yasm_expr *e, *f; 1340 e = parse_expr0(parser_gas); 1341 if (!e) 1342 return NULL; 1343 1344 while (curtok == '+' || curtok == '-') { 1345 int op = curtok; 1346 get_next_token(); 1347 f = parse_expr0(parser_gas); 1348 if (!f) { 1349 yasm_expr_destroy(e); 1350 return NULL; 1351 } 1352 1353 switch (op) { 1354 case '+': e = p_expr_new_tree(e, YASM_EXPR_ADD, f); break; 1355 case '-': e = p_expr_new_tree(e, YASM_EXPR_SUB, f); break; 1356 } 1357 } 1358 return e; 1359 } 1360 1361 static yasm_expr * 1362 parse_expr0(yasm_parser_gas *parser_gas) 1363 { 1364 yasm_expr *e, *f; 1365 e = parse_expr1(parser_gas); 1366 if (!e) 1367 return NULL; 1368 1369 while (curtok == '|' || curtok == '^' || curtok == '&' || curtok == '!') { 1370 int op = curtok; 1371 get_next_token(); 1372 f = parse_expr1(parser_gas); 1373 if (!f) { 1374 yasm_expr_destroy(e); 1375 return NULL; 1376 } 1377 1378 switch (op) { 1379 case '|': e = p_expr_new_tree(e, YASM_EXPR_OR, f); break; 1380 case '^': e = p_expr_new_tree(e, YASM_EXPR_XOR, f); break; 1381 case '&': e = p_expr_new_tree(e, YASM_EXPR_AND, f); break; 1382 case '!': e = p_expr_new_tree(e, YASM_EXPR_NOR, f); break; 1383 } 1384 } 1385 return e; 1386 } 1387 1388 static yasm_expr * 1389 parse_expr1(yasm_parser_gas *parser_gas) 1390 { 1391 yasm_expr *e, *f; 1392 e = parse_expr2(parser_gas); 1393 if (!e) 1394 return NULL; 1395 1396 while (curtok == '*' || curtok == '/' || curtok == '%' || curtok == LEFT_OP 1397 || curtok == RIGHT_OP) { 1398 int op = curtok; 1399 get_next_token(); 1400 f = parse_expr2(parser_gas); 1401 if (!f) { 1402 yasm_expr_destroy(e); 1403 return NULL; 1404 } 1405 1406 switch (op) { 1407 case '*': e = p_expr_new_tree(e, YASM_EXPR_MUL, f); break; 1408 case '/': e = p_expr_new_tree(e, YASM_EXPR_DIV, f); break; 1409 case '%': e = p_expr_new_tree(e, YASM_EXPR_MOD, f); break; 1410 case LEFT_OP: e = p_expr_new_tree(e, YASM_EXPR_SHL, f); break; 1411 case RIGHT_OP: e = p_expr_new_tree(e, YASM_EXPR_SHR, f); break; 1412 } 1413 } 1414 return e; 1415 } 1416 1417 static yasm_expr * 1418 parse_expr2(yasm_parser_gas *parser_gas) 1419 { 1420 yasm_expr *e; 1421 yasm_symrec *sym; 1422 1423 switch (curtok) { 1424 case '+': 1425 get_next_token(); 1426 return parse_expr2(parser_gas); 1427 case '-': 1428 get_next_token(); 1429 e = parse_expr2(parser_gas); 1430 if (!e) 1431 return NULL; 1432 return p_expr_new_branch(YASM_EXPR_NEG, e); 1433 case '~': 1434 get_next_token(); 1435 e = parse_expr2(parser_gas); 1436 if (!e) 1437 return NULL; 1438 return p_expr_new_branch(YASM_EXPR_NOT, e); 1439 case '(': 1440 get_next_token(); 1441 e = parse_expr(parser_gas); 1442 if (!e) 1443 return NULL; 1444 if (!expect(')')) { 1445 yasm_error_set(YASM_ERROR_SYNTAX, N_("missing parenthesis")); 1446 return NULL; 1447 } 1448 get_next_token(); 1449 return e; 1450 case INTNUM: 1451 e = p_expr_new_ident(yasm_expr_int(INTNUM_val)); 1452 get_next_token(); 1453 return e; 1454 case FLTNUM: 1455 e = p_expr_new_ident(yasm_expr_float(FLTNUM_val)); 1456 get_next_token(); 1457 return e; 1458 case ID: 1459 { 1460 char *name = ID_val; 1461 get_next_token(); /* ID */ 1462 1463 /* "." references the current assembly position */ 1464 if (name[1] == '\0' && name[0] == '.') 1465 sym = yasm_symtab_define_curpos(p_symtab, ".", 1466 parser_gas->prev_bc, cur_line); 1467 else 1468 sym = yasm_symtab_use(p_symtab, name, cur_line); 1469 yasm_xfree(name); 1470 1471 if (curtok == '@') { 1472 yasm_symrec *wrt; 1473 /* TODO: this is needed for shared objects, e.g. sym@PLT */ 1474 get_next_token(); /* '@' */ 1475 if (!expect(ID)) { 1476 yasm_error_set(YASM_ERROR_SYNTAX, 1477 N_("expected identifier after `@'")); 1478 return NULL; 1479 } 1480 wrt = yasm_objfmt_get_special_sym(p_object, ID_val, "gas"); 1481 yasm_xfree(ID_val); 1482 get_next_token(); /* ID */ 1483 if (!wrt) { 1484 yasm_warn_set(YASM_WARN_GENERAL, 1485 N_("unrecognized identifier after `@'")); 1486 return p_expr_new_ident(yasm_expr_sym(sym)); 1487 } 1488 return p_expr_new(yasm_expr_sym(sym), YASM_EXPR_WRT, 1489 yasm_expr_sym(wrt)); 1490 } 1491 1492 return p_expr_new_ident(yasm_expr_sym(sym)); 1493 } 1494 default: 1495 return NULL; 1496 } 1497 } 1498 1499 static void 1500 define_label(yasm_parser_gas *parser_gas, char *name, int local) 1501 { 1502 if (!local) { 1503 if (parser_gas->locallabel_base) 1504 yasm_xfree(parser_gas->locallabel_base); 1505 parser_gas->locallabel_base_len = strlen(name); 1506 parser_gas->locallabel_base = 1507 yasm_xmalloc(parser_gas->locallabel_base_len+1); 1508 strcpy(parser_gas->locallabel_base, name); 1509 } 1510 1511 yasm_symtab_define_label(p_symtab, name, parser_gas->prev_bc, 1, 1512 cur_line); 1513 yasm_xfree(name); 1514 } 1515 1516 static void 1517 define_lcomm(yasm_parser_gas *parser_gas, /*@only@*/ char *name, 1518 yasm_expr *size, /*@null@*/ yasm_expr *align) 1519 { 1520 /* Put into .bss section. */ 1521 /*@dependent@*/ yasm_section *bss = 1522 gas_get_section(parser_gas, yasm__xstrdup(".bss"), NULL, NULL, NULL, 1); 1523 1524 if (align) { 1525 /* XXX: assume alignment is in bytes, not power-of-two */ 1526 yasm_section_bcs_append(bss, gas_parser_align(parser_gas, bss, align, 1527 NULL, NULL, 0)); 1528 } 1529 1530 yasm_symtab_define_label(p_symtab, name, yasm_section_bcs_last(bss), 1, 1531 cur_line); 1532 yasm_section_bcs_append(bss, yasm_bc_create_reserve(size, 1, cur_line)); 1533 yasm_xfree(name); 1534 } 1535 1536 static yasm_section * 1537 gas_get_section(yasm_parser_gas *parser_gas, char *name, 1538 /*@null@*/ char *flags, /*@null@*/ char *type, 1539 /*@null@*/ yasm_valparamhead *objext_valparams, 1540 int builtin) 1541 { 1542 yasm_valparamhead vps; 1543 yasm_valparam *vp; 1544 char *gasflags; 1545 yasm_section *new_section; 1546 1547 yasm_vps_initialize(&vps); 1548 vp = yasm_vp_create_id(NULL, name, '\0'); 1549 yasm_vps_append(&vps, vp); 1550 1551 if (!builtin) { 1552 if (flags) 1553 gasflags = yasm__xstrdup(flags); 1554 else 1555 gasflags = yasm__xstrdup(""); 1556 vp = yasm_vp_create_string(yasm__xstrdup("gasflags"), gasflags); 1557 yasm_vps_append(&vps, vp); 1558 if (type) { 1559 vp = yasm_vp_create_id(NULL, type, '\0'); 1560 yasm_vps_append(&vps, vp); 1561 } 1562 } 1563 1564 new_section = yasm_objfmt_section_switch(p_object, &vps, objext_valparams, 1565 cur_line); 1566 1567 yasm_vps_delete(&vps); 1568 return new_section; 1569 } 1570 1571 static void 1572 gas_switch_section(yasm_parser_gas *parser_gas, const char *name, 1573 /*@null@*/ char *flags, /*@null@*/ char *type, 1574 /*@null@*/ yasm_valparamhead *objext_valparams, 1575 int builtin) 1576 { 1577 yasm_section *new_section; 1578 1579 new_section = gas_get_section(parser_gas, yasm__xstrdup(name), flags, type, 1580 objext_valparams, builtin); 1581 if (new_section) { 1582 cursect = new_section; 1583 parser_gas->prev_bc = yasm_section_bcs_last(new_section); 1584 } else 1585 yasm_error_set(YASM_ERROR_GENERAL, N_("invalid section name `%s'"), 1586 name); 1587 1588 if (objext_valparams) 1589 yasm_vps_delete(objext_valparams); 1590 } 1591 1592 static yasm_bytecode * 1593 gas_parser_align(yasm_parser_gas *parser_gas, yasm_section *sect, 1594 yasm_expr *boundval, /*@null@*/ yasm_expr *fillval, 1595 /*@null@*/ yasm_expr *maxskipval, int power2) 1596 { 1597 yasm_intnum *boundintn; 1598 1599 /* Convert power of two to number of bytes if necessary */ 1600 if (power2) 1601 boundval = yasm_expr_create(YASM_EXPR_SHL, 1602 yasm_expr_int(yasm_intnum_create_uint(1)), 1603 yasm_expr_expr(boundval), cur_line); 1604 1605 /* Largest .align in the section specifies section alignment. */ 1606 boundintn = yasm_expr_get_intnum(&boundval, 0); 1607 if (boundintn) { 1608 unsigned long boundint = yasm_intnum_get_uint(boundintn); 1609 1610 /* Alignments must be a power of two. */ 1611 if (is_exp2(boundint)) { 1612 if (boundint > yasm_section_get_align(sect)) 1613 yasm_section_set_align(sect, boundint, cur_line); 1614 } 1615 } 1616 1617 return yasm_bc_create_align(boundval, fillval, maxskipval, 1618 yasm_section_is_code(sect) ? 1619 yasm_arch_get_fill(p_object->arch) : NULL, 1620 cur_line); 1621 } 1622 1623 static yasm_bytecode * 1624 gas_parser_dir_fill(yasm_parser_gas *parser_gas, /*@only@*/ yasm_expr *repeat, 1625 /*@only@*/ /*@null@*/ yasm_expr *size, 1626 /*@only@*/ /*@null@*/ yasm_expr *value) 1627 { 1628 yasm_datavalhead dvs; 1629 yasm_bytecode *bc; 1630 unsigned int ssize; 1631 1632 if (size) { 1633 /*@dependent@*/ /*@null@*/ yasm_intnum *intn; 1634 intn = yasm_expr_get_intnum(&size, 0); 1635 if (!intn) { 1636 yasm_error_set(YASM_ERROR_NOT_ABSOLUTE, 1637 N_("size must be an absolute expression")); 1638 yasm_expr_destroy(repeat); 1639 yasm_expr_destroy(size); 1640 if (value) 1641 yasm_expr_destroy(value); 1642 return NULL; 1643 } 1644 ssize = yasm_intnum_get_uint(intn); 1645 } else 1646 ssize = 1; 1647 1648 if (!value) 1649 value = yasm_expr_create_ident( 1650 yasm_expr_int(yasm_intnum_create_uint(0)), cur_line); 1651 1652 yasm_dvs_initialize(&dvs); 1653 yasm_dvs_append(&dvs, yasm_dv_create_expr(value)); 1654 bc = yasm_bc_create_data(&dvs, ssize, 0, p_object->arch, cur_line); 1655 1656 yasm_bc_set_multiple(bc, repeat); 1657 1658 return bc; 1659 } 1660 1661 static dir_lookup dirs_static[] = { 1662 /* FIXME: Whether this is power-of-two or not depends on arch and objfmt. */ 1663 {".align", dir_align, 0, INITIAL}, 1664 {".p2align", dir_align, 1, INITIAL}, 1665 {".balign", dir_align, 0, INITIAL}, 1666 {".org", dir_org, 0, INITIAL}, 1667 /* data visibility directives */ 1668 {".local", dir_local, 0, INITIAL}, 1669 {".comm", dir_comm, 0, INITIAL}, 1670 {".lcomm", dir_comm, 1, INITIAL}, 1671 /* integer data declaration directives */ 1672 {".byte", dir_data, 1, INITIAL}, 1673 {".2byte", dir_data, 2, INITIAL}, 1674 {".4byte", dir_data, 4, INITIAL}, 1675 {".8byte", dir_data, 8, INITIAL}, 1676 {".16byte", dir_data, 16, INITIAL}, 1677 /* TODO: These should depend on arch */ 1678 {".short", dir_data, 2, INITIAL}, 1679 {".int", dir_data, 4, INITIAL}, 1680 {".long", dir_data, 4, INITIAL}, 1681 {".hword", dir_data, 2, INITIAL}, 1682 {".quad", dir_data, 8, INITIAL}, 1683 {".octa", dir_data, 16, INITIAL}, 1684 /* XXX: At least on x86, this is 2 bytes */ 1685 {".value", dir_data, 2, INITIAL}, 1686 /* ASCII data declaration directives */ 1687 {".ascii", dir_ascii, 0, INITIAL}, /* no terminating zero */ 1688 {".asciz", dir_ascii, 1, INITIAL}, /* add terminating zero */ 1689 {".string", dir_ascii, 1, INITIAL}, /* add terminating zero */ 1690 /* LEB128 integer data declaration directives */ 1691 {".sleb128", dir_leb128, 1, INITIAL}, /* signed */ 1692 {".uleb128", dir_leb128, 0, INITIAL}, /* unsigned */ 1693 /* floating point data declaration directives */ 1694 {".float", dir_data, 4, INITIAL}, 1695 {".single", dir_data, 4, INITIAL}, 1696 {".double", dir_data, 8, INITIAL}, 1697 {".tfloat", dir_data, 10, INITIAL}, 1698 /* section directives */ 1699 {".bss", dir_bss_section, 0, INITIAL}, 1700 {".data", dir_data_section, 0, INITIAL}, 1701 {".text", dir_text_section, 0, INITIAL}, 1702 {".section", dir_section, 0, SECTION_DIRECTIVE}, 1703 /* empty space/fill directives */ 1704 {".skip", dir_skip, 0, INITIAL}, 1705 {".space", dir_skip, 0, INITIAL}, 1706 {".fill", dir_fill, 0, INITIAL}, 1707 {".zero", dir_zero, 0, INITIAL}, 1708 /* syntax directives */ 1709 {".intel_syntax", dir_intel_syntax, 0, INITIAL}, 1710 {".att_syntax", dir_att_syntax, 0, INITIAL}, 1711 /* other directives */ 1712 {".equ", dir_equ, 0, INITIAL}, 1713 {".file", dir_file, 0, INITIAL}, 1714 {".line", dir_line, 0, INITIAL}, 1715 {".set", dir_equ, 0, INITIAL} 1716 }; 1717 1718 static void 1719 no_delete(void *data) 1720 { 1721 } 1722 1723 void 1724 gas_parser_parse(yasm_parser_gas *parser_gas) 1725 { 1726 dir_lookup word; 1727 unsigned int i; 1728 int replace = 1; 1729 1730 word.name = ".word"; 1731 word.handler = dir_data; 1732 word.param = yasm_arch_wordsize(p_object->arch)/8; 1733 word.newstate = INITIAL; 1734 1735 /* Create directive lookup */ 1736 parser_gas->dirs = HAMT_create(1, yasm_internal_error_); 1737 HAMT_insert(parser_gas->dirs, word.name, &word, &replace, no_delete); 1738 for (i=0; i<NELEMS(dirs_static); i++) { 1739 replace = 1; 1740 HAMT_insert(parser_gas->dirs, dirs_static[i].name, 1741 &dirs_static[i], &replace, no_delete); 1742 } 1743 1744 while (get_next_token() != 0) { 1745 yasm_bytecode *bc = NULL, *temp_bc; 1746 1747 if (!is_eol()) { 1748 bc = parse_line(parser_gas); 1749 demand_eol(); 1750 } 1751 1752 yasm_errwarn_propagate(parser_gas->errwarns, cur_line); 1753 1754 temp_bc = yasm_section_bcs_append(cursect, bc); 1755 if (temp_bc) 1756 parser_gas->prev_bc = temp_bc; 1757 if (curtok == ';') 1758 continue; /* don't advance line number until \n */ 1759 if (parser_gas->save_input) 1760 yasm_linemap_add_source(parser_gas->linemap, 1761 temp_bc, 1762 (char *)parser_gas->save_line[parser_gas->save_last ^ 1]); 1763 yasm_linemap_goto_next(parser_gas->linemap); 1764 parser_gas->dir_line++; /* keep track for .line followed by .file */ 1765 } 1766 1767 HAMT_destroy(parser_gas->dirs, no_delete); 1768 } 1769