aggas.pas 44 KB

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