1 { 2 Copyright (c) 1998-2002 by Carl Eric Codere and Peter Vreman 3 Copyright (c) 2014 by Jonas Maebe 4 5 Does the parsing for the AArch64 GNU AS styled inline assembler. 6 7 This program is free software; you can redistribute it and/or modify 8 it under the terms of the GNU General Public License as published by 9 the Free Software Foundation; either version 2 of the License, or 10 (at your option) any later version. 11 12 This program is distributed in the hope that it will be useful, 13 but WITHOUT ANY WARRANTY; without even the implied warranty of 14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 GNU General Public License for more details. 16 17 You should have received a copy of the GNU General Public License 18 along with this program; if not, write to the Free Software 19 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 20 21 **************************************************************************** 22 } 23 Unit racpugas; 24 25 {$i fpcdefs.inc} 26 27 Interface 28 29 uses 30 raatt,racpu, 31 cpubase; 32 33 type 34 taarch64attreader = class(tattreader) 35 actoppostfix : TOpPostfix; is_asmopcodenull36 function is_asmopcode(const s: string):boolean;override; is_registernull37 function is_register(const s:string):boolean;override; 38 procedure handleopcode;override; 39 procedure BuildReference(oper: taarch64operand; is64bit: boolean); 40 procedure BuildOperand(oper: taarch64operand; is64bit: boolean); TryBuildShifterOpnull41 function TryBuildShifterOp(instr: taarch64instruction; opnr: longint) : boolean; 42 procedure BuildOpCode(instr: taarch64instruction); 43 procedure ReadSym(oper: taarch64operand; is64bit: boolean); 44 procedure ConvertCalljmp(instr: taarch64instruction); ToConditionCodenull45 function ToConditionCode(const hs: string; is_operand: boolean): tasmcond; 46 end; 47 48 49 Implementation 50 51 uses 52 { helpers } 53 cutils, 54 { global } 55 globtype,verbose, 56 systems,aasmbase,aasmtai,aasmdata,aasmcpu, 57 { symtable } 58 symconst,symsym,symdef, 59 procinfo, 60 rabase,rautils, 61 cgbase,cgutils,paramgr; 62 63 taarch64attreader.is_registernull64 function taarch64attreader.is_register(const s:string):boolean; 65 type 66 treg2str = record 67 name : string[3]; 68 reg : tregister; 69 end; 70 71 const 72 extraregs : array[0..3] of treg2str = ( 73 (name: 'FP' ; reg: NR_FP), 74 (name: 'LR' ; reg: NR_LR), 75 (name: 'IP0'; reg: NR_IP0), 76 (name: 'IP1'; reg: NR_IP1)); 77 78 var 79 i : longint; 80 81 begin 82 result:=inherited is_register(s); 83 { reg found? 84 possible aliases are always 2 or 3 chars 85 } 86 if result or not(length(s) in [2,3]) then 87 exit; 88 for i:=low(extraregs) to high(extraregs) do 89 begin 90 if s=extraregs[i].name then 91 begin 92 actasmregister:=extraregs[i].reg; 93 result:=true; 94 actasmtoken:=AS_REGISTER; 95 exit; 96 end; 97 end; 98 end; 99 100 101 procedure taarch64attreader.ReadSym(oper: taarch64operand; is64bit: boolean); 102 var 103 tempstr, mangledname : string; 104 typesize,l,k: aint; 105 begin 106 tempstr:=actasmpattern; 107 Consume(AS_ID); 108 { typecasting? } 109 if (actasmtoken=AS_LPAREN) and 110 SearchType(tempstr,typesize) then 111 begin 112 oper.hastype:=true; 113 Consume(AS_LPAREN); 114 BuildOperand(oper,is64bit); 115 Consume(AS_RPAREN); 116 if oper.opr.typ in [OPR_REFERENCE,OPR_LOCAL] then 117 oper.SetSize(typesize,true); 118 end 119 else 120 if not oper.SetupVar(tempstr,false) then 121 Message1(sym_e_unknown_id,tempstr); 122 { record.field ? } 123 if actasmtoken=AS_DOT then 124 begin 125 BuildRecordOffsetSize(tempstr,l,k,mangledname,false); 126 if (mangledname<>'') then 127 Message(asmr_e_invalid_reference_syntax); 128 inc(oper.opr.ref.offset,l); 129 end; 130 end; 131 132 133 Procedure taarch64attreader.BuildReference(oper: taarch64operand; is64bit: boolean); 134 135 procedure do_error; 136 begin 137 Message(asmr_e_invalid_reference_syntax); 138 RecoverConsume(false); 139 end; 140 141 142 procedure test_end(require_rbracket : boolean); 143 begin 144 if require_rbracket then begin 145 if not(actasmtoken=AS_RBRACKET) then 146 begin 147 do_error; 148 exit; 149 end 150 else 151 Consume(AS_RBRACKET); 152 if (actasmtoken=AS_NOT) then 153 begin 154 oper.opr.ref.addressmode:=AM_PREINDEXED; 155 Consume(AS_NOT); 156 end; 157 end; 158 if not(actasmtoken in [AS_SEPARATOR,AS_end]) then 159 do_error 160 else 161 begin 162 {$IFDEF debugasmreader} 163 writeln('TEST_end_FINAL_OK. Created the following ref:'); 164 writeln('oper.opr.ref.shiftimm=',oper.opr.ref.shiftimm); 165 writeln('oper.opr.ref.shiftmode=',ord(oper.opr.ref.shiftmode)); 166 writeln('oper.opr.ref.index=',ord(oper.opr.ref.index)); 167 writeln('oper.opr.ref.base=',ord(oper.opr.ref.base)); 168 writeln('oper.opr.ref.signindex=',ord(oper.opr.ref.signindex)); 169 writeln('oper.opr.ref.addressmode=',ord(oper.opr.ref.addressmode)); 170 writeln; 171 {$endIF debugasmreader} 172 end; 173 end; 174 175 is_shifter_ref_operationnull176 function is_shifter_ref_operation(var a : tshiftmode) : boolean; 177 begin 178 a:=SM_NONE; 179 if (actasmpattern='LSL') then 180 a:=SM_LSL 181 else if (actasmpattern='UXTW') then 182 a:=SM_UXTW 183 else if (actasmpattern='SXTW') then 184 a:=SM_SXTW 185 else if (actasmpattern='SXTX') then 186 a:=SM_SXTX; 187 is_shifter_ref_operation:=not(a=SM_NONE); 188 end; 189 190 191 procedure read_index_shift(require_rbracket : boolean); 192 var 193 shift: aint; 194 begin 195 case actasmtoken of 196 AS_COMMA : 197 begin 198 Consume(AS_COMMA); 199 if not(actasmtoken=AS_ID) then 200 do_error; 201 if is_shifter_ref_operation(oper.opr.ref.shiftmode) then 202 begin 203 Consume(actasmtoken); 204 if actasmtoken=AS_HASH then 205 begin 206 Consume(AS_HASH); 207 shift:=BuildConstExpression(false,true); 208 if not(shift in [0,2+ord(is64bit)]) then 209 do_error; 210 oper.opr.ref.shiftimm:=shift; 211 test_end(require_rbracket); 212 end; 213 end 214 else 215 begin 216 do_error; 217 exit; 218 end; 219 end; 220 AS_RBRACKET : 221 if require_rbracket then 222 test_end(require_rbracket) 223 else 224 begin 225 do_error; 226 exit; 227 end; 228 AS_SEPARATOR,AS_END : 229 if not require_rbracket then 230 test_end(false) 231 else 232 do_error; 233 else 234 begin 235 do_error; 236 exit; 237 end; 238 end; 239 end; 240 241 242 procedure read_index(require_rbracket : boolean); 243 var 244 recname : string; 245 o_int,s_int : aint; 246 begin 247 case actasmtoken of 248 AS_REGISTER : 249 begin 250 if getsupreg(actasmregister)=RS_XZR then 251 Message1(asmr_e_invalid_ref_register,actasmpattern); 252 oper.opr.ref.index:=actasmregister; 253 Consume(AS_REGISTER); 254 read_index_shift(require_rbracket); 255 exit; 256 end; 257 AS_HASH : // constant 258 begin 259 Consume(AS_HASH); 260 (* 261 if actasmtoken=AS_COLON then 262 begin 263 consume(AS_COLON); 264 { GNU-style lower 12 bits of address of non-GOT-based 265 access } 266 if (actasmpattern='LO12') then 267 begin 268 consume(actasmtoken); 269 consume(AS_COLON); 270 if not oper.SetupVar(actasmpattern,false) then 271 begin 272 do_error; 273 exit 274 end; 275 consume(AS_ID); 276 oper.opr.ref.refaddr:=addr_??? (not gotpageoffset); 277 end 278 else 279 begin 280 do_error; 281 exit 282 end; 283 end 284 else 285 *) 286 begin 287 o_int:=BuildConstExpression(false,true); 288 inc(oper.opr.ref.offset,o_int); 289 end; 290 test_end(require_rbracket); 291 exit; 292 end; 293 AS_ID : 294 begin 295 recname:=actasmpattern; 296 Consume(AS_ID); 297 { Apple-style got page offset } 298 if actasmtoken=AS_AT then 299 begin 300 if not oper.SetupVar(recname,false) then 301 begin 302 do_error; 303 exit 304 end; 305 consume(AS_AT); 306 if actasmpattern='GOTPAGEOFF' then 307 begin 308 consume(actasmtoken); 309 oper.opr.ref.refaddr:=addr_gotpageoffset; 310 end 311 else if actasmpattern='PAGEOFF' then 312 begin 313 consume(actasmtoken); 314 oper.opr.ref.refaddr:=addr_pageoffset; 315 end 316 else 317 begin 318 do_error; 319 exit 320 end; 321 end 322 else 323 begin 324 BuildRecordOffsetSize(recname,o_int,s_int,recname,false); 325 inc(oper.opr.ref.offset,o_int); 326 end; 327 test_end(require_rbracket); 328 exit; 329 end; 330 AS_AT: 331 begin 332 do_error; 333 exit; 334 end; 335 AS_RBRACKET : 336 begin 337 if require_rbracket then 338 begin 339 test_end(require_rbracket); 340 exit; 341 end 342 else 343 begin 344 do_error; // unexpected rbracket 345 exit; 346 end; 347 end; 348 AS_SEPARATOR,AS_end : 349 begin 350 if not require_rbracket then 351 begin 352 test_end(false); 353 exit; 354 end 355 else 356 begin 357 do_error; 358 exit; 359 end; 360 end; 361 else 362 begin 363 // unexpected token 364 do_error; 365 exit; 366 end; 367 end; // case 368 end; 369 370 371 procedure try_prepostindexed; 372 begin 373 Consume(AS_RBRACKET); 374 case actasmtoken of 375 AS_COMMA : 376 begin // post-indexed 377 Consume(AS_COMMA); 378 oper.opr.ref.addressmode:=AM_POSTINDEXED; 379 read_index(false); 380 exit; 381 end; 382 AS_NOT : 383 begin // pre-indexed 384 Consume(AS_NOT); 385 oper.opr.ref.addressmode:=AM_PREINDEXED; 386 test_end(false); 387 exit; 388 end; 389 else 390 begin 391 test_end(false); 392 exit; 393 end; 394 end; // case 395 end; 396 397 begin 398 Consume(AS_LBRACKET); 399 oper.opr.ref.addressmode:=AM_OFFSET; // assume "neither PRE nor POST inc" 400 if actasmtoken=AS_REGISTER then 401 begin 402 if getsupreg(actasmregister)=RS_XZR then 403 Message1(asmr_e_invalid_ref_register,actasmpattern); 404 oper.opr.ref.base:=actasmregister; 405 Consume(AS_REGISTER); 406 case actasmtoken of 407 AS_RBRACKET : 408 begin 409 try_prepostindexed; 410 exit; 411 end; 412 AS_COMMA : 413 begin 414 Consume(AS_COMMA); 415 read_index(true); 416 exit; 417 end; 418 else 419 begin 420 Message(asmr_e_invalid_reference_syntax); 421 RecoverConsume(false); 422 end; 423 end; 424 end 425 else 426 Begin 427 case actasmtoken of 428 AS_ID : 429 begin 430 { TODO: local variables and parameters } 431 Message(asmr_e_invalid_reference_syntax); 432 RecoverConsume(false); 433 exit; 434 end; 435 else 436 begin // elsecase 437 Message(asmr_e_invalid_reference_syntax); 438 RecoverConsume(false); 439 exit; 440 end; 441 end; 442 end; 443 end; 444 445 taarch64attreader.TryBuildShifterOpnull446 function taarch64attreader.TryBuildShifterOp(instr: taarch64instruction; opnr: longint): boolean; 447 448 procedure handlepara(sm : tshiftmode); 449 begin 450 consume(AS_ID); 451 fillchar(instr.operands[opnr].opr,sizeof(instr.operands[opnr].opr),0); 452 instr.operands[opnr].opr.typ:=OPR_SHIFTEROP; 453 instr.operands[opnr].opr.shifterop.shiftmode:=sm; 454 if (sm=SM_LSL) or 455 (actasmtoken=AS_HASH) then 456 begin 457 consume(AS_HASH); 458 instr.operands[opnr].opr.shifterop.shiftimm:=BuildConstExpression(false,false); 459 end; 460 end; 461 462 const 463 shiftmode2str: array[SM_LSL..SM_SXTX] of string[4] = 464 ('LSL','LSR','ASR', 465 'UXTB','UXTH','UXTW','UXTX', 466 'SXTB','SXTH','SXTW','SXTX'); 467 var 468 sm: tshiftmode; 469 i: longint; 470 usessp, 471 useszr: boolean; 472 begin 473 result:=false; 474 if (actasmtoken=AS_ID) then 475 begin 476 for sm:=low(shiftmode2str) to high(shiftmode2str) do 477 if actasmpattern=shiftmode2str[sm] then 478 begin 479 handlepara(sm); 480 if instr.operands[1].opr.typ=OPR_REGISTER then 481 begin 482 { the possible shifter ops depend on whether this 483 instruction uses sp and/or zr } 484 usessp:=false; 485 useszr:=false; 486 for i:=low(instr.operands) to pred(opnr) do 487 begin 488 if (instr.operands[i].opr.typ=OPR_REGISTER) then 489 case getsupreg(instr.operands[i].opr.reg) of 490 RS_XZR: 491 useszr:=true; 492 RS_SP: 493 usessp:=true; 494 end; 495 end; 496 result:=valid_shifter_operand(instr.opcode,useszr,usessp,instr.Is64bit,sm,instr.operands[opnr].opr.shifterop.shiftimm); 497 if result then 498 instr.Ops:=opnr; 499 end; 500 break; 501 end; 502 end; 503 end; 504 505 taarch64attreader.ToConditionCodenull506 function taarch64attreader.ToConditionCode(const hs: string; is_operand: boolean): tasmcond; 507 begin 508 case actopcode of 509 A_CSEL,A_CSINC,A_CSINV,A_CSNEG,A_CSET,A_CSETM, 510 A_CINC,A_CINV,A_CNEG,A_CCMN,A_CCMP, 511 A_B: 512 begin 513 { search for condition, conditions are always 2 chars } 514 if (is_operand<>(actopcode=A_B)) and 515 (length(hs)>1) then 516 begin 517 { workaround for DFA bug } 518 result:=low(tasmcond); 519 for result:=low(tasmcond) to high(tasmcond) do 520 begin 521 if hs=uppercond2str[result] then 522 exit; 523 end; 524 end; 525 end; 526 end; 527 result:=C_None;; 528 end; 529 530 531 Procedure taarch64attreader.BuildOperand(oper: taarch64operand; is64bit: boolean); 532 var 533 expr: string; 534 typesize, l: aint; 535 536 procedure MaybeAddGotAddrMode; 537 begin 538 if actasmtoken=AS_AT then 539 begin 540 consume(AS_AT); 541 if actasmpattern='GOTPAGE' then 542 oper.opr.ref.refaddr:=addr_gotpage 543 else if actasmpattern='GOTPAGEOFF' then 544 oper.opr.ref.refaddr:=addr_gotpageoffset 545 else if actasmpattern='PAGE' then 546 oper.opr.ref.refaddr:=addr_page 547 else if actasmpattern='PAGEOFF' then 548 oper.opr.ref.refaddr:=addr_pageoffset 549 else 550 Message(asmr_e_expr_illegal); 551 consume(actasmtoken); 552 end 553 else 554 oper.opr.ref.refaddr:=addr_pic; 555 end; 556 557 procedure AddLabelOperand(hl:tasmlabel); 558 begin 559 if not(actasmtoken in [AS_PLUS,AS_MINUS,AS_LPAREN]) and 560 is_calljmp(actopcode) then 561 begin 562 oper.opr.typ:=OPR_SYMBOL; 563 oper.opr.symbol:=hl; 564 end 565 else if (actopcode=A_ADR) or 566 (actopcode=A_ADRP) or 567 (actopcode=A_LDR) then 568 begin 569 oper.InitRef; 570 MaybeAddGotAddrMode; 571 oper.opr.ref.symbol:=hl; 572 if (actasmtoken in [AS_PLUS, AS_MINUS]) then 573 begin 574 l:=BuildConstExpression(true,false); 575 oper.opr.ref.offset:=l; 576 end; 577 end; 578 end; 579 580 581 procedure MaybeRecordOffset; 582 var 583 mangledname: string; 584 hasdot : boolean; 585 l, 586 toffset, 587 tsize : aint; 588 begin 589 if not(actasmtoken in [AS_DOT,AS_PLUS,AS_MINUS]) then 590 exit; 591 l:=0; 592 mangledname:=''; 593 hasdot:=(actasmtoken=AS_DOT); 594 if hasdot then 595 begin 596 if expr<>'' then 597 begin 598 BuildRecordOffsetSize(expr,toffset,tsize,mangledname,false); 599 if (oper.opr.typ<>OPR_CONSTANT) and 600 (mangledname<>'') then 601 Message(asmr_e_wrong_sym_type); 602 inc(l,toffset); 603 oper.SetSize(tsize,true); 604 end; 605 end; 606 if actasmtoken in [AS_PLUS,AS_MINUS] then 607 inc(l,BuildConstExpression(true,false)); 608 case oper.opr.typ of 609 OPR_LOCAL : 610 begin 611 { don't allow direct access to fields of parameters, because that 612 will generate buggy code. Allow it only for explicit typecasting } 613 if hasdot and 614 (not oper.hastype) then 615 checklocalsubscript(oper.opr.localsym); 616 inc(oper.opr.localsymofs,l) 617 end; 618 OPR_CONSTANT : 619 inc(oper.opr.val,l); 620 OPR_REFERENCE : 621 if (mangledname<>'') then 622 begin 623 if (oper.opr.val<>0) then 624 Message(asmr_e_wrong_sym_type); 625 oper.opr.typ:=OPR_SYMBOL; 626 oper.opr.symbol:=current_asmdata.RefAsmSymbol(mangledname,AT_FUNCTION); endnull627 end 628 else 629 inc(oper.opr.val,l); 630 OPR_SYMBOL: 631 Message(asmr_e_invalid_symbol_ref); 632 else 633 internalerror(200309221); 634 end; 635 end; 636 637 MaybeBuildReferencenull638 function MaybeBuildReference(is64bit: boolean):boolean; 639 { Try to create a reference, if not a reference is found then false 640 is returned } 641 begin 642 MaybeBuildReference:=true; 643 case actasmtoken of 644 AS_INTNUM, 645 AS_MINUS, 646 AS_PLUS: 647 Begin 648 oper.opr.ref.offset:=BuildConstExpression(True,False); 649 if actasmtoken<>AS_LPAREN then 650 Message(asmr_e_invalid_reference_syntax) 651 else 652 BuildReference(oper,is64bit); 653 end; 654 AS_LPAREN: 655 BuildReference(oper,is64bit); 656 AS_ID: { only a variable is allowed ... } 657 Begin 658 ReadSym(oper,is64bit); 659 case actasmtoken of 660 AS_end, 661 AS_SEPARATOR, 662 AS_COMMA: ; 663 AS_LPAREN: 664 BuildReference(oper,is64bit); 665 else 666 Begin 667 Message(asmr_e_invalid_reference_syntax); 668 Consume(actasmtoken); 669 end; 670 end; {end case } 671 end; 672 else 673 MaybeBuildReference:=false; 674 end; { end case } 675 end; 676 677 678 var 679 tempreg: tregister; 680 hl: tasmlabel; 681 icond: tasmcond; 682 Begin 683 expr:=''; 684 case actasmtoken of 685 AS_LBRACKET: { Memory reference or constant expression } 686 Begin 687 oper.InitRef; 688 BuildReference(oper,is64bit); 689 end; 690 691 AS_HASH: { Constant expression } 692 Begin 693 Consume(AS_HASH); 694 BuildConstantOperand(oper); 695 end; 696 697 (* 698 AS_INTNUM, 699 AS_MINUS, 700 AS_PLUS: 701 Begin 702 { Constant memory offset } 703 { This must absolutely be followed by ( } 704 oper.InitRef; 705 oper.opr.ref.offset:=BuildConstExpression(True,False); 706 if actasmtoken<>AS_LPAREN then 707 begin 708 ofs:=oper.opr.ref.offset; 709 BuildConstantOperand(oper); 710 inc(oper.opr.val,ofs); 711 end 712 else 713 BuildReference(oper,is64bit); 714 end; 715 *) 716 AS_ID: { A constant expression, or a Variable ref. } 717 Begin 718 { Condition code? } 719 icond:=ToConditionCode(actasmpattern,true); 720 if icond<>C_None then 721 begin 722 oper.opr.typ:=OPR_COND; 723 oper.opr.cc:=icond; 724 consume(AS_ID); 725 end 726 else 727 { Local Label ? } 728 if is_locallabel(actasmpattern) then 729 begin 730 CreateLocalLabel(actasmpattern,hl,false); 731 Consume(AS_ID); 732 AddLabelOperand(hl); 733 end 734 else 735 { Check for label } 736 if SearchLabel(actasmpattern,hl,false) then 737 begin 738 Consume(AS_ID); 739 AddLabelOperand(hl); 740 end 741 else 742 { probably a variable or normal expression } 743 { or a procedure (such as in CALL ID) } 744 begin 745 { is it a constant ? } 746 if SearchIConstant(actasmpattern,l) then 747 begin 748 if not (oper.opr.typ in [OPR_NONE,OPR_CONSTANT]) then 749 Message(asmr_e_invalid_operand_type); 750 BuildConstantOperand(oper); 751 end 752 else 753 begin 754 expr:=actasmpattern; 755 Consume(AS_ID); 756 { typecasting? } 757 if (actasmtoken=AS_LPAREN) and 758 SearchType(expr,typesize) then 759 begin 760 oper.hastype:=true; 761 Consume(AS_LPAREN); 762 BuildOperand(oper,is64bit); 763 Consume(AS_RPAREN); 764 if oper.opr.typ in [OPR_REFERENCE,OPR_LOCAL] then 765 oper.SetSize(typesize,true); 766 end 767 else 768 begin 769 if not(oper.SetupVar(expr,false)) then 770 Begin 771 { look for special symbols ... } 772 if expr= '__HIGH' then 773 begin 774 consume(AS_LPAREN); 775 if not oper.setupvar('high'+actasmpattern,false) then 776 Message1(sym_e_unknown_id,'high'+actasmpattern); 777 consume(AS_ID); 778 consume(AS_RPAREN); 779 end 780 else 781 if expr = '__RESULT' then 782 oper.SetUpResult 783 else 784 if expr = '__SELF' then 785 oper.SetupSelf 786 else 787 if expr = '__OLDEBP' then 788 oper.SetupOldEBP 789 else 790 Message1(sym_e_unknown_id,expr); 791 end 792 else if oper.opr.typ<>OPR_LOCAL then 793 begin 794 oper.InitRef; 795 MaybeAddGotAddrMode; 796 end; 797 end; 798 end; 799 if actasmtoken=AS_DOT then 800 MaybeRecordOffset; 801 { add a constant expression? } 802 if (actasmtoken=AS_PLUS) then 803 begin 804 l:=BuildConstExpression(true,false); 805 case oper.opr.typ of 806 OPR_CONSTANT : 807 inc(oper.opr.val,l); 808 OPR_LOCAL : 809 inc(oper.opr.localsymofs,l); 810 OPR_REFERENCE : 811 inc(oper.opr.ref.offset,l); 812 else 813 internalerror(200309202); 814 end; 815 end 816 end; 817 { Do we have a indexing reference, then parse it also } 818 if actasmtoken=AS_LPAREN then 819 BuildReference(oper,is64bit); 820 end; 821 822 { Register, a variable reference or a constant reference } 823 AS_REGISTER: 824 Begin 825 { save the type of register used. } 826 tempreg:=actasmregister; 827 Consume(AS_REGISTER); 828 if (actasmtoken in [AS_end,AS_SEPARATOR,AS_COMMA]) then 829 Begin 830 if not (oper.opr.typ in [OPR_NONE,OPR_REGISTER]) then 831 Message(asmr_e_invalid_operand_type); 832 oper.opr.typ:=OPR_REGISTER; 833 oper.opr.reg:=tempreg; 834 end 835 else 836 Message(asmr_e_syn_operand); 837 end; 838 839 AS_end, 840 AS_SEPARATOR, 841 AS_COMMA: ; 842 else 843 Begin 844 Message(asmr_e_syn_operand); 845 Consume(actasmtoken); 846 end; 847 end; { end case } 848 end; 849 850 {***************************************************************************** 851 taarch64attreader 852 *****************************************************************************} 853 854 procedure taarch64attreader.BuildOpCode(instr: taarch64instruction); 855 var 856 operandnum : longint; 857 Begin 858 { opcode } 859 if (actasmtoken<>AS_OPCODE) then 860 Begin 861 Message(asmr_e_invalid_or_missing_opcode); 862 RecoverConsume(true); 863 exit; 864 end; 865 { Fill the instr object with the current state } 866 with instr do 867 begin 868 Opcode:=ActOpcode; 869 condition:=ActCondition; 870 oppostfix:=actoppostfix; 871 end; 872 Consume(AS_OPCODE); 873 874 { We are reading operands, so opcode will be an AS_ID } 875 operandnum:=1; 876 { Zero operand opcode ? } 877 if actasmtoken in [AS_SEPARATOR,AS_end] then 878 begin 879 instr.Ops:=0; 880 exit; 881 end; 882 { Read the operands } 883 repeat 884 case actasmtoken of 885 AS_COMMA: { Operand delimiter } 886 Begin 887 { operandnum and not operandnum+1, because tinstruction is 888 one-based and taicpu is zero-based) 889 } 890 if can_be_shifter_operand(instr.opcode,operandnum) then 891 begin 892 Consume(AS_COMMA); 893 if not TryBuildShifterOp(instr,operandnum+1) then 894 Message(asmr_e_illegal_shifterop_syntax); 895 Inc(operandnum); 896 end 897 else 898 begin 899 if operandnum>Max_Operands then 900 Message(asmr_e_too_many_operands) 901 else 902 Inc(operandnum); 903 Consume(AS_COMMA); 904 end; 905 end; 906 AS_SEPARATOR, 907 AS_end : { End of asm operands for this opcode } 908 begin 909 break; 910 end; 911 else 912 begin 913 BuildOperand(taarch64operand(instr.operands[operandnum]),instr.Is64bit); 914 instr.Ops:=operandnum; 915 if instr.operands[operandnum].opr.typ=OPR_REFERENCE then 916 if simple_ref_type(instr.opcode,instr.cgsize,instr.oppostfix,instr.operands[operandnum].opr.ref)<>sr_simple then 917 Message(asmr_e_invalid_reference_syntax); 918 ; 919 end; 920 end; { end case } 921 until false; 922 end; 923 924 taarch64attreader.is_asmopcodenull925 function taarch64attreader.is_asmopcode(const s: string):boolean; 926 927 const 928 { sorted by length so longer postfixes will match first } 929 postfix2strsorted : array[1..7] of string[3] = ( 930 'SB','SH','SW', 931 'B','H','W', 932 'S'); 933 934 postfixsorted : array[1..7] of TOpPostfix = ( 935 PF_SB,PF_SH,PF_SW, 936 PF_B,PF_H,PF_W, 937 PF_S); 938 939 var 940 j : longint; 941 hs : string; 942 maxlen : longint; 943 icond : tasmcond; 944 Begin 945 { making s a value parameter would break other assembler readers } 946 hs:=s; 947 is_asmopcode:=false; 948 949 { clear opcode } 950 actopcode:=A_None; 951 actcondition:=C_None; 952 953 { b.cond ? } 954 if (length(hs)=4) and 955 (hs[1]='B') and 956 (hs[2]='.') then 957 begin 958 actopcode:=A_B; 959 actasmtoken:=AS_OPCODE; 960 actcondition:=ToConditionCode(copy(hs,3,length(actasmpattern)-2),false); 961 if actcondition<>C_None then 962 is_asmopcode:=true; 963 exit; 964 end; 965 966 maxlen:=max(length(hs),7); 967 actopcode:=A_NONE; 968 for j:=maxlen downto 1 do 969 begin 970 actopcode:=tasmop(PtrUInt(iasmops.Find(copy(hs,1,j)))); 971 if actopcode<>A_NONE then 972 begin 973 actasmtoken:=AS_OPCODE; 974 { strip op code } 975 delete(hs,1,j); 976 break; 977 end; 978 end; 979 if actopcode=A_NONE then 980 exit; 981 982 { check for postfix } 983 if length(hs)>0 then 984 begin 985 for j:=low(postfixsorted) to high(postfixsorted) do 986 begin 987 if copy(hs,1,length(postfix2strsorted[j]))=postfix2strsorted[j] then 988 begin 989 actoppostfix:=postfixsorted[j]; 990 { strip postfix } 991 delete(hs,1,length(postfix2strsorted[j])); 992 break; 993 end; 994 end; 995 end; 996 { if we stripped all postfixes, it's a valid opcode } 997 is_asmopcode:=length(hs)=0; 998 end; 999 1000 1001 procedure taarch64attreader.ConvertCalljmp(instr: taarch64instruction); 1002 var 1003 newopr : toprrec; 1004 begin 1005 if instr.Operands[1].opr.typ=OPR_REFERENCE then 1006 begin 1007 newopr.typ:=OPR_SYMBOL; 1008 newopr.symbol:=instr.Operands[1].opr.ref.symbol; 1009 newopr.symofs:=instr.Operands[1].opr.ref.offset; 1010 if (instr.Operands[1].opr.ref.base<>NR_NO) or 1011 (instr.Operands[1].opr.ref.index<>NR_NO) or 1012 (instr.Operands[1].opr.ref.refaddr<>addr_pic) then 1013 Message(asmr_e_syn_operand); 1014 instr.Operands[1].opr:=newopr; 1015 end; 1016 end; 1017 1018 procedure taarch64attreader.handleopcode; 1019 var 1020 instr: taarch64instruction; 1021 begin 1022 instr:=taarch64instruction.Create(taarch64operand); 1023 BuildOpcode(instr); 1024 if is_calljmp(instr.opcode) then 1025 ConvertCalljmp(instr); 1026 { 1027 instr.AddReferenceSizes; 1028 instr.SetInstructionOpsize; 1029 instr.CheckOperandSizes; 1030 } 1031 instr.ConcatInstruction(curlist); 1032 instr.Free; 1033 actoppostfix:=PF_None; 1034 end; 1035 1036 1037 {***************************************************************************** 1038 Initialize 1039 *****************************************************************************} 1040 1041 const 1042 asmmode_arm_att_info : tasmmodeinfo = 1043 ( 1044 id : asmmode_arm_gas; 1045 idtxt : 'GAS'; 1046 casmreader : taarch64attreader; 1047 ); 1048 1049 asmmode_arm_standard_info : tasmmodeinfo = 1050 ( 1051 id : asmmode_standard; 1052 idtxt : 'STANDARD'; 1053 casmreader : taarch64attreader; 1054 ); 1055 1056 initialization 1057 RegisterAsmMode(asmmode_arm_att_info); 1058 RegisterAsmMode(asmmode_arm_standard_info); 1059 end. 1060