aggas.pas 40 KB

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