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