aggas.pas 37 KB

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