aggas.pas 39 KB

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