aggas.pas 38 KB

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