aggas.pas 45 KB

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