aggas.pas 37 KB

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