racpugas.pas 42 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285
  1. {
  2. Copyright (c) 1998-2002 by Carl Eric Codere and Peter Vreman
  3. Copyright (c) 2014 by Jonas Maebe
  4. Does the parsing for the AArch64 GNU AS styled inline assembler.
  5. This program is free software; you can redistribute it and/or modify
  6. it under the terms of the GNU General Public License as published by
  7. the Free Software Foundation; either version 2 of the License, or
  8. (at your option) any later version.
  9. This program is distributed in the hope that it will be useful,
  10. but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. GNU General Public License for more details.
  13. You should have received a copy of the GNU General Public License
  14. along with this program; if not, write to the Free Software
  15. Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  16. ****************************************************************************
  17. }
  18. Unit racpugas;
  19. {$i fpcdefs.inc}
  20. Interface
  21. uses
  22. raatt,racpu,
  23. aasmtai,
  24. cpubase;
  25. type
  26. { taarch64attreader }
  27. taarch64attreader = class(tattreader)
  28. actoppostfix : TOpPostfix;
  29. actsehdirective : TAsmSehDirective;
  30. function is_asmopcode(const s: string):boolean;override;
  31. function is_register(const s:string):boolean;override;
  32. function is_targetdirective(const s: string): boolean;override;
  33. procedure handleopcode;override;
  34. procedure handletargetdirective; override;
  35. procedure BuildReference(oper: taarch64operand; is64bit: boolean);
  36. procedure BuildOperand(oper: taarch64operand; is64bit: boolean);
  37. function TryBuildShifterOp(instr: taarch64instruction; opnr: longint) : boolean;
  38. procedure BuildOpCode(instr: taarch64instruction);
  39. procedure ReadSym(oper: taarch64operand; is64bit: boolean);
  40. procedure ConvertCalljmp(instr: taarch64instruction);
  41. function ToConditionCode(const hs: string; is_operand: boolean): tasmcond;
  42. end;
  43. Implementation
  44. uses
  45. { helpers }
  46. cutils,
  47. { global }
  48. globtype,verbose,
  49. systems,aasmbase,aasmdata,aasmcpu,
  50. { symtable }
  51. symconst,symsym,symdef,
  52. procinfo,
  53. rabase,rautils,
  54. cgbase,cgutils,paramgr;
  55. function taarch64attreader.is_register(const s:string):boolean;
  56. type
  57. treg2str = record
  58. name : string[3];
  59. reg : tregister;
  60. end;
  61. const
  62. extraregs : array[0..3] of treg2str = (
  63. (name: 'FP' ; reg: NR_FP),
  64. (name: 'LR' ; reg: NR_LR),
  65. (name: 'IP0'; reg: NR_IP0),
  66. (name: 'IP1'; reg: NR_IP1));
  67. var
  68. i : longint;
  69. begin
  70. result:=inherited is_register(s);
  71. { reg found?
  72. possible aliases are always 2 or 3 chars
  73. }
  74. if result or not(length(s) in [2,3]) then
  75. exit;
  76. for i:=low(extraregs) to high(extraregs) do
  77. begin
  78. if s=extraregs[i].name then
  79. begin
  80. actasmregister:=extraregs[i].reg;
  81. result:=true;
  82. actasmtoken:=AS_REGISTER;
  83. exit;
  84. end;
  85. end;
  86. end;
  87. const
  88. { Aarch64 subset of SEH directives. .seh_proc, .seh_endproc and .seh_endepilogue
  89. excluded because they are generated automatically when needed. }
  90. recognized_directives: set of TAsmSehDirective=[
  91. ash_endprologue,ash_handler,ash_handlerdata,
  92. ash_stackalloc,ash_nop,ash_savefplr,ash_savefplr_x,
  93. ash_savereg,ash_savereg_x,ash_saveregp,ash_saveregp_x,
  94. ash_savefreg,ash_savefreg_x,ash_savefregp,ash_savefregp_x,
  95. ash_setfp,ash_addfp
  96. ];
  97. function taarch64attreader.is_targetdirective(const s: string): boolean;
  98. var
  99. i: TAsmSehDirective;
  100. begin
  101. result:=false;
  102. if target_info.system<>system_aarch64_win64 then
  103. exit;
  104. for i:=low(TAsmSehDirective) to high(TAsmSehDirective) do
  105. begin
  106. if not (i in recognized_directives) then
  107. continue;
  108. if s=sehdirectivestr[i] then
  109. begin
  110. actsehdirective:=i;
  111. result:=true;
  112. break;
  113. end;
  114. end;
  115. { allow SEH directives only in pure assember routines }
  116. if result and not (po_assembler in current_procinfo.procdef.procoptions) then
  117. begin
  118. Message(asmr_e_seh_in_pure_asm_only);
  119. result:=false;
  120. end;
  121. end;
  122. procedure taarch64attreader.ReadSym(oper: taarch64operand; is64bit: boolean);
  123. var
  124. tempstr, mangledname : string;
  125. typesize,l,k: aint;
  126. begin
  127. tempstr:=actasmpattern;
  128. Consume(AS_ID);
  129. { typecasting? }
  130. if (actasmtoken=AS_LPAREN) and
  131. SearchType(tempstr,typesize) then
  132. begin
  133. oper.hastype:=true;
  134. Consume(AS_LPAREN);
  135. BuildOperand(oper,is64bit);
  136. Consume(AS_RPAREN);
  137. if oper.opr.typ in [OPR_REFERENCE,OPR_LOCAL] then
  138. oper.SetSize(typesize,true);
  139. end
  140. else
  141. if not oper.SetupVar(tempstr,false) then
  142. Message1(sym_e_unknown_id,tempstr);
  143. { record.field ? }
  144. if actasmtoken=AS_DOT then
  145. begin
  146. BuildRecordOffsetSize(tempstr,l,k,mangledname,false);
  147. if (mangledname<>'') then
  148. Message(asmr_e_invalid_reference_syntax);
  149. inc(oper.opr.ref.offset,l);
  150. end;
  151. end;
  152. Procedure taarch64attreader.BuildReference(oper: taarch64operand; is64bit: boolean);
  153. procedure do_error;
  154. begin
  155. Message(asmr_e_invalid_reference_syntax);
  156. RecoverConsume(false);
  157. end;
  158. procedure test_end(require_rbracket : boolean);
  159. begin
  160. if require_rbracket then begin
  161. if not(actasmtoken=AS_RBRACKET) then
  162. begin
  163. do_error;
  164. exit;
  165. end
  166. else
  167. Consume(AS_RBRACKET);
  168. if (actasmtoken=AS_NOT) then
  169. begin
  170. oper.opr.ref.addressmode:=AM_PREINDEXED;
  171. Consume(AS_NOT);
  172. end;
  173. end;
  174. if not(actasmtoken in [AS_SEPARATOR,AS_end]) then
  175. do_error
  176. else
  177. begin
  178. {$IFDEF debugasmreader}
  179. writeln('TEST_end_FINAL_OK. Created the following ref:');
  180. writeln('oper.opr.ref.shiftimm=',oper.opr.ref.shiftimm);
  181. writeln('oper.opr.ref.shiftmode=',ord(oper.opr.ref.shiftmode));
  182. writeln('oper.opr.ref.index=',ord(oper.opr.ref.index));
  183. writeln('oper.opr.ref.base=',ord(oper.opr.ref.base));
  184. writeln('oper.opr.ref.signindex=',ord(oper.opr.ref.signindex));
  185. writeln('oper.opr.ref.addressmode=',ord(oper.opr.ref.addressmode));
  186. writeln;
  187. {$endIF debugasmreader}
  188. end;
  189. end;
  190. function is_shifter_ref_operation(var a : tshiftmode) : boolean;
  191. begin
  192. a:=SM_NONE;
  193. if (actasmpattern='LSL') then
  194. a:=SM_LSL
  195. else if (actasmpattern='UXTW') then
  196. a:=SM_UXTW
  197. else if (actasmpattern='SXTW') then
  198. a:=SM_SXTW
  199. else if (actasmpattern='SXTX') then
  200. a:=SM_SXTX;
  201. is_shifter_ref_operation:=not(a=SM_NONE);
  202. end;
  203. procedure read_index_shift(require_rbracket : boolean);
  204. var
  205. shift: aint;
  206. begin
  207. case actasmtoken of
  208. AS_COMMA :
  209. begin
  210. Consume(AS_COMMA);
  211. if not(actasmtoken=AS_ID) then
  212. do_error;
  213. if is_shifter_ref_operation(oper.opr.ref.shiftmode) then
  214. begin
  215. Consume(actasmtoken);
  216. if actasmtoken=AS_HASH then
  217. begin
  218. Consume(AS_HASH);
  219. shift:=BuildConstExpression(false,true);
  220. if not(shift in [0,2+ord(is64bit)]) then
  221. do_error;
  222. oper.opr.ref.shiftimm:=shift;
  223. test_end(require_rbracket);
  224. end;
  225. end
  226. else
  227. begin
  228. do_error;
  229. exit;
  230. end;
  231. end;
  232. AS_RBRACKET :
  233. if require_rbracket then
  234. test_end(require_rbracket)
  235. else
  236. begin
  237. do_error;
  238. exit;
  239. end;
  240. AS_SEPARATOR,AS_END :
  241. if not require_rbracket then
  242. test_end(false)
  243. else
  244. do_error;
  245. else
  246. begin
  247. do_error;
  248. exit;
  249. end;
  250. end;
  251. end;
  252. procedure read_index(require_rbracket : boolean);
  253. var
  254. recname : string;
  255. o_int,s_int : aint;
  256. begin
  257. case actasmtoken of
  258. AS_REGISTER :
  259. begin
  260. if getsupreg(actasmregister)=RS_XZR then
  261. Message1(asmr_e_invalid_ref_register,actasmpattern);
  262. oper.opr.ref.index:=actasmregister;
  263. Consume(AS_REGISTER);
  264. read_index_shift(require_rbracket);
  265. exit;
  266. end;
  267. AS_HASH : // constant
  268. begin
  269. Consume(AS_HASH);
  270. (*
  271. if actasmtoken=AS_COLON then
  272. begin
  273. consume(AS_COLON);
  274. { GNU-style lower 12 bits of address of non-GOT-based
  275. access }
  276. if (actasmpattern='LO12') then
  277. begin
  278. consume(actasmtoken);
  279. consume(AS_COLON);
  280. if not oper.SetupVar(actasmpattern,false) then
  281. begin
  282. do_error;
  283. exit
  284. end;
  285. consume(AS_ID);
  286. oper.opr.ref.refaddr:=addr_??? (not gotpageoffset);
  287. end
  288. else
  289. begin
  290. do_error;
  291. exit
  292. end;
  293. end
  294. else
  295. *)
  296. begin
  297. o_int:=BuildConstExpression(false,true);
  298. inc(oper.opr.ref.offset,o_int);
  299. end;
  300. test_end(require_rbracket);
  301. exit;
  302. end;
  303. AS_ID :
  304. begin
  305. recname:=actasmpattern;
  306. Consume(AS_ID);
  307. { Apple-style got page offset }
  308. if actasmtoken=AS_AT then
  309. begin
  310. if not oper.SetupVar(recname,false) then
  311. begin
  312. do_error;
  313. exit
  314. end;
  315. consume(AS_AT);
  316. if actasmpattern='GOTPAGEOFF' then
  317. begin
  318. consume(actasmtoken);
  319. oper.opr.ref.refaddr:=addr_gotpageoffset;
  320. end
  321. else if actasmpattern='PAGEOFF' then
  322. begin
  323. consume(actasmtoken);
  324. oper.opr.ref.refaddr:=addr_pageoffset;
  325. end
  326. else
  327. begin
  328. do_error;
  329. exit
  330. end;
  331. end
  332. else
  333. begin
  334. BuildRecordOffsetSize(recname,o_int,s_int,recname,false);
  335. inc(oper.opr.ref.offset,o_int);
  336. end;
  337. test_end(require_rbracket);
  338. exit;
  339. end;
  340. AS_AT:
  341. begin
  342. do_error;
  343. exit;
  344. end;
  345. AS_RBRACKET :
  346. begin
  347. if require_rbracket then
  348. begin
  349. test_end(require_rbracket);
  350. exit;
  351. end
  352. else
  353. begin
  354. do_error; // unexpected rbracket
  355. exit;
  356. end;
  357. end;
  358. AS_SEPARATOR,AS_end :
  359. begin
  360. if not require_rbracket then
  361. begin
  362. test_end(false);
  363. exit;
  364. end
  365. else
  366. begin
  367. do_error;
  368. exit;
  369. end;
  370. end;
  371. else
  372. begin
  373. // unexpected token
  374. do_error;
  375. exit;
  376. end;
  377. end; // case
  378. end;
  379. procedure try_prepostindexed;
  380. begin
  381. Consume(AS_RBRACKET);
  382. case actasmtoken of
  383. AS_COMMA :
  384. begin // post-indexed
  385. Consume(AS_COMMA);
  386. oper.opr.ref.addressmode:=AM_POSTINDEXED;
  387. read_index(false);
  388. exit;
  389. end;
  390. AS_NOT :
  391. begin // pre-indexed
  392. Consume(AS_NOT);
  393. oper.opr.ref.addressmode:=AM_PREINDEXED;
  394. test_end(false);
  395. exit;
  396. end;
  397. else
  398. begin
  399. test_end(false);
  400. exit;
  401. end;
  402. end; // case
  403. end;
  404. begin
  405. Consume(AS_LBRACKET);
  406. oper.opr.ref.addressmode:=AM_OFFSET; // assume "neither PRE nor POST inc"
  407. if actasmtoken=AS_REGISTER then
  408. begin
  409. if getsupreg(actasmregister)=RS_XZR then
  410. Message1(asmr_e_invalid_ref_register,actasmpattern);
  411. oper.opr.ref.base:=actasmregister;
  412. Consume(AS_REGISTER);
  413. case actasmtoken of
  414. AS_RBRACKET :
  415. begin
  416. try_prepostindexed;
  417. exit;
  418. end;
  419. AS_COMMA :
  420. begin
  421. Consume(AS_COMMA);
  422. read_index(true);
  423. exit;
  424. end;
  425. else
  426. begin
  427. Message(asmr_e_invalid_reference_syntax);
  428. RecoverConsume(false);
  429. end;
  430. end;
  431. end
  432. else
  433. Begin
  434. case actasmtoken of
  435. AS_ID :
  436. begin
  437. { TODO: local variables and parameters }
  438. Message(asmr_e_invalid_reference_syntax);
  439. RecoverConsume(false);
  440. exit;
  441. end;
  442. else
  443. begin // elsecase
  444. Message(asmr_e_invalid_reference_syntax);
  445. RecoverConsume(false);
  446. exit;
  447. end;
  448. end;
  449. end;
  450. end;
  451. function taarch64attreader.TryBuildShifterOp(instr: taarch64instruction; opnr: longint): boolean;
  452. procedure handlepara(sm : tshiftmode);
  453. begin
  454. consume(AS_ID);
  455. fillchar(instr.operands[opnr].opr,sizeof(instr.operands[opnr].opr),0);
  456. instr.operands[opnr].opr.typ:=OPR_SHIFTEROP;
  457. instr.operands[opnr].opr.shifterop.shiftmode:=sm;
  458. if (sm=SM_LSL) or
  459. (actasmtoken=AS_HASH) then
  460. begin
  461. consume(AS_HASH);
  462. instr.operands[opnr].opr.shifterop.shiftimm:=BuildConstExpression(false,false);
  463. end;
  464. end;
  465. const
  466. shiftmode2str: array[SM_LSL..SM_SXTX] of string[4] =
  467. ('LSL','LSR','ASR','ROR',
  468. 'UXTB','UXTH','UXTW','UXTX',
  469. 'SXTB','SXTH','SXTW','SXTX');
  470. var
  471. sm: tshiftmode;
  472. i: longint;
  473. usessp,
  474. useszr: boolean;
  475. begin
  476. result:=false;
  477. if (actasmtoken=AS_ID) then
  478. begin
  479. for sm:=low(shiftmode2str) to high(shiftmode2str) do
  480. if actasmpattern=shiftmode2str[sm] then
  481. begin
  482. handlepara(sm);
  483. if instr.operands[1].opr.typ=OPR_REGISTER then
  484. begin
  485. { the possible shifter ops depend on whether this
  486. instruction uses sp and/or zr }
  487. usessp:=false;
  488. useszr:=false;
  489. for i:=low(instr.operands) to pred(opnr) do
  490. begin
  491. if (instr.operands[i].opr.typ=OPR_REGISTER) then
  492. case getsupreg(instr.operands[i].opr.reg) of
  493. RS_XZR:
  494. useszr:=true;
  495. RS_SP:
  496. usessp:=true;
  497. end;
  498. end;
  499. result:=valid_shifter_operand(instr.opcode,useszr,usessp,instr.Is64bit,sm,instr.operands[opnr].opr.shifterop.shiftimm);
  500. if result then
  501. instr.Ops:=opnr;
  502. end;
  503. break;
  504. end;
  505. end;
  506. end;
  507. function taarch64attreader.ToConditionCode(const hs: string; is_operand: boolean): tasmcond;
  508. begin
  509. case actopcode of
  510. A_CSEL,A_CSINC,A_CSINV,A_CSNEG,A_CSET,A_CSETM,
  511. A_CINC,A_CINV,A_CNEG,A_CCMN,A_CCMP,
  512. A_B:
  513. begin
  514. { search for condition, conditions are always 2 chars }
  515. if (is_operand<>(actopcode=A_B)) and
  516. (length(hs)>1) then
  517. begin
  518. { workaround for DFA bug }
  519. result:=low(tasmcond);
  520. for result:=low(tasmcond) to high(tasmcond) do
  521. begin
  522. if hs=uppercond2str[result] then
  523. exit;
  524. end;
  525. end;
  526. end;
  527. else
  528. ;
  529. end;
  530. result:=C_None;
  531. end;
  532. Procedure taarch64attreader.BuildOperand(oper: taarch64operand; is64bit: boolean);
  533. var
  534. expr: string;
  535. typesize, l: aint;
  536. procedure MaybeAddGotAddrMode;
  537. begin
  538. if actasmtoken=AS_AT then
  539. begin
  540. consume(AS_AT);
  541. if actasmpattern='GOTPAGE' then
  542. oper.opr.ref.refaddr:=addr_gotpage
  543. else if actasmpattern='GOTPAGEOFF' then
  544. oper.opr.ref.refaddr:=addr_gotpageoffset
  545. else if actasmpattern='PAGE' then
  546. oper.opr.ref.refaddr:=addr_page
  547. else if actasmpattern='PAGEOFF' then
  548. oper.opr.ref.refaddr:=addr_pageoffset
  549. else
  550. Message(asmr_e_expr_illegal);
  551. consume(actasmtoken);
  552. end
  553. else
  554. oper.opr.ref.refaddr:=addr_pic;
  555. end;
  556. procedure AddLabelOperand(hl:tasmlabel);
  557. begin
  558. if not(actasmtoken in [AS_PLUS,AS_MINUS,AS_LPAREN]) and
  559. is_calljmp(actopcode) then
  560. begin
  561. oper.opr.typ:=OPR_SYMBOL;
  562. oper.opr.symbol:=hl;
  563. end
  564. else if (actopcode=A_ADR) or
  565. (actopcode=A_ADRP) or
  566. (actopcode=A_LDR) then
  567. begin
  568. oper.InitRef;
  569. MaybeAddGotAddrMode;
  570. oper.opr.ref.symbol:=hl;
  571. if (actasmtoken in [AS_PLUS, AS_MINUS]) then
  572. begin
  573. l:=BuildConstExpression(true,false);
  574. oper.opr.ref.offset:=l;
  575. end;
  576. end;
  577. end;
  578. procedure MaybeRecordOffset;
  579. var
  580. mangledname: string;
  581. hasdot : boolean;
  582. l,
  583. toffset,
  584. tsize : aint;
  585. begin
  586. if not(actasmtoken in [AS_DOT,AS_PLUS,AS_MINUS]) then
  587. exit;
  588. l:=0;
  589. mangledname:='';
  590. hasdot:=(actasmtoken=AS_DOT);
  591. if hasdot then
  592. begin
  593. if expr<>'' then
  594. begin
  595. BuildRecordOffsetSize(expr,toffset,tsize,mangledname,false);
  596. if (oper.opr.typ<>OPR_CONSTANT) and
  597. (mangledname<>'') then
  598. Message(asmr_e_wrong_sym_type);
  599. inc(l,toffset);
  600. oper.SetSize(tsize,true);
  601. end;
  602. end;
  603. if actasmtoken in [AS_PLUS,AS_MINUS] then
  604. inc(l,BuildConstExpression(true,false));
  605. case oper.opr.typ of
  606. OPR_LOCAL :
  607. begin
  608. { don't allow direct access to fields of parameters, because that
  609. will generate buggy code. Allow it only for explicit typecasting }
  610. if hasdot and
  611. (not oper.hastype) then
  612. checklocalsubscript(oper.opr.localsym);
  613. inc(oper.opr.localsymofs,l)
  614. end;
  615. OPR_CONSTANT :
  616. inc(oper.opr.val,l);
  617. OPR_REFERENCE :
  618. if (mangledname<>'') then
  619. begin
  620. if (oper.opr.val<>0) then
  621. Message(asmr_e_wrong_sym_type);
  622. oper.opr.typ:=OPR_SYMBOL;
  623. oper.opr.symbol:=current_asmdata.RefAsmSymbol(mangledname,AT_FUNCTION);
  624. end
  625. else
  626. inc(oper.opr.val,l);
  627. OPR_SYMBOL:
  628. Message(asmr_e_invalid_symbol_ref);
  629. else
  630. internalerror(200309221);
  631. end;
  632. end;
  633. function MaybeBuildReference(is64bit: boolean):boolean;
  634. { Try to create a reference, if not a reference is found then false
  635. is returned }
  636. begin
  637. MaybeBuildReference:=true;
  638. case actasmtoken of
  639. AS_INTNUM,
  640. AS_MINUS,
  641. AS_PLUS:
  642. Begin
  643. oper.opr.ref.offset:=BuildConstExpression(True,False);
  644. if actasmtoken<>AS_LPAREN then
  645. Message(asmr_e_invalid_reference_syntax)
  646. else
  647. BuildReference(oper,is64bit);
  648. end;
  649. AS_LPAREN:
  650. BuildReference(oper,is64bit);
  651. AS_ID: { only a variable is allowed ... }
  652. Begin
  653. ReadSym(oper,is64bit);
  654. case actasmtoken of
  655. AS_end,
  656. AS_SEPARATOR,
  657. AS_COMMA: ;
  658. AS_LPAREN:
  659. BuildReference(oper,is64bit);
  660. else
  661. Begin
  662. Message(asmr_e_invalid_reference_syntax);
  663. Consume(actasmtoken);
  664. end;
  665. end; {end case }
  666. end;
  667. else
  668. MaybeBuildReference:=false;
  669. end; { end case }
  670. end;
  671. var
  672. tempreg: tregister;
  673. hl: tasmlabel;
  674. icond: tasmcond;
  675. Begin
  676. expr:='';
  677. case actasmtoken of
  678. AS_LBRACKET: { Memory reference or constant expression }
  679. Begin
  680. oper.InitRef;
  681. BuildReference(oper,is64bit);
  682. end;
  683. AS_HASH: { Constant expression }
  684. Begin
  685. Consume(AS_HASH);
  686. BuildConstantOperand(oper);
  687. end;
  688. (*
  689. AS_INTNUM,
  690. AS_MINUS,
  691. AS_PLUS:
  692. Begin
  693. { Constant memory offset }
  694. { This must absolutely be followed by ( }
  695. oper.InitRef;
  696. oper.opr.ref.offset:=BuildConstExpression(True,False);
  697. if actasmtoken<>AS_LPAREN then
  698. begin
  699. ofs:=oper.opr.ref.offset;
  700. BuildConstantOperand(oper);
  701. inc(oper.opr.val,ofs);
  702. end
  703. else
  704. BuildReference(oper,is64bit);
  705. end;
  706. *)
  707. AS_ID: { A constant expression, or a Variable ref. }
  708. Begin
  709. { Condition code? }
  710. icond:=ToConditionCode(actasmpattern,true);
  711. if icond<>C_None then
  712. begin
  713. oper.opr.typ:=OPR_COND;
  714. oper.opr.cc:=icond;
  715. consume(AS_ID);
  716. end
  717. else
  718. { Local Label ? }
  719. if is_locallabel(actasmpattern) then
  720. begin
  721. CreateLocalLabel(actasmpattern,hl,false);
  722. Consume(AS_ID);
  723. AddLabelOperand(hl);
  724. end
  725. else
  726. { Check for label }
  727. if SearchLabel(actasmpattern,hl,false) then
  728. begin
  729. Consume(AS_ID);
  730. AddLabelOperand(hl);
  731. end
  732. else
  733. { probably a variable or normal expression }
  734. { or a procedure (such as in CALL ID) }
  735. begin
  736. { is it a constant ? }
  737. if SearchIConstant(actasmpattern,l) then
  738. begin
  739. if not (oper.opr.typ in [OPR_NONE,OPR_CONSTANT]) then
  740. Message(asmr_e_invalid_operand_type);
  741. BuildConstantOperand(oper);
  742. end
  743. else
  744. begin
  745. expr:=actasmpattern;
  746. Consume(AS_ID);
  747. { typecasting? }
  748. if (actasmtoken=AS_LPAREN) and
  749. SearchType(expr,typesize) then
  750. begin
  751. oper.hastype:=true;
  752. Consume(AS_LPAREN);
  753. BuildOperand(oper,is64bit);
  754. Consume(AS_RPAREN);
  755. if oper.opr.typ in [OPR_REFERENCE,OPR_LOCAL] then
  756. oper.SetSize(typesize,true);
  757. end
  758. else
  759. begin
  760. if not(oper.SetupVar(expr,false)) then
  761. Begin
  762. { look for special symbols ... }
  763. if expr= '__HIGH' then
  764. begin
  765. consume(AS_LPAREN);
  766. if not oper.setupvar('high'+actasmpattern,false) then
  767. Message1(sym_e_unknown_id,'high'+actasmpattern);
  768. consume(AS_ID);
  769. consume(AS_RPAREN);
  770. end
  771. else
  772. if expr = '__RESULT' then
  773. oper.SetUpResult
  774. else
  775. if expr = '__SELF' then
  776. oper.SetupSelf
  777. else
  778. if expr = '__OLDEBP' then
  779. oper.SetupOldEBP
  780. else
  781. Message1(sym_e_unknown_id,expr);
  782. end
  783. else if oper.opr.typ<>OPR_LOCAL then
  784. begin
  785. oper.InitRef;
  786. MaybeAddGotAddrMode;
  787. end;
  788. end;
  789. end;
  790. if actasmtoken=AS_DOT then
  791. MaybeRecordOffset;
  792. { add a constant expression? }
  793. if (actasmtoken=AS_PLUS) then
  794. begin
  795. l:=BuildConstExpression(true,false);
  796. case oper.opr.typ of
  797. OPR_CONSTANT :
  798. inc(oper.opr.val,l);
  799. OPR_LOCAL :
  800. inc(oper.opr.localsymofs,l);
  801. OPR_REFERENCE :
  802. inc(oper.opr.ref.offset,l);
  803. else
  804. internalerror(200309202);
  805. end;
  806. end
  807. end;
  808. { Do we have a indexing reference, then parse it also }
  809. if actasmtoken=AS_LPAREN then
  810. BuildReference(oper,is64bit);
  811. end;
  812. { Register, a variable reference or a constant reference }
  813. AS_REGISTER:
  814. Begin
  815. { save the type of register used. }
  816. tempreg:=actasmregister;
  817. Consume(AS_REGISTER);
  818. if (actasmtoken in [AS_end,AS_SEPARATOR,AS_COMMA]) then
  819. Begin
  820. if not (oper.opr.typ in [OPR_NONE,OPR_REGISTER]) then
  821. Message(asmr_e_invalid_operand_type);
  822. oper.opr.typ:=OPR_REGISTER;
  823. oper.opr.reg:=tempreg;
  824. end
  825. else
  826. Message(asmr_e_syn_operand);
  827. end;
  828. AS_end,
  829. AS_SEPARATOR,
  830. AS_COMMA: ;
  831. else
  832. Begin
  833. Message(asmr_e_syn_operand);
  834. Consume(actasmtoken);
  835. end;
  836. end; { end case }
  837. end;
  838. {*****************************************************************************
  839. taarch64attreader
  840. *****************************************************************************}
  841. procedure taarch64attreader.BuildOpCode(instr: taarch64instruction);
  842. var
  843. operandnum : longint;
  844. Begin
  845. { opcode }
  846. if (actasmtoken<>AS_OPCODE) then
  847. Begin
  848. Message(asmr_e_invalid_or_missing_opcode);
  849. RecoverConsume(true);
  850. exit;
  851. end;
  852. { Fill the instr object with the current state }
  853. with instr do
  854. begin
  855. Opcode:=ActOpcode;
  856. condition:=ActCondition;
  857. oppostfix:=actoppostfix;
  858. end;
  859. Consume(AS_OPCODE);
  860. { We are reading operands, so opcode will be an AS_ID }
  861. operandnum:=1;
  862. { Zero operand opcode ? }
  863. if actasmtoken in [AS_SEPARATOR,AS_end] then
  864. begin
  865. instr.Ops:=0;
  866. exit;
  867. end;
  868. { Read the operands }
  869. repeat
  870. case actasmtoken of
  871. AS_COMMA: { Operand delimiter }
  872. Begin
  873. { operandnum and not operandnum+1, because tinstruction is
  874. one-based and taicpu is zero-based)
  875. }
  876. if can_be_shifter_operand(instr.opcode,operandnum) then
  877. begin
  878. Consume(AS_COMMA);
  879. if not TryBuildShifterOp(instr,operandnum+1) then
  880. Message(asmr_e_illegal_shifterop_syntax);
  881. Inc(operandnum);
  882. end
  883. else
  884. begin
  885. if operandnum>Max_Operands then
  886. Message(asmr_e_too_many_operands)
  887. else
  888. Inc(operandnum);
  889. Consume(AS_COMMA);
  890. end;
  891. end;
  892. AS_SEPARATOR,
  893. AS_end : { End of asm operands for this opcode }
  894. begin
  895. break;
  896. end;
  897. else
  898. begin
  899. BuildOperand(taarch64operand(instr.operands[operandnum]),instr.Is64bit);
  900. instr.Ops:=operandnum;
  901. if instr.operands[operandnum].opr.typ=OPR_REFERENCE then
  902. if simple_ref_type(instr.opcode,instr.cgsize,instr.oppostfix,instr.operands[operandnum].opr.ref)<>sr_simple then
  903. Message(asmr_e_invalid_reference_syntax);
  904. ;
  905. end;
  906. end; { end case }
  907. until false;
  908. end;
  909. function taarch64attreader.is_asmopcode(const s: string):boolean;
  910. const
  911. { sorted by length so longer postfixes will match first }
  912. postfix2strsorted : array[1..7] of string[3] = (
  913. 'SB','SH','SW',
  914. 'B','H','W',
  915. 'S');
  916. postfixsorted : array[1..7] of TOpPostfix = (
  917. PF_SB,PF_SH,PF_SW,
  918. PF_B,PF_H,PF_W,
  919. PF_S);
  920. var
  921. j : longint;
  922. hs : string;
  923. maxlen : longint;
  924. Begin
  925. { making s a value parameter would break other assembler readers }
  926. hs:=s;
  927. is_asmopcode:=false;
  928. { clear opcode }
  929. actopcode:=A_None;
  930. actcondition:=C_None;
  931. { b.cond ? }
  932. if (length(hs)=4) and
  933. (hs[1]='B') and
  934. (hs[2]='.') then
  935. begin
  936. actopcode:=A_B;
  937. actasmtoken:=AS_OPCODE;
  938. actcondition:=ToConditionCode(copy(hs,3,length(actasmpattern)-2),false);
  939. if actcondition<>C_None then
  940. is_asmopcode:=true;
  941. exit;
  942. end;
  943. maxlen:=max(length(hs),7);
  944. actopcode:=A_NONE;
  945. for j:=maxlen downto 1 do
  946. begin
  947. actopcode:=tasmop(PtrUInt(iasmops.Find(copy(hs,1,j))));
  948. if actopcode<>A_NONE then
  949. begin
  950. actasmtoken:=AS_OPCODE;
  951. { strip op code }
  952. delete(hs,1,j);
  953. break;
  954. end;
  955. end;
  956. if actopcode=A_NONE then
  957. exit;
  958. { check for postfix }
  959. if length(hs)>0 then
  960. begin
  961. for j:=low(postfixsorted) to high(postfixsorted) do
  962. begin
  963. if copy(hs,1,length(postfix2strsorted[j]))=postfix2strsorted[j] then
  964. begin
  965. actoppostfix:=postfixsorted[j];
  966. { strip postfix }
  967. delete(hs,1,length(postfix2strsorted[j]));
  968. break;
  969. end;
  970. end;
  971. end;
  972. { if we stripped all postfixes, it's a valid opcode }
  973. is_asmopcode:=length(hs)=0;
  974. end;
  975. procedure taarch64attreader.ConvertCalljmp(instr: taarch64instruction);
  976. var
  977. newopr : toprrec;
  978. begin
  979. if instr.Operands[1].opr.typ=OPR_REFERENCE then
  980. begin
  981. newopr.typ:=OPR_SYMBOL;
  982. newopr.symbol:=instr.Operands[1].opr.ref.symbol;
  983. newopr.symofs:=instr.Operands[1].opr.ref.offset;
  984. if (instr.Operands[1].opr.ref.base<>NR_NO) or
  985. (instr.Operands[1].opr.ref.index<>NR_NO) or
  986. (instr.Operands[1].opr.ref.refaddr<>addr_pic) then
  987. Message(asmr_e_syn_operand);
  988. instr.Operands[1].opr:=newopr;
  989. end;
  990. end;
  991. procedure taarch64attreader.handleopcode;
  992. var
  993. instr: taarch64instruction;
  994. begin
  995. instr:=taarch64instruction.Create(taarch64operand);
  996. BuildOpcode(instr);
  997. if is_calljmp(instr.opcode) then
  998. ConvertCalljmp(instr);
  999. {
  1000. instr.AddReferenceSizes;
  1001. instr.SetInstructionOpsize;
  1002. instr.CheckOperandSizes;
  1003. }
  1004. instr.ConcatInstruction(curlist);
  1005. instr.Free;
  1006. actoppostfix:=PF_None;
  1007. end;
  1008. procedure taarch64attreader.handletargetdirective;
  1009. function maxoffset(ash:TAsmSehDirective):aint;
  1010. begin
  1011. case ash of
  1012. ash_savefplr,
  1013. ash_saveregp,
  1014. ash_savereg,
  1015. ash_savefregp,
  1016. ash_savefreg:
  1017. result:=504;
  1018. ash_savefplr_x,
  1019. ash_saveregp_x,
  1020. ash_savefregp_x:
  1021. result:=-512;
  1022. ash_savereg_x,
  1023. ash_savefreg_x:
  1024. result:=-256;
  1025. ash_addfp:
  1026. result:=2040;
  1027. else
  1028. internalerror(2020041204);
  1029. end;
  1030. end;
  1031. procedure add_reg_with_offset(ash:TAsmSehDirective;hreg:tregister;hnum:aint;neg:boolean);
  1032. begin
  1033. if (neg and ((hnum>0) or (hnum<maxoffset(ash)) or (((-hnum) and $7)<>0))) or
  1034. (not neg and ((hnum<0) or (hnum>maxoffset(ash)) or ((hnum and $7)<>0))) then
  1035. Message1(asmr_e_bad_seh_directive_offset,sehdirectivestr[actsehdirective])
  1036. else
  1037. begin
  1038. if neg then
  1039. hnum:=-hnum;
  1040. if hreg=NR_NO then
  1041. curlist.concat(cai_seh_directive.create_offset(actsehdirective,hnum))
  1042. else
  1043. curlist.concat(cai_seh_directive.create_reg_offset(actsehdirective,hreg,hnum));
  1044. end;
  1045. end;
  1046. var
  1047. hreg,
  1048. hreg2 : TRegister;
  1049. hnum : aint;
  1050. flags : integer;
  1051. ai : tai_seh_directive;
  1052. hs : string;
  1053. err : boolean;
  1054. begin
  1055. if actasmtoken<>AS_TARGET_DIRECTIVE then
  1056. InternalError(2020033102);
  1057. Consume(AS_TARGET_DIRECTIVE);
  1058. Include(current_procinfo.flags,pi_has_unwind_info);
  1059. case actsehdirective of
  1060. ash_nop,
  1061. ash_setfp,
  1062. ash_endprologue,
  1063. ash_handlerdata:
  1064. curlist.concat(cai_seh_directive.create(actsehdirective));
  1065. ash_handler:
  1066. begin
  1067. hs:=actasmpattern;
  1068. Consume(AS_ID);
  1069. flags:=0;
  1070. err:=false;
  1071. while actasmtoken=AS_COMMA do
  1072. begin
  1073. Consume(AS_COMMA);
  1074. if actasmtoken=AS_AT then
  1075. begin
  1076. Consume(AS_AT);
  1077. if actasmtoken=AS_ID then
  1078. begin
  1079. uppervar(actasmpattern);
  1080. if actasmpattern='EXCEPT' then
  1081. flags:=flags or 1
  1082. else if actasmpattern='UNWIND' then
  1083. flags:=flags or 2
  1084. else
  1085. err:=true;
  1086. Consume(AS_ID);
  1087. end
  1088. else
  1089. err:=true;
  1090. end
  1091. else
  1092. err:=true;
  1093. if err then
  1094. begin
  1095. Message(asmr_e_syntax_error);
  1096. RecoverConsume(false);
  1097. exit;
  1098. end;
  1099. end;
  1100. ai:=cai_seh_directive.create_name(ash_handler,hs);
  1101. ai.data.flags:=flags;
  1102. curlist.concat(ai);
  1103. end;
  1104. ash_savefplr,
  1105. ash_savefplr_x:
  1106. begin
  1107. hnum:=BuildConstExpression(false,false);
  1108. add_reg_with_offset(actsehdirective,NR_NO,hnum,actsehdirective=ash_savefplr_x);
  1109. end;
  1110. ash_savereg,
  1111. ash_savereg_x:
  1112. begin
  1113. hreg:=actasmregister;
  1114. Consume(AS_REGISTER);
  1115. if (getregtype(hreg)<>R_INTREGISTER) or (getsubreg(hreg)<>R_SUBWHOLE) or (getsupreg(hreg)<19) then
  1116. Message1(asmr_e_bad_seh_directive_register,sehdirectivestr[actsehdirective]);
  1117. Consume(AS_COMMA);
  1118. hnum:=BuildConstExpression(false,false);
  1119. add_reg_with_offset(actsehdirective,hreg,hnum,actsehdirective=ash_savereg_x);
  1120. end;
  1121. ash_saveregp,
  1122. ash_saveregp_x:
  1123. begin
  1124. hreg:=actasmregister;
  1125. consume(AS_REGISTER);
  1126. if (getregtype(hreg)<>R_INTREGISTER) or (getsubreg(hreg)<>R_SUBWHOLE) or (getsupreg(hreg)<19) then
  1127. Message1(asmr_e_bad_seh_directive_register,sehdirectivestr[actsehdirective]);
  1128. consume(AS_COMMA);
  1129. hreg2:=actasmregister;
  1130. consume(AS_REGISTER);
  1131. if (getregtype(hreg2)<>R_INTREGISTER) or (getsubreg(hreg2)<>R_SUBWHOLE) or (getsupreg(hreg2)<>getsupreg(hreg)+1) then
  1132. Message1(asmr_e_bad_seh_directive_register,sehdirectivestr[actsehdirective]);
  1133. consume(AS_COMMA);
  1134. hnum:=BuildConstExpression(false,false);
  1135. add_reg_with_offset(actsehdirective,hreg,hnum,actsehdirective=ash_saveregp_x);
  1136. end;
  1137. ash_savefreg,
  1138. ash_savefreg_x:
  1139. begin
  1140. hreg:=actasmregister;
  1141. Consume(AS_REGISTER);
  1142. if (getregtype(hreg)<>R_MMREGISTER) or (getsubreg(hreg)<>R_SUBWHOLE) or (getsupreg(hreg)<8) then
  1143. Message1(asmr_e_bad_seh_directive_register,sehdirectivestr[actsehdirective]);
  1144. Consume(AS_COMMA);
  1145. hnum:=BuildConstExpression(false,false);
  1146. add_reg_with_offset(actsehdirective,hreg,hnum,actsehdirective=ash_savefreg_x);
  1147. end;
  1148. ash_savefregp,
  1149. ash_savefregp_x:
  1150. begin
  1151. hreg:=actasmregister;
  1152. consume(AS_REGISTER);
  1153. if (getregtype(hreg)<>R_MMREGISTER) or (getsubreg(hreg)<>R_SUBWHOLE) or (getsupreg(hreg)<8) then
  1154. Message1(asmr_e_bad_seh_directive_register,sehdirectivestr[actsehdirective]);
  1155. consume(AS_COMMA);
  1156. hreg2:=actasmregister;
  1157. consume(AS_REGISTER);
  1158. if (getregtype(hreg2)<>R_MMREGISTER) or (getsubreg(hreg2)<>R_SUBWHOLE) or (getsupreg(hreg2)<>getsupreg(hreg)+1) then
  1159. Message1(asmr_e_bad_seh_directive_register,sehdirectivestr[actsehdirective]);
  1160. consume(AS_COMMA);
  1161. hnum:=BuildConstExpression(false,false);
  1162. add_reg_with_offset(actsehdirective,hreg,hnum,actsehdirective=ash_savefregp_x);
  1163. end;
  1164. ash_stackalloc:
  1165. begin
  1166. hnum:=BuildConstExpression(false,false);
  1167. if (hnum<0) or (hnum>$FFFFFF) or ((hnum and 7)<>0) then
  1168. Message1(asmr_e_bad_seh_directive_offset,sehdirectivestr[ash_stackalloc])
  1169. else
  1170. curlist.concat(cai_seh_directive.create_offset(ash_stackalloc,hnum));
  1171. end;
  1172. else
  1173. InternalError(2020033103);
  1174. end;
  1175. if actasmtoken<>AS_SEPARATOR then
  1176. Consume(AS_SEPARATOR);
  1177. end;
  1178. {*****************************************************************************
  1179. Initialize
  1180. *****************************************************************************}
  1181. const
  1182. asmmode_arm_att_info : tasmmodeinfo =
  1183. (
  1184. id : asmmode_arm_gas;
  1185. idtxt : 'GAS';
  1186. casmreader : taarch64attreader;
  1187. );
  1188. asmmode_arm_standard_info : tasmmodeinfo =
  1189. (
  1190. id : asmmode_standard;
  1191. idtxt : 'STANDARD';
  1192. casmreader : taarch64attreader;
  1193. );
  1194. initialization
  1195. RegisterAsmMode(asmmode_arm_att_info);
  1196. RegisterAsmMode(asmmode_arm_standard_info);
  1197. end.