rax86att.pas 44 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248
  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,aasmdata,aasmcpu,
  50. { symtable }
  51. symconst,symsym,symdef,
  52. { parser }
  53. scanner,
  54. procinfo,
  55. itcpugas,
  56. paramgr,
  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. else
  101. ;
  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. procedure Consume_Index;
  183. procedure Check_Scaling;
  184. begin
  185. { check for scaling ... }
  186. case actasmtoken of
  187. AS_RPAREN:
  188. Begin
  189. Consume_RParen;
  190. exit;
  191. end;
  192. AS_COMMA:
  193. Begin
  194. Consume(AS_COMMA);
  195. Consume_Scale;
  196. Consume_RParen;
  197. end;
  198. else
  199. Begin
  200. Message(asmr_e_invalid_reference_syntax);
  201. RecoverConsume(false);
  202. end;
  203. end; { end case }
  204. end;
  205. var
  206. tmp : tx86operand;
  207. expr : string;
  208. begin
  209. if actasmtoken=AS_REGISTER then
  210. Begin
  211. oper.opr.ref.index:=actasmregister;
  212. Consume(AS_REGISTER);
  213. Check_Scaling;
  214. end
  215. else if actasmtoken=AS_ID then
  216. begin
  217. expr:=actasmpattern;
  218. Consume(AS_ID);
  219. tmp:=Tx86Operand.create;
  220. if not tmp.SetupVar(expr,false) then
  221. begin
  222. { look for special symbols ... }
  223. if expr= '__HIGH' then
  224. begin
  225. consume(AS_LPAREN);
  226. if not tmp.setupvar('high'+actasmpattern,false) then
  227. Message1(sym_e_unknown_id,'high'+actasmpattern);
  228. consume(AS_ID);
  229. consume(AS_RPAREN);
  230. end
  231. else
  232. if expr = '__SELF' then
  233. tmp.SetupSelf
  234. else
  235. begin
  236. message1(sym_e_unknown_id,expr);
  237. RecoverConsume(false);
  238. tmp.free;
  239. Exit;
  240. end;
  241. end;
  242. { convert OPR_LOCAL register para into a reference base }
  243. if (tmp.opr.typ=OPR_LOCAL) and
  244. AsmRegisterPara(tmp.opr.localsym) then
  245. begin
  246. tmp.InitRefConvertLocal;
  247. if (tmp.opr.ref.index<>NR_NO) or
  248. (tmp.opr.ref.offset<>0) or
  249. (tmp.opr.ref.scalefactor<>0) or
  250. (tmp.opr.ref.segment<>NR_NO) or
  251. (tmp.opr.ref.base=NR_NO) then
  252. begin
  253. message(asmr_e_invalid_reference_syntax);
  254. RecoverConsume(false);
  255. tmp.free;
  256. Exit;
  257. end;
  258. oper.opr.ref.index:=tmp.opr.ref.base;
  259. tmp.free;
  260. Check_Scaling;
  261. end
  262. else
  263. begin
  264. message(asmr_e_invalid_reference_syntax);
  265. RecoverConsume(false);
  266. tmp.free;
  267. Exit;
  268. end;
  269. end
  270. else
  271. Begin
  272. Message(asmr_e_invalid_reference_syntax);
  273. RecoverConsume(false);
  274. end;
  275. end;
  276. var
  277. expr : string;
  278. tmp : tx86operand;
  279. begin
  280. oper.InitRef;
  281. Consume(AS_LPAREN);
  282. Case actasmtoken of
  283. AS_INTNUM,
  284. AS_MINUS,
  285. AS_PLUS: { absolute offset, such as fs:(0x046c) }
  286. Begin
  287. { offset(offset) is invalid }
  288. If oper.opr.Ref.Offset <> 0 Then
  289. Begin
  290. Message(asmr_e_invalid_reference_syntax);
  291. RecoverConsume(true);
  292. End
  293. Else
  294. Begin
  295. oper.opr.Ref.Offset:=BuildConstExpression(false,true);
  296. Consume_RParen;
  297. end;
  298. exit;
  299. End;
  300. AS_REGISTER: { (reg ... }
  301. Begin
  302. { Check if there is already a base (mostly ebp,esp) than this is
  303. not allowed, because it will give crashing code }
  304. if ((oper.opr.typ=OPR_REFERENCE) and (oper.opr.ref.base<>NR_NO)) or
  305. ((oper.opr.typ=OPR_LOCAL) and (oper.opr.localsym.localloc.loc<>LOC_REGISTER)) then
  306. message(asmr_e_cannot_index_relative_var);
  307. oper.opr.ref.base:=actasmregister;
  308. {$ifdef x86_64}
  309. { non-GOT based RIP-relative accesses are also position-independent }
  310. if (oper.opr.ref.base=NR_RIP) and
  311. (oper.opr.ref.refaddr<>addr_pic) then
  312. oper.opr.ref.refaddr:=addr_pic_no_got;
  313. {$endif x86_64}
  314. Consume(AS_REGISTER);
  315. { can either be a register, an identifier or a right parenthesis }
  316. { (reg) }
  317. if actasmtoken=AS_RPAREN then
  318. Begin
  319. Consume_RParen;
  320. exit;
  321. end;
  322. { (reg,reg .. }
  323. Consume(AS_COMMA);
  324. Consume_Index;
  325. end; {end case }
  326. AS_ID: { identifier (parameter, variable, ...), but only those that might be in a register }
  327. begin
  328. expr:=actasmpattern;
  329. Consume(AS_ID);
  330. tmp:=Tx86Operand.create;
  331. if not tmp.SetupVar(expr,false) then
  332. begin
  333. { look for special symbols ... }
  334. if expr= '__HIGH' then
  335. begin
  336. consume(AS_LPAREN);
  337. if not tmp.setupvar('high'+actasmpattern,false) then
  338. Message1(sym_e_unknown_id,'high'+actasmpattern);
  339. consume(AS_ID);
  340. consume(AS_RPAREN);
  341. end
  342. else
  343. if expr = '__SELF' then
  344. tmp.SetupSelf
  345. else
  346. begin
  347. message1(sym_e_unknown_id,expr);
  348. RecoverConsume(false);
  349. tmp.free;
  350. Exit;
  351. end;
  352. end;
  353. { convert OPR_LOCAL register para into a reference base }
  354. if (tmp.opr.typ=OPR_LOCAL) and
  355. AsmRegisterPara(tmp.opr.localsym) then
  356. begin
  357. tmp.InitRefConvertLocal;
  358. if (tmp.opr.ref.index<>NR_NO) or
  359. (tmp.opr.ref.offset<>0) or
  360. (tmp.opr.ref.scalefactor<>0) or
  361. (tmp.opr.ref.segment<>NR_NO) or
  362. (tmp.opr.ref.base=NR_NO) then
  363. begin
  364. message(asmr_e_invalid_reference_syntax);
  365. RecoverConsume(false);
  366. tmp.free;
  367. Exit;
  368. end;
  369. oper.opr.ref.base:=tmp.opr.ref.base;
  370. tmp.free;
  371. end
  372. else
  373. begin
  374. message(asmr_e_invalid_reference_syntax);
  375. RecoverConsume(false);
  376. tmp.free;
  377. Exit;
  378. end;
  379. { can either be a register, an identifier or a right parenthesis }
  380. { (reg) }
  381. if actasmtoken=AS_RPAREN then
  382. begin
  383. Consume_RParen;
  384. exit;
  385. end;
  386. Consume(AS_COMMA);
  387. Consume_Index;
  388. end;
  389. AS_COMMA: { (, ... can either be scaling, or index }
  390. Begin
  391. Consume(AS_COMMA);
  392. { Index }
  393. if (actasmtoken=AS_REGISTER) then
  394. Begin
  395. oper.opr.ref.index:=actasmregister;
  396. Consume(AS_REGISTER);
  397. { check for scaling ... }
  398. case actasmtoken of
  399. AS_RPAREN:
  400. Begin
  401. Consume_RParen;
  402. exit;
  403. end;
  404. AS_COMMA:
  405. Begin
  406. Consume(AS_COMMA);
  407. Consume_Scale;
  408. Consume_RParen;
  409. end;
  410. else
  411. Begin
  412. Message(asmr_e_invalid_reference_syntax);
  413. RecoverConsume(false);
  414. end;
  415. end; {end case }
  416. end
  417. { Scaling }
  418. else
  419. Begin
  420. Consume_Scale;
  421. Consume_RParen;
  422. exit;
  423. end;
  424. end;
  425. else
  426. Begin
  427. Message(asmr_e_invalid_reference_syntax);
  428. RecoverConsume(false);
  429. end;
  430. end;
  431. end;
  432. Procedure tx86attreader.MaybeGetPICModifier(var oper: tx86operand);
  433. var
  434. relsym: string;
  435. asmsymtyp: tasmsymtype;
  436. l: tcgint;
  437. sym: tasmsymbol;
  438. begin
  439. case actasmtoken of
  440. AS_AT:
  441. begin
  442. { darwin/i386 needs a relsym instead, and we can't }
  443. { generate this automatically }
  444. if (target_info.system in [system_i386_darwin,system_i386_iphonesim]) then
  445. Message(asmr_e_invalid_reference_syntax);
  446. consume(AS_AT);
  447. if actasmtoken=AS_ID then
  448. begin
  449. {$ifdef x86_64}
  450. if (actasmpattern='GOTPCREL') or
  451. (actasmpattern='PLT') then
  452. {$endif x86_64}
  453. {$ifdef i386}
  454. if actasmpattern='GOT' then
  455. {$endif i386}
  456. {$ifdef i8086}
  457. if actasmpattern='GOT' then
  458. {$endif i8086}
  459. begin
  460. case oper.opr.typ of
  461. OPR_SYMBOL:
  462. begin
  463. sym:=oper.opr.symbol;
  464. if oper.opr.symofs<>0 then
  465. Message(asmr_e_invalid_reference_syntax);
  466. oper.opr.typ:=OPR_REFERENCE;
  467. fillchar(oper.opr.ref,sizeof(oper.opr.ref),0);
  468. oper.opr.ref.symbol:=sym;
  469. end;
  470. OPR_REFERENCE:
  471. begin
  472. { ok }
  473. end;
  474. else
  475. Message(asmr_e_invalid_reference_syntax)
  476. end;
  477. oper.opr.ref.refaddr:=addr_pic;
  478. consume(AS_ID);
  479. end
  480. else
  481. Message(asmr_e_invalid_reference_syntax);
  482. end
  483. else
  484. Message(asmr_e_invalid_reference_syntax);
  485. end;
  486. AS_MINUS:
  487. begin
  488. { relsym? }
  489. Consume(AS_MINUS);
  490. BuildConstSymbolExpression(true,true,false,l,relsym,asmsymtyp);
  491. if (relsym<>'') then
  492. if not assigned(oper.opr.ref.relsymbol) then
  493. oper.opr.ref.relsymbol:=current_asmdata.RefAsmSymbol(relsym,asmsymtyp)
  494. else
  495. Message(asmr_e_invalid_reference_syntax)
  496. else
  497. dec(oper.opr.ref.offset,l);
  498. end;
  499. else
  500. ;
  501. end;
  502. end;
  503. Procedure tx86attreader.BuildOperand(oper : tx86operand);
  504. var
  505. tempstr,
  506. expr : string;
  507. typesize,l,k : tcgint;
  508. procedure AddLabelOperand(hl:tasmlabel);
  509. begin
  510. if not(actasmtoken in [AS_PLUS,AS_MINUS,AS_LPAREN]) and
  511. is_calljmp(actopcode) then
  512. begin
  513. oper.opr.typ:=OPR_SYMBOL;
  514. oper.opr.symbol:=hl;
  515. end
  516. else
  517. begin
  518. oper.InitRef;
  519. oper.opr.ref.symbol:=hl;
  520. end;
  521. end;
  522. procedure MaybeRecordOffset;
  523. var
  524. mangledname: string;
  525. hasdot : boolean;
  526. l,
  527. toffset,
  528. tsize : tcgint;
  529. begin
  530. if not(actasmtoken in [AS_DOT,AS_PLUS,AS_MINUS]) then
  531. exit;
  532. l:=0;
  533. mangledname:='';
  534. hasdot:=(actasmtoken=AS_DOT);
  535. if hasdot then
  536. begin
  537. if expr<>'' then
  538. begin
  539. BuildRecordOffsetSize(expr,toffset,tsize,mangledname,false);
  540. if (oper.opr.typ<>OPR_CONSTANT) and
  541. (mangledname<>'') then
  542. Message(asmr_e_wrong_sym_type);
  543. inc(l,toffset);
  544. oper.SetSize(tsize,true);
  545. case oper.opr.typ of
  546. OPR_REFERENCE: oper.opr.varsize := tsize;
  547. OPR_LOCAL: oper.opr.localvarsize := tsize;
  548. else
  549. ;
  550. end;
  551. end;
  552. end;
  553. if actasmtoken in [AS_PLUS,AS_MINUS] then
  554. inc(l,BuildConstExpression(true,false));
  555. case oper.opr.typ of
  556. OPR_LOCAL :
  557. begin
  558. { don't allow direct access to fields of parameters, because that
  559. will generate buggy code. Allow it only for explicit typecasting }
  560. if hasdot and
  561. (not oper.hastype) then
  562. checklocalsubscript(oper.opr.localsym);
  563. inc(oper.opr.localsymofs,l);
  564. inc(oper.opr.localconstoffset,l);
  565. end;
  566. OPR_CONSTANT :
  567. if (mangledname<>'') then
  568. begin
  569. if (oper.opr.val<>0) then
  570. Message(asmr_e_wrong_sym_type);
  571. oper.opr.typ:=OPR_SYMBOL;
  572. oper.opr.symbol:=current_asmdata.RefAsmSymbol(mangledname,AT_FUNCTION);
  573. end
  574. else
  575. inc(oper.opr.val,l);
  576. OPR_REFERENCE :
  577. begin
  578. inc(oper.opr.ref.offset,l);
  579. inc(oper.opr.constoffset,l);
  580. end;
  581. OPR_SYMBOL:
  582. Message(asmr_e_invalid_symbol_ref);
  583. else
  584. internalerror(200309221);
  585. end;
  586. end;
  587. function MaybeBuildReference:boolean;
  588. { Try to create a reference, if not a reference is found then false
  589. is returned }
  590. var
  591. mangledname: string;
  592. begin
  593. MaybeBuildReference:=true;
  594. case actasmtoken of
  595. AS_INTNUM:
  596. Begin
  597. { allow %segmentregister:number }
  598. if oper.opr.ref.segment<>NR_NO then
  599. begin
  600. // already done before calling oper.InitRef;
  601. if oper.opr.Ref.Offset <> 0 Then
  602. Message(asmr_e_invalid_reference_syntax)
  603. else
  604. begin
  605. oper.opr.Ref.Offset:=BuildConstExpression(true,false);
  606. if actasmtoken=AS_LPAREN then
  607. BuildReference(oper)
  608. else if (oper.opr.ref.segment <> NR_FS) and
  609. (oper.opr.ref.segment <> NR_GS) then
  610. Message(asmr_w_general_segment_with_constant);
  611. end;
  612. end
  613. else
  614. begin
  615. oper.opr.ref.offset:=BuildConstExpression(True,False);
  616. BuildReference(oper);
  617. end;
  618. end;
  619. AS_MINUS,
  620. AS_PLUS:
  621. Begin
  622. oper.opr.ref.offset:=BuildConstExpression(True,False);
  623. if actasmtoken<>AS_LPAREN then
  624. Message(asmr_e_invalid_reference_syntax)
  625. else
  626. BuildReference(oper);
  627. end;
  628. AS_LPAREN:
  629. BuildReference(oper);
  630. AS_ID: { only a variable is allowed ... }
  631. Begin
  632. tempstr:=actasmpattern;
  633. Consume(AS_ID);
  634. { typecasting? }
  635. if (actasmtoken=AS_LPAREN) and
  636. SearchType(tempstr,typesize) then
  637. begin
  638. oper.hastype:=true;
  639. Consume(AS_LPAREN);
  640. BuildOperand(oper);
  641. Consume(AS_RPAREN);
  642. if oper.opr.typ in [OPR_REFERENCE,OPR_LOCAL] then
  643. oper.SetSize(typesize,true);
  644. end
  645. else
  646. if not oper.SetupVar(tempstr,false) then
  647. Message1(sym_e_unknown_id,tempstr);
  648. { record.field ? }
  649. if actasmtoken=AS_DOT then
  650. begin
  651. BuildRecordOffsetSize(tempstr,l,k,mangledname,false);
  652. if (mangledname<>'') then
  653. Message(asmr_e_invalid_reference_syntax);
  654. inc(oper.opr.ref.offset,l);
  655. case oper.opr.typ of
  656. OPR_REFERENCE: oper.opr.varsize := k;
  657. OPR_LOCAL: oper.opr.localvarsize := k;
  658. else
  659. ;
  660. end;
  661. end;
  662. MaybeGetPICModifier(oper);
  663. case actasmtoken of
  664. AS_END,
  665. AS_SEPARATOR,
  666. AS_COMMA: ;
  667. AS_LPAREN:
  668. BuildReference(oper);
  669. else
  670. Begin
  671. Message(asmr_e_invalid_reference_syntax);
  672. Consume(actasmtoken);
  673. end;
  674. end; {end case }
  675. end;
  676. else
  677. MaybeBuildReference:=false;
  678. end; { end case }
  679. end;
  680. var
  681. tempreg : tregister;
  682. hl : tasmlabel;
  683. Begin
  684. expr:='';
  685. case actasmtoken of
  686. AS_LPAREN: { Memory reference or constant expression }
  687. Begin
  688. oper.InitRef;
  689. BuildReference(oper);
  690. end;
  691. AS_DOLLAR: { Constant expression }
  692. Begin
  693. Consume(AS_DOLLAR);
  694. BuildConstantOperand(oper);
  695. end;
  696. AS_INTNUM,
  697. AS_MINUS,
  698. AS_PLUS:
  699. Begin
  700. { Constant memory offset }
  701. { This must absolutely be followed by ( }
  702. oper.InitRef;
  703. oper.opr.ref.offset:=asizeint(BuildConstExpression(True,False));
  704. if actasmtoken<>AS_LPAREN then
  705. Message(asmr_e_invalid_reference_syntax)
  706. else
  707. BuildReference(oper);
  708. end;
  709. AS_STAR: { Call from memory address }
  710. Begin
  711. Consume(AS_STAR);
  712. if actasmtoken=AS_REGISTER then
  713. begin
  714. oper.opr.typ:=OPR_REGISTER;
  715. oper.opr.reg:=actasmregister;
  716. oper.SetSize(tcgsize2size[reg_cgsize(actasmregister)],true);
  717. Consume(AS_REGISTER);
  718. end
  719. else
  720. begin
  721. oper.InitRef;
  722. if not MaybeBuildReference then
  723. Message(asmr_e_syn_operand);
  724. end;
  725. { this is only allowed for call's and jmp's }
  726. if not is_calljmp(actopcode) then
  727. Message(asmr_e_syn_operand);
  728. end;
  729. AS_ID: { A constant expression, or a Variable ref. }
  730. Begin
  731. { Local Label ? }
  732. if is_locallabel(actasmpattern) then
  733. begin
  734. CreateLocalLabel(actasmpattern,hl,false);
  735. Consume(AS_ID);
  736. AddLabelOperand(hl);
  737. MaybeGetPICModifier(oper);
  738. end
  739. else
  740. { Check for label }
  741. if SearchLabel(actasmpattern,hl,false) then
  742. begin
  743. Consume(AS_ID);
  744. AddLabelOperand(hl);
  745. MaybeGetPICModifier(oper);
  746. end
  747. else
  748. { probably a variable or normal expression }
  749. { or a procedure (such as in CALL ID) }
  750. Begin
  751. { is it a constant ? }
  752. if SearchIConstant(actasmpattern,l) then
  753. Begin
  754. if not (oper.opr.typ in [OPR_NONE,OPR_CONSTANT]) then
  755. Message(asmr_e_invalid_operand_type);
  756. BuildConstantOperand(oper);
  757. end
  758. else
  759. begin
  760. expr:=actasmpattern;
  761. Consume(AS_ID);
  762. { typecasting? }
  763. if (actasmtoken=AS_LPAREN) and
  764. SearchType(expr,typesize) then
  765. begin
  766. oper.hastype:=true;
  767. Consume(AS_LPAREN);
  768. BuildOperand(oper);
  769. Consume(AS_RPAREN);
  770. if oper.opr.typ in [OPR_REFERENCE,OPR_LOCAL] then
  771. oper.SetSize(typesize,true);
  772. end
  773. else
  774. begin
  775. if oper.SetupVar(expr,false) then
  776. MaybeGetPICModifier(oper)
  777. else
  778. Begin
  779. { look for special symbols ... }
  780. if expr= '__HIGH' then
  781. begin
  782. consume(AS_LPAREN);
  783. if not oper.setupvar('high'+actasmpattern,false) then
  784. Message1(sym_e_unknown_id,'high'+actasmpattern);
  785. consume(AS_ID);
  786. consume(AS_RPAREN);
  787. end
  788. else
  789. if expr = '__RESULT' then
  790. oper.SetUpResult
  791. else
  792. if expr = '__SELF' then
  793. oper.SetupSelf
  794. else
  795. if expr = '__OLDEBP' then
  796. oper.SetupOldEBP
  797. else
  798. Message1(sym_e_unknown_id,expr);
  799. end;
  800. end;
  801. end;
  802. if oper.opr.typ<>OPR_NONE Then
  803. begin
  804. if (actasmtoken=AS_DOT) then
  805. MaybeRecordOffset;
  806. { add a constant expression? }
  807. if (actasmtoken=AS_PLUS) then
  808. begin
  809. l:=BuildConstExpression(true,false);
  810. if errorcount=0 then
  811. case oper.opr.typ of
  812. OPR_CONSTANT :
  813. inc(oper.opr.val,l);
  814. OPR_LOCAL :
  815. begin
  816. inc(oper.opr.localsymofs,l);
  817. inc(oper.opr.localconstoffset, l);
  818. end;
  819. OPR_REFERENCE :
  820. begin
  821. inc(oper.opr.ref.offset,l);
  822. inc(oper.opr.constoffset, l);
  823. end;
  824. else
  825. internalerror(2003092011);
  826. end;
  827. end;
  828. end;
  829. end;
  830. { Do we have a indexing reference, then parse it also }
  831. if actasmtoken=AS_LPAREN then
  832. BuildReference(oper);
  833. end;
  834. AS_REGISTER: { Register, a variable reference or a constant reference }
  835. Begin
  836. { save the type of register used. }
  837. tempreg:=actasmregister;
  838. Consume(AS_REGISTER);
  839. if actasmtoken = AS_COLON then
  840. Begin
  841. Consume(AS_COLON);
  842. oper.InitRef;
  843. if not is_segment_reg(tempreg) then
  844. Message(asmr_e_invalid_seg_override);
  845. {$ifdef x86_64}
  846. if (tempreg=NR_CS) or (tempreg=NR_DS) or (tempreg=NR_SS) or (tempreg=NR_ES) then
  847. Message1(asmr_w_segment_override_ignored_in_64bit_mode,gas_regname(tempreg));
  848. {$endif x86_64}
  849. oper.opr.ref.segment:=tempreg;
  850. { This must absolutely be followed by a reference }
  851. if not MaybeBuildReference then
  852. Begin
  853. Message(asmr_e_invalid_seg_override);
  854. Consume(actasmtoken);
  855. end;
  856. end
  857. { Simple register }
  858. else if (actasmtoken in [AS_END,AS_SEPARATOR,AS_COMMA]) then
  859. Begin
  860. if not (oper.opr.typ in [OPR_NONE,OPR_REGISTER]) then
  861. Message(asmr_e_invalid_operand_type);
  862. oper.opr.typ:=OPR_REGISTER;
  863. oper.opr.reg:=tempreg;
  864. oper.SetSize(tcgsize2size[reg_cgsize(oper.opr.reg)],true);
  865. end
  866. else
  867. Message(asmr_e_syn_operand);
  868. end;
  869. AS_END,
  870. AS_SEPARATOR,
  871. AS_COMMA: ;
  872. else
  873. Begin
  874. Message(asmr_e_syn_operand);
  875. Consume(actasmtoken);
  876. end;
  877. end; { end case }
  878. end;
  879. procedure tx86attreader.BuildOpCode(instr : tx86instruction);
  880. var
  881. operandnum : longint;
  882. PrefixOp,OverrideOp: tasmop;
  883. di_param, si_param: ShortInt;
  884. Begin
  885. PrefixOp:=A_None;
  886. OverrideOp:=A_None;
  887. { prefix seg opcode / prefix opcode }
  888. repeat
  889. if is_prefix(actopcode) then
  890. begin
  891. PrefixOp:=ActOpcode;
  892. with instr do
  893. begin
  894. opcode:=ActOpcode;
  895. condition:=ActCondition;
  896. opsize:=ActOpsize;
  897. ConcatInstruction(curlist);
  898. end;
  899. Consume(AS_OPCODE);
  900. end
  901. else
  902. if is_override(actopcode) then
  903. begin
  904. OverrideOp:=ActOpcode;
  905. with instr do
  906. begin
  907. opcode:=ActOpcode;
  908. condition:=ActCondition;
  909. opsize:=ActOpsize;
  910. ConcatInstruction(curlist);
  911. end;
  912. Consume(AS_OPCODE);
  913. end
  914. else
  915. break;
  916. { allow for newline as in gas styled syntax }
  917. while actasmtoken=AS_SEPARATOR do
  918. Consume(AS_SEPARATOR);
  919. until (actasmtoken<>AS_OPCODE);
  920. { opcode }
  921. if (actasmtoken<>AS_OPCODE) then
  922. Begin
  923. Message(asmr_e_invalid_or_missing_opcode);
  924. RecoverConsume(true);
  925. exit;
  926. end;
  927. { Fill the instr object with the current state }
  928. with instr do
  929. begin
  930. Opcode:=ActOpcode;
  931. condition:=ActCondition;
  932. opsize:=ActOpsize;
  933. end;
  934. { Valid combination of prefix/override and instruction ? }
  935. if (prefixop<>A_NONE) and (NOT CheckPrefix(PrefixOp,actopcode)) then
  936. Message1(asmr_e_invalid_prefix_and_opcode,actasmpattern);
  937. if (overrideop<>A_NONE) and (NOT CheckOverride(OverrideOp,ActOpcode)) then
  938. Message1(asmr_e_invalid_override_and_opcode,actasmpattern);
  939. { We are reading operands, so opcode will be an AS_ID }
  940. operandnum:=1;
  941. Consume(AS_OPCODE);
  942. { Zero operand opcode ? }
  943. if actasmtoken in [AS_SEPARATOR,AS_END] then
  944. begin
  945. operandnum:=0;
  946. exit;
  947. end;
  948. { Read the operands }
  949. repeat
  950. case actasmtoken of
  951. AS_COMMA: { Operand delimiter }
  952. Begin
  953. if operandnum > Max_Operands then
  954. Message(asmr_e_too_many_operands)
  955. else
  956. Inc(operandnum);
  957. Consume(AS_COMMA);
  958. end;
  959. AS_SEPARATOR,
  960. AS_END : { End of asm operands for this opcode }
  961. begin
  962. break;
  963. end;
  964. else
  965. BuildOperand(instr.Operands[operandnum] as tx86operand);
  966. end; { end case }
  967. until false;
  968. instr.Ops:=operandnum;
  969. { handle string instructions with parameters }
  970. with instr do
  971. if is_x86_parameterless_string_op(opcode) and
  972. (Ops>=1) and (Ops<=2) then
  973. begin
  974. if opcode=A_MOVSD then
  975. begin
  976. { distinguish between MOVS and the SSE MOVSD instruction:
  977. MOVS must have memory 2 reference operands (there's no need
  978. to distinguish from SSE CMPSD, because the SSE version has 3
  979. arguments and we've already checked that above) }
  980. if (Ops=2) and (operands[1].opr.typ=OPR_REFERENCE) and (operands[2].opr.typ=OPR_REFERENCE) then
  981. begin
  982. opcode:=A_MOVS;
  983. opsize:=S_L;
  984. end;
  985. end
  986. else
  987. begin
  988. opsize:=get_x86_string_op_size(opcode);
  989. opcode:=x86_param2paramless_string_op(opcode);
  990. end;
  991. end;
  992. { Check for invalid ES: overrides }
  993. if is_x86_parameterized_string_op(instr.opcode) then
  994. begin
  995. si_param:=get_x86_string_op_si_param(instr.opcode);
  996. if si_param<>-1 then
  997. begin
  998. si_param:=x86_parameterized_string_op_param_count(instr.opcode)-si_param;
  999. if si_param<=operandnum then
  1000. with instr.operands[si_param] do
  1001. if (opr.typ=OPR_REFERENCE) then
  1002. begin
  1003. if not((((opr.ref.index<>NR_NO) and
  1004. (opr.ref.base=NR_NO) and
  1005. (getregtype(opr.ref.index)=R_INTREGISTER) and
  1006. (getsupreg(opr.ref.index)=RS_ESI)) or
  1007. ((opr.ref.index=NR_NO) and
  1008. (opr.ref.base<>NR_NO) and
  1009. (getregtype(opr.ref.base)=R_INTREGISTER) and
  1010. (getsupreg(opr.ref.base)=RS_ESI))) and
  1011. (opr.ref.offset=0) and
  1012. (opr.ref.scalefactor<=1) and
  1013. (opr.ref.refaddr=addr_no) and
  1014. (opr.ref.symbol=nil) and
  1015. (opr.ref.relsymbol=nil)) then
  1016. {$if defined(i8086)}
  1017. Message1(asmr_w_invalid_reference,'(%si)');
  1018. {$elseif defined(i386)}
  1019. Message1(asmr_w_invalid_reference,'(%esi)');
  1020. {$elseif defined(x86_64)}
  1021. Message1(asmr_w_invalid_reference,'(%rsi)');
  1022. {$endif}
  1023. end;
  1024. end;
  1025. di_param:=get_x86_string_op_di_param(instr.opcode);
  1026. if di_param<>-1 then
  1027. begin
  1028. di_param:=x86_parameterized_string_op_param_count(instr.opcode)-di_param;
  1029. if di_param<=operandnum then
  1030. with instr.operands[di_param] do
  1031. if (opr.typ=OPR_REFERENCE) then
  1032. begin
  1033. if (opr.ref.segment<>NR_NO) and
  1034. (opr.ref.segment<>NR_ES) then
  1035. Message(asmr_e_cannot_override_es_segment);
  1036. if not((((opr.ref.index<>NR_NO) and
  1037. (opr.ref.base=NR_NO) and
  1038. (getregtype(opr.ref.index)=R_INTREGISTER) and
  1039. (getsupreg(opr.ref.index)=RS_EDI)) or
  1040. ((opr.ref.index=NR_NO) and
  1041. (opr.ref.base<>NR_NO) and
  1042. (getregtype(opr.ref.base)=R_INTREGISTER) and
  1043. (getsupreg(opr.ref.base)=RS_EDI))) and
  1044. (opr.ref.offset=0) and
  1045. (opr.ref.scalefactor<=1) and
  1046. (opr.ref.refaddr=addr_no) and
  1047. (opr.ref.symbol=nil) and
  1048. (opr.ref.relsymbol=nil)) then
  1049. {$if defined(i8086)}
  1050. Message1(asmr_w_invalid_reference,'(%di)');
  1051. {$elseif defined(i386)}
  1052. Message1(asmr_w_invalid_reference,'(%edi)');
  1053. {$elseif defined(x86_64)}
  1054. Message1(asmr_w_invalid_reference,'(%rdi)');
  1055. {$endif}
  1056. end;
  1057. end;
  1058. { if two memory parameters, check whether their address sizes are equal }
  1059. if (si_param<>-1) and (di_param<>-1) and
  1060. (si_param<=operandnum) and (di_param<=operandnum) and
  1061. (instr.operands[si_param].opr.typ=OPR_REFERENCE) and
  1062. (instr.operands[di_param].opr.typ=OPR_REFERENCE) then
  1063. begin
  1064. if get_ref_address_size(instr.operands[si_param].opr.ref)<>
  1065. get_ref_address_size(instr.operands[di_param].opr.ref) then
  1066. Message(asmr_e_address_sizes_do_not_match);
  1067. end;
  1068. end;
  1069. end;
  1070. function tx86attreader.is_asmopcode(const s: string):boolean;
  1071. var
  1072. cond : string[4];
  1073. cnd : tasmcond;
  1074. len,
  1075. j,
  1076. sufidx,
  1077. suflen : longint;
  1078. Begin
  1079. is_asmopcode:=FALSE;
  1080. actopcode:=A_None;
  1081. actcondition:=C_None;
  1082. actopsize:=S_NO;
  1083. { search for all possible suffixes }
  1084. for sufidx:=low(att_sizesuffixstr) to high(att_sizesuffixstr) do
  1085. begin
  1086. suflen:=length(att_sizesuffixstr[sufidx]);
  1087. len:=length(s)-suflen;
  1088. if copy(s,len+1,suflen)=att_sizesuffixstr[sufidx] then
  1089. begin
  1090. { Search opcodes }
  1091. if len>0 then
  1092. begin
  1093. actopcode:=tasmop(PtrUInt(iasmops.Find(copy(s,1,len))));
  1094. { movsd needs special handling because it has two namings in at&t syntax (movsl for string handling and
  1095. movsd for the sse instruction) while only one in intel syntax (movsd, both string and sse)
  1096. this cannot be expressed by the instruction table format so we have to hack around this here }
  1097. if (actopcode = A_NONE) and (upper(s) = 'MOVSD') then
  1098. actopcode := A_MOVSD;
  1099. { cmpsd also needs special handling for pretty much the same reasons as movsd }
  1100. if (actopcode = A_NONE) and (upper(s) = 'CMPSD') then
  1101. actopcode := A_CMPSD;
  1102. { disambiguation between A_MOVS (movsb/movsw/movsl/movsq) and
  1103. A_MOVSX (movsbw/movsbl/movswl/movsbq/movswq) }
  1104. if (actopcode = A_MOVS) and (suflen=2) then
  1105. actopcode := A_MOVSX;
  1106. { two-letter suffix is allowed by just a few instructions (movsx,movzx),
  1107. and it is always required whenever allowed }
  1108. if (gas_needsuffix[actopcode]=attsufINTdual) xor (suflen=2) then
  1109. continue;
  1110. { We need to refuse the opcodes that require a condition }
  1111. if (actopcode=A_Jcc) or (actopcode=A_SETcc) or (actopcode=A_CMOVcc) then
  1112. actopcode:=A_NONE;
  1113. if actopcode<>A_NONE then
  1114. begin
  1115. if gas_needsuffix[actopcode]=attsufFPU then
  1116. actopsize:=att_sizefpusuffix[sufidx]
  1117. else if gas_needsuffix[actopcode]=attsufFPUint then
  1118. actopsize:=att_sizefpuintsuffix[sufidx]
  1119. else if gas_needsuffix[actopcode]in[attsufMM,attsufMMS] then
  1120. actopsize:=att_sizemmsuffix[sufidx]
  1121. else if gas_needsuffix[actopcode]=attsufMMX then
  1122. actopsize:=att_sizemmXsuffix[sufidx]
  1123. else
  1124. actopsize:=att_sizesuffix[sufidx];
  1125. { only accept suffix from the same category that the opcode belongs to }
  1126. if (actopsize<>S_NO) or (suflen=0) then
  1127. begin
  1128. actasmtoken:=AS_OPCODE;
  1129. is_asmopcode:=TRUE;
  1130. exit;
  1131. end;
  1132. end;
  1133. end;
  1134. { not found, check condition opcodes }
  1135. j:=0;
  1136. while (j<CondAsmOps) do
  1137. begin
  1138. if Copy(s,1,Length(CondAsmOpStr[j]))=CondAsmOpStr[j] then
  1139. begin
  1140. cond:=Copy(s,Length(CondAsmOpStr[j])+1,len-Length(CondAsmOpStr[j]));
  1141. if cond<>'' then
  1142. begin
  1143. for cnd:=low(TasmCond) to high(TasmCond) do
  1144. if Cond=Upper(cond2str[cnd]) then
  1145. begin
  1146. actopcode:=CondASmOp[j];
  1147. { conditional instructions (cmovcc, setcc) use only INT suffixes;
  1148. other stuff like fcmovcc is represented as group of individual instructions }
  1149. if gas_needsuffix[actopcode]=attsufINT then
  1150. actopsize:=att_sizesuffix[sufidx];
  1151. { only accept suffix from the same category that the opcode belongs to }
  1152. if (actopsize<>S_NO) or (suflen=0) then
  1153. begin
  1154. actcondition:=cnd;
  1155. actasmtoken:=AS_OPCODE;
  1156. is_asmopcode:=TRUE;
  1157. exit;
  1158. end;
  1159. end;
  1160. end;
  1161. end;
  1162. inc(j);
  1163. end;
  1164. end;
  1165. end;
  1166. end;
  1167. procedure tx86attreader.handleopcode;
  1168. var
  1169. instr : Tx86Instruction;
  1170. begin
  1171. instr:=Tx86attInstruction.Create(Tx86Operand);
  1172. BuildOpcode(instr);
  1173. instr.AddReferenceSizes;
  1174. instr.SetInstructionOpsize;
  1175. instr.CheckOperandSizes;
  1176. instr.FixupOpcode;
  1177. instr.ConcatInstruction(curlist);
  1178. instr.Free;
  1179. end;
  1180. end.