aggas.pas 39 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155
  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 [system_powerpc_darwin,system_i386_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 [system_powerpc_darwin,system_i386_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. begin
  296. if (atype = sec_stub) then
  297. AsmWrite('.section ');
  298. end
  299. else
  300. AsmWrite('.section ');
  301. end;
  302. s:=sectionname(atype,aname,aorder);
  303. AsmWrite(s);
  304. case atype of
  305. sec_fpc :
  306. if aname = 'resptrs' then
  307. AsmWrite(', "a", @progbits');
  308. sec_stub :
  309. begin
  310. case target_info.system of
  311. { there are processor-independent shortcuts available }
  312. { for this, namely .symbol_stub and .picsymbol_stub, but }
  313. { they don't work and gcc doesn't use them either... }
  314. system_powerpc_darwin:
  315. AsmWriteln('__TEXT,__symbol_stub1,symbol_stubs,pure_instructions,16');
  316. system_i386_darwin:
  317. AsmWriteln('__IMPORT,__jump_table,symbol_stubs,self_modifying_code+pure_instructions,5');
  318. else
  319. internalerror(2006031101);
  320. end;
  321. end;
  322. end;
  323. AsmLn;
  324. CurrSecType:=atype;
  325. end;
  326. procedure TGNUAssembler.WriteDecodedUleb128(a: qword);
  327. var
  328. i,len : longint;
  329. buf : array[0..63] of byte;
  330. begin
  331. len:=EncodeUleb128(a,buf);
  332. for i:=0 to len-1 do
  333. begin
  334. if (i > 0) then
  335. AsmWrite(',');
  336. AsmWrite(tostr(buf[i]));
  337. end;
  338. end;
  339. procedure TGNUAssembler.WriteDecodedSleb128(a: int64);
  340. var
  341. i,len : longint;
  342. buf : array[0..255] of byte;
  343. begin
  344. len:=EncodeSleb128(a,buf);
  345. for i:=0 to len-1 do
  346. begin
  347. if (i > 0) then
  348. AsmWrite(',');
  349. AsmWrite(tostr(buf[i]));
  350. end;
  351. end;
  352. procedure TGNUAssembler.WriteTree(p:TAsmList);
  353. function needsObject(hp : tai_symbol) : boolean;
  354. begin
  355. needsObject :=
  356. (
  357. assigned(hp.next) and
  358. (tai(hp.next).typ in [ait_const,ait_datablock,
  359. ait_real_32bit,ait_real_64bit,ait_real_80bit,ait_comp_64bit])
  360. ) or
  361. (hp.sym.typ=AT_DATA);
  362. end;
  363. var
  364. ch : char;
  365. hp : tai;
  366. hp1 : tailineinfo;
  367. constdef : taiconst_type;
  368. s,t : string;
  369. i,pos,l : longint;
  370. InlineLevel : longint;
  371. last_align : longint;
  372. co : comp;
  373. sin : single;
  374. d : double;
  375. {$ifdef cpuextended}
  376. e : extended;
  377. {$endif cpuextended}
  378. do_line : boolean;
  379. sepChar : char;
  380. nextdwarffileidx : longint;
  381. begin
  382. if not assigned(p) then
  383. exit;
  384. nextdwarffileidx:=1;
  385. last_align := 2;
  386. InlineLevel:=0;
  387. { lineinfo is only needed for al_procedures (PFV) }
  388. do_line:=(cs_asm_source in current_settings.globalswitches) or
  389. ((cs_lineinfo in current_settings.moduleswitches)
  390. and (p=current_asmdata.asmlists[al_procedures]));
  391. hp:=tai(p.first);
  392. while assigned(hp) do
  393. begin
  394. if not(hp.typ in SkipLineInfo) then
  395. begin
  396. hp1 := hp as tailineinfo;
  397. current_filepos:=hp1.fileinfo;
  398. { no line info for inlined code }
  399. if do_line and (inlinelevel=0) then
  400. begin
  401. { load infile }
  402. if lastfileinfo.fileindex<>hp1.fileinfo.fileindex then
  403. begin
  404. infile:=current_module.sourcefiles.get_file(hp1.fileinfo.fileindex);
  405. if assigned(infile) then
  406. begin
  407. { open only if needed !! }
  408. if (cs_asm_source in current_settings.globalswitches) then
  409. infile.open;
  410. end;
  411. { avoid unnecessary reopens of the same file !! }
  412. lastfileinfo.fileindex:=hp1.fileinfo.fileindex;
  413. { be sure to change line !! }
  414. lastfileinfo.line:=-1;
  415. end;
  416. { write source }
  417. if (cs_asm_source in current_settings.globalswitches) and
  418. assigned(infile) then
  419. begin
  420. if (infile<>lastinfile) then
  421. begin
  422. AsmWriteLn(target_asm.comment+'['+infile.name^+']');
  423. if assigned(lastinfile) then
  424. lastinfile.close;
  425. end;
  426. if (hp1.fileinfo.line<>lastfileinfo.line) and
  427. ((hp1.fileinfo.line<infile.maxlinebuf) or (InlineLevel>0)) then
  428. begin
  429. if (hp1.fileinfo.line<>0) and
  430. ((infile.linebuf^[hp1.fileinfo.line]>=0) or (InlineLevel>0)) then
  431. AsmWriteLn(target_asm.comment+'['+tostr(hp1.fileinfo.line)+'] '+
  432. fixline(infile.GetLineStr(hp1.fileinfo.line)));
  433. { set it to a negative value !
  434. to make that is has been read already !! PM }
  435. if (infile.linebuf^[hp1.fileinfo.line]>=0) then
  436. infile.linebuf^[hp1.fileinfo.line]:=-infile.linebuf^[hp1.fileinfo.line]-1;
  437. end;
  438. end;
  439. lastfileinfo:=hp1.fileinfo;
  440. lastinfile:=infile;
  441. end;
  442. end;
  443. case hp.typ of
  444. ait_comment :
  445. Begin
  446. AsmWrite(target_asm.comment);
  447. AsmWritePChar(tai_comment(hp).str);
  448. AsmLn;
  449. End;
  450. ait_regalloc :
  451. begin
  452. if (cs_asm_regalloc in current_settings.globalswitches) then
  453. begin
  454. AsmWrite(#9+target_asm.comment+'Register ');
  455. repeat
  456. AsmWrite(std_regname(Tai_regalloc(hp).reg));
  457. if (hp.next=nil) or
  458. (tai(hp.next).typ<>ait_regalloc) or
  459. (tai_regalloc(hp.next).ratype<>tai_regalloc(hp).ratype) then
  460. break;
  461. hp:=tai(hp.next);
  462. AsmWrite(',');
  463. until false;
  464. AsmWrite(' ');
  465. AsmWriteLn(regallocstr[tai_regalloc(hp).ratype]);
  466. end;
  467. end;
  468. ait_tempalloc :
  469. begin
  470. if (cs_asm_tempalloc in current_settings.globalswitches) then
  471. begin
  472. {$ifdef EXTDEBUG}
  473. if assigned(tai_tempalloc(hp).problem) then
  474. AsmWriteLn(target_asm.comment+'Temp '+tostr(tai_tempalloc(hp).temppos)+','+
  475. tostr(tai_tempalloc(hp).tempsize)+' '+tai_tempalloc(hp).problem^)
  476. else
  477. {$endif EXTDEBUG}
  478. AsmWriteLn(target_asm.comment+'Temp '+tostr(tai_tempalloc(hp).temppos)+','+
  479. tostr(tai_tempalloc(hp).tempsize)+' '+tempallocstr[tai_tempalloc(hp).allocation]);
  480. end;
  481. end;
  482. ait_align :
  483. begin
  484. if tai_align_abstract(hp).aligntype>1 then
  485. begin
  486. if not(target_info.system in [system_powerpc_darwin,system_i386_darwin]) then
  487. begin
  488. AsmWrite(#9'.balign '+tostr(tai_align_abstract(hp).aligntype));
  489. if tai_align_abstract(hp).use_op then
  490. AsmWrite(','+tostr(tai_align_abstract(hp).fillop))
  491. {$ifdef x86}
  492. { force NOP as alignment op code }
  493. else if CurrSecType=sec_code then
  494. AsmWrite(',0x90');
  495. {$endif x86}
  496. end
  497. else
  498. begin
  499. { darwin as only supports .align }
  500. if not ispowerof2(tai_align_abstract(hp).aligntype,i) then
  501. internalerror(2003010305);
  502. AsmWrite(#9'.align '+tostr(i));
  503. last_align := i;
  504. end;
  505. AsmLn;
  506. end;
  507. end;
  508. ait_section :
  509. begin
  510. if tai_section(hp).sectype<>sec_none then
  511. WriteSection(tai_section(hp).sectype,tai_section(hp).name^,tai_section(hp).secorder)
  512. else
  513. begin
  514. {$ifdef EXTDEBUG}
  515. AsmWrite(target_asm.comment);
  516. AsmWriteln(' sec_none');
  517. {$endif EXTDEBUG}
  518. end;
  519. end;
  520. ait_datablock :
  521. begin
  522. if target_info.system in [system_powerpc_darwin,system_i386_darwin] then
  523. begin
  524. {On Mac OS X you can't have common symbols in a shared
  525. library, since those are in the TEXT section and the text section is
  526. read-only in shared libraries (so it can be shared among different
  527. processes). The alternate code creates some kind of common symbols in
  528. the data segment. The generic code no longer uses common symbols, but
  529. this doesn't work on Mac OS X as well.}
  530. if tai_datablock(hp).is_global then
  531. begin
  532. asmwrite('.globl ');
  533. asmwriteln(tai_datablock(hp).sym.name);
  534. asmwriteln('.data');
  535. asmwrite('.zerofill __DATA, __common, ');
  536. asmwrite(tai_datablock(hp).sym.name);
  537. asmwriteln(', '+tostr(tai_datablock(hp).size)+','+tostr(last_align));
  538. if not(CurrSecType in [sec_data,sec_none]) then
  539. writesection(CurrSecType,'',secorder_default);
  540. end
  541. else
  542. begin
  543. asmwrite(#9'.lcomm'#9);
  544. asmwrite(tai_datablock(hp).sym.name);
  545. asmwrite(','+tostr(tai_datablock(hp).size));
  546. if not(target_info.system in [system_arm_linux,system_i386_win32]) then
  547. asmwrite(','+tostr(last_align));
  548. asmwriteln('');
  549. end
  550. end
  551. else
  552. begin
  553. { The .comm is required for COMMON symbols. These are used
  554. in the shared library loading. All the symbols declared in
  555. the .so file need to resolve to the data allocated in the main
  556. program (PFV) }
  557. if Tai_datablock(hp).is_global then
  558. begin
  559. asmwrite(#9'.comm'#9);
  560. asmwrite(tai_datablock(hp).sym.name);
  561. asmwrite(','+tostr(tai_datablock(hp).size));
  562. if not(target_info.system in [system_arm_linux,system_i386_win32]) then
  563. asmwrite(','+tostr(last_align));
  564. asmwriteln('');
  565. end
  566. else
  567. begin
  568. asmwrite(#9'.lcomm'#9);
  569. asmwrite(tai_datablock(hp).sym.name);
  570. asmwrite(','+tostr(tai_datablock(hp).size));
  571. if not(target_info.system in [system_arm_linux,system_i386_win32]) then
  572. asmwrite(','+tostr(last_align));
  573. asmwriteln('');
  574. end;
  575. end;
  576. end;
  577. ait_const:
  578. begin
  579. constdef:=tai_const(hp).consttype;
  580. case constdef of
  581. {$ifndef cpu64bit}
  582. aitconst_128bit :
  583. begin
  584. internalerror(200404291);
  585. end;
  586. aitconst_64bit :
  587. begin
  588. if assigned(tai_const(hp).sym) then
  589. internalerror(200404292);
  590. AsmWrite(ait_const2str[aitconst_32bit]);
  591. if target_info.endian = endian_little then
  592. begin
  593. AsmWrite(tostr(longint(lo(tai_const(hp).value))));
  594. AsmWrite(',');
  595. AsmWrite(tostr(longint(hi(tai_const(hp).value))));
  596. end
  597. else
  598. begin
  599. AsmWrite(tostr(longint(hi(tai_const(hp).value))));
  600. AsmWrite(',');
  601. AsmWrite(tostr(longint(lo(tai_const(hp).value))));
  602. end;
  603. AsmLn;
  604. end;
  605. {$endif cpu64bit}
  606. aitconst_uleb128bit,
  607. aitconst_sleb128bit,
  608. {$ifdef cpu64bit}
  609. aitconst_128bit,
  610. aitconst_64bit,
  611. {$endif cpu64bit}
  612. aitconst_32bit,
  613. aitconst_16bit,
  614. aitconst_8bit,
  615. aitconst_rva_symbol,
  616. aitconst_indirect_symbol :
  617. begin
  618. if (target_info.system in [system_powerpc_darwin,system_i386_darwin]) and
  619. (tai_const(hp).consttype in [aitconst_uleb128bit,aitconst_sleb128bit]) then
  620. begin
  621. AsmWrite(ait_const2str[aitconst_8bit]);
  622. case tai_const(hp).consttype of
  623. aitconst_uleb128bit:
  624. WriteDecodedUleb128(qword(tai_const(hp).value));
  625. aitconst_sleb128bit:
  626. WriteDecodedSleb128(int64(tai_const(hp).value));
  627. end
  628. end
  629. else
  630. begin
  631. AsmWrite(ait_const2str[tai_const(hp).consttype]);
  632. l:=0;
  633. t := '';
  634. repeat
  635. if assigned(tai_const(hp).sym) then
  636. begin
  637. if assigned(tai_const(hp).endsym) then
  638. begin
  639. if (target_info.system in [system_powerpc_darwin,system_i386_darwin]) then
  640. begin
  641. s := NextSetLabel;
  642. t := #9'.set '+s+','+tai_const(hp).endsym.name+'-'+tai_const(hp).sym.name;
  643. end
  644. else
  645. s:=tai_const(hp).endsym.name+'-'+tai_const(hp).sym.name
  646. end
  647. else
  648. s:=tai_const(hp).sym.name;
  649. if tai_const(hp).value<>0 then
  650. s:=s+tostr_with_plus(tai_const(hp).value);
  651. end
  652. else
  653. s:=tostr(tai_const(hp).value);
  654. AsmWrite(s);
  655. inc(l,length(s));
  656. { Values with symbols are written on a single line to improve
  657. reading of the .s file (PFV) }
  658. if assigned(tai_const(hp).sym) or
  659. not(CurrSecType in [sec_data,sec_rodata]) or
  660. (l>line_length) or
  661. (hp.next=nil) or
  662. (tai(hp.next).typ<>ait_const) or
  663. (tai_const(hp.next).consttype<>constdef) or
  664. assigned(tai_const(hp.next).sym) then
  665. break;
  666. hp:=tai(hp.next);
  667. AsmWrite(',');
  668. until false;
  669. if (t <> '') then
  670. begin
  671. AsmLn;
  672. AsmWrite(t);
  673. end;
  674. end;
  675. AsmLn;
  676. end;
  677. end;
  678. end;
  679. { the "and defined(FPC_HAS_TYPE_EXTENDED)" isn't optimal but currently the only solution
  680. it prevents proper cross compilation to i386 though
  681. }
  682. {$if defined(cpuextended) and defined(FPC_HAS_TYPE_EXTENDED)}
  683. ait_real_80bit :
  684. begin
  685. if do_line then
  686. AsmWriteLn(target_asm.comment+'value: '+extended2str(tai_real_80bit(hp).value));
  687. { Make sure e is a extended type, bestreal could be
  688. a different type (bestreal) !! (PFV) }
  689. e:=tai_real_80bit(hp).value;
  690. AsmWrite(#9'.byte'#9);
  691. for i:=0 to 9 do
  692. begin
  693. if i<>0 then
  694. AsmWrite(',');
  695. AsmWrite(tostr(t80bitarray(e)[i]));
  696. end;
  697. AsmLn;
  698. end;
  699. {$endif cpuextended}
  700. ait_real_64bit :
  701. begin
  702. if do_line then
  703. AsmWriteLn(target_asm.comment+'value: '+double2str(tai_real_64bit(hp).value));
  704. d:=tai_real_64bit(hp).value;
  705. { swap the values to correct endian if required }
  706. if source_info.endian <> target_info.endian then
  707. swap64bitarray(t64bitarray(d));
  708. AsmWrite(#9'.byte'#9);
  709. {$ifdef arm}
  710. { on a real arm cpu, it's already hi/lo swapped }
  711. {$ifndef cpuarm}
  712. if tai_real_64bit(hp).formatoptions=fo_hiloswapped then
  713. begin
  714. for i:=4 to 7 do
  715. begin
  716. if i<>4 then
  717. AsmWrite(',');
  718. AsmWrite(tostr(t64bitarray(d)[i]));
  719. end;
  720. for i:=0 to 3 do
  721. begin
  722. AsmWrite(',');
  723. AsmWrite(tostr(t64bitarray(d)[i]));
  724. end;
  725. end
  726. else
  727. {$endif cpuarm}
  728. {$endif arm}
  729. begin
  730. for i:=0 to 7 do
  731. begin
  732. if i<>0 then
  733. AsmWrite(',');
  734. AsmWrite(tostr(t64bitarray(d)[i]));
  735. end;
  736. end;
  737. AsmLn;
  738. end;
  739. ait_real_32bit :
  740. begin
  741. if do_line then
  742. AsmWriteLn(target_asm.comment+'value: '+single2str(tai_real_32bit(hp).value));
  743. sin:=tai_real_32bit(hp).value;
  744. { swap the values to correct endian if required }
  745. if source_info.endian <> target_info.endian then
  746. swap32bitarray(t32bitarray(sin));
  747. AsmWrite(#9'.byte'#9);
  748. for i:=0 to 3 do
  749. begin
  750. if i<>0 then
  751. AsmWrite(',');
  752. AsmWrite(tostr(t32bitarray(sin)[i]));
  753. end;
  754. AsmLn;
  755. end;
  756. ait_comp_64bit :
  757. begin
  758. if do_line then
  759. AsmWriteLn(target_asm.comment+'value: '+extended2str(tai_comp_64bit(hp).value));
  760. AsmWrite(#9'.byte'#9);
  761. co:=comp(tai_comp_64bit(hp).value);
  762. { swap the values to correct endian if required }
  763. if source_info.endian <> target_info.endian then
  764. swap64bitarray(t64bitarray(co));
  765. for i:=0 to 7 do
  766. begin
  767. if i<>0 then
  768. AsmWrite(',');
  769. AsmWrite(tostr(t64bitarray(co)[i]));
  770. end;
  771. AsmLn;
  772. end;
  773. ait_string :
  774. begin
  775. pos:=0;
  776. for i:=1 to tai_string(hp).len do
  777. begin
  778. if pos=0 then
  779. begin
  780. AsmWrite(#9'.ascii'#9'"');
  781. pos:=20;
  782. end;
  783. ch:=tai_string(hp).str[i-1];
  784. case ch of
  785. #0, {This can't be done by range, because a bug in FPC}
  786. #1..#31,
  787. #128..#255 : s:='\'+tostr(ord(ch) shr 6)+tostr((ord(ch) and 63) shr 3)+tostr(ord(ch) and 7);
  788. '"' : s:='\"';
  789. '\' : s:='\\';
  790. else
  791. s:=ch;
  792. end;
  793. AsmWrite(s);
  794. inc(pos,length(s));
  795. if (pos>line_length) or (i=tai_string(hp).len) then
  796. begin
  797. AsmWriteLn('"');
  798. pos:=0;
  799. end;
  800. end;
  801. end;
  802. ait_label :
  803. begin
  804. if (tai_label(hp).labsym.is_used) then
  805. begin
  806. if tai_label(hp).labsym.bind=AB_GLOBAL then
  807. begin
  808. AsmWrite('.globl'#9);
  809. AsmWriteLn(tai_label(hp).labsym.name);
  810. end;
  811. AsmWrite(tai_label(hp).labsym.name);
  812. AsmWriteLn(':');
  813. end;
  814. end;
  815. ait_symbol :
  816. begin
  817. if (target_info.system = system_powerpc64_linux) and
  818. (tai_symbol(hp).sym.typ = AT_FUNCTION) and (cs_profile in current_settings.moduleswitches) then
  819. begin
  820. AsmWriteLn('.globl _mcount');
  821. end;
  822. if tai_symbol(hp).is_global then
  823. begin
  824. AsmWrite('.globl'#9);
  825. AsmWriteLn(tai_symbol(hp).sym.name);
  826. end;
  827. if (target_info.system = system_powerpc64_linux) and
  828. (tai_symbol(hp).sym.typ = AT_FUNCTION) then
  829. begin
  830. AsmWriteLn('.section "opd", "aw"');
  831. AsmWriteLn('.align 3');
  832. AsmWriteLn(tai_symbol(hp).sym.name + ':');
  833. AsmWriteLn('.quad .' + tai_symbol(hp).sym.name + ', .TOC.@tocbase, 0');
  834. AsmWriteLn('.previous');
  835. AsmWriteLn('.size ' + tai_symbol(hp).sym.name + ', 24');
  836. if (tai_symbol(hp).is_global) then
  837. AsmWriteLn('.globl .' + tai_symbol(hp).sym.name);
  838. AsmWriteLn('.type .' + tai_symbol(hp).sym.name + ', @function');
  839. { the dotted name is the name of the actual function entry }
  840. AsmWrite('.');
  841. end
  842. else
  843. begin
  844. if (target_info.system <> system_arm_linux) then
  845. sepChar := '@'
  846. else
  847. sepChar := '#';
  848. if (tf_needs_symbol_type in target_info.flags) then
  849. begin
  850. AsmWrite(#9'.type'#9 + tai_symbol(hp).sym.name);
  851. if (needsObject(tai_symbol(hp))) then
  852. AsmWriteLn(',' + sepChar + 'object')
  853. else
  854. AsmWriteLn(',' + sepChar + 'function');
  855. end;
  856. end;
  857. AsmWriteLn(tai_symbol(hp).sym.name + ':');
  858. end;
  859. ait_symbol_end :
  860. begin
  861. if tf_needs_symbol_size in target_info.flags then
  862. begin
  863. s:=target_asm.labelprefix+'e'+tostr(symendcount);
  864. inc(symendcount);
  865. AsmWriteLn(s+':');
  866. AsmWrite(#9'.size'#9);
  867. if (target_info.system = system_powerpc64_linux) and (tai_symbol_end(hp).sym.typ = AT_FUNCTION) then
  868. AsmWrite('.');
  869. AsmWrite(tai_symbol_end(hp).sym.name);
  870. AsmWrite(', '+s+' - ');
  871. if (target_info.system = system_powerpc64_linux) and (tai_symbol_end(hp).sym.typ = AT_FUNCTION) then
  872. AsmWrite('.');
  873. AsmWriteLn(tai_symbol_end(hp).sym.name);
  874. end;
  875. end;
  876. ait_instruction :
  877. begin
  878. WriteInstruction(hp);
  879. end;
  880. ait_stab :
  881. begin
  882. if assigned(tai_stab(hp).str) then
  883. begin
  884. AsmWrite(#9'.'+stabtypestr[tai_stab(hp).stabtype]+' ');
  885. AsmWritePChar(tai_stab(hp).str);
  886. AsmLn;
  887. end;
  888. end;
  889. ait_file :
  890. begin
  891. tai_file(hp).idx:=nextdwarffileidx;
  892. inc(nextdwarffileidx);
  893. AsmWrite(#9'.file '+tostr(tai_file(hp).idx)+' "');
  894. AsmWritePChar(tai_file(hp).str);
  895. AsmWrite('"');
  896. AsmLn;
  897. end;
  898. ait_loc :
  899. begin
  900. AsmWrite(#9'.loc '+tostr(tai_loc(hp).fileentry.idx)+' '+tostr(tai_loc(hp).line)+' '+tostr(tai_loc(hp).column));
  901. AsmLn;
  902. end;
  903. ait_force_line,
  904. ait_function_name : ;
  905. ait_cutobject :
  906. begin
  907. if SmartAsm then
  908. begin
  909. { only reset buffer if nothing has changed }
  910. if AsmSize=AsmStartSize then
  911. AsmClear
  912. else
  913. begin
  914. AsmClose;
  915. DoAssemble;
  916. AsmCreate(tai_cutobject(hp).place);
  917. end;
  918. { avoid empty files }
  919. while assigned(hp.next) and (tai(hp.next).typ in [ait_cutobject,ait_section,ait_comment]) do
  920. begin
  921. if tai(hp.next).typ=ait_section then
  922. CurrSecType:=tai_section(hp.next).sectype;
  923. hp:=tai(hp.next);
  924. end;
  925. if CurrSecType<>sec_none then
  926. WriteSection(CurrSecType,'',secorder_default);
  927. AsmStartSize:=AsmSize;
  928. { reset dwarf file index }
  929. nextdwarffileidx:=1;
  930. end;
  931. end;
  932. ait_marker :
  933. if tai_marker(hp).kind=mark_InlineStart then
  934. inc(InlineLevel)
  935. else if tai_marker(hp).kind=mark_InlineEnd then
  936. dec(InlineLevel);
  937. ait_directive :
  938. begin
  939. AsmWrite('.'+directivestr[tai_directive(hp).directive]+' ');
  940. if assigned(tai_directive(hp).name) then
  941. AsmWrite(tai_directive(hp).name^);
  942. AsmLn;
  943. end;
  944. else
  945. internalerror(2006012201);
  946. end;
  947. hp:=tai(hp.next);
  948. end;
  949. end;
  950. procedure TGNUAssembler.WriteExtraHeader;
  951. begin
  952. end;
  953. procedure TGNUAssembler.WriteInstruction(hp: tai);
  954. begin
  955. InstrWriter.WriteInstruction(hp);
  956. end;
  957. procedure TGNUAssembler.WriteAsmList;
  958. var
  959. n : string;
  960. hal : tasmlisttype;
  961. begin
  962. {$ifdef EXTDEBUG}
  963. if assigned(current_module.mainsource) then
  964. Comment(V_Debug,'Start writing gas-styled assembler output for '+current_module.mainsource^);
  965. {$endif}
  966. CurrSecType:=sec_none;
  967. FillChar(lastfileinfo,sizeof(lastfileinfo),0);
  968. LastInfile:=nil;
  969. if assigned(current_module.mainsource) then
  970. n:=ExtractFileName(current_module.mainsource^)
  971. else
  972. n:=InputFileName;
  973. AsmWriteLn(#9'.file "'+FixFileName(n)+'"');
  974. WriteExtraHeader;
  975. AsmStartSize:=AsmSize;
  976. symendcount:=0;
  977. for hal:=low(TasmlistType) to high(TasmlistType) do
  978. begin
  979. AsmWriteLn(target_asm.comment+'Begin asmlist '+AsmlistTypeStr[hal]);
  980. writetree(current_asmdata.asmlists[hal]);
  981. AsmWriteLn(target_asm.comment+'End asmlist '+AsmlistTypeStr[hal]);
  982. end;
  983. {
  984. Result doesn't work properly yet due to a bug in Apple's linker
  985. if (cs_create_smart in current_settings.moduleswitches) and
  986. (target_info.system in [system_powerpc_darwin,system_i386_darwin]) then
  987. AsmWriteLn(#9'.subsections_via_symbols');
  988. }
  989. AsmLn;
  990. {$ifdef EXTDEBUG}
  991. if assigned(current_module.mainsource) then
  992. Comment(V_Debug,'Done writing gas-styled assembler output for '+current_module.mainsource^);
  993. {$endif EXTDEBUG}
  994. end;
  995. {****************************************************************************}
  996. { Apple/GNU Assembler writer }
  997. {****************************************************************************}
  998. function TAppleGNUAssembler.sectionname(atype:TAsmSectiontype;const aname:string;aorder:TAsmSectionOrder):string;
  999. begin
  1000. if (target_info.system in [system_powerpc_darwin,system_i386_darwin]) then
  1001. case atype of
  1002. sec_bss:
  1003. { all bss (lcomm) symbols are automatically put in the right }
  1004. { place by using the lcomm assembler directive }
  1005. atype := sec_none;
  1006. sec_debug_frame,
  1007. sec_eh_frame:
  1008. begin
  1009. result := '.section __DWARFA,__debug_frame,coalesced,no_toc+strip_static_syms'#10'EH_frame'+tostr(debugframecount)+':';
  1010. inc(debugframecount);
  1011. exit;
  1012. end;
  1013. sec_debug_line:
  1014. begin
  1015. result := '.section __DWARF,__debug_line,regular,debug';
  1016. exit;
  1017. end;
  1018. sec_debug_info:
  1019. begin
  1020. result := '.section __DWARF,__debug_info,regular,debug';
  1021. exit;
  1022. end;
  1023. sec_debug_abbrev:
  1024. begin
  1025. result := '.section __DWARF,__debug_abbrev,regular,debug';
  1026. exit;
  1027. end;
  1028. sec_rodata:
  1029. begin
  1030. result := '.const';
  1031. exit;
  1032. end;
  1033. sec_fpc:
  1034. begin
  1035. result := '.section __TEXT, .fpc, regular, no_dead_strip';
  1036. exit;
  1037. end;
  1038. end;
  1039. result := inherited sectionname(atype,aname,aorder);
  1040. end;
  1041. {****************************************************************************}
  1042. { Abstract Instruction Writer }
  1043. {****************************************************************************}
  1044. constructor TCPUInstrWriter.create(_owner: TGNUAssembler);
  1045. begin
  1046. inherited create;
  1047. owner := _owner;
  1048. end;
  1049. end.