aggas.pas 41 KB

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