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