aggas.pas 44 KB

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