aggas.pas 41 KB

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