agcpugas.pas 30 KB

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