aggas.pas 43 KB

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