aggas.pas 41 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201
  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,cfileutils,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 .data.ro not yet working}
  207. {$if defined(arm) or defined(powerpc)}
  208. '.rodata',
  209. {$else arm}
  210. '.data',
  211. {$endif arm}
  212. '.rodata',
  213. '.bss',
  214. '.threadvar',
  215. '.pdata',
  216. '', { stubs }
  217. '.stab',
  218. '.stabstr',
  219. '.idata$2','.idata$4','.idata$5','.idata$6','.idata$7','.edata',
  220. '.eh_frame',
  221. '.debug_frame','.debug_info','.debug_line','.debug_abbrev',
  222. '.fpc',
  223. '.toc',
  224. '.init',
  225. '.fini'
  226. );
  227. secnames_pic : array[TAsmSectiontype] of string[17] = ('',
  228. '.text',
  229. '.data.rel',
  230. '.data.rel',
  231. '.data.rel',
  232. '.bss',
  233. '.threadvar',
  234. '.pdata',
  235. '', { stubs }
  236. '.stab',
  237. '.stabstr',
  238. '.idata$2','.idata$4','.idata$5','.idata$6','.idata$7','.edata',
  239. '.eh_frame',
  240. '.debug_frame','.debug_info','.debug_line','.debug_abbrev',
  241. '.fpc',
  242. '.toc',
  243. '.init',
  244. '.fini'
  245. );
  246. var
  247. sep : string[3];
  248. secname : string;
  249. begin
  250. if (cs_create_pic in current_settings.moduleswitches) and
  251. not(target_info.system in systems_darwin) then
  252. secname:=secnames_pic[atype]
  253. else
  254. secname:=secnames[atype];
  255. {$ifdef m68k}
  256. { old Amiga GNU AS doesn't support .section .fpc }
  257. if (atype=sec_fpc) and (target_info.system = system_m68k_amiga) then
  258. secname:=secnames[sec_data];
  259. {$endif}
  260. if (atype=sec_fpc) and (Copy(aname,1,3)='res') then
  261. begin
  262. result:=secname+'.'+aname;
  263. exit;
  264. end;
  265. if (atype=sec_threadvar) and
  266. (target_info.system=system_i386_win32) then
  267. secname:='.tls';
  268. { For bss we need to set some flags that are target dependent,
  269. it is easier to disable it for smartlinking. It doesn't take up
  270. filespace }
  271. if not(target_info.system in systems_darwin) and
  272. create_smartlink_sections and
  273. (aname<>'') and
  274. (atype <> sec_toc) and
  275. (atype<>sec_bss) then
  276. begin
  277. case aorder of
  278. secorder_begin :
  279. sep:='.b_';
  280. secorder_end :
  281. sep:='.z_';
  282. else
  283. sep:='.n_';
  284. end;
  285. result:=secname+sep+aname
  286. end
  287. else
  288. result:=secname;
  289. end;
  290. procedure TGNUAssembler.WriteSection(atype:TAsmSectiontype;const aname:string;aorder:TAsmSectionOrder);
  291. var
  292. s : string;
  293. begin
  294. AsmLn;
  295. case target_info.system of
  296. system_i386_OS2,
  297. system_i386_EMX,
  298. system_m68k_amiga, { amiga has old GNU AS (2.14), which blews up from .section (KB) }
  299. system_m68k_linux: ;
  300. system_powerpc_darwin,
  301. system_i386_darwin,
  302. system_powerpc64_darwin,
  303. system_x86_64_darwin:
  304. begin
  305. if (atype = sec_stub) then
  306. AsmWrite('.section ');
  307. end
  308. else
  309. AsmWrite('.section ');
  310. end;
  311. s:=sectionname(atype,aname,aorder);
  312. AsmWrite(s);
  313. case atype of
  314. sec_fpc :
  315. if aname = 'resptrs' then
  316. AsmWrite(', "a", @progbits');
  317. sec_stub :
  318. begin
  319. case target_info.system of
  320. { there are processor-independent shortcuts available }
  321. { for this, namely .symbol_stub and .picsymbol_stub, but }
  322. { they don't work and gcc doesn't use them either... }
  323. system_powerpc_darwin,
  324. system_powerpc64_darwin:
  325. if (cs_create_pic in current_settings.moduleswitches) then
  326. AsmWriteln('__TEXT,__picsymbolstub1,symbol_stubs,pure_instructions,32')
  327. else
  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 library
  537. 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
  540. in the data segment.
  541. }
  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,sec_rodata_norel]) 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. if create_smartlink_sections and
  975. (target_info.system in systems_darwin) then
  976. AsmWriteLn(#9'.subsections_via_symbols');
  977. AsmLn;
  978. {$ifdef EXTDEBUG}
  979. if assigned(current_module.mainsource) then
  980. Comment(V_Debug,'Done writing gas-styled assembler output for '+current_module.mainsource^);
  981. {$endif EXTDEBUG}
  982. end;
  983. {****************************************************************************}
  984. { Apple/GNU Assembler writer }
  985. {****************************************************************************}
  986. function TAppleGNUAssembler.sectionname(atype:TAsmSectiontype;const aname:string;aorder:TAsmSectionOrder):string;
  987. begin
  988. if (target_info.system in systems_darwin) then
  989. case atype of
  990. sec_bss:
  991. { all bss (lcomm) symbols are automatically put in the right }
  992. { place by using the lcomm assembler directive }
  993. atype := sec_none;
  994. sec_debug_frame,
  995. sec_eh_frame:
  996. begin
  997. result := '.section __DWARFA,__debug_frame,coalesced,no_toc+strip_static_syms'#10'EH_frame'+tostr(debugframecount)+':';
  998. inc(debugframecount);
  999. exit;
  1000. end;
  1001. sec_debug_line:
  1002. begin
  1003. result := '.section __DWARF,__debug_line,regular,debug';
  1004. exit;
  1005. end;
  1006. sec_debug_info:
  1007. begin
  1008. result := '.section __DWARF,__debug_info,regular,debug';
  1009. exit;
  1010. end;
  1011. sec_debug_abbrev:
  1012. begin
  1013. result := '.section __DWARF,__debug_abbrev,regular,debug';
  1014. exit;
  1015. end;
  1016. sec_rodata:
  1017. begin
  1018. result := '.const_data';
  1019. exit;
  1020. end;
  1021. sec_rodata_norel:
  1022. begin
  1023. result := '.const';
  1024. exit;
  1025. end;
  1026. sec_fpc:
  1027. begin
  1028. result := '.section __TEXT, .fpc, regular, no_dead_strip';
  1029. exit;
  1030. end;
  1031. sec_code:
  1032. begin
  1033. if (aname='fpc_geteipasebx') or
  1034. (aname='fpc_geteipasecx') then
  1035. begin
  1036. result:='.section __TEXT,__textcoal_nt,coalesced,pure_instructions'#10'.weak_definition '+aname+
  1037. #10'.private_extern '+aname;
  1038. exit;
  1039. end;
  1040. end;
  1041. end;
  1042. result := inherited sectionname(atype,aname,aorder);
  1043. end;
  1044. {****************************************************************************}
  1045. { a.out/GNU Assembler writer }
  1046. {****************************************************************************}
  1047. function TAoutGNUAssembler.sectionname(atype:TAsmSectiontype;const aname:string;aorder:TAsmSectionOrder):string;
  1048. const
  1049. (* Translation table - replace unsupported section types with basic ones. *)
  1050. SecXTable: array[TAsmSectionType] of TAsmSectionType = (
  1051. sec_none,
  1052. sec_code,
  1053. sec_data,
  1054. sec_data (* sec_rodata *),
  1055. sec_data (* sec_rodata_norel *),
  1056. sec_bss,
  1057. sec_data (* sec_threadvar *),
  1058. { used for wince exception handling }
  1059. sec_code (* sec_pdata *),
  1060. { used for darwin import stubs }
  1061. sec_code (* sec_stub *),
  1062. { stabs }
  1063. sec_stab,sec_stabstr,
  1064. { win32 }
  1065. sec_data (* sec_idata2 *),
  1066. sec_data (* sec_idata4 *),
  1067. sec_data (* sec_idata5 *),
  1068. sec_data (* sec_idata6 *),
  1069. sec_data (* sec_idata7 *),
  1070. sec_data (* sec_edata *),
  1071. { C++ exception handling unwinding (uses dwarf) }
  1072. sec_eh_frame,
  1073. { dwarf }
  1074. sec_debug_frame,
  1075. sec_debug_info,
  1076. sec_debug_line,
  1077. sec_debug_abbrev,
  1078. { ELF resources (+ references to stabs debug information sections) }
  1079. sec_code (* sec_fpc *),
  1080. { Table of contents section }
  1081. sec_code (* sec_toc *),
  1082. sec_code (* sec_init *),
  1083. sec_code (* sec_fini *)
  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.