aggas.pas 38 KB

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