aggas.pas 38 KB

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