rax86att.pas 43 KB

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