aggas.pas 38 KB

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