aggas.pas 43 KB

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