rax86att.pas 32 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967
  1. {
  2. Copyright (c) 1998-2002 by Carl Eric Codere and Peter Vreman
  3. Does the parsing for the x86 GNU AS styled inline assembler.
  4. This program is free software; you can redistribute it and/or modify
  5. it under the terms of the GNU General Public License as published by
  6. the Free Software Foundation; either version 2 of the License, or
  7. (at your option) any later version.
  8. This program is distributed in the hope that it will be useful,
  9. but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11. GNU General Public License for more details.
  12. You should have received a copy of the GNU General Public License
  13. along with this program; if not, write to the Free Software
  14. Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  15. ****************************************************************************
  16. }
  17. Unit rax86att;
  18. {$i fpcdefs.inc}
  19. Interface
  20. uses
  21. cpubase,
  22. raatt,rax86, rautils;
  23. type
  24. { tx86attreader }
  25. tx86attreader = class(tattreader)
  26. ActOpsize : topsize;
  27. function is_asmopcode(const s: string):boolean;override;
  28. procedure handleopcode;override;
  29. procedure BuildReference(oper : tx86operand);
  30. procedure BuildOperand(oper : tx86operand);
  31. procedure BuildOpCode(instr : tx86instruction);
  32. procedure handlepercent;override;
  33. protected
  34. procedure MaybeGetPICModifier(var oper: tx86operand);
  35. end;
  36. { Tx86attInstruction }
  37. Tx86attInstruction = class(Tx86Instruction)
  38. procedure AddReferenceSizes; override;
  39. procedure FixupOpcode;override;
  40. end;
  41. Implementation
  42. uses
  43. { helpers }
  44. cutils,
  45. { global }
  46. globtype,verbose,
  47. systems,
  48. { aasm }
  49. aasmbase,aasmtai,aasmdata,aasmcpu,
  50. { symtable }
  51. symconst,
  52. { parser }
  53. scanner,
  54. procinfo,
  55. itcpugas,
  56. rabase,
  57. cgbase
  58. ;
  59. { Tx86attInstruction }
  60. procedure Tx86attInstruction.AddReferenceSizes;
  61. var
  62. i: integer;
  63. begin
  64. if (Opsize <> S_NO) and
  65. (MemRefInfo(opcode).ExistsSSEAVX) and
  66. (MemRefInfo(opcode).MemRefSize in MemRefMultiples) then
  67. begin
  68. for i := 1 to ops do
  69. begin
  70. if operands[i].Opr.Typ in [OPR_REFERENCE, OPR_LOCAL] then
  71. begin
  72. if (tx86operand(operands[i]).opsize = S_NO) then
  73. tx86operand(operands[i]).opsize := Opsize;
  74. end;
  75. end;
  76. end;
  77. inherited AddReferenceSizes;
  78. end;
  79. procedure Tx86attInstruction.FixupOpcode;
  80. begin
  81. if (OpOrder=op_intel) then
  82. SwapOperands;
  83. case opcode of
  84. A_MOVQ:
  85. begin
  86. { May be either real 'movq' or a generic 'mov' with 'q' suffix. Convert to mov
  87. if source is a constant, or if neither operand is an mmx/xmm register }
  88. {$ifdef x86_64}
  89. if (ops=2) and
  90. (
  91. (operands[1].opr.typ=OPR_CONSTANT) or not
  92. (
  93. ((operands[1].opr.typ=OPR_REGISTER) and
  94. (getregtype(operands[1].opr.reg) in [R_MMXREGISTER,R_MMREGISTER])) or
  95. ((operands[2].opr.typ=OPR_REGISTER) and
  96. (getregtype(operands[2].opr.reg) in [R_MMXREGISTER,R_MMREGISTER]))
  97. )
  98. ) then
  99. opcode:=A_MOV;
  100. {$endif x86_64}
  101. end;
  102. end;
  103. end;
  104. { Tx86attReader }
  105. procedure tx86attreader.handlepercent;
  106. var
  107. len : longint;
  108. begin
  109. len:=1;
  110. actasmpattern[len]:='%';
  111. c:=current_scanner.asmgetchar;
  112. { to be a register there must be a letter and not a number }
  113. if c in ['0'..'9'] then
  114. begin
  115. actasmtoken:=AS_MOD;
  116. end
  117. else
  118. begin
  119. while c in ['a'..'z','A'..'Z','0'..'9'] do
  120. Begin
  121. inc(len);
  122. actasmpattern[len]:=c;
  123. c:=current_scanner.asmgetchar;
  124. end;
  125. actasmpattern[0]:=chr(len);
  126. uppervar(actasmpattern);
  127. if (actasmpattern = '%ST') and (c='(') then
  128. Begin
  129. actasmpattern:=actasmpattern+c;
  130. c:=current_scanner.asmgetchar;
  131. if c in ['0'..'9'] then
  132. actasmpattern:=actasmpattern + c
  133. else
  134. Message(asmr_e_invalid_fpu_register);
  135. c:=current_scanner.asmgetchar;
  136. if c <> ')' then
  137. Message(asmr_e_invalid_fpu_register)
  138. else
  139. Begin
  140. actasmpattern:=actasmpattern + c;
  141. c:=current_scanner.asmgetchar; { let us point to next character. }
  142. end;
  143. end;
  144. if is_register(actasmpattern) then
  145. exit;
  146. Message(asmr_e_invalid_register);
  147. actasmtoken:=raatt.AS_NONE;
  148. end;
  149. end;
  150. Procedure tx86attreader.BuildReference(oper : tx86operand);
  151. procedure Consume_RParen;
  152. begin
  153. if actasmtoken <> AS_RPAREN then
  154. Begin
  155. Message(asmr_e_invalid_reference_syntax);
  156. RecoverConsume(true);
  157. end
  158. else
  159. begin
  160. Consume(AS_RPAREN);
  161. if not (actasmtoken in [AS_COMMA,AS_SEPARATOR,AS_END]) then
  162. Begin
  163. Message(asmr_e_invalid_reference_syntax);
  164. RecoverConsume(true);
  165. end;
  166. end;
  167. end;
  168. procedure Consume_Scale;
  169. var
  170. l : aint;
  171. begin
  172. { we have to process the scaling }
  173. l:=BuildConstExpression(false,true);
  174. if ((l = 2) or (l = 4) or (l = 8) or (l = 1)) then
  175. oper.opr.ref.scalefactor:=l
  176. else
  177. Begin
  178. Message(asmr_e_wrong_scale_factor);
  179. oper.opr.ref.scalefactor:=0;
  180. end;
  181. end;
  182. begin
  183. oper.InitRef;
  184. Consume(AS_LPAREN);
  185. Case actasmtoken of
  186. AS_INTNUM,
  187. AS_MINUS,
  188. AS_PLUS: { absolute offset, such as fs:(0x046c) }
  189. Begin
  190. { offset(offset) is invalid }
  191. If oper.opr.Ref.Offset <> 0 Then
  192. Begin
  193. Message(asmr_e_invalid_reference_syntax);
  194. RecoverConsume(true);
  195. End
  196. Else
  197. Begin
  198. oper.opr.Ref.Offset:=BuildConstExpression(false,true);
  199. Consume_RParen;
  200. end;
  201. exit;
  202. End;
  203. AS_REGISTER: { (reg ... }
  204. Begin
  205. { Check if there is already a base (mostly ebp,esp) than this is
  206. not allowed, because it will give crashing code }
  207. if ((oper.opr.typ=OPR_REFERENCE) and (oper.opr.ref.base<>NR_NO)) or
  208. ((oper.opr.typ=OPR_LOCAL) and (oper.opr.localsym.localloc.loc<>LOC_REGISTER)) then
  209. message(asmr_e_cannot_index_relative_var);
  210. oper.opr.ref.base:=actasmregister;
  211. {$ifdef x86_64}
  212. { non-GOT based RIP-relative accesses are also position-independent }
  213. if (oper.opr.ref.base=NR_RIP) and
  214. (oper.opr.ref.refaddr<>addr_pic) then
  215. oper.opr.ref.refaddr:=addr_pic_no_got;
  216. {$endif x86_64}
  217. Consume(AS_REGISTER);
  218. { can either be a register or a right parenthesis }
  219. { (reg) }
  220. if actasmtoken=AS_RPAREN then
  221. Begin
  222. Consume_RParen;
  223. exit;
  224. end;
  225. { (reg,reg .. }
  226. Consume(AS_COMMA);
  227. if actasmtoken=AS_REGISTER then
  228. Begin
  229. oper.opr.ref.index:=actasmregister;
  230. Consume(AS_REGISTER);
  231. { check for scaling ... }
  232. case actasmtoken of
  233. AS_RPAREN:
  234. Begin
  235. Consume_RParen;
  236. exit;
  237. end;
  238. AS_COMMA:
  239. Begin
  240. Consume(AS_COMMA);
  241. Consume_Scale;
  242. Consume_RParen;
  243. end;
  244. else
  245. Begin
  246. Message(asmr_e_invalid_reference_syntax);
  247. RecoverConsume(false);
  248. end;
  249. end; { end case }
  250. end
  251. else
  252. Begin
  253. Message(asmr_e_invalid_reference_syntax);
  254. RecoverConsume(false);
  255. end;
  256. end; {end case }
  257. AS_COMMA: { (, ... can either be scaling, or index }
  258. Begin
  259. Consume(AS_COMMA);
  260. { Index }
  261. if (actasmtoken=AS_REGISTER) then
  262. Begin
  263. oper.opr.ref.index:=actasmregister;
  264. Consume(AS_REGISTER);
  265. { check for scaling ... }
  266. case actasmtoken of
  267. AS_RPAREN:
  268. Begin
  269. Consume_RParen;
  270. exit;
  271. end;
  272. AS_COMMA:
  273. Begin
  274. Consume(AS_COMMA);
  275. Consume_Scale;
  276. Consume_RParen;
  277. end;
  278. else
  279. Begin
  280. Message(asmr_e_invalid_reference_syntax);
  281. RecoverConsume(false);
  282. end;
  283. end; {end case }
  284. end
  285. { Scaling }
  286. else
  287. Begin
  288. Consume_Scale;
  289. Consume_RParen;
  290. exit;
  291. end;
  292. end;
  293. else
  294. Begin
  295. Message(asmr_e_invalid_reference_syntax);
  296. RecoverConsume(false);
  297. end;
  298. end;
  299. end;
  300. Procedure tx86attreader.MaybeGetPICModifier(var oper: tx86operand);
  301. var
  302. relsym: string;
  303. asmsymtyp: tasmsymtype;
  304. l: aint;
  305. begin
  306. case actasmtoken of
  307. AS_AT:
  308. begin
  309. { darwin/i386 needs a relsym instead, and we can't }
  310. { generate this automatically }
  311. if (target_info.system in [system_i386_darwin,system_i386_iphonesim]) then
  312. Message(asmr_e_invalid_reference_syntax);
  313. consume(AS_AT);
  314. if actasmtoken=AS_ID then
  315. begin
  316. {$ifdef x86_64}
  317. if (actasmpattern='GOTPCREL') or
  318. (actasmpattern='PLT') then
  319. {$endif x86_64}
  320. {$ifdef i386}
  321. if actasmpattern='GOT' then
  322. {$endif i386}
  323. begin
  324. oper.opr.ref.refaddr:=addr_pic;
  325. consume(AS_ID);
  326. end
  327. else
  328. Message(asmr_e_invalid_reference_syntax);
  329. end
  330. else
  331. Message(asmr_e_invalid_reference_syntax);
  332. end;
  333. AS_MINUS:
  334. begin
  335. { relsym? }
  336. Consume(AS_MINUS);
  337. BuildConstSymbolExpression(true,true,false,l,relsym,asmsymtyp);
  338. if (relsym<>'') then
  339. if not assigned(oper.opr.ref.relsymbol) then
  340. oper.opr.ref.relsymbol:=current_asmdata.RefAsmSymbol(relsym)
  341. else
  342. Message(asmr_e_invalid_reference_syntax)
  343. else
  344. dec(oper.opr.ref.offset,l);
  345. end;
  346. end;
  347. end;
  348. Procedure tx86attreader.BuildOperand(oper : tx86operand);
  349. var
  350. tempstr,
  351. expr : string;
  352. typesize,l,k : aint;
  353. procedure AddLabelOperand(hl:tasmlabel);
  354. begin
  355. if not(actasmtoken in [AS_PLUS,AS_MINUS,AS_LPAREN]) and
  356. is_calljmp(actopcode) then
  357. begin
  358. oper.opr.typ:=OPR_SYMBOL;
  359. oper.opr.symbol:=hl;
  360. end
  361. else
  362. begin
  363. oper.InitRef;
  364. oper.opr.ref.symbol:=hl;
  365. end;
  366. end;
  367. procedure MaybeRecordOffset;
  368. var
  369. mangledname: string;
  370. hasdot : boolean;
  371. l,
  372. toffset,
  373. tsize : aint;
  374. begin
  375. if not(actasmtoken in [AS_DOT,AS_PLUS,AS_MINUS]) then
  376. exit;
  377. l:=0;
  378. hasdot:=(actasmtoken=AS_DOT);
  379. if hasdot then
  380. begin
  381. if expr<>'' then
  382. begin
  383. BuildRecordOffsetSize(expr,toffset,tsize,mangledname,false);
  384. if (oper.opr.typ<>OPR_CONSTANT) and
  385. (mangledname<>'') then
  386. Message(asmr_e_wrong_sym_type);
  387. inc(l,toffset);
  388. oper.SetSize(tsize,true);
  389. case oper.opr.typ of
  390. OPR_REFERENCE: oper.opr.varsize := tsize;
  391. OPR_LOCAL: oper.opr.localvarsize := tsize;
  392. end;
  393. end;
  394. end;
  395. if actasmtoken in [AS_PLUS,AS_MINUS] then
  396. inc(l,BuildConstExpression(true,false));
  397. case oper.opr.typ of
  398. OPR_LOCAL :
  399. begin
  400. { don't allow direct access to fields of parameters, because that
  401. will generate buggy code. Allow it only for explicit typecasting }
  402. if hasdot and
  403. (not oper.hastype) and
  404. (oper.opr.localsym.owner.symtabletype=parasymtable) and
  405. (current_procinfo.procdef.proccalloption<>pocall_register) then
  406. Message(asmr_e_cannot_access_field_directly_for_parameters);
  407. inc(oper.opr.localsymofs,l);
  408. inc(oper.opr.localconstoffset,l);
  409. end;
  410. OPR_CONSTANT :
  411. if (mangledname<>'') then
  412. begin
  413. if (oper.opr.val<>0) then
  414. Message(asmr_e_wrong_sym_type);
  415. oper.opr.typ:=OPR_SYMBOL;
  416. oper.opr.symbol:=current_asmdata.RefAsmSymbol(mangledname);
  417. end
  418. else
  419. inc(oper.opr.val,l);
  420. OPR_REFERENCE :
  421. begin
  422. inc(oper.opr.ref.offset,l);
  423. inc(oper.opr.constoffset,l);
  424. end;
  425. OPR_SYMBOL:
  426. Message(asmr_e_invalid_symbol_ref);
  427. else
  428. internalerror(200309221);
  429. end;
  430. end;
  431. function MaybeBuildReference:boolean;
  432. { Try to create a reference, if not a reference is found then false
  433. is returned }
  434. var
  435. mangledname: string;
  436. begin
  437. MaybeBuildReference:=true;
  438. case actasmtoken of
  439. AS_INTNUM:
  440. Begin
  441. { allow %segmentregister:number }
  442. if oper.opr.ref.segment<>NR_NO then
  443. begin
  444. // already done before calling oper.InitRef;
  445. if oper.opr.Ref.Offset <> 0 Then
  446. Message(asmr_e_invalid_reference_syntax)
  447. else
  448. begin
  449. oper.opr.Ref.Offset:=BuildConstExpression(true,false);
  450. if actasmtoken=AS_LPAREN then
  451. BuildReference(oper)
  452. else if (oper.opr.ref.segment <> NR_FS) and
  453. (oper.opr.ref.segment <> NR_GS) then
  454. Message(asmr_w_general_segment_with_constant);
  455. end;
  456. end
  457. else
  458. begin
  459. oper.opr.ref.offset:=BuildConstExpression(True,False);
  460. BuildReference(oper);
  461. end;
  462. end;
  463. AS_MINUS,
  464. AS_PLUS:
  465. Begin
  466. oper.opr.ref.offset:=BuildConstExpression(True,False);
  467. if actasmtoken<>AS_LPAREN then
  468. Message(asmr_e_invalid_reference_syntax)
  469. else
  470. BuildReference(oper);
  471. end;
  472. AS_LPAREN:
  473. BuildReference(oper);
  474. AS_ID: { only a variable is allowed ... }
  475. Begin
  476. tempstr:=actasmpattern;
  477. Consume(AS_ID);
  478. { typecasting? }
  479. if (actasmtoken=AS_LPAREN) and
  480. SearchType(tempstr,typesize) then
  481. begin
  482. oper.hastype:=true;
  483. Consume(AS_LPAREN);
  484. BuildOperand(oper);
  485. Consume(AS_RPAREN);
  486. if oper.opr.typ in [OPR_REFERENCE,OPR_LOCAL] then
  487. oper.SetSize(typesize,true);
  488. end
  489. else
  490. if not oper.SetupVar(tempstr,false) then
  491. Message1(sym_e_unknown_id,tempstr);
  492. { record.field ? }
  493. if actasmtoken=AS_DOT then
  494. begin
  495. BuildRecordOffsetSize(tempstr,l,k,mangledname,false);
  496. if (mangledname<>'') then
  497. Message(asmr_e_invalid_reference_syntax);
  498. inc(oper.opr.ref.offset,l);
  499. case oper.opr.typ of
  500. OPR_REFERENCE: oper.opr.varsize := k;
  501. OPR_LOCAL: oper.opr.localvarsize := k;
  502. end;
  503. end;
  504. MaybeGetPICModifier(oper);
  505. case actasmtoken of
  506. AS_END,
  507. AS_SEPARATOR,
  508. AS_COMMA: ;
  509. AS_LPAREN:
  510. BuildReference(oper);
  511. else
  512. Begin
  513. Message(asmr_e_invalid_reference_syntax);
  514. Consume(actasmtoken);
  515. end;
  516. end; {end case }
  517. end;
  518. else
  519. MaybeBuildReference:=false;
  520. end; { end case }
  521. end;
  522. var
  523. tempreg : tregister;
  524. hl : tasmlabel;
  525. Begin
  526. expr:='';
  527. case actasmtoken of
  528. AS_LPAREN: { Memory reference or constant expression }
  529. Begin
  530. oper.InitRef;
  531. BuildReference(oper);
  532. end;
  533. AS_DOLLAR: { Constant expression }
  534. Begin
  535. Consume(AS_DOLLAR);
  536. BuildConstantOperand(oper);
  537. end;
  538. AS_INTNUM,
  539. AS_MINUS,
  540. AS_PLUS:
  541. Begin
  542. { Constant memory offset }
  543. { This must absolutely be followed by ( }
  544. oper.InitRef;
  545. oper.opr.ref.offset:=BuildConstExpression(True,False);
  546. if actasmtoken<>AS_LPAREN then
  547. Message(asmr_e_invalid_reference_syntax)
  548. else
  549. BuildReference(oper);
  550. end;
  551. AS_STAR: { Call from memory address }
  552. Begin
  553. Consume(AS_STAR);
  554. if actasmtoken=AS_REGISTER then
  555. begin
  556. oper.opr.typ:=OPR_REGISTER;
  557. oper.opr.reg:=actasmregister;
  558. oper.SetSize(tcgsize2size[reg_cgsize(actasmregister)],true);
  559. Consume(AS_REGISTER);
  560. end
  561. else
  562. begin
  563. oper.InitRef;
  564. if not MaybeBuildReference then
  565. Message(asmr_e_syn_operand);
  566. end;
  567. { this is only allowed for call's and jmp's }
  568. if not is_calljmp(actopcode) then
  569. Message(asmr_e_syn_operand);
  570. end;
  571. AS_ID: { A constant expression, or a Variable ref. }
  572. Begin
  573. { Local Label ? }
  574. if is_locallabel(actasmpattern) then
  575. begin
  576. CreateLocalLabel(actasmpattern,hl,false);
  577. Consume(AS_ID);
  578. AddLabelOperand(hl);
  579. end
  580. else
  581. { Check for label }
  582. if SearchLabel(actasmpattern,hl,false) then
  583. begin
  584. Consume(AS_ID);
  585. AddLabelOperand(hl);
  586. end
  587. else
  588. { probably a variable or normal expression }
  589. { or a procedure (such as in CALL ID) }
  590. Begin
  591. { is it a constant ? }
  592. if SearchIConstant(actasmpattern,l) then
  593. Begin
  594. if not (oper.opr.typ in [OPR_NONE,OPR_CONSTANT]) then
  595. Message(asmr_e_invalid_operand_type);
  596. BuildConstantOperand(oper);
  597. end
  598. else
  599. begin
  600. expr:=actasmpattern;
  601. Consume(AS_ID);
  602. { typecasting? }
  603. if (actasmtoken=AS_LPAREN) and
  604. SearchType(expr,typesize) then
  605. begin
  606. oper.hastype:=true;
  607. Consume(AS_LPAREN);
  608. BuildOperand(oper);
  609. Consume(AS_RPAREN);
  610. if oper.opr.typ in [OPR_REFERENCE,OPR_LOCAL] then
  611. oper.SetSize(typesize,true);
  612. end
  613. else
  614. begin
  615. if oper.SetupVar(expr,false) then
  616. MaybeGetPICModifier(oper)
  617. else
  618. Begin
  619. { look for special symbols ... }
  620. if expr= '__HIGH' then
  621. begin
  622. consume(AS_LPAREN);
  623. if not oper.setupvar('high'+actasmpattern,false) then
  624. Message1(sym_e_unknown_id,'high'+actasmpattern);
  625. consume(AS_ID);
  626. consume(AS_RPAREN);
  627. end
  628. else
  629. if expr = '__RESULT' then
  630. oper.SetUpResult
  631. else
  632. if expr = '__SELF' then
  633. oper.SetupSelf
  634. else
  635. if expr = '__OLDEBP' then
  636. oper.SetupOldEBP
  637. else
  638. Message1(sym_e_unknown_id,expr);
  639. end;
  640. end;
  641. end;
  642. if oper.opr.typ<>OPR_NONE Then
  643. begin
  644. if (actasmtoken=AS_DOT) then
  645. MaybeRecordOffset;
  646. { add a constant expression? }
  647. if (actasmtoken=AS_PLUS) then
  648. begin
  649. l:=BuildConstExpression(true,false);
  650. case oper.opr.typ of
  651. OPR_CONSTANT :
  652. inc(oper.opr.val,l);
  653. OPR_LOCAL :
  654. begin
  655. inc(oper.opr.localsymofs,l);
  656. inc(oper.opr.localconstoffset, l);
  657. end;
  658. OPR_REFERENCE :
  659. begin
  660. inc(oper.opr.ref.offset,l);
  661. inc(oper.opr.constoffset, l);
  662. end;
  663. else
  664. internalerror(200309202);
  665. end;
  666. end;
  667. end;
  668. end;
  669. { Do we have a indexing reference, then parse it also }
  670. if actasmtoken=AS_LPAREN then
  671. BuildReference(oper);
  672. end;
  673. AS_REGISTER: { Register, a variable reference or a constant reference }
  674. Begin
  675. { save the type of register used. }
  676. tempreg:=actasmregister;
  677. Consume(AS_REGISTER);
  678. if actasmtoken = AS_COLON then
  679. Begin
  680. Consume(AS_COLON);
  681. oper.InitRef;
  682. oper.opr.ref.segment:=tempreg;
  683. { This must absolutely be followed by a reference }
  684. if not MaybeBuildReference then
  685. Begin
  686. Message(asmr_e_invalid_seg_override);
  687. Consume(actasmtoken);
  688. end;
  689. end
  690. { Simple register }
  691. else if (actasmtoken in [AS_END,AS_SEPARATOR,AS_COMMA]) then
  692. Begin
  693. if not (oper.opr.typ in [OPR_NONE,OPR_REGISTER]) then
  694. Message(asmr_e_invalid_operand_type);
  695. oper.opr.typ:=OPR_REGISTER;
  696. oper.opr.reg:=tempreg;
  697. oper.SetSize(tcgsize2size[reg_cgsize(oper.opr.reg)],true);
  698. end
  699. else
  700. Message(asmr_e_syn_operand);
  701. end;
  702. AS_END,
  703. AS_SEPARATOR,
  704. AS_COMMA: ;
  705. else
  706. Begin
  707. Message(asmr_e_syn_operand);
  708. Consume(actasmtoken);
  709. end;
  710. end; { end case }
  711. end;
  712. procedure tx86attreader.BuildOpCode(instr : tx86instruction);
  713. var
  714. operandnum : longint;
  715. PrefixOp,OverrideOp: tasmop;
  716. Begin
  717. PrefixOp:=A_None;
  718. OverrideOp:=A_None;
  719. { prefix seg opcode / prefix opcode }
  720. repeat
  721. if is_prefix(actopcode) then
  722. begin
  723. PrefixOp:=ActOpcode;
  724. with instr do
  725. begin
  726. opcode:=ActOpcode;
  727. condition:=ActCondition;
  728. opsize:=ActOpsize;
  729. ConcatInstruction(curlist);
  730. end;
  731. Consume(AS_OPCODE);
  732. end
  733. else
  734. if is_override(actopcode) then
  735. begin
  736. OverrideOp:=ActOpcode;
  737. with instr do
  738. begin
  739. opcode:=ActOpcode;
  740. condition:=ActCondition;
  741. opsize:=ActOpsize;
  742. ConcatInstruction(curlist);
  743. end;
  744. Consume(AS_OPCODE);
  745. end
  746. else
  747. break;
  748. { allow for newline as in gas styled syntax }
  749. while actasmtoken=AS_SEPARATOR do
  750. Consume(AS_SEPARATOR);
  751. until (actasmtoken<>AS_OPCODE);
  752. { opcode }
  753. if (actasmtoken<>AS_OPCODE) then
  754. Begin
  755. Message(asmr_e_invalid_or_missing_opcode);
  756. RecoverConsume(true);
  757. exit;
  758. end;
  759. { Fill the instr object with the current state }
  760. with instr do
  761. begin
  762. Opcode:=ActOpcode;
  763. condition:=ActCondition;
  764. opsize:=ActOpsize;
  765. end;
  766. { Valid combination of prefix/override and instruction ? }
  767. if (prefixop<>A_NONE) and (NOT CheckPrefix(PrefixOp,actopcode)) then
  768. Message1(asmr_e_invalid_prefix_and_opcode,actasmpattern);
  769. if (overrideop<>A_NONE) and (NOT CheckOverride(OverrideOp,ActOpcode)) then
  770. Message1(asmr_e_invalid_override_and_opcode,actasmpattern);
  771. { We are reading operands, so opcode will be an AS_ID }
  772. operandnum:=1;
  773. Consume(AS_OPCODE);
  774. { Zero operand opcode ? }
  775. if actasmtoken in [AS_SEPARATOR,AS_END] then
  776. begin
  777. operandnum:=0;
  778. exit;
  779. end;
  780. { Read the operands }
  781. repeat
  782. case actasmtoken of
  783. AS_COMMA: { Operand delimiter }
  784. Begin
  785. if operandnum > Max_Operands then
  786. Message(asmr_e_too_many_operands)
  787. else
  788. Inc(operandnum);
  789. Consume(AS_COMMA);
  790. end;
  791. AS_SEPARATOR,
  792. AS_END : { End of asm operands for this opcode }
  793. begin
  794. break;
  795. end;
  796. else
  797. BuildOperand(instr.Operands[operandnum] as tx86operand);
  798. end; { end case }
  799. until false;
  800. instr.Ops:=operandnum;
  801. end;
  802. function tx86attreader.is_asmopcode(const s: string):boolean;
  803. var
  804. cond : string[4];
  805. cnd : tasmcond;
  806. len,
  807. j,
  808. sufidx,
  809. suflen : longint;
  810. Begin
  811. is_asmopcode:=FALSE;
  812. actopcode:=A_None;
  813. actcondition:=C_None;
  814. actopsize:=S_NO;
  815. { search for all possible suffixes }
  816. for sufidx:=low(att_sizesuffixstr) to high(att_sizesuffixstr) do
  817. begin
  818. suflen:=length(att_sizesuffixstr[sufidx]);
  819. len:=length(s)-suflen;
  820. if copy(s,len+1,suflen)=att_sizesuffixstr[sufidx] then
  821. begin
  822. { Search opcodes }
  823. if len>0 then
  824. begin
  825. actopcode:=tasmop(PtrUInt(iasmops.Find(copy(s,1,len))));
  826. { movsd needs special handling because it has two namings in at&t syntax (movsl for string handling and
  827. movsd for the sse instruction) while only one in intel syntax (movsd, both string and sse)
  828. this cannot be expressed by the instruction table format so we have to hack around this here }
  829. if (actopcode = A_NONE) and (upper(s) = 'MOVSD') then
  830. actopcode := A_MOVSD;
  831. { two-letter suffix is allowed by just a few instructions (movsx,movzx),
  832. and it is always required whenever allowed }
  833. if (gas_needsuffix[actopcode]=attsufINTdual) xor (suflen=2) then
  834. continue;
  835. if actopcode<>A_NONE then
  836. begin
  837. if gas_needsuffix[actopcode]=attsufFPU then
  838. actopsize:=att_sizefpusuffix[sufidx]
  839. else if gas_needsuffix[actopcode]=attsufFPUint then
  840. actopsize:=att_sizefpuintsuffix[sufidx]
  841. else
  842. actopsize:=att_sizesuffix[sufidx];
  843. { only accept suffix from the same category that the opcode belongs to }
  844. if (actopsize<>S_NO) or (suflen=0) then
  845. begin
  846. actasmtoken:=AS_OPCODE;
  847. is_asmopcode:=TRUE;
  848. exit;
  849. end;
  850. end;
  851. end;
  852. { not found, check condition opcodes }
  853. j:=0;
  854. while (j<CondAsmOps) do
  855. begin
  856. if Copy(s,1,Length(CondAsmOpStr[j]))=CondAsmOpStr[j] then
  857. begin
  858. cond:=Copy(s,Length(CondAsmOpStr[j])+1,len-Length(CondAsmOpStr[j]));
  859. if cond<>'' then
  860. begin
  861. for cnd:=low(TasmCond) to high(TasmCond) do
  862. if Cond=Upper(cond2str[cnd]) then
  863. begin
  864. actopcode:=CondASmOp[j];
  865. if gas_needsuffix[actopcode]=attsufFPU then
  866. actopsize:=att_sizefpusuffix[sufidx]
  867. else if gas_needsuffix[actopcode]=attsufFPUint then
  868. actopsize:=att_sizefpuintsuffix[sufidx]
  869. else
  870. actopsize:=att_sizesuffix[sufidx];
  871. { only accept suffix from the same category that the opcode belongs to }
  872. if (actopsize<>S_NO) or (suflen=0) then
  873. begin
  874. actcondition:=cnd;
  875. actasmtoken:=AS_OPCODE;
  876. is_asmopcode:=TRUE;
  877. exit;
  878. end;
  879. end;
  880. end;
  881. end;
  882. inc(j);
  883. end;
  884. end;
  885. end;
  886. end;
  887. procedure tx86attreader.handleopcode;
  888. var
  889. instr : Tx86Instruction;
  890. begin
  891. instr:=Tx86attInstruction.Create(Tx86Operand);
  892. instr.OpOrder:=op_att;
  893. BuildOpcode(instr);
  894. instr.AddReferenceSizes;
  895. instr.SetInstructionOpsize;
  896. instr.CheckOperandSizes;
  897. instr.FixupOpcode;
  898. instr.ConcatInstruction(curlist);
  899. instr.Free;
  900. end;
  901. end.