agcpugas.pas 31 KB

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