aggas.pas 38 KB

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