aggas.pas 39 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152
  1. {
  2. Copyright (c) 1998-2006 by the Free Pascal team
  3. This unit implements the generic part of the GNU assembler
  4. (v2.8 or later) writer
  5. This program is free software; you can redistribute it and/or modify
  6. it under the terms of the GNU General Public License as published by
  7. the Free Software Foundation; either version 2 of the License, or
  8. (at your option) any later version.
  9. This program is distributed in the hope that it will be useful,
  10. but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. GNU General Public License for more details.
  13. You should have received a copy of the GNU General Public License
  14. along with this program; if not, write to the Free Software
  15. Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  16. ****************************************************************************
  17. }
  18. { Base unit for writing GNU assembler output.
  19. }
  20. unit aggas;
  21. {$i fpcdefs.inc}
  22. interface
  23. uses
  24. cclasses,
  25. globtype,globals,
  26. aasmbase,aasmtai,aasmdata,aasmcpu,
  27. assemble;
  28. type
  29. TCPUInstrWriter = class;
  30. {# This is a derived class which is used to write
  31. GAS styled assembler.
  32. }
  33. TGNUAssembler=class(texternalassembler)
  34. protected
  35. function sectionname(atype:TAsmSectiontype;const aname:string;aorder:TAsmSectionOrder):string;virtual;
  36. procedure WriteSection(atype:TAsmSectiontype;const aname:string;aorder:TAsmSectionOrder);
  37. procedure WriteExtraHeader;virtual;
  38. procedure WriteInstruction(hp: tai);
  39. public
  40. function MakeCmdLine: TCmdStr; override;
  41. procedure WriteTree(p:TAsmList);override;
  42. procedure WriteAsmList;override;
  43. destructor destroy; override;
  44. private
  45. setcount: longint;
  46. procedure WriteDecodedSleb128(a: int64);
  47. procedure WriteDecodedUleb128(a: qword);
  48. function NextSetLabel: string;
  49. protected
  50. InstrWriter: TCPUInstrWriter;
  51. end;
  52. {# This is the base class for writing instructions.
  53. The WriteInstruction() method must be overriden
  54. to write a single instruction to the assembler
  55. file.
  56. }
  57. TCPUInstrWriter = class
  58. constructor create(_owner: TGNUAssembler);
  59. procedure WriteInstruction(hp : tai); virtual; abstract;
  60. protected
  61. owner: TGNUAssembler;
  62. end;
  63. TAppleGNUAssembler=class(TGNUAssembler)
  64. function sectionname(atype:TAsmSectiontype;const aname:string;aorder:TAsmSectionOrder):string;override;
  65. private
  66. debugframecount: aint;
  67. end;
  68. implementation
  69. uses
  70. SysUtils,
  71. cutils,cfileutils,systems,
  72. fmodule,finput,verbose,
  73. itcpugas,cpubase
  74. ;
  75. const
  76. line_length = 70;
  77. var
  78. CurrSecType : TAsmSectiontype; { last section type written }
  79. lastfileinfo : tfileposinfo;
  80. infile,
  81. lastinfile : tinputfile;
  82. symendcount : longint;
  83. type
  84. {$ifdef cpuextended}
  85. t80bitarray = array[0..9] of byte;
  86. {$endif cpuextended}
  87. t64bitarray = array[0..7] of byte;
  88. t32bitarray = array[0..3] of byte;
  89. {****************************************************************************}
  90. { Support routines }
  91. {****************************************************************************}
  92. function fixline(s:string):string;
  93. {
  94. return s with all leading and ending spaces and tabs removed
  95. }
  96. var
  97. i,j,k : integer;
  98. begin
  99. i:=length(s);
  100. while (i>0) and (s[i] in [#9,' ']) do
  101. dec(i);
  102. j:=1;
  103. while (j<i) and (s[j] in [#9,' ']) do
  104. inc(j);
  105. for k:=j to i do
  106. if s[k] in [#0..#31,#127..#255] then
  107. s[k]:='.';
  108. fixline:=Copy(s,j,i-j+1);
  109. end;
  110. function single2str(d : single) : string;
  111. var
  112. hs : string;
  113. begin
  114. str(d,hs);
  115. { replace space with + }
  116. if hs[1]=' ' then
  117. hs[1]:='+';
  118. single2str:='0d'+hs
  119. end;
  120. function double2str(d : double) : string;
  121. var
  122. hs : string;
  123. begin
  124. str(d,hs);
  125. { replace space with + }
  126. if hs[1]=' ' then
  127. hs[1]:='+';
  128. double2str:='0d'+hs
  129. end;
  130. function extended2str(e : extended) : string;
  131. var
  132. hs : string;
  133. begin
  134. str(e,hs);
  135. { replace space with + }
  136. if hs[1]=' ' then
  137. hs[1]:='+';
  138. extended2str:='0d'+hs
  139. end;
  140. { convert floating point values }
  141. { to correct endian }
  142. procedure swap64bitarray(var t: t64bitarray);
  143. var
  144. b: byte;
  145. begin
  146. b:= t[7];
  147. t[7] := t[0];
  148. t[0] := b;
  149. b := t[6];
  150. t[6] := t[1];
  151. t[1] := b;
  152. b:= t[5];
  153. t[5] := t[2];
  154. t[2] := b;
  155. b:= t[4];
  156. t[4] := t[3];
  157. t[3] := b;
  158. end;
  159. procedure swap32bitarray(var t: t32bitarray);
  160. var
  161. b: byte;
  162. begin
  163. b:= t[1];
  164. t[1]:= t[2];
  165. t[2]:= b;
  166. b:= t[0];
  167. t[0]:= t[3];
  168. t[3]:= b;
  169. end;
  170. const
  171. ait_const2str : array[aitconst_128bit..aitconst_indirect_symbol] of string[20]=(
  172. #9'.fixme128'#9,#9'.quad'#9,#9'.long'#9,#9'.short'#9,#9'.byte'#9,
  173. #9'.sleb128'#9,#9'.uleb128'#9,
  174. #9'.rva'#9,#9'.indirect_symbol'#9
  175. );
  176. {****************************************************************************}
  177. { GNU Assembler writer }
  178. {****************************************************************************}
  179. destructor TGNUAssembler.Destroy;
  180. begin
  181. InstrWriter.free;
  182. inherited destroy;
  183. end;
  184. function TGNUAssembler.MakeCmdLine: TCmdStr;
  185. begin
  186. result := inherited MakeCmdLine;
  187. // MWE: disabled again. It generates dwarf info for the generated .s
  188. // files as well. This conflicts with the info we generate
  189. // if target_dbg.id = dbg_dwarf then
  190. // result := result + ' --gdwarf-2';
  191. end;
  192. function TGNUAssembler.NextSetLabel: string;
  193. begin
  194. inc(setcount);
  195. result := target_asm.labelprefix+'$set$'+tostr(setcount);
  196. end;
  197. function TGNUAssembler.sectionname(atype:TAsmSectiontype;const aname:string;aorder:TAsmSectionOrder):string;
  198. const
  199. secnames : array[TAsmSectiontype] of string[17] = ('',
  200. '.text',
  201. '.data',
  202. { why doesn't .rodata work? (FK) }
  203. {$warning TODO .rodata not yet working}
  204. {$if defined(arm) or defined(powerpc)}
  205. '.rodata',
  206. {$else arm}
  207. '.data',
  208. {$endif arm}
  209. '.bss',
  210. '.threadvar',
  211. '.pdata',
  212. '', { stubs }
  213. '.stab',
  214. '.stabstr',
  215. '.idata$2','.idata$4','.idata$5','.idata$6','.idata$7','.edata',
  216. '.eh_frame',
  217. '.debug_frame','.debug_info','.debug_line','.debug_abbrev',
  218. '.fpc',
  219. '.toc',
  220. '.init'
  221. );
  222. secnames_pic : array[TAsmSectiontype] of string[17] = ('',
  223. '.text',
  224. '.data.rel',
  225. '.data.rel',
  226. '.bss',
  227. '.threadvar',
  228. '.pdata',
  229. '', { stubs }
  230. '.stab',
  231. '.stabstr',
  232. '.idata$2','.idata$4','.idata$5','.idata$6','.idata$7','.edata',
  233. '.eh_frame',
  234. '.debug_frame','.debug_info','.debug_line','.debug_abbrev',
  235. '.fpc',
  236. '.toc',
  237. '.init'
  238. );
  239. var
  240. sep : string[3];
  241. secname : string;
  242. begin
  243. if (cs_create_pic in current_settings.moduleswitches) and
  244. not(target_info.system in systems_darwin) then
  245. secname:=secnames_pic[atype]
  246. else
  247. secname:=secnames[atype];
  248. {$ifdef m68k}
  249. { old Amiga GNU AS doesn't support .section .fpc }
  250. if (atype=sec_fpc) and (target_info.system = system_m68k_amiga) then
  251. secname:=secnames[sec_data];
  252. {$endif}
  253. if (atype=sec_fpc) and (Copy(aname,1,3)='res') then
  254. begin
  255. result:=secname+'.'+aname;
  256. exit;
  257. end;
  258. if (atype=sec_threadvar) and
  259. (target_info.system=system_i386_win32) then
  260. secname:='.tls';
  261. { For bss we need to set some flags that are target dependent,
  262. it is easier to disable it for smartlinking. It doesn't take up
  263. filespace }
  264. if not(target_info.system in systems_darwin) and
  265. use_smartlink_section and
  266. (aname<>'') and
  267. (atype <> sec_toc) and
  268. (atype<>sec_bss) then
  269. begin
  270. case aorder of
  271. secorder_begin :
  272. sep:='.b_';
  273. secorder_end :
  274. sep:='.z_';
  275. else
  276. sep:='.n_';
  277. end;
  278. result:=secname+sep+aname
  279. end
  280. else
  281. result:=secname;
  282. end;
  283. procedure TGNUAssembler.WriteSection(atype:TAsmSectiontype;const aname:string;aorder:TAsmSectionOrder);
  284. var
  285. s : string;
  286. begin
  287. AsmLn;
  288. case target_info.system of
  289. system_i386_OS2,
  290. system_i386_EMX,
  291. system_m68k_amiga, { amiga has old GNU AS (2.14), which blews up from .section (KB) }
  292. system_m68k_linux: ;
  293. system_powerpc_darwin,
  294. system_i386_darwin,
  295. system_powerpc64_darwin,
  296. system_x86_64_darwin:
  297. begin
  298. if (atype = sec_stub) then
  299. AsmWrite('.section ');
  300. end
  301. else
  302. AsmWrite('.section ');
  303. end;
  304. s:=sectionname(atype,aname,aorder);
  305. AsmWrite(s);
  306. case atype of
  307. sec_fpc :
  308. if aname = 'resptrs' then
  309. AsmWrite(', "a", @progbits');
  310. sec_stub :
  311. begin
  312. case target_info.system of
  313. { there are processor-independent shortcuts available }
  314. { for this, namely .symbol_stub and .picsymbol_stub, but }
  315. { they don't work and gcc doesn't use them either... }
  316. system_powerpc_darwin,
  317. system_powerpc64_darwin:
  318. AsmWriteln('__TEXT,__symbol_stub1,symbol_stubs,pure_instructions,16');
  319. system_i386_darwin:
  320. AsmWriteln('__IMPORT,__jump_table,symbol_stubs,self_modifying_code+pure_instructions,5');
  321. { darwin/x86-64 uses RIP-based GOT addressing }
  322. else
  323. internalerror(2006031101);
  324. end;
  325. end;
  326. end;
  327. AsmLn;
  328. CurrSecType:=atype;
  329. end;
  330. procedure TGNUAssembler.WriteDecodedUleb128(a: qword);
  331. var
  332. i,len : longint;
  333. buf : array[0..63] of byte;
  334. begin
  335. len:=EncodeUleb128(a,buf);
  336. for i:=0 to len-1 do
  337. begin
  338. if (i > 0) then
  339. AsmWrite(',');
  340. AsmWrite(tostr(buf[i]));
  341. end;
  342. end;
  343. procedure TGNUAssembler.WriteDecodedSleb128(a: int64);
  344. var
  345. i,len : longint;
  346. buf : array[0..255] of byte;
  347. begin
  348. len:=EncodeSleb128(a,buf);
  349. for i:=0 to len-1 do
  350. begin
  351. if (i > 0) then
  352. AsmWrite(',');
  353. AsmWrite(tostr(buf[i]));
  354. end;
  355. end;
  356. procedure TGNUAssembler.WriteTree(p:TAsmList);
  357. function needsObject(hp : tai_symbol) : boolean;
  358. begin
  359. needsObject :=
  360. (
  361. assigned(hp.next) and
  362. (tai(hp.next).typ in [ait_const,ait_datablock,
  363. ait_real_32bit,ait_real_64bit,ait_real_80bit,ait_comp_64bit])
  364. ) or
  365. (hp.sym.typ=AT_DATA);
  366. end;
  367. var
  368. ch : char;
  369. hp : tai;
  370. hp1 : tailineinfo;
  371. constdef : taiconst_type;
  372. s,t : string;
  373. i,pos,l : longint;
  374. InlineLevel : longint;
  375. last_align : longint;
  376. co : comp;
  377. sin : single;
  378. d : double;
  379. {$ifdef cpuextended}
  380. e : extended;
  381. {$endif cpuextended}
  382. do_line : boolean;
  383. sepChar : char;
  384. nextdwarffileidx : longint;
  385. begin
  386. if not assigned(p) then
  387. exit;
  388. nextdwarffileidx:=1;
  389. last_align := 2;
  390. InlineLevel:=0;
  391. { lineinfo is only needed for al_procedures (PFV) }
  392. do_line:=(cs_asm_source in current_settings.globalswitches) or
  393. ((cs_lineinfo in current_settings.moduleswitches)
  394. and (p=current_asmdata.asmlists[al_procedures]));
  395. hp:=tai(p.first);
  396. while assigned(hp) do
  397. begin
  398. if not(hp.typ in SkipLineInfo) then
  399. begin
  400. hp1 := hp as tailineinfo;
  401. current_filepos:=hp1.fileinfo;
  402. { no line info for inlined code }
  403. if do_line and (inlinelevel=0) then
  404. begin
  405. { load infile }
  406. if lastfileinfo.fileindex<>hp1.fileinfo.fileindex then
  407. begin
  408. infile:=current_module.sourcefiles.get_file(hp1.fileinfo.fileindex);
  409. if assigned(infile) then
  410. begin
  411. { open only if needed !! }
  412. if (cs_asm_source in current_settings.globalswitches) then
  413. infile.open;
  414. end;
  415. { avoid unnecessary reopens of the same file !! }
  416. lastfileinfo.fileindex:=hp1.fileinfo.fileindex;
  417. { be sure to change line !! }
  418. lastfileinfo.line:=-1;
  419. end;
  420. { write source }
  421. if (cs_asm_source in current_settings.globalswitches) and
  422. assigned(infile) then
  423. begin
  424. if (infile<>lastinfile) then
  425. begin
  426. AsmWriteLn(target_asm.comment+'['+infile.name^+']');
  427. if assigned(lastinfile) then
  428. lastinfile.close;
  429. end;
  430. if (hp1.fileinfo.line<>lastfileinfo.line) and
  431. ((hp1.fileinfo.line<infile.maxlinebuf) or (InlineLevel>0)) then
  432. begin
  433. if (hp1.fileinfo.line<>0) and
  434. ((infile.linebuf^[hp1.fileinfo.line]>=0) or (InlineLevel>0)) then
  435. AsmWriteLn(target_asm.comment+'['+tostr(hp1.fileinfo.line)+'] '+
  436. fixline(infile.GetLineStr(hp1.fileinfo.line)));
  437. { set it to a negative value !
  438. to make that is has been read already !! PM }
  439. if (infile.linebuf^[hp1.fileinfo.line]>=0) then
  440. infile.linebuf^[hp1.fileinfo.line]:=-infile.linebuf^[hp1.fileinfo.line]-1;
  441. end;
  442. end;
  443. lastfileinfo:=hp1.fileinfo;
  444. lastinfile:=infile;
  445. end;
  446. end;
  447. case hp.typ of
  448. ait_comment :
  449. Begin
  450. AsmWrite(target_asm.comment);
  451. AsmWritePChar(tai_comment(hp).str);
  452. AsmLn;
  453. End;
  454. ait_regalloc :
  455. begin
  456. if (cs_asm_regalloc in current_settings.globalswitches) then
  457. begin
  458. AsmWrite(#9+target_asm.comment+'Register ');
  459. repeat
  460. AsmWrite(std_regname(Tai_regalloc(hp).reg));
  461. if (hp.next=nil) or
  462. (tai(hp.next).typ<>ait_regalloc) or
  463. (tai_regalloc(hp.next).ratype<>tai_regalloc(hp).ratype) then
  464. break;
  465. hp:=tai(hp.next);
  466. AsmWrite(',');
  467. until false;
  468. AsmWrite(' ');
  469. AsmWriteLn(regallocstr[tai_regalloc(hp).ratype]);
  470. end;
  471. end;
  472. ait_tempalloc :
  473. begin
  474. if (cs_asm_tempalloc in current_settings.globalswitches) then
  475. begin
  476. {$ifdef EXTDEBUG}
  477. if assigned(tai_tempalloc(hp).problem) then
  478. AsmWriteLn(target_asm.comment+'Temp '+tostr(tai_tempalloc(hp).temppos)+','+
  479. tostr(tai_tempalloc(hp).tempsize)+' '+tai_tempalloc(hp).problem^)
  480. else
  481. {$endif EXTDEBUG}
  482. AsmWriteLn(target_asm.comment+'Temp '+tostr(tai_tempalloc(hp).temppos)+','+
  483. tostr(tai_tempalloc(hp).tempsize)+' '+tempallocstr[tai_tempalloc(hp).allocation]);
  484. end;
  485. end;
  486. ait_align :
  487. begin
  488. if tai_align_abstract(hp).aligntype>1 then
  489. begin
  490. if not(target_info.system in systems_darwin) then
  491. begin
  492. AsmWrite(#9'.balign '+tostr(tai_align_abstract(hp).aligntype));
  493. if tai_align_abstract(hp).use_op then
  494. AsmWrite(','+tostr(tai_align_abstract(hp).fillop))
  495. {$ifdef x86}
  496. { force NOP as alignment op code }
  497. else if CurrSecType=sec_code then
  498. AsmWrite(',0x90');
  499. {$endif x86}
  500. end
  501. else
  502. begin
  503. { darwin as only supports .align }
  504. if not ispowerof2(tai_align_abstract(hp).aligntype,i) then
  505. internalerror(2003010305);
  506. AsmWrite(#9'.align '+tostr(i));
  507. last_align := i;
  508. end;
  509. AsmLn;
  510. end;
  511. end;
  512. ait_section :
  513. begin
  514. if tai_section(hp).sectype<>sec_none then
  515. WriteSection(tai_section(hp).sectype,tai_section(hp).name^,tai_section(hp).secorder)
  516. else
  517. begin
  518. {$ifdef EXTDEBUG}
  519. AsmWrite(target_asm.comment);
  520. AsmWriteln(' sec_none');
  521. {$endif EXTDEBUG}
  522. end;
  523. end;
  524. ait_datablock :
  525. begin
  526. if (target_info.system in systems_darwin) then
  527. begin
  528. {On Mac OS X you can't have common symbols in a shared
  529. library, since those are in the TEXT section and the text section is
  530. read-only in shared libraries (so it can be shared among different
  531. processes). The alternate code creates some kind of common symbols in
  532. the data segment. The generic code no longer uses common symbols, but
  533. this doesn't work on Mac OS X as well.}
  534. if tai_datablock(hp).is_global then
  535. begin
  536. asmwrite('.globl ');
  537. asmwriteln(tai_datablock(hp).sym.name);
  538. asmwriteln('.data');
  539. asmwrite('.zerofill __DATA, __common, ');
  540. asmwrite(tai_datablock(hp).sym.name);
  541. asmwriteln(', '+tostr(tai_datablock(hp).size)+','+tostr(last_align));
  542. if not(CurrSecType in [sec_data,sec_none]) then
  543. writesection(CurrSecType,'',secorder_default);
  544. end
  545. else
  546. begin
  547. asmwrite(#9'.lcomm'#9);
  548. asmwrite(tai_datablock(hp).sym.name);
  549. asmwrite(','+tostr(tai_datablock(hp).size));
  550. asmwrite(','+tostr(last_align));
  551. asmwriteln('');
  552. end
  553. end
  554. else
  555. begin
  556. if Tai_datablock(hp).is_global then
  557. begin
  558. asmwrite(#9'.globl ');
  559. asmwriteln(Tai_datablock(hp).sym.name);
  560. end;
  561. if (target_info.system <> system_arm_linux) then
  562. sepChar := '@'
  563. else
  564. sepChar := '%';
  565. if (tf_needs_symbol_type in target_info.flags) then
  566. asmwriteln(#9'.type '+Tai_datablock(hp).sym.name+','+sepChar+'object');
  567. if (tf_needs_symbol_size in target_info.flags) and (tai_datablock(hp).size > 0) then
  568. asmwriteln(#9'.size '+Tai_datablock(hp).sym.name+','+tostr(Tai_datablock(hp).size));
  569. asmwrite(Tai_datablock(hp).sym.name);
  570. asmwriteln(':');
  571. asmwriteln(#9'.zero '+tostr(Tai_datablock(hp).size));
  572. end;
  573. end;
  574. ait_const:
  575. begin
  576. constdef:=tai_const(hp).consttype;
  577. case constdef of
  578. {$ifndef cpu64bit}
  579. aitconst_128bit :
  580. begin
  581. internalerror(200404291);
  582. end;
  583. aitconst_64bit :
  584. begin
  585. if assigned(tai_const(hp).sym) then
  586. internalerror(200404292);
  587. AsmWrite(ait_const2str[aitconst_32bit]);
  588. if target_info.endian = endian_little then
  589. begin
  590. AsmWrite(tostr(longint(lo(tai_const(hp).value))));
  591. AsmWrite(',');
  592. AsmWrite(tostr(longint(hi(tai_const(hp).value))));
  593. end
  594. else
  595. begin
  596. AsmWrite(tostr(longint(hi(tai_const(hp).value))));
  597. AsmWrite(',');
  598. AsmWrite(tostr(longint(lo(tai_const(hp).value))));
  599. end;
  600. AsmLn;
  601. end;
  602. {$endif cpu64bit}
  603. aitconst_uleb128bit,
  604. aitconst_sleb128bit,
  605. {$ifdef cpu64bit}
  606. aitconst_128bit,
  607. aitconst_64bit,
  608. {$endif cpu64bit}
  609. aitconst_32bit,
  610. aitconst_16bit,
  611. aitconst_8bit,
  612. aitconst_rva_symbol,
  613. aitconst_indirect_symbol :
  614. begin
  615. if (target_info.system in systems_darwin) and
  616. (tai_const(hp).consttype in [aitconst_uleb128bit,aitconst_sleb128bit]) then
  617. begin
  618. AsmWrite(ait_const2str[aitconst_8bit]);
  619. case tai_const(hp).consttype of
  620. aitconst_uleb128bit:
  621. WriteDecodedUleb128(qword(tai_const(hp).value));
  622. aitconst_sleb128bit:
  623. WriteDecodedSleb128(int64(tai_const(hp).value));
  624. end
  625. end
  626. else
  627. begin
  628. AsmWrite(ait_const2str[tai_const(hp).consttype]);
  629. l:=0;
  630. t := '';
  631. repeat
  632. if assigned(tai_const(hp).sym) then
  633. begin
  634. if assigned(tai_const(hp).endsym) then
  635. begin
  636. if (target_info.system in systems_darwin) then
  637. begin
  638. s := NextSetLabel;
  639. t := #9'.set '+s+','+tai_const(hp).endsym.name+'-'+tai_const(hp).sym.name;
  640. end
  641. else
  642. s:=tai_const(hp).endsym.name+'-'+tai_const(hp).sym.name
  643. end
  644. else
  645. s:=tai_const(hp).sym.name;
  646. if tai_const(hp).value<>0 then
  647. s:=s+tostr_with_plus(tai_const(hp).value);
  648. end
  649. else
  650. s:=tostr(tai_const(hp).value);
  651. AsmWrite(s);
  652. inc(l,length(s));
  653. { Values with symbols are written on a single line to improve
  654. reading of the .s file (PFV) }
  655. if assigned(tai_const(hp).sym) or
  656. not(CurrSecType in [sec_data,sec_rodata]) or
  657. (l>line_length) or
  658. (hp.next=nil) or
  659. (tai(hp.next).typ<>ait_const) or
  660. (tai_const(hp.next).consttype<>constdef) or
  661. assigned(tai_const(hp.next).sym) then
  662. break;
  663. hp:=tai(hp.next);
  664. AsmWrite(',');
  665. until false;
  666. if (t <> '') then
  667. begin
  668. AsmLn;
  669. AsmWrite(t);
  670. end;
  671. end;
  672. AsmLn;
  673. end;
  674. end;
  675. end;
  676. { the "and defined(FPC_HAS_TYPE_EXTENDED)" isn't optimal but currently the only solution
  677. it prevents proper cross compilation to i386 though
  678. }
  679. {$if defined(cpuextended) and defined(FPC_HAS_TYPE_EXTENDED)}
  680. ait_real_80bit :
  681. begin
  682. if do_line then
  683. AsmWriteLn(target_asm.comment+'value: '+extended2str(tai_real_80bit(hp).value));
  684. { Make sure e is a extended type, bestreal could be
  685. a different type (bestreal) !! (PFV) }
  686. e:=tai_real_80bit(hp).value;
  687. AsmWrite(#9'.byte'#9);
  688. for i:=0 to 9 do
  689. begin
  690. if i<>0 then
  691. AsmWrite(',');
  692. AsmWrite(tostr(t80bitarray(e)[i]));
  693. end;
  694. AsmLn;
  695. end;
  696. {$endif cpuextended}
  697. ait_real_64bit :
  698. begin
  699. if do_line then
  700. AsmWriteLn(target_asm.comment+'value: '+double2str(tai_real_64bit(hp).value));
  701. d:=tai_real_64bit(hp).value;
  702. { swap the values to correct endian if required }
  703. if source_info.endian <> target_info.endian then
  704. swap64bitarray(t64bitarray(d));
  705. AsmWrite(#9'.byte'#9);
  706. {$ifdef arm}
  707. { on a real arm cpu, it's already hi/lo swapped }
  708. {$ifndef cpuarm}
  709. if tai_real_64bit(hp).formatoptions=fo_hiloswapped then
  710. begin
  711. for i:=4 to 7 do
  712. begin
  713. if i<>4 then
  714. AsmWrite(',');
  715. AsmWrite(tostr(t64bitarray(d)[i]));
  716. end;
  717. for i:=0 to 3 do
  718. begin
  719. AsmWrite(',');
  720. AsmWrite(tostr(t64bitarray(d)[i]));
  721. end;
  722. end
  723. else
  724. {$endif cpuarm}
  725. {$endif arm}
  726. begin
  727. for i:=0 to 7 do
  728. begin
  729. if i<>0 then
  730. AsmWrite(',');
  731. AsmWrite(tostr(t64bitarray(d)[i]));
  732. end;
  733. end;
  734. AsmLn;
  735. end;
  736. ait_real_32bit :
  737. begin
  738. if do_line then
  739. AsmWriteLn(target_asm.comment+'value: '+single2str(tai_real_32bit(hp).value));
  740. sin:=tai_real_32bit(hp).value;
  741. { swap the values to correct endian if required }
  742. if source_info.endian <> target_info.endian then
  743. swap32bitarray(t32bitarray(sin));
  744. AsmWrite(#9'.byte'#9);
  745. for i:=0 to 3 do
  746. begin
  747. if i<>0 then
  748. AsmWrite(',');
  749. AsmWrite(tostr(t32bitarray(sin)[i]));
  750. end;
  751. AsmLn;
  752. end;
  753. ait_comp_64bit :
  754. begin
  755. if do_line then
  756. AsmWriteLn(target_asm.comment+'value: '+extended2str(tai_comp_64bit(hp).value));
  757. AsmWrite(#9'.byte'#9);
  758. co:=comp(tai_comp_64bit(hp).value);
  759. { swap the values to correct endian if required }
  760. if source_info.endian <> target_info.endian then
  761. swap64bitarray(t64bitarray(co));
  762. for i:=0 to 7 do
  763. begin
  764. if i<>0 then
  765. AsmWrite(',');
  766. AsmWrite(tostr(t64bitarray(co)[i]));
  767. end;
  768. AsmLn;
  769. end;
  770. ait_string :
  771. begin
  772. pos:=0;
  773. for i:=1 to tai_string(hp).len do
  774. begin
  775. if pos=0 then
  776. begin
  777. AsmWrite(#9'.ascii'#9'"');
  778. pos:=20;
  779. end;
  780. ch:=tai_string(hp).str[i-1];
  781. case ch of
  782. #0, {This can't be done by range, because a bug in FPC}
  783. #1..#31,
  784. #128..#255 : s:='\'+tostr(ord(ch) shr 6)+tostr((ord(ch) and 63) shr 3)+tostr(ord(ch) and 7);
  785. '"' : s:='\"';
  786. '\' : s:='\\';
  787. else
  788. s:=ch;
  789. end;
  790. AsmWrite(s);
  791. inc(pos,length(s));
  792. if (pos>line_length) or (i=tai_string(hp).len) then
  793. begin
  794. AsmWriteLn('"');
  795. pos:=0;
  796. end;
  797. end;
  798. end;
  799. ait_label :
  800. begin
  801. if (tai_label(hp).labsym.is_used) then
  802. begin
  803. if tai_label(hp).labsym.bind=AB_GLOBAL then
  804. begin
  805. AsmWrite('.globl'#9);
  806. AsmWriteLn(tai_label(hp).labsym.name);
  807. end;
  808. AsmWrite(tai_label(hp).labsym.name);
  809. AsmWriteLn(':');
  810. end;
  811. end;
  812. ait_symbol :
  813. begin
  814. if (target_info.system = system_powerpc64_linux) and
  815. (tai_symbol(hp).sym.typ = AT_FUNCTION) and (cs_profile in current_settings.moduleswitches) then
  816. begin
  817. AsmWriteLn('.globl _mcount');
  818. end;
  819. if tai_symbol(hp).is_global then
  820. begin
  821. AsmWrite('.globl'#9);
  822. AsmWriteLn(tai_symbol(hp).sym.name);
  823. end;
  824. if (target_info.system = system_powerpc64_linux) and
  825. (tai_symbol(hp).sym.typ = AT_FUNCTION) then
  826. begin
  827. AsmWriteLn('.section "opd", "aw"');
  828. AsmWriteLn('.align 3');
  829. AsmWriteLn(tai_symbol(hp).sym.name + ':');
  830. AsmWriteLn('.quad .' + tai_symbol(hp).sym.name + ', .TOC.@tocbase, 0');
  831. AsmWriteLn('.previous');
  832. AsmWriteLn('.size ' + tai_symbol(hp).sym.name + ', 24');
  833. if (tai_symbol(hp).is_global) then
  834. AsmWriteLn('.globl .' + tai_symbol(hp).sym.name);
  835. AsmWriteLn('.type .' + tai_symbol(hp).sym.name + ', @function');
  836. { the dotted name is the name of the actual function entry }
  837. AsmWrite('.');
  838. end
  839. else
  840. begin
  841. if (target_info.system <> system_arm_linux) then
  842. sepChar := '@'
  843. else
  844. sepChar := '#';
  845. if (tf_needs_symbol_type in target_info.flags) then
  846. begin
  847. AsmWrite(#9'.type'#9 + tai_symbol(hp).sym.name);
  848. if (needsObject(tai_symbol(hp))) then
  849. AsmWriteLn(',' + sepChar + 'object')
  850. else
  851. AsmWriteLn(',' + sepChar + 'function');
  852. end;
  853. end;
  854. AsmWriteLn(tai_symbol(hp).sym.name + ':');
  855. end;
  856. ait_symbol_end :
  857. begin
  858. if tf_needs_symbol_size in target_info.flags then
  859. begin
  860. s:=target_asm.labelprefix+'e'+tostr(symendcount);
  861. inc(symendcount);
  862. AsmWriteLn(s+':');
  863. AsmWrite(#9'.size'#9);
  864. if (target_info.system = system_powerpc64_linux) and (tai_symbol_end(hp).sym.typ = AT_FUNCTION) then
  865. AsmWrite('.');
  866. AsmWrite(tai_symbol_end(hp).sym.name);
  867. AsmWrite(', '+s+' - ');
  868. if (target_info.system = system_powerpc64_linux) and (tai_symbol_end(hp).sym.typ = AT_FUNCTION) then
  869. AsmWrite('.');
  870. AsmWriteLn(tai_symbol_end(hp).sym.name);
  871. end;
  872. end;
  873. ait_instruction :
  874. begin
  875. WriteInstruction(hp);
  876. end;
  877. ait_stab :
  878. begin
  879. if assigned(tai_stab(hp).str) then
  880. begin
  881. AsmWrite(#9'.'+stabtypestr[tai_stab(hp).stabtype]+' ');
  882. AsmWritePChar(tai_stab(hp).str);
  883. AsmLn;
  884. end;
  885. end;
  886. ait_file :
  887. begin
  888. tai_file(hp).idx:=nextdwarffileidx;
  889. inc(nextdwarffileidx);
  890. AsmWrite(#9'.file '+tostr(tai_file(hp).idx)+' "');
  891. AsmWritePChar(tai_file(hp).str);
  892. AsmWrite('"');
  893. AsmLn;
  894. end;
  895. ait_loc :
  896. begin
  897. AsmWrite(#9'.loc '+tostr(tai_loc(hp).fileentry.idx)+' '+tostr(tai_loc(hp).line)+' '+tostr(tai_loc(hp).column));
  898. AsmLn;
  899. end;
  900. ait_force_line,
  901. ait_function_name : ;
  902. ait_cutobject :
  903. begin
  904. if SmartAsm then
  905. begin
  906. { only reset buffer if nothing has changed }
  907. if AsmSize=AsmStartSize then
  908. AsmClear
  909. else
  910. begin
  911. AsmClose;
  912. DoAssemble;
  913. AsmCreate(tai_cutobject(hp).place);
  914. end;
  915. { avoid empty files }
  916. while assigned(hp.next) and (tai(hp.next).typ in [ait_cutobject,ait_section,ait_comment]) do
  917. begin
  918. if tai(hp.next).typ=ait_section then
  919. CurrSecType:=tai_section(hp.next).sectype;
  920. hp:=tai(hp.next);
  921. end;
  922. if CurrSecType<>sec_none then
  923. WriteSection(CurrSecType,'',secorder_default);
  924. AsmStartSize:=AsmSize;
  925. { reset dwarf file index }
  926. nextdwarffileidx:=1;
  927. end;
  928. end;
  929. ait_marker :
  930. if tai_marker(hp).kind=mark_InlineStart then
  931. inc(InlineLevel)
  932. else if tai_marker(hp).kind=mark_InlineEnd then
  933. dec(InlineLevel);
  934. ait_directive :
  935. begin
  936. AsmWrite('.'+directivestr[tai_directive(hp).directive]+' ');
  937. if assigned(tai_directive(hp).name) then
  938. AsmWrite(tai_directive(hp).name^);
  939. AsmLn;
  940. end;
  941. else
  942. internalerror(2006012201);
  943. end;
  944. hp:=tai(hp.next);
  945. end;
  946. end;
  947. procedure TGNUAssembler.WriteExtraHeader;
  948. begin
  949. end;
  950. procedure TGNUAssembler.WriteInstruction(hp: tai);
  951. begin
  952. InstrWriter.WriteInstruction(hp);
  953. end;
  954. procedure TGNUAssembler.WriteAsmList;
  955. var
  956. n : string;
  957. hal : tasmlisttype;
  958. begin
  959. {$ifdef EXTDEBUG}
  960. if assigned(current_module.mainsource) then
  961. Comment(V_Debug,'Start writing gas-styled assembler output for '+current_module.mainsource^);
  962. {$endif}
  963. CurrSecType:=sec_none;
  964. FillChar(lastfileinfo,sizeof(lastfileinfo),0);
  965. LastInfile:=nil;
  966. if assigned(current_module.mainsource) then
  967. n:=ExtractFileName(current_module.mainsource^)
  968. else
  969. n:=InputFileName;
  970. AsmWriteLn(#9'.file "'+FixFileName(n)+'"');
  971. WriteExtraHeader;
  972. AsmStartSize:=AsmSize;
  973. symendcount:=0;
  974. for hal:=low(TasmlistType) to high(TasmlistType) do
  975. begin
  976. AsmWriteLn(target_asm.comment+'Begin asmlist '+AsmlistTypeStr[hal]);
  977. writetree(current_asmdata.asmlists[hal]);
  978. AsmWriteLn(target_asm.comment+'End asmlist '+AsmlistTypeStr[hal]);
  979. end;
  980. {
  981. Result doesn't work properly yet due to a bug in Apple's linker
  982. if (cs_create_smart in current_settings.moduleswitches) and
  983. (target_info.system in systems_darwin) then
  984. AsmWriteLn(#9'.subsections_via_symbols');
  985. }
  986. AsmLn;
  987. {$ifdef EXTDEBUG}
  988. if assigned(current_module.mainsource) then
  989. Comment(V_Debug,'Done writing gas-styled assembler output for '+current_module.mainsource^);
  990. {$endif EXTDEBUG}
  991. end;
  992. {****************************************************************************}
  993. { Apple/GNU Assembler writer }
  994. {****************************************************************************}
  995. function TAppleGNUAssembler.sectionname(atype:TAsmSectiontype;const aname:string;aorder:TAsmSectionOrder):string;
  996. begin
  997. if (target_info.system in systems_darwin) then
  998. case atype of
  999. sec_bss:
  1000. { all bss (lcomm) symbols are automatically put in the right }
  1001. { place by using the lcomm assembler directive }
  1002. atype := sec_none;
  1003. sec_debug_frame,
  1004. sec_eh_frame:
  1005. begin
  1006. result := '.section __DWARFA,__debug_frame,coalesced,no_toc+strip_static_syms'#10'EH_frame'+tostr(debugframecount)+':';
  1007. inc(debugframecount);
  1008. exit;
  1009. end;
  1010. sec_debug_line:
  1011. begin
  1012. result := '.section __DWARF,__debug_line,regular,debug';
  1013. exit;
  1014. end;
  1015. sec_debug_info:
  1016. begin
  1017. result := '.section __DWARF,__debug_info,regular,debug';
  1018. exit;
  1019. end;
  1020. sec_debug_abbrev:
  1021. begin
  1022. result := '.section __DWARF,__debug_abbrev,regular,debug';
  1023. exit;
  1024. end;
  1025. sec_rodata:
  1026. begin
  1027. result := '.const';
  1028. exit;
  1029. end;
  1030. sec_fpc:
  1031. begin
  1032. result := '.section __TEXT, .fpc, regular, no_dead_strip';
  1033. exit;
  1034. end;
  1035. end;
  1036. result := inherited sectionname(atype,aname,aorder);
  1037. end;
  1038. {****************************************************************************}
  1039. { Abstract Instruction Writer }
  1040. {****************************************************************************}
  1041. constructor TCPUInstrWriter.create(_owner: TGNUAssembler);
  1042. begin
  1043. inherited create;
  1044. owner := _owner;
  1045. end;
  1046. end.