aggas.pas 44 KB

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