aggas.pas 32 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985
  1. {
  2. Copyright (c) 1998-2004 by the Free Pascal team
  3. This unit implements generic GNU assembler (v2.8 or later)
  4. This program is free software; you can redistribute it and/or modify
  5. it under the terms of the GNU General Public License as published by
  6. the Free Software Foundation; either version 2 of the License, or
  7. (at your option) any later version.
  8. This program is distributed in the hope that it will be useful,
  9. but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11. GNU General Public License for more details.
  12. You should have received a copy of the GNU General Public License
  13. along with this program; if not, write to the Free Software
  14. Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  15. ****************************************************************************
  16. }
  17. { Base unit for writing GNU assembler output.
  18. }
  19. unit aggas;
  20. {$i fpcdefs.inc}
  21. interface
  22. uses
  23. {$IFDEF USE_SYSUTILS}
  24. SysUtils,
  25. {$ELSE USE_SYSUTILS}
  26. dos,
  27. {$ENDIF USE_SYSUTILS}
  28. cclasses,
  29. globtype,globals,
  30. aasmbase,aasmtai,aasmcpu,
  31. assemble;
  32. type
  33. {# This is a derived class which is used to write
  34. GAS styled assembler.
  35. The WriteInstruction() method must be overriden
  36. to write a single instruction to the assembler
  37. file.
  38. }
  39. TGNUAssembler=class(texternalassembler)
  40. protected
  41. function sectionname(atype:tasmsectiontype;const aname:string):string;virtual;
  42. procedure WriteSection(atype:tasmsectiontype;const aname:string);
  43. procedure WriteExtraHeader;virtual;
  44. procedure WriteInstruction(hp: tai); virtual; abstract;
  45. public
  46. procedure WriteTree(p:TAAsmoutput);override;
  47. procedure WriteAsmList;override;
  48. private
  49. setcount: longint;
  50. procedure WriteDecodedSleb128(a: aint);
  51. procedure WriteDecodedUleb128(a: aword);
  52. function NextSetLabel: string;
  53. end;
  54. implementation
  55. uses
  56. cutils,systems,
  57. fmodule,finput,verbose,
  58. itcpugas
  59. ;
  60. const
  61. line_length = 70;
  62. var
  63. CurrSecType : TAsmSectionType; { last section type written }
  64. lastfileinfo : tfileposinfo;
  65. infile,
  66. lastinfile : tinputfile;
  67. symendcount : longint;
  68. type
  69. {$ifdef cpuextended}
  70. t80bitarray = array[0..9] of byte;
  71. {$endif cpuextended}
  72. t64bitarray = array[0..7] of byte;
  73. t32bitarray = array[0..3] of byte;
  74. {****************************************************************************}
  75. { Support routines }
  76. {****************************************************************************}
  77. function fixline(s:string):string;
  78. {
  79. return s with all leading and ending spaces and tabs removed
  80. }
  81. var
  82. i,j,k : integer;
  83. begin
  84. i:=length(s);
  85. while (i>0) and (s[i] in [#9,' ']) do
  86. dec(i);
  87. j:=1;
  88. while (j<i) and (s[j] in [#9,' ']) do
  89. inc(j);
  90. for k:=j to i do
  91. if s[k] in [#0..#31,#127..#255] then
  92. s[k]:='.';
  93. fixline:=Copy(s,j,i-j+1);
  94. end;
  95. function single2str(d : single) : string;
  96. var
  97. hs : string;
  98. begin
  99. str(d,hs);
  100. { replace space with + }
  101. if hs[1]=' ' then
  102. hs[1]:='+';
  103. single2str:='0d'+hs
  104. end;
  105. function double2str(d : double) : string;
  106. var
  107. hs : string;
  108. begin
  109. str(d,hs);
  110. { replace space with + }
  111. if hs[1]=' ' then
  112. hs[1]:='+';
  113. double2str:='0d'+hs
  114. end;
  115. function extended2str(e : extended) : string;
  116. var
  117. hs : string;
  118. begin
  119. str(e,hs);
  120. { replace space with + }
  121. if hs[1]=' ' then
  122. hs[1]:='+';
  123. extended2str:='0d'+hs
  124. end;
  125. { convert floating point values }
  126. { to correct endian }
  127. procedure swap64bitarray(var t: t64bitarray);
  128. var
  129. b: byte;
  130. begin
  131. b:= t[7];
  132. t[7] := t[0];
  133. t[0] := b;
  134. b := t[6];
  135. t[6] := t[1];
  136. t[1] := b;
  137. b:= t[5];
  138. t[5] := t[2];
  139. t[2] := b;
  140. b:= t[4];
  141. t[4] := t[3];
  142. t[3] := b;
  143. end;
  144. procedure swap32bitarray(var t: t32bitarray);
  145. var
  146. b: byte;
  147. begin
  148. b:= t[1];
  149. t[1]:= t[2];
  150. t[2]:= b;
  151. b:= t[0];
  152. t[0]:= t[3];
  153. t[3]:= b;
  154. end;
  155. const
  156. ait_const2str : array[ait_const_128bit..ait_const_indirect_symbol] of string[20]=(
  157. #9'.fixme128'#9,#9'.quad'#9,#9'.long'#9,#9'.short'#9,#9'.byte'#9,
  158. #9'.sleb128'#9,#9'.uleb128'#9,
  159. #9'.rva'#9,#9'.indirect_symbol'#9
  160. );
  161. {****************************************************************************}
  162. { GNU Assembler writer }
  163. {****************************************************************************}
  164. function TGNUAssembler.NextSetLabel: string;
  165. begin
  166. inc(setcount);
  167. result := target_asm.labelprefix+'$set$'+tostr(setcount);
  168. end;
  169. function TGNUAssembler.sectionname(atype:tasmsectiontype;const aname:string):string;
  170. const
  171. secnames : array[tasmsectiontype] of string[12] = ('',
  172. {$warning TODO .rodata not yet working}
  173. '.text','.data','.data','.bss','.threadvar',
  174. 'common',
  175. '.note',
  176. '__TEXT', { stubs }
  177. '.stab','.stabstr',
  178. '.idata$2','.idata$4','.idata$5','.idata$6','.idata$7','.edata',
  179. '.eh_frame',
  180. '.debug_frame',
  181. 'fpc.resptrs',
  182. '.toc'
  183. );
  184. secnames_pic : array[tasmsectiontype] of string[12] = ('',
  185. '.text','.data.rel','.data.rel','.bss','.threadvar',
  186. 'common',
  187. '.note',
  188. '__TEXT', { stubs }
  189. '.stab','.stabstr',
  190. '.idata$2','.idata$4','.idata$5','.idata$6','.idata$7','.edata',
  191. '.eh_frame',
  192. '.debug_frame',
  193. 'fpc.resptrs',
  194. '.toc'
  195. );
  196. var
  197. secname : string;
  198. begin
  199. if (cs_create_pic in aktmoduleswitches) and
  200. not(target_info.system in [system_powerpc_darwin,system_i386_darwin]) then
  201. secname:=secnames_pic[atype]
  202. else
  203. secname:=secnames[atype];
  204. if (atype=sec_threadvar) and
  205. (target_info.system=system_i386_win32) then
  206. secname:='.tls';
  207. if use_smartlink_section and
  208. (aname<>'') then
  209. result:=secname+'.'+aname
  210. else
  211. result:=secname;
  212. end;
  213. procedure TGNUAssembler.WriteSection(atype:tasmsectiontype;const aname:string);
  214. var
  215. s : string;
  216. begin
  217. AsmLn;
  218. case target_info.system of
  219. system_i386_OS2,
  220. system_i386_EMX : ;
  221. system_powerpc_darwin :
  222. begin
  223. if atype=sec_stub then
  224. AsmWrite('.section ');
  225. end;
  226. else
  227. AsmWrite('.section ');
  228. end;
  229. s:=sectionname(atype,aname);
  230. AsmWrite(s);
  231. case atype of
  232. sec_fpc :
  233. AsmWrite(', "a", @progbits');
  234. sec_stub :
  235. begin
  236. if target_info.system=system_powerpc_darwin then
  237. AsmWrite(',__symbol_stub1,symbol_stubs,pure_instructions,16');
  238. end;
  239. end;
  240. AsmLn;
  241. CurrSecType:=atype;
  242. end;
  243. procedure TGNUAssembler.WriteDecodedUleb128(a: aword);
  244. var
  245. b: byte;
  246. begin
  247. repeat
  248. b := a and $7f;
  249. a := a shr 7;
  250. if (a <> 0) then
  251. b := b or $80;
  252. AsmWrite(tostr(b));
  253. if (a <> 0) then
  254. AsmWrite(',')
  255. else
  256. break;
  257. until false;
  258. end;
  259. procedure TGNUAssembler.WriteDecodedSleb128(a: aint);
  260. var
  261. b, size: byte;
  262. neg, more: boolean;
  263. begin
  264. more := true;
  265. neg := a < 0;
  266. size := sizeof(a)*8;
  267. repeat
  268. b := a and $7f;
  269. a := a shr 7;
  270. if (neg) then
  271. a := a or -(1 shl (size - 7));
  272. if (((a = 0) and
  273. (a and $40 = 0)) or
  274. ((a = -1) and
  275. (a and $40 <> 0))) then
  276. more := false
  277. else
  278. b := b or $80;
  279. AsmWrite(tostr(b));
  280. if (more) then
  281. AsmWrite(',')
  282. else
  283. break;
  284. until false;
  285. end;
  286. procedure TGNUAssembler.WriteTree(p:TAAsmoutput);
  287. function needsObject(hp : tai_symbol) : boolean;
  288. begin
  289. needsObject :=
  290. (
  291. assigned(hp.next) and
  292. (tai_symbol(hp.next).typ in [ait_const_rva_symbol,
  293. ait_const_32bit,ait_const_16bit,ait_const_8bit,ait_datablock,
  294. ait_real_32bit,ait_real_64bit,ait_real_80bit,ait_comp_64bit])
  295. ) or
  296. (hp.sym.typ=AT_DATA);
  297. end;
  298. var
  299. ch : char;
  300. hp : tai;
  301. hp1 : tailineinfo;
  302. consttyp : taitype;
  303. s,t : string;
  304. i,pos,l : longint;
  305. InlineLevel : longint;
  306. last_align : longint;
  307. co : comp;
  308. sin : single;
  309. d : double;
  310. {$ifdef cpuextended}
  311. e : extended;
  312. {$endif cpuextended}
  313. do_line : boolean;
  314. sepChar : char;
  315. begin
  316. if not assigned(p) then
  317. exit;
  318. last_align := 2;
  319. InlineLevel:=0;
  320. { lineinfo is only needed for al_procedures (PFV) }
  321. do_line:=(cs_asm_source in aktglobalswitches) or
  322. ((cs_lineinfo in aktmoduleswitches)
  323. and (p=asmlist[al_procedures]));
  324. hp:=tai(p.first);
  325. while assigned(hp) do
  326. begin
  327. if not(hp.typ in SkipLineInfo) then
  328. begin
  329. hp1 := hp as tailineinfo;
  330. aktfilepos:=hp1.fileinfo;
  331. { no line info for inlined code }
  332. if do_line and (inlinelevel=0) then
  333. begin
  334. { load infile }
  335. if lastfileinfo.fileindex<>hp1.fileinfo.fileindex then
  336. begin
  337. infile:=current_module.sourcefiles.get_file(hp1.fileinfo.fileindex);
  338. if assigned(infile) then
  339. begin
  340. { open only if needed !! }
  341. if (cs_asm_source in aktglobalswitches) then
  342. infile.open;
  343. end;
  344. { avoid unnecessary reopens of the same file !! }
  345. lastfileinfo.fileindex:=hp1.fileinfo.fileindex;
  346. { be sure to change line !! }
  347. lastfileinfo.line:=-1;
  348. end;
  349. { write source }
  350. if (cs_asm_source in aktglobalswitches) and
  351. assigned(infile) then
  352. begin
  353. if (infile<>lastinfile) then
  354. begin
  355. AsmWriteLn(target_asm.comment+'['+infile.name^+']');
  356. if assigned(lastinfile) then
  357. lastinfile.close;
  358. end;
  359. if (hp1.fileinfo.line<>lastfileinfo.line) and
  360. ((hp1.fileinfo.line<infile.maxlinebuf) or (InlineLevel>0)) then
  361. begin
  362. if (hp1.fileinfo.line<>0) and
  363. ((infile.linebuf^[hp1.fileinfo.line]>=0) or (InlineLevel>0)) then
  364. AsmWriteLn(target_asm.comment+'['+tostr(hp1.fileinfo.line)+'] '+
  365. fixline(infile.GetLineStr(hp1.fileinfo.line)));
  366. { set it to a negative value !
  367. to make that is has been read already !! PM }
  368. if (infile.linebuf^[hp1.fileinfo.line]>=0) then
  369. infile.linebuf^[hp1.fileinfo.line]:=-infile.linebuf^[hp1.fileinfo.line]-1;
  370. end;
  371. end;
  372. lastfileinfo:=hp1.fileinfo;
  373. lastinfile:=infile;
  374. end;
  375. end;
  376. case hp.typ of
  377. ait_comment :
  378. Begin
  379. AsmWrite(target_asm.comment);
  380. AsmWritePChar(tai_comment(hp).str);
  381. AsmLn;
  382. End;
  383. ait_regalloc :
  384. begin
  385. if (cs_asm_regalloc in aktglobalswitches) then
  386. begin
  387. AsmWrite(#9+target_asm.comment+'Register ');
  388. repeat
  389. AsmWrite(gas_regname(Tai_regalloc(hp).reg));
  390. if (hp.next=nil) or
  391. (tai(hp.next).typ<>ait_regalloc) or
  392. (tai_regalloc(hp.next).ratype<>tai_regalloc(hp).ratype) then
  393. break;
  394. hp:=tai(hp.next);
  395. AsmWrite(',');
  396. until false;
  397. AsmWrite(' ');
  398. AsmWriteLn(regallocstr[tai_regalloc(hp).ratype]);
  399. end;
  400. end;
  401. ait_tempalloc :
  402. begin
  403. if (cs_asm_tempalloc in aktglobalswitches) then
  404. begin
  405. {$ifdef EXTDEBUG}
  406. if assigned(tai_tempalloc(hp).problem) then
  407. AsmWriteLn(target_asm.comment+'Temp '+tostr(tai_tempalloc(hp).temppos)+','+
  408. tostr(tai_tempalloc(hp).tempsize)+' '+tai_tempalloc(hp).problem^)
  409. else
  410. {$endif EXTDEBUG}
  411. AsmWriteLn(target_asm.comment+'Temp '+tostr(tai_tempalloc(hp).temppos)+','+
  412. tostr(tai_tempalloc(hp).tempsize)+' '+tempallocstr[tai_tempalloc(hp).allocation]);
  413. end;
  414. end;
  415. ait_align :
  416. begin
  417. if tai_align(hp).aligntype>1 then
  418. begin
  419. if target_info.system <> system_powerpc_darwin then
  420. begin
  421. AsmWrite(#9'.balign '+tostr(tai_align(hp).aligntype));
  422. if tai_align(hp).use_op then
  423. AsmWrite(','+tostr(tai_align(hp).fillop))
  424. end
  425. else
  426. begin
  427. { darwin as only supports .align }
  428. if not ispowerof2(tai_align(hp).aligntype,i) then
  429. internalerror(2003010305);
  430. AsmWrite(#9'.align '+tostr(i));
  431. last_align := i;
  432. end;
  433. AsmLn;
  434. end;
  435. end;
  436. ait_section :
  437. begin
  438. if tai_section(hp).sectype<>sec_none then
  439. WriteSection(tai_section(hp).sectype,tai_section(hp).name^)
  440. else
  441. begin
  442. {$ifdef EXTDEBUG}
  443. AsmWrite(target_asm.comment);
  444. AsmWriteln(' sec_none');
  445. {$endif EXTDEBUG}
  446. end;
  447. end;
  448. ait_datablock :
  449. begin
  450. if target_info.system=system_powerpc_darwin then
  451. begin
  452. {On Mac OS X you can't have common symbols in a shared
  453. library, since those are in the TEXT section and the text section is
  454. read-only in shared libraries (so it can be shared among different
  455. processes). The alternate code creates some kind of common symbols in
  456. the data segment. The generic code no longer uses common symbols, but
  457. this doesn't work on Mac OS X as well.}
  458. if tai_datablock(hp).is_global then
  459. begin
  460. asmwrite('.globl ');
  461. asmwriteln(tai_datablock(hp).sym.name);
  462. asmwriteln('.data');
  463. asmwrite('.zerofill __DATA, __common, ');
  464. asmwrite(tai_datablock(hp).sym.name);
  465. asmwriteln(', '+tostr(tai_datablock(hp).size)+','+tostr(last_align));
  466. if not(CurrSecType in [sec_data,sec_none]) then
  467. writesection(CurrSecType,'');
  468. end
  469. else
  470. begin
  471. asmwrite(#9'.lcomm'#9);
  472. asmwrite(tai_datablock(hp).sym.name);
  473. asmwrite(','+tostr(tai_datablock(hp).size));
  474. asmwrite(','+tostr(last_align));
  475. asmwriteln('');
  476. end
  477. end
  478. else
  479. begin
  480. if Tai_datablock(hp).is_global then
  481. begin
  482. asmwrite(#9'.globl ');
  483. asmwriteln(Tai_datablock(hp).sym.name);
  484. end;
  485. if (tf_needs_symbol_type in target_info.flags) then
  486. asmwriteln(#9'.type '+Tai_datablock(hp).sym.name+',@object');
  487. if (tf_needs_symbol_size in target_info.flags) and (tai_datablock(hp).size > 0) then
  488. asmwriteln(#9'.size '+Tai_datablock(hp).sym.name+','+tostr(Tai_datablock(hp).size));
  489. asmwrite(Tai_datablock(hp).sym.name);
  490. asmwriteln(':');
  491. asmwriteln(#9'.zero '+tostr(Tai_datablock(hp).size));
  492. end;
  493. end;
  494. {$ifndef cpu64bit}
  495. ait_const_128bit :
  496. begin
  497. internalerror(200404291);
  498. end;
  499. ait_const_64bit :
  500. begin
  501. if assigned(tai_const(hp).sym) then
  502. internalerror(200404292);
  503. AsmWrite(ait_const2str[ait_const_32bit]);
  504. if target_info.endian = endian_little then
  505. begin
  506. AsmWrite(tostr(longint(lo(tai_const(hp).value))));
  507. AsmWrite(',');
  508. AsmWrite(tostr(longint(hi(tai_const(hp).value))));
  509. end
  510. else
  511. begin
  512. AsmWrite(tostr(longint(hi(tai_const(hp).value))));
  513. AsmWrite(',');
  514. AsmWrite(tostr(longint(lo(tai_const(hp).value))));
  515. end;
  516. AsmLn;
  517. end;
  518. {$endif cpu64bit}
  519. ait_const_uleb128bit,
  520. ait_const_sleb128bit,
  521. {$ifdef cpu64bit}
  522. ait_const_128bit,
  523. ait_const_64bit,
  524. {$endif cpu64bit}
  525. ait_const_32bit,
  526. ait_const_16bit,
  527. ait_const_8bit,
  528. ait_const_rva_symbol,
  529. ait_const_indirect_symbol :
  530. begin
  531. if (target_info.system in [system_powerpc_darwin,system_i386_darwin]) and
  532. (hp.typ in [ait_const_uleb128bit,ait_const_sleb128bit]) then
  533. begin
  534. AsmWrite(ait_const2str[ait_const_8bit]);
  535. case hp.typ of
  536. ait_const_uleb128bit:
  537. WriteDecodedUleb128(aword(tai_const(hp).value));
  538. ait_const_sleb128bit:
  539. WriteDecodedSleb128(aint(tai_const(hp).value));
  540. end
  541. end
  542. else
  543. begin
  544. AsmWrite(ait_const2str[hp.typ]);
  545. consttyp:=hp.typ;
  546. l:=0;
  547. t := '';
  548. repeat
  549. if assigned(tai_const(hp).sym) then
  550. begin
  551. if assigned(tai_const(hp).endsym) then
  552. begin
  553. if (target_info.system in [system_powerpc_darwin,system_i386_darwin]) then
  554. begin
  555. s := NextSetLabel;
  556. t := #9'.set '+s+','+tai_const(hp).endsym.name+'-'+tai_const(hp).sym.name;
  557. end
  558. else
  559. s:=tai_const(hp).endsym.name+'-'+tai_const(hp).sym.name
  560. end
  561. else
  562. s:=tai_const(hp).sym.name;
  563. if tai_const(hp).value<>0 then
  564. s:=s+tostr_with_plus(tai_const(hp).value);
  565. end
  566. else
  567. s:=tostr(tai_const(hp).value);
  568. AsmWrite(s);
  569. inc(l,length(s));
  570. { Values with symbols are written on a single line to improve
  571. reading of the .s file (PFV) }
  572. if assigned(tai_const(hp).sym) or
  573. not(CurrSecType in [sec_data,sec_rodata]) or
  574. (l>line_length) or
  575. (hp.next=nil) or
  576. (tai(hp.next).typ<>consttyp) or
  577. assigned(tai_const(hp.next).sym) then
  578. break;
  579. hp:=tai(hp.next);
  580. AsmWrite(',');
  581. until false;
  582. if (t <> '') then
  583. begin
  584. AsmLn;
  585. AsmWrite(t);
  586. end;
  587. end;
  588. AsmLn;
  589. end;
  590. {$ifdef cpuextended}
  591. ait_real_80bit :
  592. begin
  593. if do_line then
  594. AsmWriteLn(target_asm.comment+'value: '+extended2str(tai_real_80bit(hp).value));
  595. { Make sure e is a extended type, bestreal could be
  596. a different type (bestreal) !! (PFV) }
  597. e:=tai_real_80bit(hp).value;
  598. AsmWrite(#9'.byte'#9);
  599. for i:=0 to 9 do
  600. begin
  601. if i<>0 then
  602. AsmWrite(',');
  603. AsmWrite(tostr(t80bitarray(e)[i]));
  604. end;
  605. AsmLn;
  606. end;
  607. {$endif cpuextended}
  608. ait_real_64bit :
  609. begin
  610. if do_line then
  611. AsmWriteLn(target_asm.comment+'value: '+double2str(tai_real_64bit(hp).value));
  612. d:=tai_real_64bit(hp).value;
  613. { swap the values to correct endian if required }
  614. if source_info.endian <> target_info.endian then
  615. swap64bitarray(t64bitarray(d));
  616. AsmWrite(#9'.byte'#9);
  617. {$ifdef arm}
  618. { on a real arm cpu, it's already hi/lo swapped }
  619. {$ifndef cpuarm}
  620. if tai_real_64bit(hp).formatoptions=fo_hiloswapped then
  621. begin
  622. for i:=4 to 7 do
  623. begin
  624. if i<>4 then
  625. AsmWrite(',');
  626. AsmWrite(tostr(t64bitarray(d)[i]));
  627. end;
  628. for i:=0 to 3 do
  629. begin
  630. AsmWrite(',');
  631. AsmWrite(tostr(t64bitarray(d)[i]));
  632. end;
  633. end
  634. else
  635. {$endif cpuarm}
  636. {$endif arm}
  637. begin
  638. for i:=0 to 7 do
  639. begin
  640. if i<>0 then
  641. AsmWrite(',');
  642. AsmWrite(tostr(t64bitarray(d)[i]));
  643. end;
  644. end;
  645. AsmLn;
  646. end;
  647. ait_real_32bit :
  648. begin
  649. if do_line then
  650. AsmWriteLn(target_asm.comment+'value: '+single2str(tai_real_32bit(hp).value));
  651. sin:=tai_real_32bit(hp).value;
  652. { swap the values to correct endian if required }
  653. if source_info.endian <> target_info.endian then
  654. swap32bitarray(t32bitarray(sin));
  655. AsmWrite(#9'.byte'#9);
  656. for i:=0 to 3 do
  657. begin
  658. if i<>0 then
  659. AsmWrite(',');
  660. AsmWrite(tostr(t32bitarray(sin)[i]));
  661. end;
  662. AsmLn;
  663. end;
  664. ait_comp_64bit :
  665. begin
  666. if do_line then
  667. AsmWriteLn(target_asm.comment+'value: '+extended2str(tai_comp_64bit(hp).value));
  668. AsmWrite(#9'.byte'#9);
  669. {$ifdef FPC}
  670. co:=comp(tai_comp_64bit(hp).value);
  671. {$else}
  672. co:=tai_comp_64bit(hp).value;
  673. {$endif}
  674. { swap the values to correct endian if required }
  675. if source_info.endian <> target_info.endian then
  676. swap64bitarray(t64bitarray(co));
  677. for i:=0 to 7 do
  678. begin
  679. if i<>0 then
  680. AsmWrite(',');
  681. AsmWrite(tostr(t64bitarray(co)[i]));
  682. end;
  683. AsmLn;
  684. end;
  685. ait_string :
  686. begin
  687. pos:=0;
  688. for i:=1 to tai_string(hp).len do
  689. begin
  690. if pos=0 then
  691. begin
  692. AsmWrite(#9'.ascii'#9'"');
  693. pos:=20;
  694. end;
  695. ch:=tai_string(hp).str[i-1];
  696. case ch of
  697. #0, {This can't be done by range, because a bug in FPC}
  698. #1..#31,
  699. #128..#255 : s:='\'+tostr(ord(ch) shr 6)+tostr((ord(ch) and 63) shr 3)+tostr(ord(ch) and 7);
  700. '"' : s:='\"';
  701. '\' : s:='\\';
  702. else
  703. s:=ch;
  704. end;
  705. AsmWrite(s);
  706. inc(pos,length(s));
  707. if (pos>line_length) or (i=tai_string(hp).len) then
  708. begin
  709. AsmWriteLn('"');
  710. pos:=0;
  711. end;
  712. end;
  713. end;
  714. ait_label :
  715. begin
  716. if (tai_label(hp).l.is_used) then
  717. begin
  718. if tai_label(hp).l.defbind=AB_GLOBAL then
  719. begin
  720. AsmWrite('.globl'#9);
  721. AsmWriteLn(tai_label(hp).l.name);
  722. end;
  723. AsmWrite(tai_label(hp).l.name);
  724. AsmWriteLn(':');
  725. end;
  726. end;
  727. ait_symbol :
  728. begin
  729. if tai_symbol(hp).is_global then
  730. begin
  731. AsmWrite('.globl'#9);
  732. AsmWriteLn(tai_symbol(hp).sym.name);
  733. end;
  734. if (target_info.system = system_powerpc64_linux) and
  735. (tai_symbol(hp).sym.typ = AT_FUNCTION) then
  736. begin
  737. AsmWriteLn('.section "opd", "aw"');
  738. AsmWriteLn('.align 3');
  739. AsmWriteLn(tai_symbol(hp).sym.name + ':');
  740. AsmWriteLn('.quad .' + tai_symbol(hp).sym.name + ', .TOC.@tocbase, 0');
  741. AsmWriteLn('.previous');
  742. AsmWriteLn('.size ' + tai_symbol(hp).sym.name + ', 24');
  743. AsmWriteLn('.globl .' + tai_symbol(hp).sym.name);
  744. AsmWriteLn('.type .' + tai_symbol(hp).sym.name + ', @function');
  745. { the dotted name is the name of the actual function entry }
  746. AsmWrite('.');
  747. end
  748. else
  749. begin
  750. if (target_info.system <> system_arm_linux) then
  751. begin
  752. sepChar := '@';
  753. end
  754. else
  755. begin
  756. sepChar := '#';
  757. end;
  758. if (tf_needs_symbol_type in target_info.flags) then
  759. begin
  760. AsmWrite(#9'.type'#9 + tai_symbol(hp).sym.name);
  761. if (needsObject(tai_symbol(hp))) then
  762. begin
  763. AsmWriteLn(',' + sepChar + 'object');
  764. end
  765. else
  766. begin
  767. AsmWriteLn(',' + sepChar + 'function');
  768. end;
  769. end;
  770. if (tf_needs_symbol_size in target_info.flags) and (tai_symbol(hp).sym.size > 0) then begin
  771. AsmWriteLn(#9'.size'#9 + tai_symbol(hp).sym.name + ', ' + tostr(tai_symbol(hp).sym.size));
  772. end;
  773. end;
  774. AsmWriteLn(tai_symbol(hp).sym.name + ':');
  775. end;
  776. ait_symbol_end :
  777. begin
  778. if tf_needs_symbol_size in target_info.flags then
  779. begin
  780. s:=target_asm.labelprefix+'e'+tostr(symendcount);
  781. inc(symendcount);
  782. AsmWriteLn(s+':');
  783. AsmWrite(#9'.size'#9);
  784. if (target_info.system = system_powerpc64_linux) and (tai_symbol_end(hp).sym.typ = AT_FUNCTION) then
  785. AsmWrite('.');
  786. AsmWrite(tai_symbol_end(hp).sym.name);
  787. AsmWrite(', '+s+' - ');
  788. if (target_info.system = system_powerpc64_linux) and (tai_symbol_end(hp).sym.typ = AT_FUNCTION) then
  789. AsmWrite('.');
  790. AsmWriteLn(tai_symbol_end(hp).sym.name);
  791. end;
  792. end;
  793. ait_instruction :
  794. begin
  795. WriteInstruction(hp);
  796. end;
  797. ait_stab :
  798. begin
  799. if assigned(tai_stab(hp).str) then
  800. begin
  801. AsmWrite(#9'.'+stabtypestr[tai_stab(hp).stabtype]+' ');
  802. AsmWritePChar(tai_stab(hp).str);
  803. AsmLn;
  804. end;
  805. end;
  806. ait_force_line,
  807. ait_function_name : ;
  808. ait_cutobject :
  809. begin
  810. if SmartAsm then
  811. begin
  812. { only reset buffer if nothing has changed }
  813. if AsmSize=AsmStartSize then
  814. AsmClear
  815. else
  816. begin
  817. AsmClose;
  818. DoAssemble;
  819. AsmCreate(tai_cutobject(hp).place);
  820. end;
  821. { avoid empty files }
  822. while assigned(hp.next) and (tai(hp.next).typ in [ait_cutobject,ait_section,ait_comment]) do
  823. begin
  824. if tai(hp.next).typ=ait_section then
  825. CurrSecType:=tai_section(hp.next).sectype;
  826. hp:=tai(hp.next);
  827. end;
  828. if CurrSecType<>sec_none then
  829. WriteSection(CurrSecType,'');
  830. AsmStartSize:=AsmSize;
  831. end;
  832. end;
  833. ait_marker :
  834. if tai_marker(hp).kind=InlineStart then
  835. inc(InlineLevel)
  836. else if tai_marker(hp).kind=InlineEnd then
  837. dec(InlineLevel);
  838. ait_directive :
  839. begin
  840. AsmWrite('.'+directivestr[tai_directive(hp).directive]+' ');
  841. if assigned(tai_directive(hp).name) then
  842. AsmWrite(tai_directive(hp).name^);
  843. AsmLn;
  844. end;
  845. else
  846. internalerror(10000);
  847. end;
  848. hp:=tai(hp.next);
  849. end;
  850. end;
  851. procedure TGNUAssembler.WriteExtraHeader;
  852. begin
  853. end;
  854. procedure TGNUAssembler.WriteAsmList;
  855. var
  856. p:dirstr;
  857. n:namestr;
  858. e:extstr;
  859. hal : tasmlist;
  860. begin
  861. {$ifdef EXTDEBUG}
  862. if assigned(current_module.mainsource) then
  863. Comment(V_Debug,'Start writing gas-styled assembler output for '+current_module.mainsource^);
  864. {$endif}
  865. CurrSecType:=sec_none;
  866. FillChar(lastfileinfo,sizeof(lastfileinfo),0);
  867. LastInfile:=nil;
  868. if assigned(current_module.mainsource) then
  869. {$IFDEF USE_SYSUTILS}
  870. begin
  871. p := SplitPath(current_module.mainsource^);
  872. n := SplitName(current_module.mainsource^);
  873. e := SplitExtension(current_module.mainsource^);
  874. end
  875. {$ELSE USE_SYSUTILS}
  876. fsplit(current_module.mainsource^,p,n,e)
  877. {$ENDIF USE_SYSUTILS}
  878. else
  879. begin
  880. p:=inputdir;
  881. n:=inputfile;
  882. e:=inputextension;
  883. end;
  884. { to get symify to work }
  885. AsmWriteLn(#9'.file "'+FixFileName(n+e)+'"');
  886. WriteExtraHeader;
  887. AsmStartSize:=AsmSize;
  888. symendcount:=0;
  889. for hal:=low(Tasmlist) to high(Tasmlist) do
  890. begin
  891. AsmWriteLn(target_asm.comment+'Begin asmlist '+TasmlistStr[hal]);
  892. writetree(asmlist[hal]);
  893. AsmWriteLn(target_asm.comment+'End asmlist '+TasmlistStr[hal]);
  894. end;
  895. AsmLn;
  896. {$ifdef EXTDEBUG}
  897. if assigned(current_module.mainsource) then
  898. Comment(V_Debug,'Done writing gas-styled assembler output for '+current_module.mainsource^);
  899. {$endif EXTDEBUG}
  900. end;
  901. end.