rax86att.pas 39 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105
  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. 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: tcgint;
  305. sym: tasmsymbol;
  306. begin
  307. case actasmtoken of
  308. AS_AT:
  309. begin
  310. { darwin/i386 needs a relsym instead, and we can't }
  311. { generate this automatically }
  312. if (target_info.system in [system_i386_darwin,system_i386_iphonesim]) then
  313. Message(asmr_e_invalid_reference_syntax);
  314. consume(AS_AT);
  315. if actasmtoken=AS_ID then
  316. begin
  317. {$ifdef x86_64}
  318. if (actasmpattern='GOTPCREL') or
  319. (actasmpattern='PLT') then
  320. {$endif x86_64}
  321. {$ifdef i386}
  322. if actasmpattern='GOT' then
  323. {$endif i386}
  324. {$ifdef i8086}
  325. if actasmpattern='GOT' then
  326. {$endif i8086}
  327. begin
  328. case oper.opr.typ of
  329. OPR_SYMBOL:
  330. begin
  331. sym:=oper.opr.symbol;
  332. if oper.opr.symofs<>0 then
  333. Message(asmr_e_invalid_reference_syntax);
  334. oper.opr.typ:=OPR_REFERENCE;
  335. fillchar(oper.opr.ref,sizeof(oper.opr.ref),0);
  336. oper.opr.ref.symbol:=sym;
  337. end;
  338. OPR_REFERENCE:
  339. begin
  340. { ok }
  341. end;
  342. else
  343. Message(asmr_e_invalid_reference_syntax)
  344. end;
  345. oper.opr.ref.refaddr:=addr_pic;
  346. consume(AS_ID);
  347. end
  348. else
  349. Message(asmr_e_invalid_reference_syntax);
  350. end
  351. else
  352. Message(asmr_e_invalid_reference_syntax);
  353. end;
  354. AS_MINUS:
  355. begin
  356. { relsym? }
  357. Consume(AS_MINUS);
  358. BuildConstSymbolExpression(true,true,false,l,relsym,asmsymtyp);
  359. if (relsym<>'') then
  360. if not assigned(oper.opr.ref.relsymbol) then
  361. oper.opr.ref.relsymbol:=current_asmdata.RefAsmSymbol(relsym,asmsymtyp)
  362. else
  363. Message(asmr_e_invalid_reference_syntax)
  364. else
  365. dec(oper.opr.ref.offset,l);
  366. end;
  367. else
  368. ;
  369. end;
  370. end;
  371. Procedure tx86attreader.BuildOperand(oper : tx86operand);
  372. var
  373. tempstr,
  374. expr : string;
  375. typesize,l,k : tcgint;
  376. procedure AddLabelOperand(hl:tasmlabel);
  377. begin
  378. if not(actasmtoken in [AS_PLUS,AS_MINUS,AS_LPAREN]) and
  379. is_calljmp(actopcode) then
  380. begin
  381. oper.opr.typ:=OPR_SYMBOL;
  382. oper.opr.symbol:=hl;
  383. end
  384. else
  385. begin
  386. oper.InitRef;
  387. oper.opr.ref.symbol:=hl;
  388. end;
  389. end;
  390. procedure MaybeRecordOffset;
  391. var
  392. mangledname: string;
  393. hasdot : boolean;
  394. l,
  395. toffset,
  396. tsize : tcgint;
  397. begin
  398. if not(actasmtoken in [AS_DOT,AS_PLUS,AS_MINUS]) then
  399. exit;
  400. l:=0;
  401. mangledname:='';
  402. hasdot:=(actasmtoken=AS_DOT);
  403. if hasdot then
  404. begin
  405. if expr<>'' then
  406. begin
  407. BuildRecordOffsetSize(expr,toffset,tsize,mangledname,false);
  408. if (oper.opr.typ<>OPR_CONSTANT) and
  409. (mangledname<>'') then
  410. Message(asmr_e_wrong_sym_type);
  411. inc(l,toffset);
  412. oper.SetSize(tsize,true);
  413. case oper.opr.typ of
  414. OPR_REFERENCE: oper.opr.varsize := tsize;
  415. OPR_LOCAL: oper.opr.localvarsize := tsize;
  416. else
  417. ;
  418. end;
  419. end;
  420. end;
  421. if actasmtoken in [AS_PLUS,AS_MINUS] then
  422. inc(l,BuildConstExpression(true,false));
  423. case oper.opr.typ of
  424. OPR_LOCAL :
  425. begin
  426. { don't allow direct access to fields of parameters, because that
  427. will generate buggy code. Allow it only for explicit typecasting }
  428. if hasdot and
  429. (not oper.hastype) then
  430. checklocalsubscript(oper.opr.localsym);
  431. inc(oper.opr.localsymofs,l);
  432. inc(oper.opr.localconstoffset,l);
  433. end;
  434. OPR_CONSTANT :
  435. if (mangledname<>'') then
  436. begin
  437. if (oper.opr.val<>0) then
  438. Message(asmr_e_wrong_sym_type);
  439. oper.opr.typ:=OPR_SYMBOL;
  440. oper.opr.symbol:=current_asmdata.RefAsmSymbol(mangledname,AT_FUNCTION);
  441. end
  442. else
  443. inc(oper.opr.val,l);
  444. OPR_REFERENCE :
  445. begin
  446. inc(oper.opr.ref.offset,l);
  447. inc(oper.opr.constoffset,l);
  448. end;
  449. OPR_SYMBOL:
  450. Message(asmr_e_invalid_symbol_ref);
  451. else
  452. internalerror(200309221);
  453. end;
  454. end;
  455. function MaybeBuildReference:boolean;
  456. { Try to create a reference, if not a reference is found then false
  457. is returned }
  458. var
  459. mangledname: string;
  460. begin
  461. MaybeBuildReference:=true;
  462. case actasmtoken of
  463. AS_INTNUM:
  464. Begin
  465. { allow %segmentregister:number }
  466. if oper.opr.ref.segment<>NR_NO then
  467. begin
  468. // already done before calling oper.InitRef;
  469. if oper.opr.Ref.Offset <> 0 Then
  470. Message(asmr_e_invalid_reference_syntax)
  471. else
  472. begin
  473. oper.opr.Ref.Offset:=BuildConstExpression(true,false);
  474. if actasmtoken=AS_LPAREN then
  475. BuildReference(oper)
  476. else if (oper.opr.ref.segment <> NR_FS) and
  477. (oper.opr.ref.segment <> NR_GS) then
  478. Message(asmr_w_general_segment_with_constant);
  479. end;
  480. end
  481. else
  482. begin
  483. oper.opr.ref.offset:=BuildConstExpression(True,False);
  484. BuildReference(oper);
  485. end;
  486. end;
  487. AS_MINUS,
  488. AS_PLUS:
  489. Begin
  490. oper.opr.ref.offset:=BuildConstExpression(True,False);
  491. if actasmtoken<>AS_LPAREN then
  492. Message(asmr_e_invalid_reference_syntax)
  493. else
  494. BuildReference(oper);
  495. end;
  496. AS_LPAREN:
  497. BuildReference(oper);
  498. AS_ID: { only a variable is allowed ... }
  499. Begin
  500. tempstr:=actasmpattern;
  501. Consume(AS_ID);
  502. { typecasting? }
  503. if (actasmtoken=AS_LPAREN) and
  504. SearchType(tempstr,typesize) then
  505. begin
  506. oper.hastype:=true;
  507. Consume(AS_LPAREN);
  508. BuildOperand(oper);
  509. Consume(AS_RPAREN);
  510. if oper.opr.typ in [OPR_REFERENCE,OPR_LOCAL] then
  511. oper.SetSize(typesize,true);
  512. end
  513. else
  514. if not oper.SetupVar(tempstr,false) then
  515. Message1(sym_e_unknown_id,tempstr);
  516. { record.field ? }
  517. if actasmtoken=AS_DOT then
  518. begin
  519. BuildRecordOffsetSize(tempstr,l,k,mangledname,false);
  520. if (mangledname<>'') then
  521. Message(asmr_e_invalid_reference_syntax);
  522. inc(oper.opr.ref.offset,l);
  523. case oper.opr.typ of
  524. OPR_REFERENCE: oper.opr.varsize := k;
  525. OPR_LOCAL: oper.opr.localvarsize := k;
  526. else
  527. ;
  528. end;
  529. end;
  530. MaybeGetPICModifier(oper);
  531. case actasmtoken of
  532. AS_END,
  533. AS_SEPARATOR,
  534. AS_COMMA: ;
  535. AS_LPAREN:
  536. BuildReference(oper);
  537. else
  538. Begin
  539. Message(asmr_e_invalid_reference_syntax);
  540. Consume(actasmtoken);
  541. end;
  542. end; {end case }
  543. end;
  544. else
  545. MaybeBuildReference:=false;
  546. end; { end case }
  547. end;
  548. var
  549. tempreg : tregister;
  550. hl : tasmlabel;
  551. Begin
  552. expr:='';
  553. case actasmtoken of
  554. AS_LPAREN: { Memory reference or constant expression }
  555. Begin
  556. oper.InitRef;
  557. BuildReference(oper);
  558. end;
  559. AS_DOLLAR: { Constant expression }
  560. Begin
  561. Consume(AS_DOLLAR);
  562. BuildConstantOperand(oper);
  563. end;
  564. AS_INTNUM,
  565. AS_MINUS,
  566. AS_PLUS:
  567. Begin
  568. { Constant memory offset }
  569. { This must absolutely be followed by ( }
  570. oper.InitRef;
  571. oper.opr.ref.offset:=asizeint(BuildConstExpression(True,False));
  572. if actasmtoken<>AS_LPAREN then
  573. Message(asmr_e_invalid_reference_syntax)
  574. else
  575. BuildReference(oper);
  576. end;
  577. AS_STAR: { Call from memory address }
  578. Begin
  579. Consume(AS_STAR);
  580. if actasmtoken=AS_REGISTER then
  581. begin
  582. oper.opr.typ:=OPR_REGISTER;
  583. oper.opr.reg:=actasmregister;
  584. oper.SetSize(tcgsize2size[reg_cgsize(actasmregister)],true);
  585. Consume(AS_REGISTER);
  586. end
  587. else
  588. begin
  589. oper.InitRef;
  590. if not MaybeBuildReference then
  591. Message(asmr_e_syn_operand);
  592. end;
  593. { this is only allowed for call's and jmp's }
  594. if not is_calljmp(actopcode) then
  595. Message(asmr_e_syn_operand);
  596. end;
  597. AS_ID: { A constant expression, or a Variable ref. }
  598. Begin
  599. { Local Label ? }
  600. if is_locallabel(actasmpattern) then
  601. begin
  602. CreateLocalLabel(actasmpattern,hl,false);
  603. Consume(AS_ID);
  604. AddLabelOperand(hl);
  605. end
  606. else
  607. { Check for label }
  608. if SearchLabel(actasmpattern,hl,false) then
  609. begin
  610. Consume(AS_ID);
  611. AddLabelOperand(hl);
  612. end
  613. else
  614. { probably a variable or normal expression }
  615. { or a procedure (such as in CALL ID) }
  616. Begin
  617. { is it a constant ? }
  618. if SearchIConstant(actasmpattern,l) then
  619. Begin
  620. if not (oper.opr.typ in [OPR_NONE,OPR_CONSTANT]) then
  621. Message(asmr_e_invalid_operand_type);
  622. BuildConstantOperand(oper);
  623. end
  624. else
  625. begin
  626. expr:=actasmpattern;
  627. Consume(AS_ID);
  628. { typecasting? }
  629. if (actasmtoken=AS_LPAREN) and
  630. SearchType(expr,typesize) then
  631. begin
  632. oper.hastype:=true;
  633. Consume(AS_LPAREN);
  634. BuildOperand(oper);
  635. Consume(AS_RPAREN);
  636. if oper.opr.typ in [OPR_REFERENCE,OPR_LOCAL] then
  637. oper.SetSize(typesize,true);
  638. end
  639. else
  640. begin
  641. if oper.SetupVar(expr,false) then
  642. MaybeGetPICModifier(oper)
  643. else
  644. Begin
  645. { look for special symbols ... }
  646. if expr= '__HIGH' then
  647. begin
  648. consume(AS_LPAREN);
  649. if not oper.setupvar('high'+actasmpattern,false) then
  650. Message1(sym_e_unknown_id,'high'+actasmpattern);
  651. consume(AS_ID);
  652. consume(AS_RPAREN);
  653. end
  654. else
  655. if expr = '__RESULT' then
  656. oper.SetUpResult
  657. else
  658. if expr = '__SELF' then
  659. oper.SetupSelf
  660. else
  661. if expr = '__OLDEBP' then
  662. oper.SetupOldEBP
  663. else
  664. Message1(sym_e_unknown_id,expr);
  665. end;
  666. end;
  667. end;
  668. if oper.opr.typ<>OPR_NONE Then
  669. begin
  670. if (actasmtoken=AS_DOT) then
  671. MaybeRecordOffset;
  672. { add a constant expression? }
  673. if (actasmtoken=AS_PLUS) then
  674. begin
  675. l:=BuildConstExpression(true,false);
  676. case oper.opr.typ of
  677. OPR_CONSTANT :
  678. inc(oper.opr.val,l);
  679. OPR_LOCAL :
  680. begin
  681. inc(oper.opr.localsymofs,l);
  682. inc(oper.opr.localconstoffset, l);
  683. end;
  684. OPR_REFERENCE :
  685. begin
  686. inc(oper.opr.ref.offset,l);
  687. inc(oper.opr.constoffset, l);
  688. end;
  689. else
  690. internalerror(200309202);
  691. end;
  692. end;
  693. end;
  694. end;
  695. { Do we have a indexing reference, then parse it also }
  696. if actasmtoken=AS_LPAREN then
  697. BuildReference(oper);
  698. end;
  699. AS_REGISTER: { Register, a variable reference or a constant reference }
  700. Begin
  701. { save the type of register used. }
  702. tempreg:=actasmregister;
  703. Consume(AS_REGISTER);
  704. if actasmtoken = AS_COLON then
  705. Begin
  706. Consume(AS_COLON);
  707. oper.InitRef;
  708. if not is_segment_reg(tempreg) then
  709. Message(asmr_e_invalid_seg_override);
  710. {$ifdef x86_64}
  711. if (tempreg=NR_CS) or (tempreg=NR_DS) or (tempreg=NR_SS) or (tempreg=NR_ES) then
  712. Message1(asmr_w_segment_override_ignored_in_64bit_mode,gas_regname(tempreg));
  713. {$endif x86_64}
  714. oper.opr.ref.segment:=tempreg;
  715. { This must absolutely be followed by a reference }
  716. if not MaybeBuildReference then
  717. Begin
  718. Message(asmr_e_invalid_seg_override);
  719. Consume(actasmtoken);
  720. end;
  721. end
  722. { Simple register }
  723. else if (actasmtoken in [AS_END,AS_SEPARATOR,AS_COMMA]) then
  724. Begin
  725. if not (oper.opr.typ in [OPR_NONE,OPR_REGISTER]) then
  726. Message(asmr_e_invalid_operand_type);
  727. oper.opr.typ:=OPR_REGISTER;
  728. oper.opr.reg:=tempreg;
  729. oper.SetSize(tcgsize2size[reg_cgsize(oper.opr.reg)],true);
  730. end
  731. else
  732. Message(asmr_e_syn_operand);
  733. end;
  734. AS_END,
  735. AS_SEPARATOR,
  736. AS_COMMA: ;
  737. else
  738. Begin
  739. Message(asmr_e_syn_operand);
  740. Consume(actasmtoken);
  741. end;
  742. end; { end case }
  743. end;
  744. procedure tx86attreader.BuildOpCode(instr : tx86instruction);
  745. var
  746. operandnum : longint;
  747. PrefixOp,OverrideOp: tasmop;
  748. di_param, si_param: ShortInt;
  749. Begin
  750. PrefixOp:=A_None;
  751. OverrideOp:=A_None;
  752. { prefix seg opcode / prefix opcode }
  753. repeat
  754. if is_prefix(actopcode) then
  755. begin
  756. PrefixOp:=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. if is_override(actopcode) then
  768. begin
  769. OverrideOp:=ActOpcode;
  770. with instr do
  771. begin
  772. opcode:=ActOpcode;
  773. condition:=ActCondition;
  774. opsize:=ActOpsize;
  775. ConcatInstruction(curlist);
  776. end;
  777. Consume(AS_OPCODE);
  778. end
  779. else
  780. break;
  781. { allow for newline as in gas styled syntax }
  782. while actasmtoken=AS_SEPARATOR do
  783. Consume(AS_SEPARATOR);
  784. until (actasmtoken<>AS_OPCODE);
  785. { opcode }
  786. if (actasmtoken<>AS_OPCODE) then
  787. Begin
  788. Message(asmr_e_invalid_or_missing_opcode);
  789. RecoverConsume(true);
  790. exit;
  791. end;
  792. { Fill the instr object with the current state }
  793. with instr do
  794. begin
  795. Opcode:=ActOpcode;
  796. condition:=ActCondition;
  797. opsize:=ActOpsize;
  798. end;
  799. { Valid combination of prefix/override and instruction ? }
  800. if (prefixop<>A_NONE) and (NOT CheckPrefix(PrefixOp,actopcode)) then
  801. Message1(asmr_e_invalid_prefix_and_opcode,actasmpattern);
  802. if (overrideop<>A_NONE) and (NOT CheckOverride(OverrideOp,ActOpcode)) then
  803. Message1(asmr_e_invalid_override_and_opcode,actasmpattern);
  804. { We are reading operands, so opcode will be an AS_ID }
  805. operandnum:=1;
  806. Consume(AS_OPCODE);
  807. { Zero operand opcode ? }
  808. if actasmtoken in [AS_SEPARATOR,AS_END] then
  809. begin
  810. operandnum:=0;
  811. exit;
  812. end;
  813. { Read the operands }
  814. repeat
  815. case actasmtoken of
  816. AS_COMMA: { Operand delimiter }
  817. Begin
  818. if operandnum > Max_Operands then
  819. Message(asmr_e_too_many_operands)
  820. else
  821. Inc(operandnum);
  822. Consume(AS_COMMA);
  823. end;
  824. AS_SEPARATOR,
  825. AS_END : { End of asm operands for this opcode }
  826. begin
  827. break;
  828. end;
  829. else
  830. BuildOperand(instr.Operands[operandnum] as tx86operand);
  831. end; { end case }
  832. until false;
  833. instr.Ops:=operandnum;
  834. { handle string instructions with parameters }
  835. with instr do
  836. if is_x86_parameterless_string_op(opcode) and
  837. (Ops>=1) and (Ops<=2) then
  838. begin
  839. if opcode=A_MOVSD then
  840. begin
  841. { distinguish between MOVS and the SSE MOVSD instruction:
  842. MOVS must have memory 2 reference operands (there's no need
  843. to distinguish from SSE CMPSD, because the SSE version has 3
  844. arguments and we've already checked that above) }
  845. if (Ops=2) and (operands[1].opr.typ=OPR_REFERENCE) and (operands[2].opr.typ=OPR_REFERENCE) then
  846. begin
  847. opcode:=A_MOVS;
  848. opsize:=S_L;
  849. end;
  850. end
  851. else
  852. begin
  853. opsize:=get_x86_string_op_size(opcode);
  854. opcode:=x86_param2paramless_string_op(opcode);
  855. end;
  856. end;
  857. { Check for invalid ES: overrides }
  858. if is_x86_parameterized_string_op(instr.opcode) then
  859. begin
  860. si_param:=get_x86_string_op_si_param(instr.opcode);
  861. if si_param<>-1 then
  862. begin
  863. si_param:=x86_parameterized_string_op_param_count(instr.opcode)-si_param;
  864. if si_param<=operandnum then
  865. with instr.operands[si_param] do
  866. if (opr.typ=OPR_REFERENCE) then
  867. begin
  868. if not((((opr.ref.index<>NR_NO) and
  869. (opr.ref.base=NR_NO) and
  870. (getregtype(opr.ref.index)=R_INTREGISTER) and
  871. (getsupreg(opr.ref.index)=RS_ESI)) or
  872. ((opr.ref.index=NR_NO) and
  873. (opr.ref.base<>NR_NO) and
  874. (getregtype(opr.ref.base)=R_INTREGISTER) and
  875. (getsupreg(opr.ref.base)=RS_ESI))) and
  876. (opr.ref.offset=0) and
  877. (opr.ref.scalefactor<=1) and
  878. (opr.ref.refaddr=addr_no) and
  879. (opr.ref.symbol=nil) and
  880. (opr.ref.relsymbol=nil)) then
  881. {$if defined(i8086)}
  882. Message1(asmr_w_invalid_reference,'(%si)');
  883. {$elseif defined(i386)}
  884. Message1(asmr_w_invalid_reference,'(%esi)');
  885. {$elseif defined(x86_64)}
  886. Message1(asmr_w_invalid_reference,'(%rsi)');
  887. {$endif}
  888. end;
  889. end;
  890. di_param:=get_x86_string_op_di_param(instr.opcode);
  891. if di_param<>-1 then
  892. begin
  893. di_param:=x86_parameterized_string_op_param_count(instr.opcode)-di_param;
  894. if di_param<=operandnum then
  895. with instr.operands[di_param] do
  896. if (opr.typ=OPR_REFERENCE) then
  897. begin
  898. if (opr.ref.segment<>NR_NO) and
  899. (opr.ref.segment<>NR_ES) then
  900. Message(asmr_e_cannot_override_es_segment);
  901. if not((((opr.ref.index<>NR_NO) and
  902. (opr.ref.base=NR_NO) and
  903. (getregtype(opr.ref.index)=R_INTREGISTER) and
  904. (getsupreg(opr.ref.index)=RS_EDI)) or
  905. ((opr.ref.index=NR_NO) and
  906. (opr.ref.base<>NR_NO) and
  907. (getregtype(opr.ref.base)=R_INTREGISTER) and
  908. (getsupreg(opr.ref.base)=RS_EDI))) and
  909. (opr.ref.offset=0) and
  910. (opr.ref.scalefactor<=1) and
  911. (opr.ref.refaddr=addr_no) and
  912. (opr.ref.symbol=nil) and
  913. (opr.ref.relsymbol=nil)) then
  914. {$if defined(i8086)}
  915. Message1(asmr_w_invalid_reference,'(%di)');
  916. {$elseif defined(i386)}
  917. Message1(asmr_w_invalid_reference,'(%edi)');
  918. {$elseif defined(x86_64)}
  919. Message1(asmr_w_invalid_reference,'(%rdi)');
  920. {$endif}
  921. end;
  922. end;
  923. { if two memory parameters, check whether their address sizes are equal }
  924. if (si_param<>-1) and (di_param<>-1) and
  925. (si_param<=operandnum) and (di_param<=operandnum) and
  926. (instr.operands[si_param].opr.typ=OPR_REFERENCE) and
  927. (instr.operands[di_param].opr.typ=OPR_REFERENCE) then
  928. begin
  929. if get_ref_address_size(instr.operands[si_param].opr.ref)<>
  930. get_ref_address_size(instr.operands[di_param].opr.ref) then
  931. Message(asmr_e_address_sizes_do_not_match);
  932. end;
  933. end;
  934. end;
  935. function tx86attreader.is_asmopcode(const s: string):boolean;
  936. var
  937. cond : string[4];
  938. cnd : tasmcond;
  939. len,
  940. j,
  941. sufidx,
  942. suflen : longint;
  943. Begin
  944. is_asmopcode:=FALSE;
  945. actopcode:=A_None;
  946. actcondition:=C_None;
  947. actopsize:=S_NO;
  948. { search for all possible suffixes }
  949. for sufidx:=low(att_sizesuffixstr) to high(att_sizesuffixstr) do
  950. begin
  951. suflen:=length(att_sizesuffixstr[sufidx]);
  952. len:=length(s)-suflen;
  953. if copy(s,len+1,suflen)=att_sizesuffixstr[sufidx] then
  954. begin
  955. { Search opcodes }
  956. if len>0 then
  957. begin
  958. actopcode:=tasmop(PtrUInt(iasmops.Find(copy(s,1,len))));
  959. { movsd needs special handling because it has two namings in at&t syntax (movsl for string handling and
  960. movsd for the sse instruction) while only one in intel syntax (movsd, both string and sse)
  961. this cannot be expressed by the instruction table format so we have to hack around this here }
  962. if (actopcode = A_NONE) and (upper(s) = 'MOVSD') then
  963. actopcode := A_MOVSD;
  964. { cmpsd also needs special handling for pretty much the same reasons as movsd }
  965. if (actopcode = A_NONE) and (upper(s) = 'CMPSD') then
  966. actopcode := A_CMPSD;
  967. { disambiguation between A_MOVS (movsb/movsw/movsl/movsq) and
  968. A_MOVSX (movsbw/movsbl/movswl/movsbq/movswq) }
  969. if (actopcode = A_MOVS) and (suflen=2) then
  970. actopcode := A_MOVSX;
  971. { two-letter suffix is allowed by just a few instructions (movsx,movzx),
  972. and it is always required whenever allowed }
  973. if (gas_needsuffix[actopcode]=attsufINTdual) xor (suflen=2) then
  974. continue;
  975. if actopcode<>A_NONE then
  976. begin
  977. if gas_needsuffix[actopcode]=attsufFPU then
  978. actopsize:=att_sizefpusuffix[sufidx]
  979. else if gas_needsuffix[actopcode]=attsufFPUint then
  980. actopsize:=att_sizefpuintsuffix[sufidx]
  981. else if gas_needsuffix[actopcode]=attsufMM then
  982. actopsize:=att_sizemmsuffix[sufidx]
  983. else
  984. actopsize:=att_sizesuffix[sufidx];
  985. { only accept suffix from the same category that the opcode belongs to }
  986. if (actopsize<>S_NO) or (suflen=0) then
  987. begin
  988. actasmtoken:=AS_OPCODE;
  989. is_asmopcode:=TRUE;
  990. exit;
  991. end;
  992. end;
  993. end;
  994. { not found, check condition opcodes }
  995. j:=0;
  996. while (j<CondAsmOps) do
  997. begin
  998. if Copy(s,1,Length(CondAsmOpStr[j]))=CondAsmOpStr[j] then
  999. begin
  1000. cond:=Copy(s,Length(CondAsmOpStr[j])+1,len-Length(CondAsmOpStr[j]));
  1001. if cond<>'' then
  1002. begin
  1003. for cnd:=low(TasmCond) to high(TasmCond) do
  1004. if Cond=Upper(cond2str[cnd]) then
  1005. begin
  1006. actopcode:=CondASmOp[j];
  1007. { conditional instructions (cmovcc, setcc) use only INT suffixes;
  1008. other stuff like fcmovcc is represented as group of individual instructions }
  1009. if gas_needsuffix[actopcode]=attsufINT then
  1010. actopsize:=att_sizesuffix[sufidx];
  1011. { only accept suffix from the same category that the opcode belongs to }
  1012. if (actopsize<>S_NO) or (suflen=0) then
  1013. begin
  1014. actcondition:=cnd;
  1015. actasmtoken:=AS_OPCODE;
  1016. is_asmopcode:=TRUE;
  1017. exit;
  1018. end;
  1019. end;
  1020. end;
  1021. end;
  1022. inc(j);
  1023. end;
  1024. end;
  1025. end;
  1026. end;
  1027. procedure tx86attreader.handleopcode;
  1028. var
  1029. instr : Tx86Instruction;
  1030. begin
  1031. instr:=Tx86attInstruction.Create(Tx86Operand);
  1032. BuildOpcode(instr);
  1033. instr.AddReferenceSizes;
  1034. instr.SetInstructionOpsize;
  1035. instr.CheckOperandSizes;
  1036. instr.FixupOpcode;
  1037. instr.ConcatInstruction(curlist);
  1038. instr.Free;
  1039. end;
  1040. end.