agcpugas.pas 34 KB

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