aggas.pas 43 KB

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