rax86att.pas 33 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970
  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. {$ifdef i8086}
  324. if actasmpattern='GOT' then
  325. {$endif i8086}
  326. begin
  327. oper.opr.ref.refaddr:=addr_pic;
  328. consume(AS_ID);
  329. end
  330. else
  331. Message(asmr_e_invalid_reference_syntax);
  332. end
  333. else
  334. Message(asmr_e_invalid_reference_syntax);
  335. end;
  336. AS_MINUS:
  337. begin
  338. { relsym? }
  339. Consume(AS_MINUS);
  340. BuildConstSymbolExpression(true,true,false,l,relsym,asmsymtyp);
  341. if (relsym<>'') then
  342. if not assigned(oper.opr.ref.relsymbol) then
  343. oper.opr.ref.relsymbol:=current_asmdata.RefAsmSymbol(relsym)
  344. else
  345. Message(asmr_e_invalid_reference_syntax)
  346. else
  347. dec(oper.opr.ref.offset,l);
  348. end;
  349. end;
  350. end;
  351. Procedure tx86attreader.BuildOperand(oper : tx86operand);
  352. var
  353. tempstr,
  354. expr : string;
  355. typesize,l,k : aint;
  356. procedure AddLabelOperand(hl:tasmlabel);
  357. begin
  358. if not(actasmtoken in [AS_PLUS,AS_MINUS,AS_LPAREN]) and
  359. is_calljmp(actopcode) then
  360. begin
  361. oper.opr.typ:=OPR_SYMBOL;
  362. oper.opr.symbol:=hl;
  363. end
  364. else
  365. begin
  366. oper.InitRef;
  367. oper.opr.ref.symbol:=hl;
  368. end;
  369. end;
  370. procedure MaybeRecordOffset;
  371. var
  372. mangledname: string;
  373. hasdot : boolean;
  374. l,
  375. toffset,
  376. tsize : aint;
  377. begin
  378. if not(actasmtoken in [AS_DOT,AS_PLUS,AS_MINUS]) then
  379. exit;
  380. l:=0;
  381. hasdot:=(actasmtoken=AS_DOT);
  382. if hasdot then
  383. begin
  384. if expr<>'' then
  385. begin
  386. BuildRecordOffsetSize(expr,toffset,tsize,mangledname,false);
  387. if (oper.opr.typ<>OPR_CONSTANT) and
  388. (mangledname<>'') then
  389. Message(asmr_e_wrong_sym_type);
  390. inc(l,toffset);
  391. oper.SetSize(tsize,true);
  392. case oper.opr.typ of
  393. OPR_REFERENCE: oper.opr.varsize := tsize;
  394. OPR_LOCAL: oper.opr.localvarsize := tsize;
  395. end;
  396. end;
  397. end;
  398. if actasmtoken in [AS_PLUS,AS_MINUS] then
  399. inc(l,BuildConstExpression(true,false));
  400. case oper.opr.typ of
  401. OPR_LOCAL :
  402. begin
  403. { don't allow direct access to fields of parameters, because that
  404. will generate buggy code. Allow it only for explicit typecasting }
  405. if hasdot and
  406. (not oper.hastype) and
  407. (oper.opr.localsym.owner.symtabletype=parasymtable) and
  408. (current_procinfo.procdef.proccalloption<>pocall_register) then
  409. Message(asmr_e_cannot_access_field_directly_for_parameters);
  410. inc(oper.opr.localsymofs,l);
  411. inc(oper.opr.localconstoffset,l);
  412. end;
  413. OPR_CONSTANT :
  414. if (mangledname<>'') then
  415. begin
  416. if (oper.opr.val<>0) then
  417. Message(asmr_e_wrong_sym_type);
  418. oper.opr.typ:=OPR_SYMBOL;
  419. oper.opr.symbol:=current_asmdata.RefAsmSymbol(mangledname);
  420. end
  421. else
  422. inc(oper.opr.val,l);
  423. OPR_REFERENCE :
  424. begin
  425. inc(oper.opr.ref.offset,l);
  426. inc(oper.opr.constoffset,l);
  427. end;
  428. OPR_SYMBOL:
  429. Message(asmr_e_invalid_symbol_ref);
  430. else
  431. internalerror(200309221);
  432. end;
  433. end;
  434. function MaybeBuildReference:boolean;
  435. { Try to create a reference, if not a reference is found then false
  436. is returned }
  437. var
  438. mangledname: string;
  439. begin
  440. MaybeBuildReference:=true;
  441. case actasmtoken of
  442. AS_INTNUM:
  443. Begin
  444. { allow %segmentregister:number }
  445. if oper.opr.ref.segment<>NR_NO then
  446. begin
  447. // already done before calling oper.InitRef;
  448. if oper.opr.Ref.Offset <> 0 Then
  449. Message(asmr_e_invalid_reference_syntax)
  450. else
  451. begin
  452. oper.opr.Ref.Offset:=BuildConstExpression(true,false);
  453. if actasmtoken=AS_LPAREN then
  454. BuildReference(oper)
  455. else if (oper.opr.ref.segment <> NR_FS) and
  456. (oper.opr.ref.segment <> NR_GS) then
  457. Message(asmr_w_general_segment_with_constant);
  458. end;
  459. end
  460. else
  461. begin
  462. oper.opr.ref.offset:=BuildConstExpression(True,False);
  463. BuildReference(oper);
  464. end;
  465. end;
  466. AS_MINUS,
  467. AS_PLUS:
  468. Begin
  469. oper.opr.ref.offset:=BuildConstExpression(True,False);
  470. if actasmtoken<>AS_LPAREN then
  471. Message(asmr_e_invalid_reference_syntax)
  472. else
  473. BuildReference(oper);
  474. end;
  475. AS_LPAREN:
  476. BuildReference(oper);
  477. AS_ID: { only a variable is allowed ... }
  478. Begin
  479. tempstr:=actasmpattern;
  480. Consume(AS_ID);
  481. { typecasting? }
  482. if (actasmtoken=AS_LPAREN) and
  483. SearchType(tempstr,typesize) then
  484. begin
  485. oper.hastype:=true;
  486. Consume(AS_LPAREN);
  487. BuildOperand(oper);
  488. Consume(AS_RPAREN);
  489. if oper.opr.typ in [OPR_REFERENCE,OPR_LOCAL] then
  490. oper.SetSize(typesize,true);
  491. end
  492. else
  493. if not oper.SetupVar(tempstr,false) then
  494. Message1(sym_e_unknown_id,tempstr);
  495. { record.field ? }
  496. if actasmtoken=AS_DOT then
  497. begin
  498. BuildRecordOffsetSize(tempstr,l,k,mangledname,false);
  499. if (mangledname<>'') then
  500. Message(asmr_e_invalid_reference_syntax);
  501. inc(oper.opr.ref.offset,l);
  502. case oper.opr.typ of
  503. OPR_REFERENCE: oper.opr.varsize := k;
  504. OPR_LOCAL: oper.opr.localvarsize := k;
  505. end;
  506. end;
  507. MaybeGetPICModifier(oper);
  508. case actasmtoken of
  509. AS_END,
  510. AS_SEPARATOR,
  511. AS_COMMA: ;
  512. AS_LPAREN:
  513. BuildReference(oper);
  514. else
  515. Begin
  516. Message(asmr_e_invalid_reference_syntax);
  517. Consume(actasmtoken);
  518. end;
  519. end; {end case }
  520. end;
  521. else
  522. MaybeBuildReference:=false;
  523. end; { end case }
  524. end;
  525. var
  526. tempreg : tregister;
  527. hl : tasmlabel;
  528. Begin
  529. expr:='';
  530. case actasmtoken of
  531. AS_LPAREN: { Memory reference or constant expression }
  532. Begin
  533. oper.InitRef;
  534. BuildReference(oper);
  535. end;
  536. AS_DOLLAR: { Constant expression }
  537. Begin
  538. Consume(AS_DOLLAR);
  539. BuildConstantOperand(oper);
  540. end;
  541. AS_INTNUM,
  542. AS_MINUS,
  543. AS_PLUS:
  544. Begin
  545. { Constant memory offset }
  546. { This must absolutely be followed by ( }
  547. oper.InitRef;
  548. oper.opr.ref.offset:=BuildConstExpression(True,False);
  549. if actasmtoken<>AS_LPAREN then
  550. Message(asmr_e_invalid_reference_syntax)
  551. else
  552. BuildReference(oper);
  553. end;
  554. AS_STAR: { Call from memory address }
  555. Begin
  556. Consume(AS_STAR);
  557. if actasmtoken=AS_REGISTER then
  558. begin
  559. oper.opr.typ:=OPR_REGISTER;
  560. oper.opr.reg:=actasmregister;
  561. oper.SetSize(tcgsize2size[reg_cgsize(actasmregister)],true);
  562. Consume(AS_REGISTER);
  563. end
  564. else
  565. begin
  566. oper.InitRef;
  567. if not MaybeBuildReference then
  568. Message(asmr_e_syn_operand);
  569. end;
  570. { this is only allowed for call's and jmp's }
  571. if not is_calljmp(actopcode) then
  572. Message(asmr_e_syn_operand);
  573. end;
  574. AS_ID: { A constant expression, or a Variable ref. }
  575. Begin
  576. { Local Label ? }
  577. if is_locallabel(actasmpattern) then
  578. begin
  579. CreateLocalLabel(actasmpattern,hl,false);
  580. Consume(AS_ID);
  581. AddLabelOperand(hl);
  582. end
  583. else
  584. { Check for label }
  585. if SearchLabel(actasmpattern,hl,false) then
  586. begin
  587. Consume(AS_ID);
  588. AddLabelOperand(hl);
  589. end
  590. else
  591. { probably a variable or normal expression }
  592. { or a procedure (such as in CALL ID) }
  593. Begin
  594. { is it a constant ? }
  595. if SearchIConstant(actasmpattern,l) then
  596. Begin
  597. if not (oper.opr.typ in [OPR_NONE,OPR_CONSTANT]) then
  598. Message(asmr_e_invalid_operand_type);
  599. BuildConstantOperand(oper);
  600. end
  601. else
  602. begin
  603. expr:=actasmpattern;
  604. Consume(AS_ID);
  605. { typecasting? }
  606. if (actasmtoken=AS_LPAREN) and
  607. SearchType(expr,typesize) then
  608. begin
  609. oper.hastype:=true;
  610. Consume(AS_LPAREN);
  611. BuildOperand(oper);
  612. Consume(AS_RPAREN);
  613. if oper.opr.typ in [OPR_REFERENCE,OPR_LOCAL] then
  614. oper.SetSize(typesize,true);
  615. end
  616. else
  617. begin
  618. if oper.SetupVar(expr,false) then
  619. MaybeGetPICModifier(oper)
  620. else
  621. Begin
  622. { look for special symbols ... }
  623. if expr= '__HIGH' then
  624. begin
  625. consume(AS_LPAREN);
  626. if not oper.setupvar('high'+actasmpattern,false) then
  627. Message1(sym_e_unknown_id,'high'+actasmpattern);
  628. consume(AS_ID);
  629. consume(AS_RPAREN);
  630. end
  631. else
  632. if expr = '__RESULT' then
  633. oper.SetUpResult
  634. else
  635. if expr = '__SELF' then
  636. oper.SetupSelf
  637. else
  638. if expr = '__OLDEBP' then
  639. oper.SetupOldEBP
  640. else
  641. Message1(sym_e_unknown_id,expr);
  642. end;
  643. end;
  644. end;
  645. if oper.opr.typ<>OPR_NONE Then
  646. begin
  647. if (actasmtoken=AS_DOT) then
  648. MaybeRecordOffset;
  649. { add a constant expression? }
  650. if (actasmtoken=AS_PLUS) then
  651. begin
  652. l:=BuildConstExpression(true,false);
  653. case oper.opr.typ of
  654. OPR_CONSTANT :
  655. inc(oper.opr.val,l);
  656. OPR_LOCAL :
  657. begin
  658. inc(oper.opr.localsymofs,l);
  659. inc(oper.opr.localconstoffset, l);
  660. end;
  661. OPR_REFERENCE :
  662. begin
  663. inc(oper.opr.ref.offset,l);
  664. inc(oper.opr.constoffset, l);
  665. end;
  666. else
  667. internalerror(200309202);
  668. end;
  669. end;
  670. end;
  671. end;
  672. { Do we have a indexing reference, then parse it also }
  673. if actasmtoken=AS_LPAREN then
  674. BuildReference(oper);
  675. end;
  676. AS_REGISTER: { Register, a variable reference or a constant reference }
  677. Begin
  678. { save the type of register used. }
  679. tempreg:=actasmregister;
  680. Consume(AS_REGISTER);
  681. if actasmtoken = AS_COLON then
  682. Begin
  683. Consume(AS_COLON);
  684. oper.InitRef;
  685. oper.opr.ref.segment:=tempreg;
  686. { This must absolutely be followed by a reference }
  687. if not MaybeBuildReference then
  688. Begin
  689. Message(asmr_e_invalid_seg_override);
  690. Consume(actasmtoken);
  691. end;
  692. end
  693. { Simple register }
  694. else if (actasmtoken in [AS_END,AS_SEPARATOR,AS_COMMA]) then
  695. Begin
  696. if not (oper.opr.typ in [OPR_NONE,OPR_REGISTER]) then
  697. Message(asmr_e_invalid_operand_type);
  698. oper.opr.typ:=OPR_REGISTER;
  699. oper.opr.reg:=tempreg;
  700. oper.SetSize(tcgsize2size[reg_cgsize(oper.opr.reg)],true);
  701. end
  702. else
  703. Message(asmr_e_syn_operand);
  704. end;
  705. AS_END,
  706. AS_SEPARATOR,
  707. AS_COMMA: ;
  708. else
  709. Begin
  710. Message(asmr_e_syn_operand);
  711. Consume(actasmtoken);
  712. end;
  713. end; { end case }
  714. end;
  715. procedure tx86attreader.BuildOpCode(instr : tx86instruction);
  716. var
  717. operandnum : longint;
  718. PrefixOp,OverrideOp: tasmop;
  719. Begin
  720. PrefixOp:=A_None;
  721. OverrideOp:=A_None;
  722. { prefix seg opcode / prefix opcode }
  723. repeat
  724. if is_prefix(actopcode) then
  725. begin
  726. PrefixOp:=ActOpcode;
  727. with instr do
  728. begin
  729. opcode:=ActOpcode;
  730. condition:=ActCondition;
  731. opsize:=ActOpsize;
  732. ConcatInstruction(curlist);
  733. end;
  734. Consume(AS_OPCODE);
  735. end
  736. else
  737. if is_override(actopcode) then
  738. begin
  739. OverrideOp:=ActOpcode;
  740. with instr do
  741. begin
  742. opcode:=ActOpcode;
  743. condition:=ActCondition;
  744. opsize:=ActOpsize;
  745. ConcatInstruction(curlist);
  746. end;
  747. Consume(AS_OPCODE);
  748. end
  749. else
  750. break;
  751. { allow for newline as in gas styled syntax }
  752. while actasmtoken=AS_SEPARATOR do
  753. Consume(AS_SEPARATOR);
  754. until (actasmtoken<>AS_OPCODE);
  755. { opcode }
  756. if (actasmtoken<>AS_OPCODE) then
  757. Begin
  758. Message(asmr_e_invalid_or_missing_opcode);
  759. RecoverConsume(true);
  760. exit;
  761. end;
  762. { Fill the instr object with the current state }
  763. with instr do
  764. begin
  765. Opcode:=ActOpcode;
  766. condition:=ActCondition;
  767. opsize:=ActOpsize;
  768. end;
  769. { Valid combination of prefix/override and instruction ? }
  770. if (prefixop<>A_NONE) and (NOT CheckPrefix(PrefixOp,actopcode)) then
  771. Message1(asmr_e_invalid_prefix_and_opcode,actasmpattern);
  772. if (overrideop<>A_NONE) and (NOT CheckOverride(OverrideOp,ActOpcode)) then
  773. Message1(asmr_e_invalid_override_and_opcode,actasmpattern);
  774. { We are reading operands, so opcode will be an AS_ID }
  775. operandnum:=1;
  776. Consume(AS_OPCODE);
  777. { Zero operand opcode ? }
  778. if actasmtoken in [AS_SEPARATOR,AS_END] then
  779. begin
  780. operandnum:=0;
  781. exit;
  782. end;
  783. { Read the operands }
  784. repeat
  785. case actasmtoken of
  786. AS_COMMA: { Operand delimiter }
  787. Begin
  788. if operandnum > Max_Operands then
  789. Message(asmr_e_too_many_operands)
  790. else
  791. Inc(operandnum);
  792. Consume(AS_COMMA);
  793. end;
  794. AS_SEPARATOR,
  795. AS_END : { End of asm operands for this opcode }
  796. begin
  797. break;
  798. end;
  799. else
  800. BuildOperand(instr.Operands[operandnum] as tx86operand);
  801. end; { end case }
  802. until false;
  803. instr.Ops:=operandnum;
  804. end;
  805. function tx86attreader.is_asmopcode(const s: string):boolean;
  806. var
  807. cond : string[4];
  808. cnd : tasmcond;
  809. len,
  810. j,
  811. sufidx,
  812. suflen : longint;
  813. Begin
  814. is_asmopcode:=FALSE;
  815. actopcode:=A_None;
  816. actcondition:=C_None;
  817. actopsize:=S_NO;
  818. { search for all possible suffixes }
  819. for sufidx:=low(att_sizesuffixstr) to high(att_sizesuffixstr) do
  820. begin
  821. suflen:=length(att_sizesuffixstr[sufidx]);
  822. len:=length(s)-suflen;
  823. if copy(s,len+1,suflen)=att_sizesuffixstr[sufidx] then
  824. begin
  825. { Search opcodes }
  826. if len>0 then
  827. begin
  828. actopcode:=tasmop(PtrUInt(iasmops.Find(copy(s,1,len))));
  829. { movsd needs special handling because it has two namings in at&t syntax (movsl for string handling and
  830. movsd for the sse instruction) while only one in intel syntax (movsd, both string and sse)
  831. this cannot be expressed by the instruction table format so we have to hack around this here }
  832. if (actopcode = A_NONE) and (upper(s) = 'MOVSD') then
  833. actopcode := A_MOVSD;
  834. { two-letter suffix is allowed by just a few instructions (movsx,movzx),
  835. and it is always required whenever allowed }
  836. if (gas_needsuffix[actopcode]=attsufINTdual) xor (suflen=2) then
  837. continue;
  838. if actopcode<>A_NONE then
  839. begin
  840. if gas_needsuffix[actopcode]=attsufFPU then
  841. actopsize:=att_sizefpusuffix[sufidx]
  842. else if gas_needsuffix[actopcode]=attsufFPUint then
  843. actopsize:=att_sizefpuintsuffix[sufidx]
  844. else
  845. actopsize:=att_sizesuffix[sufidx];
  846. { only accept suffix from the same category that the opcode belongs to }
  847. if (actopsize<>S_NO) or (suflen=0) then
  848. begin
  849. actasmtoken:=AS_OPCODE;
  850. is_asmopcode:=TRUE;
  851. exit;
  852. end;
  853. end;
  854. end;
  855. { not found, check condition opcodes }
  856. j:=0;
  857. while (j<CondAsmOps) do
  858. begin
  859. if Copy(s,1,Length(CondAsmOpStr[j]))=CondAsmOpStr[j] then
  860. begin
  861. cond:=Copy(s,Length(CondAsmOpStr[j])+1,len-Length(CondAsmOpStr[j]));
  862. if cond<>'' then
  863. begin
  864. for cnd:=low(TasmCond) to high(TasmCond) do
  865. if Cond=Upper(cond2str[cnd]) then
  866. begin
  867. actopcode:=CondASmOp[j];
  868. if gas_needsuffix[actopcode]=attsufFPU then
  869. actopsize:=att_sizefpusuffix[sufidx]
  870. else if gas_needsuffix[actopcode]=attsufFPUint then
  871. actopsize:=att_sizefpuintsuffix[sufidx]
  872. else
  873. actopsize:=att_sizesuffix[sufidx];
  874. { only accept suffix from the same category that the opcode belongs to }
  875. if (actopsize<>S_NO) or (suflen=0) then
  876. begin
  877. actcondition:=cnd;
  878. actasmtoken:=AS_OPCODE;
  879. is_asmopcode:=TRUE;
  880. exit;
  881. end;
  882. end;
  883. end;
  884. end;
  885. inc(j);
  886. end;
  887. end;
  888. end;
  889. end;
  890. procedure tx86attreader.handleopcode;
  891. var
  892. instr : Tx86Instruction;
  893. begin
  894. instr:=Tx86attInstruction.Create(Tx86Operand);
  895. instr.OpOrder:=op_att;
  896. BuildOpcode(instr);
  897. instr.AddReferenceSizes;
  898. instr.SetInstructionOpsize;
  899. instr.CheckOperandSizes;
  900. instr.FixupOpcode;
  901. instr.ConcatInstruction(curlist);
  902. instr.Free;
  903. end;
  904. end.