agcpugas.pas 31 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833
  1. {
  2. Copyright (c) 2003,2014 by Florian Klaempfl and Jonas Maebe
  3. This unit implements an asm for AArch64
  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. { This unit implements the GNU Assembler writer for AArch64
  18. }
  19. unit agcpugas;
  20. {$i fpcdefs.inc}
  21. interface
  22. uses
  23. globtype,systems,
  24. aasmtai,aasmdata,aasmbase,
  25. assemble,aggas,
  26. cpubase,cpuinfo;
  27. type
  28. TAArch64InstrWriter=class(TCPUInstrWriter)
  29. procedure WriteInstruction(hp : tai);override;
  30. end;
  31. TAArch64Assembler=class(TGNUassembler)
  32. constructor CreateWithWriter(info: pasminfo; wr: TExternalAssemblerOutputFile; freewriter, smart: boolean); override;
  33. end;
  34. TAArch64AppleAssembler=class(TAppleGNUassembler)
  35. constructor CreateWithWriter(info: pasminfo; wr: TExternalAssemblerOutputFile; freewriter, smart: boolean); override;
  36. end;
  37. TAArch64ClangGASAssembler=class(TGNUassembler)
  38. private
  39. function TargetStr:String;
  40. procedure TransformSEHDirectives(list:TAsmList);
  41. protected
  42. function sectionflags(secflags:TSectionFlags):string;override;
  43. public
  44. function MakeCmdLine:TCmdStr; override;
  45. procedure WriteAsmList; override;
  46. constructor CreateWithWriter(info: pasminfo; wr: TExternalAssemblerOutputFile; freewriter, smart: boolean); override;
  47. end;
  48. const
  49. gas_shiftmode2str : array[tshiftmode] of string[4] = (
  50. '','lsl','lsr','asr','ror',
  51. 'uxtb','uxth','uxtw','uxtx',
  52. 'sxtb','sxth','sxtw','sxtx');
  53. const
  54. cputype_to_gas_march : array[tcputype] of string = (
  55. '', // cpu_none
  56. 'armv8'
  57. );
  58. implementation
  59. uses
  60. cutils,cclasses,globals,verbose,
  61. aasmcpu,
  62. itcpugas,
  63. cgbase,cgutils;
  64. {****************************************************************************}
  65. { AArch64 Assembler writer }
  66. {****************************************************************************}
  67. constructor TAArch64Assembler.CreateWithWriter(info: pasminfo; wr: TExternalAssemblerOutputFile; freewriter, smart: boolean);
  68. begin
  69. inherited;
  70. InstrWriter := TAArch64InstrWriter.create(self);
  71. end;
  72. {****************************************************************************}
  73. { Apple AArch64 Assembler writer }
  74. {****************************************************************************}
  75. constructor TAArch64AppleAssembler.CreateWithWriter(info: pasminfo; wr: TExternalAssemblerOutputFile; freewriter, smart: boolean);
  76. begin
  77. inherited;
  78. InstrWriter := TAArch64InstrWriter.create(self);
  79. end;
  80. {****************************************************************************}
  81. { CLang AArch64 Assembler writer }
  82. {****************************************************************************}
  83. constructor TAArch64CLangGASAssembler.CreateWithWriter(info: pasminfo; wr: TExternalAssemblerOutputFile; freewriter, smart: boolean);
  84. begin
  85. inherited;
  86. InstrWriter := TAArch64InstrWriter.create(self);
  87. end;
  88. function TAArch64ClangGASAssembler.TargetStr:String;
  89. begin
  90. case target_info.system of
  91. system_aarch64_win64:
  92. result:='aarch64-windows';
  93. else
  94. internalerror(2020032201);
  95. end;
  96. end;
  97. procedure TAArch64ClangGASAssembler.TransformSEHDirectives(list:TAsmList);
  98. function convert_unwinddata(list:tasmlist):tdynamicarray;
  99. procedure check_offset(ofs,max:dword);
  100. begin
  101. if ((ofs and $7)<>0) or (ofs>max) then
  102. internalerror(2020041210);
  103. end;
  104. procedure check_reg(reg:tregister;rt:TRegisterType;min:TSuperRegister);
  105. begin
  106. if (getregtype(reg)<>rt) or (getsupreg(reg)<min) then
  107. internalerror(2020041211);
  108. end;
  109. procedure writebyte(b:byte); inline;
  110. begin
  111. result.write(b,sizeof(b));
  112. end;
  113. procedure writeword(w:word);
  114. begin
  115. w:=NtoBE(w);
  116. result.write(w,sizeof(w));
  117. end;
  118. procedure writedword(dw:dword);
  119. begin
  120. dw:=NtoBE(dw);
  121. result.write(dw,sizeof(dw));
  122. end;
  123. const
  124. min_int_reg = 19;
  125. min_mm_reg = 8;
  126. var
  127. hp : tai;
  128. seh : tai_seh_directive absolute hp;
  129. begin
  130. result:=tdynamicarray.create(0);
  131. hp:=tai(list.last);
  132. while assigned(hp) do
  133. begin
  134. if hp.typ<>ait_seh_directive then
  135. internalerror(2020041502);
  136. case seh.kind of
  137. ash_stackalloc:
  138. begin
  139. if (seh.data.offset and $f)<>0 then
  140. internalerror(2020041207);
  141. if seh.data.offset<((1 shl 5)*16) then
  142. writebyte(byte(seh.data.offset shr 4))
  143. else if seh.data.offset<((1 shl 11)*16) then
  144. writeword($C000 or word(seh.data.offset shr 4))
  145. else if seh.data.offset<((1 shl 24)*16) then
  146. writedword($E0000000 or (seh.data.offset shr 4))
  147. else begin
  148. writeln(hexstr(seh.data.offset,8));
  149. internalerror(2020041209);
  150. end;
  151. end;
  152. ash_addfp:
  153. begin
  154. check_offset(seh.data.offset,(1 shl 7)*8);
  155. writeword($E200 or (seh.data.offset shr 3));
  156. end;
  157. ash_setfp:
  158. writebyte($E1);
  159. ash_nop:
  160. writebyte($E3);
  161. ash_savefplr:
  162. begin
  163. check_offset(seh.data.offset,504);
  164. writebyte($40 or (seh.data.offset shr 3));
  165. end;
  166. ash_savefplr_x:
  167. begin
  168. check_offset(seh.data.offset,512);
  169. writebyte($80 or (seh.data.offset shr 3)-1);
  170. end;
  171. ash_savereg:
  172. begin
  173. check_offset(seh.data.offset,504);
  174. check_reg(seh.data.reg,R_INTREGISTER,min_int_reg);
  175. writeword($C000 or ((getsupreg(seh.data.reg)-min_int_reg) shl 6) or (seh.data.offset shr 3));
  176. end;
  177. ash_savereg_x:
  178. begin
  179. check_offset(seh.data.offset,256);
  180. check_reg(seh.data.reg,R_INTREGISTER,min_int_reg);
  181. writeword($C400 or ((getsupreg(seh.data.reg)-min_int_reg) shl 5) or ((seh.data.offset shr 3)-1));
  182. end;
  183. ash_saveregp:
  184. begin
  185. check_offset(seh.data.offset,504);
  186. check_reg(seh.data.reg,R_INTREGISTER,min_int_reg);
  187. writeword($C800 or ((getsupreg(seh.data.reg)-min_int_reg) shl 6) or (seh.data.offset shr 3));
  188. end;
  189. ash_saveregp_x:
  190. begin
  191. check_offset(seh.data.offset,512);
  192. check_reg(seh.data.reg,R_INTREGISTER,min_int_reg);
  193. writeword($CC00 or ((getsupreg(seh.data.reg)-min_int_reg) shl 6) or ((seh.data.offset shr 3)-1));
  194. end;
  195. ash_savefreg:
  196. begin
  197. check_offset(seh.data.offset,504);
  198. check_reg(seh.data.reg,R_MMREGISTER,min_mm_reg);
  199. writeword($DC00 or ((getsupreg(seh.data.reg)-min_mm_reg) shl 6) or (seh.data.offset shr 3));
  200. end;
  201. ash_savefreg_x:
  202. begin
  203. check_offset(seh.data.offset,256);
  204. check_reg(seh.data.reg,R_MMREGISTER,min_mm_reg);
  205. writeword($CE00 or ((getsupreg(seh.data.reg)-min_mm_reg) shl 5) or ((seh.data.offset shr 3)-1));
  206. end;
  207. ash_savefregp:
  208. begin
  209. check_offset(seh.data.offset,504);
  210. check_reg(seh.data.reg,R_MMREGISTER,min_mm_reg);
  211. writeword($D800 or ((getsupreg(seh.data.reg)-min_mm_reg) shl 6) or (seh.data.offset shr 3));
  212. end;
  213. ash_savefregp_x:
  214. begin
  215. check_offset(seh.data.offset,512);
  216. check_reg(seh.data.reg,R_MMREGISTER,min_mm_reg);
  217. writeword($DA00 or ((getsupreg(seh.data.reg)-min_int_reg) shl 6) or ((seh.data.offset shr 3)-1));
  218. end;
  219. else
  220. internalerror(2020041503);
  221. end;
  222. hp:=tai(hp.previous);
  223. end;
  224. end;
  225. var
  226. unwinddata : tdynamicarray;
  227. procedure writebyte(b:byte);
  228. begin
  229. unwinddata.write(b,sizeof(b));
  230. end;
  231. var
  232. hp,hpnext,hpdata : tai;
  233. seh : tai_seh_directive absolute hp;
  234. lastsym : tai_symbol;
  235. lastsec : tai_section;
  236. inprologue,
  237. inhandlerdata,
  238. deleteai : boolean;
  239. totalcount,
  240. instrcount,
  241. datacount : sizeint;
  242. handlername : tsymstr;
  243. handlerflags : byte;
  244. handlerdata : array of tai;
  245. handlerdataidx : sizeint;
  246. handlerdatacount : tai;
  247. sehlist,
  248. tmplist : TAsmList;
  249. xdatasym : tasmsymbol;
  250. unwindread,
  251. unwindrec : longword;
  252. begin
  253. if not assigned(list) then
  254. exit;
  255. lastsym:=nil;
  256. tmplist:=nil;
  257. sehlist:=nil;
  258. lastsec:=nil;
  259. instrcount:=0;
  260. datacount:=0;
  261. unwinddata:=nil;
  262. inhandlerdata:=false;
  263. inprologue:=false;
  264. handlerdata:=nil;
  265. handlerdataidx:=0;
  266. handlerdatacount:=nil;
  267. handlerflags:=0;
  268. handlername:='';
  269. hp:=tai(list.first);
  270. while assigned(hp) do
  271. begin
  272. deleteai:=false;
  273. case hp.typ of
  274. ait_section:
  275. begin
  276. if assigned(sehlist) then
  277. begin
  278. if assigned(lastsec) and (tai_section(hp).name^=lastsec.name^) then
  279. begin
  280. { this section was only added due to the now removed SEH data }
  281. deleteai:=true;
  282. dec(list.section_count);
  283. end
  284. else
  285. internalerror(2020041214);
  286. end
  287. else
  288. lastsec:=tai_section(hp);
  289. if assigned(tmplist) then
  290. begin
  291. list.insertListBefore(hp,tmplist);
  292. tmplist.free;
  293. tmplist:=nil;
  294. end;
  295. end;
  296. ait_symbol:
  297. begin
  298. if tai_symbol(hp).is_global then
  299. lastsym:=tai_symbol(hp);
  300. end;
  301. ait_instruction:
  302. if assigned(sehlist) then
  303. inc(instrcount);
  304. ait_const:
  305. if assigned(sehlist) then
  306. inc(datacount,tai_const(hp).size);
  307. ait_seh_directive:
  308. begin
  309. if not assigned(sehlist) and (seh.kind<>ash_proc) then
  310. internalerror(2020041208);
  311. { most seh directives are removed }
  312. deleteai:=true;
  313. case seh.kind of
  314. ash_proc:
  315. begin
  316. if not assigned(lastsec) then
  317. internalerror(2020041203);
  318. datacount:=0;
  319. instrcount:=0;
  320. handlerflags:=0;
  321. handlername:='';
  322. sehlist:=tasmlist.create;
  323. inprologue:=true;
  324. end;
  325. ash_endproc:
  326. begin
  327. if not assigned(sehlist) then
  328. internalerror(2020041501);
  329. if assigned(tmplist) then
  330. internalerror(2020041302);
  331. if not assigned(lastsym) then
  332. internalerror(2020041303);
  333. if inprologue then
  334. cgmessage(asmw_e_missing_endprologue);
  335. unwinddata:=convert_unwinddata(sehlist);
  336. writebyte($E4);
  337. { fill up with NOPs }
  338. while unwinddata.size mod 4<>0 do
  339. writebyte($E3);
  340. { note: we can pass Nil here, because in case of a LLVM
  341. backend this whole code shouldn't be required
  342. anyway }
  343. xdatasym:=current_asmdata.DefineAsmSymbol('xdata_'+lastsec.name^,AB_LOCAL,AT_DATA,nil);
  344. tmplist:=tasmlist.create;
  345. new_section(tmplist,sec_pdata,lastsec.name^,0);
  346. tmplist.concat(tai_const.Create_rva_sym(lastsym.sym));
  347. tmplist.concat(tai_const.Create_rva_sym(xdatasym));
  348. new_section(tmplist,sec_rodata,xdatasym.name,0);
  349. tmplist.concat(tai_symbol.Create(xdatasym,0));
  350. tmplist.concat(tai_comment.Create(strpnew('instr: '+tostr(instrcount)+', data: '+tostr(datacount)+', unwind: '+tostr(unwinddata.size))));
  351. {$ifdef EXTDEBUG}
  352. comment(V_Debug,'got section: '+lastsec.name^);
  353. comment(V_Debug,'got instructions: '+tostr(instrcount));
  354. comment(V_Debug,'got data: '+tostr(datacount));
  355. comment(V_Debug,'got unwinddata: '+tostr(unwinddata.size));
  356. {$endif EXTDEBUG}
  357. if datacount mod 4<>0 then
  358. cgmessage(asmw_e_seh_invalid_data_size);
  359. totalcount:=datacount div 4+instrcount;
  360. { splitting to multiple pdata/xdata sections is not yet
  361. supported, so 1 MB is our limit for now }
  362. if totalcount>(1 shl 18) then
  363. comment(V_Error,'Function is larger than 1 MB which is not supported for SEH currently');
  364. unwindrec:=min(totalcount,(1 shl 18)-1);
  365. if handlerflags<>0 then
  366. unwindrec:=unwindrec or (1 shl 20);
  367. { currently we only have one epilog, so E needs to be
  368. set to 1 and epilog scope index needs to be 0, no
  369. matter if we require the extension for the unwinddata
  370. or not }
  371. unwindrec:=unwindrec or (1 shl 21);
  372. if unwinddata.size div 4<=31 then
  373. unwindrec:=unwindrec or ((unwinddata.size div 4) shl 27);
  374. { exception record headers }
  375. tmplist.concat(tai_const.Create_32bit(unwindrec));
  376. if cs_asm_source in init_settings.globalswitches then
  377. tmplist.concat(tai_comment.create(strpnew(hexstr(unwindrec,8))));
  378. if unwinddata.size div 4>31 then
  379. begin
  380. { once we're able to split a .pdata entry this can be
  381. removed as well }
  382. if unwinddata.size div 4>255 then
  383. comment(V_Error,'Too many unwind codes for SEH');
  384. unwindrec:=(unwinddata.size div 4) shl 16;
  385. tmplist.concat(tai_const.create_32bit(unwindrec));
  386. if cs_asm_source in init_settings.globalswitches then
  387. tmplist.concat(tai_comment.create(strpnew(hexstr(unwindrec,8))));
  388. end;
  389. { unwind codes }
  390. unwinddata.seek(0);
  391. while unwinddata.pos<unwinddata.size do
  392. begin
  393. unwinddata.read(unwindrec,sizeof(longword));
  394. tmplist.concat(tai_const.Create_32bit(unwindrec));
  395. if cs_asm_source in init_settings.globalswitches then
  396. tmplist.concat(tai_comment.create(strpnew(hexstr(unwindrec,8))));
  397. end;
  398. unwinddata.free;
  399. if handlerflags<>0 then
  400. begin
  401. tmplist.concat(tai_const.Create_rva_sym(current_asmdata.RefAsmSymbol(handlername,AT_FUNCTION,false)));
  402. if length(handlerdata)>0 then
  403. begin
  404. tmplist.concat(handlerdatacount);
  405. for handlerdataidx:=0 to high(handlerdata) do
  406. tmplist.concat(handlerdata[handlerdataidx]);
  407. end;
  408. end;
  409. handlerdata:=nil;
  410. sehlist.free;
  411. sehlist:=nil;
  412. end;
  413. ash_endprologue:
  414. inprologue:=false;
  415. ash_handler:
  416. begin
  417. handlername:=seh.data.name^;
  418. handlerflags:=seh.data.flags;
  419. end;
  420. ash_handlerdata:
  421. begin
  422. if handlername='' then
  423. cgmessage(asmw_e_handlerdata_no_handler);
  424. hpdata:=tai(hp.next);
  425. if not assigned(hpdata) or (hpdata.typ<>ait_const) or (tai_const(hpdata).consttype<>aitconst_32bit) then
  426. internalerror(2020041215);
  427. handlerdatacount:=hpdata;
  428. setlength(handlerdata,tai_const(hpdata).value*4);
  429. handlerdataidx:=0;
  430. hpnext:=tai(hpdata.next);
  431. list.remove(hpdata);
  432. hpdata:=hpnext;
  433. while (handlerdataidx<length(handlerdata)) and assigned(hpdata) do
  434. begin
  435. if (hpdata.typ<>ait_const) or not (tai_const(hpdata).consttype in [aitconst_32bit,aitconst_rva_symbol]) then
  436. internalerror(2020041212);
  437. handlerdata[handlerdataidx]:=hpdata;
  438. inc(handlerdataidx);
  439. hpnext:=tai(hpdata.next);
  440. list.remove(hpdata);
  441. hpdata:=hpnext;
  442. end;
  443. if handlerdataidx<length(handlerdata) then
  444. internalerror(2020041213);
  445. end;
  446. ash_stackalloc,
  447. ash_addfp,
  448. ash_setfp,
  449. ash_nop,
  450. ash_savefplr,
  451. ash_savefplr_x,
  452. ash_savereg,
  453. ash_savereg_x,
  454. ash_saveregp,
  455. ash_saveregp_x,
  456. ash_savefreg,
  457. ash_savefreg_x,
  458. ash_savefregp,
  459. ash_savefregp_x:
  460. begin
  461. if not assigned(sehlist) then
  462. internalerror(2020041504);
  463. if not inprologue then
  464. internalerror(2020041505);
  465. hpdata:=hp;
  466. hp:=tai(hp.previous);
  467. list.Remove(hpdata);
  468. sehlist.concat(hpdata);
  469. { don't delete this }
  470. deleteai:=false;
  471. end;
  472. else
  473. internalerror(2020041206);
  474. end;
  475. end;
  476. else
  477. { ignore }
  478. ;
  479. end;
  480. if deleteai then
  481. begin
  482. hpnext:=tai(hp.next);
  483. list.remove(hp);
  484. hp.free;
  485. hp:=hpnext;
  486. end
  487. else
  488. hp:=tai(hp.next);
  489. end;
  490. if assigned(sehlist) then
  491. internalerror(2020041205);
  492. if assigned(tmplist) then
  493. begin
  494. list.concatlist(tmplist);
  495. tmplist.free;
  496. end;
  497. end;
  498. function TAArch64ClangGASAssembler.sectionflags(secflags:TSectionFlags):string;
  499. begin
  500. Result:=inherited sectionflags(secflags);
  501. if (target_info.system=system_aarch64_win64) then
  502. begin
  503. { we require an explicit "r" if write is not allowed }
  504. if not (SF_W in secflags) then
  505. result:=result+'r';
  506. end;
  507. end;
  508. function TAArch64ClangGASAssembler.MakeCmdLine:TCmdStr;
  509. begin
  510. Result:=inherited MakeCmdLine;
  511. Replace(Result,'$TARGET',TargetStr);
  512. end;
  513. procedure TAArch64ClangGASAssembler.WriteAsmList;
  514. begin
  515. { clang does not support all the directives we need, so we need to
  516. manually transform them to pdata/xdata records }
  517. if target_info.system=system_aarch64_win64 then
  518. begin
  519. TransformSEHDirectives(current_asmdata.AsmLists[al_pure_assembler]);
  520. TransformSEHDirectives(current_asmdata.AsmLists[al_procedures]);
  521. end;
  522. inherited WriteAsmList;
  523. end;
  524. {****************************************************************************}
  525. { Helper routines for Instruction Writer }
  526. {****************************************************************************}
  527. function getreferencestring(asminfo: pasminfo; var ref : treference) : string;
  528. const
  529. darwin_addrpage2str: array[addr_page..addr_gotpageoffset] of string[11] =
  530. ('@PAGE','@PAGEOFF','@GOTPAGE','@GOTPAGEOFF');
  531. linux_addrpage2str: array[addr_page..addr_gotpageoffset] of string[10] =
  532. ('',':lo12:',':got:',':got_lo12:');
  533. begin
  534. if ref.base=NR_NO then
  535. begin
  536. case ref.refaddr of
  537. addr_gotpage,
  538. addr_page,
  539. addr_gotpageoffset,
  540. addr_pageoffset:
  541. begin
  542. if not assigned(ref.symbol) or
  543. (ref.base<>NR_NO) or
  544. (ref.index<>NR_NO) or
  545. (ref.shiftmode<>SM_None) or
  546. (ref.offset<>0) then
  547. internalerror(2014121501);
  548. if target_info.system in systems_darwin then
  549. result:=ref.symbol.name+darwin_addrpage2str[ref.refaddr]
  550. else
  551. result:=linux_addrpage2str[ref.refaddr]+ref.symbol.name
  552. end;
  553. addr_pic,
  554. { for locals replaced by temp symbols on LLVM }
  555. addr_no:
  556. result:=ref.symbol.name;
  557. else
  558. internalerror(2015022302);
  559. end
  560. end
  561. else
  562. begin
  563. result:='['+gas_regname(ref.base);
  564. if ref.addressmode=AM_POSTINDEXED then
  565. result:=result+']';
  566. if ref.index<>NR_NO then
  567. begin
  568. if (ref.offset<>0) or
  569. assigned(ref.symbol) then
  570. internalerror(2014121504);
  571. result:=result+', '+gas_regname(ref.index);
  572. case ref.shiftmode of
  573. SM_None: ;
  574. SM_LSL,
  575. SM_UXTW, SM_UXTX, SM_SXTW, SM_SXTX:
  576. begin
  577. result:=result+', '+gas_shiftmode2str[ref.shiftmode];
  578. if (ref.shiftmode=SM_LSL) or
  579. (ref.shiftimm<>0) then
  580. result:=result+' #'+tostr(ref.shiftimm);
  581. end
  582. else
  583. internalerror(2014121505);
  584. end;
  585. end
  586. else
  587. begin
  588. if assigned(ref.symbol) then
  589. begin
  590. case ref.refaddr of
  591. addr_gotpageoffset,
  592. addr_pageoffset:
  593. begin
  594. if target_info.system in systems_darwin then
  595. result:=result+', '+ref.symbol.name+darwin_addrpage2str[ref.refaddr]
  596. else
  597. result:=result+', '+linux_addrpage2str[ref.refaddr]+ref.symbol.name
  598. end
  599. else
  600. { todo: not yet generated/don't know syntax }
  601. internalerror(2014121506);
  602. end;
  603. end
  604. else
  605. begin
  606. if ref.refaddr<>addr_no then
  607. internalerror(2014121506);
  608. if (ref.offset<>0) then
  609. result:=result+', #'+tostr(ref.offset);
  610. end;
  611. end;
  612. case ref.addressmode of
  613. AM_OFFSET:
  614. result:=result+']';
  615. AM_PREINDEXED:
  616. result:=result+']!';
  617. else
  618. ;
  619. end;
  620. end;
  621. end;
  622. function getopstr(asminfo: pasminfo; hp: taicpu; opnr: longint; const o: toper): string;
  623. begin
  624. case o.typ of
  625. top_reg:
  626. { we cannot yet represent "umov w0, v4.s[0]" or "ins v4.d[0], x1",
  627. so for now we use "s4" or "d4" instead -> translate here }
  628. if ((hp.opcode=A_INS) or
  629. (hp.opcode=A_UMOV)) and
  630. (getregtype(hp.oper[opnr]^.reg)=R_MMREGISTER) then
  631. begin
  632. case getsubreg(hp.oper[opnr]^.reg) of
  633. R_SUBMMS:
  634. getopstr:='v'+tostr(getsupreg(hp.oper[opnr]^.reg))+'.S[0]';
  635. R_SUBMMD:
  636. getopstr:='v'+tostr(getsupreg(hp.oper[opnr]^.reg))+'.D[0]';
  637. else
  638. internalerror(2014122907);
  639. end;
  640. end
  641. else
  642. getopstr:=gas_regname(o.reg);
  643. top_shifterop:
  644. begin
  645. getopstr:=gas_shiftmode2str[o.shifterop^.shiftmode];
  646. if o.shifterop^.shiftimm<>0 then
  647. getopstr:=getopstr+' #'+tostr(o.shifterop^.shiftimm)
  648. end;
  649. top_const:
  650. if o.val>=0 then
  651. getopstr:='#'+tostr(o.val)
  652. else
  653. getopstr:='#0x'+hexStr(o.val,16);
  654. top_conditioncode:
  655. getopstr:=cond2str[o.cc];
  656. top_ref:
  657. if is_calljmp(hp.opcode) then
  658. begin
  659. if o.ref^.refaddr<>addr_full then
  660. internalerror(2014122220);
  661. if not assigned(o.ref^.symbol) or
  662. assigned(o.ref^.relsymbol) or
  663. (o.ref^.base<>NR_NO) or
  664. (o.ref^.index<>NR_NO) or
  665. (o.ref^.offset<>0) then
  666. internalerror(2014122221);
  667. getopstr:=o.ref^.symbol.name;
  668. end
  669. else
  670. getopstr:=getreferencestring(asminfo,o.ref^);
  671. top_realconst:
  672. begin
  673. str(o.val_real,Result);
  674. Result:='#'+Result;
  675. end
  676. else
  677. internalerror(2014121507);
  678. end;
  679. end;
  680. procedure TAArch64InstrWriter.WriteInstruction(hp : tai);
  681. var
  682. op: TAsmOp;
  683. s: string;
  684. i: byte;
  685. sep: string[3];
  686. begin
  687. op:=taicpu(hp).opcode;
  688. s:=#9+gas_op2str[op]+oppostfix2str[taicpu(hp).oppostfix];
  689. if taicpu(hp).condition<>C_NONE then
  690. s:=s+'.'+cond2str[taicpu(hp).condition];
  691. if taicpu(hp).ops<>0 then
  692. begin
  693. sep:=#9;
  694. for i:=0 to taicpu(hp).ops-1 do
  695. begin
  696. // debug code
  697. // writeln(s);
  698. // writeln(taicpu(hp).fileinfo.line);
  699. s:=s+sep+getopstr(owner.asminfo,taicpu(hp),i,taicpu(hp).oper[i]^);
  700. sep:=',';
  701. end;
  702. end;
  703. owner.writer.AsmWriteLn(s);
  704. end;
  705. const
  706. as_aarch64_gas_info : tasminfo =
  707. (
  708. id : as_gas;
  709. idtxt : 'AS';
  710. asmbin : 'as';
  711. asmcmd : '-o $OBJ $EXTRAOPT $ASM';
  712. supported_targets : [system_aarch64_linux,system_aarch64_android];
  713. flags : [af_needar,af_smartlink_sections];
  714. labelprefix : '.L';
  715. labelmaxlen : -1;
  716. comment : '// ';
  717. dollarsign: '$';
  718. );
  719. as_aarch64_clang_darwin_info : tasminfo =
  720. (
  721. id : as_clang_asdarwin;
  722. idtxt : 'CLANG';
  723. asmbin : 'clang';
  724. asmcmd : '-x assembler -c -target $TRIPLET -o $OBJ $EXTRAOPT -x assembler $ASM';
  725. supported_targets : [system_aarch64_ios,system_aarch64_darwin];
  726. flags : [af_needar,af_smartlink_sections,af_supports_dwarf,af_llvm];
  727. labelprefix : 'L';
  728. labelmaxlen : -1;
  729. comment : '# ';
  730. dollarsign: '$';
  731. );
  732. as_aarch64_clang_gas_info : tasminfo =
  733. (
  734. id : as_clang_gas;
  735. idtxt : 'CLANG';
  736. asmbin : 'clang';
  737. asmcmd : '-x assembler -c -target $TRIPLET -o $OBJ $EXTRAOPT -x assembler $ASM';
  738. supported_targets : [system_aarch64_win64];
  739. flags : [af_needar,af_smartlink_sections,af_supports_dwarf,af_llvm];
  740. labelprefix : '.L';
  741. labelmaxlen : -1;
  742. comment : '// ';
  743. dollarsign: '$';
  744. );
  745. begin
  746. RegisterAssembler(as_aarch64_gas_info,TAArch64Assembler);
  747. RegisterAssembler(as_aarch64_clang_darwin_info,TAArch64AppleAssembler);
  748. RegisterAssembler(as_aarch64_clang_gas_info,TAArch64ClangGASAssembler);
  749. end.