rax86att.pas 33 KB

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