rax86att.pas 39 KB

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