aggas.pas 37 KB

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