aggas.pas 41 KB

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