aggas.pas 38 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121
  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 paratargetdbg = 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 aktmoduleswitches) 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. consttype : 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 aktglobalswitches) or
  367. ((cs_lineinfo in aktmoduleswitches)
  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 aktglobalswitches) 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 aktglobalswitches) 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 aktglobalswitches) 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 aktglobalswitches) 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. consttype:=tai_const(hp).consttype;
  551. case consttype 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<>consttype) 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. {$ifdef FPC}
  733. co:=comp(tai_comp_64bit(hp).value);
  734. {$else}
  735. co:=tai_comp_64bit(hp).value;
  736. {$endif}
  737. { swap the values to correct endian if required }
  738. if source_info.endian <> target_info.endian then
  739. swap64bitarray(t64bitarray(co));
  740. for i:=0 to 7 do
  741. begin
  742. if i<>0 then
  743. AsmWrite(',');
  744. AsmWrite(tostr(t64bitarray(co)[i]));
  745. end;
  746. AsmLn;
  747. end;
  748. ait_string :
  749. begin
  750. pos:=0;
  751. for i:=1 to tai_string(hp).len do
  752. begin
  753. if pos=0 then
  754. begin
  755. AsmWrite(#9'.ascii'#9'"');
  756. pos:=20;
  757. end;
  758. ch:=tai_string(hp).str[i-1];
  759. case ch of
  760. #0, {This can't be done by range, because a bug in FPC}
  761. #1..#31,
  762. #128..#255 : s:='\'+tostr(ord(ch) shr 6)+tostr((ord(ch) and 63) shr 3)+tostr(ord(ch) and 7);
  763. '"' : s:='\"';
  764. '\' : s:='\\';
  765. else
  766. s:=ch;
  767. end;
  768. AsmWrite(s);
  769. inc(pos,length(s));
  770. if (pos>line_length) or (i=tai_string(hp).len) then
  771. begin
  772. AsmWriteLn('"');
  773. pos:=0;
  774. end;
  775. end;
  776. end;
  777. ait_label :
  778. begin
  779. if (tai_label(hp).labsym.is_used) then
  780. begin
  781. if tai_label(hp).labsym.bind=AB_GLOBAL then
  782. begin
  783. AsmWrite('.globl'#9);
  784. AsmWriteLn(tai_label(hp).labsym.name);
  785. end;
  786. AsmWrite(tai_label(hp).labsym.name);
  787. AsmWriteLn(':');
  788. end;
  789. end;
  790. ait_symbol :
  791. begin
  792. if (target_info.system = system_powerpc64_linux) and
  793. (tai_symbol(hp).sym.typ = AT_FUNCTION) and (cs_profile in aktmoduleswitches) then
  794. begin
  795. AsmWriteLn('.globl _mcount');
  796. end;
  797. if tai_symbol(hp).is_global then
  798. begin
  799. AsmWrite('.globl'#9);
  800. AsmWriteLn(tai_symbol(hp).sym.name);
  801. end;
  802. if (target_info.system = system_powerpc64_linux) and
  803. (tai_symbol(hp).sym.typ = AT_FUNCTION) then
  804. begin
  805. AsmWriteLn('.section "opd", "aw"');
  806. AsmWriteLn('.align 3');
  807. AsmWriteLn(tai_symbol(hp).sym.name + ':');
  808. AsmWriteLn('.quad .' + tai_symbol(hp).sym.name + ', .TOC.@tocbase, 0');
  809. AsmWriteLn('.previous');
  810. AsmWriteLn('.size ' + tai_symbol(hp).sym.name + ', 24');
  811. if (tai_symbol(hp).is_global) then
  812. AsmWriteLn('.globl .' + tai_symbol(hp).sym.name);
  813. AsmWriteLn('.type .' + tai_symbol(hp).sym.name + ', @function');
  814. { the dotted name is the name of the actual function entry }
  815. AsmWrite('.');
  816. end
  817. else
  818. begin
  819. if (target_info.system <> system_arm_linux) then
  820. sepChar := '@'
  821. else
  822. sepChar := '#';
  823. if (tf_needs_symbol_type in target_info.flags) then
  824. begin
  825. AsmWrite(#9'.type'#9 + tai_symbol(hp).sym.name);
  826. if (needsObject(tai_symbol(hp))) then
  827. AsmWriteLn(',' + sepChar + 'object')
  828. else
  829. AsmWriteLn(',' + sepChar + 'function');
  830. end;
  831. end;
  832. AsmWriteLn(tai_symbol(hp).sym.name + ':');
  833. end;
  834. ait_symbol_end :
  835. begin
  836. if tf_needs_symbol_size in target_info.flags then
  837. begin
  838. s:=target_asm.labelprefix+'e'+tostr(symendcount);
  839. inc(symendcount);
  840. AsmWriteLn(s+':');
  841. AsmWrite(#9'.size'#9);
  842. if (target_info.system = system_powerpc64_linux) and (tai_symbol_end(hp).sym.typ = AT_FUNCTION) then
  843. AsmWrite('.');
  844. AsmWrite(tai_symbol_end(hp).sym.name);
  845. AsmWrite(', '+s+' - ');
  846. if (target_info.system = system_powerpc64_linux) and (tai_symbol_end(hp).sym.typ = AT_FUNCTION) then
  847. AsmWrite('.');
  848. AsmWriteLn(tai_symbol_end(hp).sym.name);
  849. end;
  850. end;
  851. ait_instruction :
  852. begin
  853. WriteInstruction(hp);
  854. end;
  855. ait_stab :
  856. begin
  857. if assigned(tai_stab(hp).str) then
  858. begin
  859. AsmWrite(#9'.'+stabtypestr[tai_stab(hp).stabtype]+' ');
  860. AsmWritePChar(tai_stab(hp).str);
  861. AsmLn;
  862. end;
  863. end;
  864. ait_file :
  865. begin
  866. tai_file(hp).idx:=nextdwarffileidx;
  867. inc(nextdwarffileidx);
  868. AsmWrite(#9'.file '+tostr(tai_file(hp).idx)+' "');
  869. AsmWritePChar(tai_file(hp).str);
  870. AsmWrite('"');
  871. AsmLn;
  872. end;
  873. ait_loc :
  874. begin
  875. AsmWrite(#9'.loc '+tostr(tai_loc(hp).fileentry.idx)+' '+tostr(tai_loc(hp).line)+' '+tostr(tai_loc(hp).column));
  876. AsmLn;
  877. end;
  878. ait_force_line,
  879. ait_function_name : ;
  880. ait_cutobject :
  881. begin
  882. if SmartAsm then
  883. begin
  884. { only reset buffer if nothing has changed }
  885. if AsmSize=AsmStartSize then
  886. AsmClear
  887. else
  888. begin
  889. AsmClose;
  890. DoAssemble;
  891. AsmCreate(tai_cutobject(hp).place);
  892. end;
  893. { avoid empty files }
  894. while assigned(hp.next) and (tai(hp.next).typ in [ait_cutobject,ait_section,ait_comment]) do
  895. begin
  896. if tai(hp.next).typ=ait_section then
  897. CurrSecType:=tai_section(hp.next).sectype;
  898. hp:=tai(hp.next);
  899. end;
  900. if CurrSecType<>sec_none then
  901. WriteSection(CurrSecType,'');
  902. AsmStartSize:=AsmSize;
  903. { reset dwarf file index }
  904. nextdwarffileidx:=1;
  905. end;
  906. end;
  907. ait_marker :
  908. if tai_marker(hp).kind=mark_InlineStart then
  909. inc(InlineLevel)
  910. else if tai_marker(hp).kind=mark_InlineEnd then
  911. dec(InlineLevel);
  912. ait_directive :
  913. begin
  914. AsmWrite('.'+directivestr[tai_directive(hp).directive]+' ');
  915. if assigned(tai_directive(hp).name) then
  916. AsmWrite(tai_directive(hp).name^);
  917. AsmLn;
  918. end;
  919. else
  920. internalerror(2006012201);
  921. end;
  922. hp:=tai(hp.next);
  923. end;
  924. end;
  925. procedure TGNUAssembler.WriteExtraHeader;
  926. begin
  927. end;
  928. procedure TGNUAssembler.WriteInstruction(hp: tai);
  929. begin
  930. InstrWriter.WriteInstruction(hp);
  931. end;
  932. procedure TGNUAssembler.WriteAsmList;
  933. var
  934. p:dirstr;
  935. n:namestr;
  936. e:extstr;
  937. hal : tasmlisttype;
  938. begin
  939. {$ifdef EXTDEBUG}
  940. if assigned(current_module.mainsource) then
  941. Comment(V_Debug,'Start writing gas-styled assembler output for '+current_module.mainsource^);
  942. {$endif}
  943. CurrSecType:=sec_none;
  944. FillChar(lastfileinfo,sizeof(lastfileinfo),0);
  945. LastInfile:=nil;
  946. if assigned(current_module.mainsource) then
  947. {$IFDEF USE_SYSUTILS}
  948. begin
  949. p := SplitPath(current_module.mainsource^);
  950. n := SplitName(current_module.mainsource^);
  951. e := SplitExtension(current_module.mainsource^);
  952. end
  953. {$ELSE USE_SYSUTILS}
  954. fsplit(current_module.mainsource^,p,n,e)
  955. {$ENDIF USE_SYSUTILS}
  956. else
  957. begin
  958. p:=inputdir;
  959. n:=inputfile;
  960. e:=inputextension;
  961. end;
  962. { to get symify to work }
  963. AsmWriteLn(#9'.file "'+FixFileName(n+e)+'"');
  964. WriteExtraHeader;
  965. AsmStartSize:=AsmSize;
  966. symendcount:=0;
  967. for hal:=low(TasmlistType) to high(TasmlistType) do
  968. begin
  969. AsmWriteLn(target_asm.comment+'Begin asmlist '+AsmlistTypeStr[hal]);
  970. writetree(current_asmdata.asmlists[hal]);
  971. AsmWriteLn(target_asm.comment+'End asmlist '+AsmlistTypeStr[hal]);
  972. end;
  973. if (cs_create_smart in aktmoduleswitches) and
  974. (target_info.system in [system_powerpc_darwin,system_i386_darwin]) then
  975. AsmWriteLn(#9'.subsections_via_symbols');
  976. AsmLn;
  977. {$ifdef EXTDEBUG}
  978. if assigned(current_module.mainsource) then
  979. Comment(V_Debug,'Done writing gas-styled assembler output for '+current_module.mainsource^);
  980. {$endif EXTDEBUG}
  981. end;
  982. {****************************************************************************}
  983. { Apple/GNU Assembler writer }
  984. {****************************************************************************}
  985. function TAppleGNUAssembler.sectionname(atype:TAsmSectiontype;const aname:string):string;
  986. begin
  987. if (target_info.system in [system_powerpc_darwin,system_i386_darwin]) then
  988. case atype of
  989. sec_bss:
  990. { all bss (lcomm) symbols are automatically put in the right }
  991. { place by using the lcomm assembler directive }
  992. atype := sec_none;
  993. sec_debug_frame,
  994. sec_eh_frame:
  995. begin
  996. result := '.section __DWARFA,__debug_frame,coalesced,no_toc+strip_static_syms'#10'EH_frame'+tostr(debugframecount)+':';
  997. inc(debugframecount);
  998. exit;
  999. end;
  1000. sec_rodata:
  1001. begin
  1002. result := '.const';
  1003. exit;
  1004. end;
  1005. end;
  1006. result := inherited sectionname(atype,aname);
  1007. end;
  1008. {****************************************************************************}
  1009. { Abstract Instruction Writer }
  1010. {****************************************************************************}
  1011. constructor TCPUInstrWriter.create(_owner: TGNUAssembler);
  1012. begin
  1013. inherited create;
  1014. owner := _owner;
  1015. end;
  1016. end.