aggas.pas 41 KB

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