aggas.pas 41 KB

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