aggas.pas 43 KB

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