aggas.pas 37 KB

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