aggas.pas 41 KB

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