aggas.pas 37 KB

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