aggas.pas 32 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983
  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. );
  183. secnames_pic : array[tasmsectiontype] of string[12] = ('',
  184. '.text','.data.rel','.data.rel','.bss','.threadvar',
  185. 'common',
  186. '.note',
  187. '__TEXT', { stubs }
  188. '.stab','.stabstr',
  189. '.idata$2','.idata$4','.idata$5','.idata$6','.idata$7','.edata',
  190. '.eh_frame',
  191. '.debug_frame',
  192. 'fpc.resptrs'
  193. );
  194. var
  195. secname : string;
  196. begin
  197. if (cs_create_pic in aktmoduleswitches) and
  198. not(target_info.system in [system_powerpc_darwin,system_i386_darwin]) then
  199. secname:=secnames_pic[atype]
  200. else
  201. secname:=secnames[atype];
  202. if use_smartlink_section and
  203. (aname<>'') then
  204. result:=secname+'.'+aname
  205. else
  206. result:=secname;
  207. end;
  208. procedure TGNUAssembler.WriteSection(atype:tasmsectiontype;const aname:string);
  209. var
  210. s : string;
  211. begin
  212. AsmLn;
  213. case target_info.system of
  214. system_i386_OS2,
  215. system_i386_EMX : ;
  216. system_powerpc_darwin :
  217. begin
  218. if atype=sec_stub then
  219. AsmWrite('.section ');
  220. end;
  221. else
  222. AsmWrite('.section ');
  223. end;
  224. s:=sectionname(atype,aname);
  225. AsmWrite(s);
  226. case atype of
  227. sec_fpc :
  228. AsmWrite(', "a", @progbits');
  229. sec_stub :
  230. begin
  231. if target_info.system=system_powerpc_darwin then
  232. AsmWrite(',__symbol_stub1,symbol_stubs,pure_instructions,16');
  233. end;
  234. end;
  235. AsmLn;
  236. CurrSecType:=atype;
  237. end;
  238. procedure TGNUAssembler.WriteDecodedUleb128(a: aword);
  239. var
  240. b: byte;
  241. begin
  242. repeat
  243. b := a and $7f;
  244. a := a shr 7;
  245. if (a <> 0) then
  246. b := b or $80;
  247. AsmWrite(tostr(b));
  248. if (a <> 0) then
  249. AsmWrite(',')
  250. else
  251. break;
  252. until false;
  253. end;
  254. procedure TGNUAssembler.WriteDecodedSleb128(a: aint);
  255. var
  256. b, size: byte;
  257. neg, more: boolean;
  258. begin
  259. more := true;
  260. neg := a < 0;
  261. size := sizeof(a)*8;
  262. repeat
  263. b := a and $7f;
  264. a := a shr 7;
  265. if (neg) then
  266. a := a or -(1 shl (size - 7));
  267. if (((a = 0) and
  268. (a and $40 = 0)) or
  269. ((a = -1) and
  270. (a and $40 <> 0))) then
  271. more := false
  272. else
  273. b := b or $80;
  274. AsmWrite(tostr(b));
  275. if (more) then
  276. AsmWrite(',')
  277. else
  278. break;
  279. until false;
  280. end;
  281. procedure TGNUAssembler.WriteTree(p:TAAsmoutput);
  282. function needsObject(hp : tai_symbol) : boolean;
  283. begin
  284. needsObject :=
  285. (
  286. assigned(hp.next) and
  287. (tai_symbol(hp.next).typ in [ait_const_rva_symbol,
  288. ait_const_32bit,ait_const_16bit,ait_const_8bit,ait_datablock,
  289. ait_real_32bit,ait_real_64bit,ait_real_80bit,ait_comp_64bit])
  290. ) or
  291. (hp.sym.typ=AT_DATA);
  292. end;
  293. var
  294. ch : char;
  295. hp : tai;
  296. hp1 : tailineinfo;
  297. consttyp : taitype;
  298. s,t : string;
  299. i,pos,l : longint;
  300. InlineLevel : longint;
  301. last_align : longint;
  302. co : comp;
  303. sin : single;
  304. d : double;
  305. {$ifdef cpuextended}
  306. e : extended;
  307. {$endif cpuextended}
  308. do_line : boolean;
  309. sepChar : char;
  310. begin
  311. if not assigned(p) then
  312. exit;
  313. last_align := 2;
  314. InlineLevel:=0;
  315. { lineinfo is only needed for al_procedures (PFV) }
  316. do_line:=(cs_asm_source in aktglobalswitches) or
  317. ((cs_lineinfo in aktmoduleswitches)
  318. and (p=asmlist[al_procedures]));
  319. hp:=tai(p.first);
  320. while assigned(hp) do
  321. begin
  322. if not(hp.typ in SkipLineInfo) then
  323. begin
  324. hp1 := hp as tailineinfo;
  325. aktfilepos:=hp1.fileinfo;
  326. { no line info for inlined code }
  327. if do_line and (inlinelevel=0) then
  328. begin
  329. { load infile }
  330. if lastfileinfo.fileindex<>hp1.fileinfo.fileindex then
  331. begin
  332. infile:=current_module.sourcefiles.get_file(hp1.fileinfo.fileindex);
  333. if assigned(infile) then
  334. begin
  335. { open only if needed !! }
  336. if (cs_asm_source in aktglobalswitches) then
  337. infile.open;
  338. end;
  339. { avoid unnecessary reopens of the same file !! }
  340. lastfileinfo.fileindex:=hp1.fileinfo.fileindex;
  341. { be sure to change line !! }
  342. lastfileinfo.line:=-1;
  343. end;
  344. { write source }
  345. if (cs_asm_source in aktglobalswitches) and
  346. assigned(infile) then
  347. begin
  348. if (infile<>lastinfile) then
  349. begin
  350. AsmWriteLn(target_asm.comment+'['+infile.name^+']');
  351. if assigned(lastinfile) then
  352. lastinfile.close;
  353. end;
  354. if (hp1.fileinfo.line<>lastfileinfo.line) and
  355. ((hp1.fileinfo.line<infile.maxlinebuf) or (InlineLevel>0)) then
  356. begin
  357. if (hp1.fileinfo.line<>0) and
  358. ((infile.linebuf^[hp1.fileinfo.line]>=0) or (InlineLevel>0)) then
  359. AsmWriteLn(target_asm.comment+'['+tostr(hp1.fileinfo.line)+'] '+
  360. fixline(infile.GetLineStr(hp1.fileinfo.line)));
  361. { set it to a negative value !
  362. to make that is has been read already !! PM }
  363. if (infile.linebuf^[hp1.fileinfo.line]>=0) then
  364. infile.linebuf^[hp1.fileinfo.line]:=-infile.linebuf^[hp1.fileinfo.line]-1;
  365. end;
  366. end;
  367. lastfileinfo:=hp1.fileinfo;
  368. lastinfile:=infile;
  369. end;
  370. end;
  371. case hp.typ of
  372. ait_comment :
  373. Begin
  374. AsmWrite(target_asm.comment);
  375. AsmWritePChar(tai_comment(hp).str);
  376. AsmLn;
  377. End;
  378. ait_regalloc :
  379. begin
  380. if (cs_asm_regalloc in aktglobalswitches) then
  381. begin
  382. AsmWrite(#9+target_asm.comment+'Register ');
  383. repeat
  384. AsmWrite(gas_regname(Tai_regalloc(hp).reg));
  385. if (hp.next=nil) or
  386. (tai(hp.next).typ<>ait_regalloc) or
  387. (tai_regalloc(hp.next).ratype<>tai_regalloc(hp).ratype) then
  388. break;
  389. hp:=tai(hp.next);
  390. AsmWrite(',');
  391. until false;
  392. AsmWrite(' ');
  393. AsmWriteLn(regallocstr[tai_regalloc(hp).ratype]);
  394. end;
  395. end;
  396. ait_tempalloc :
  397. begin
  398. if (cs_asm_tempalloc in aktglobalswitches) then
  399. begin
  400. {$ifdef EXTDEBUG}
  401. if assigned(tai_tempalloc(hp).problem) then
  402. AsmWriteLn(target_asm.comment+'Temp '+tostr(tai_tempalloc(hp).temppos)+','+
  403. tostr(tai_tempalloc(hp).tempsize)+' '+tai_tempalloc(hp).problem^)
  404. else
  405. {$endif EXTDEBUG}
  406. AsmWriteLn(target_asm.comment+'Temp '+tostr(tai_tempalloc(hp).temppos)+','+
  407. tostr(tai_tempalloc(hp).tempsize)+' '+tempallocstr[tai_tempalloc(hp).allocation]);
  408. end;
  409. end;
  410. ait_align :
  411. begin
  412. if tai_align(hp).aligntype>1 then
  413. begin
  414. if target_info.system <> system_powerpc_darwin then
  415. begin
  416. AsmWrite(#9'.balign '+tostr(tai_align(hp).aligntype));
  417. if tai_align(hp).use_op then
  418. AsmWrite(','+tostr(tai_align(hp).fillop))
  419. end
  420. else
  421. begin
  422. { darwin as only supports .align }
  423. if not ispowerof2(tai_align(hp).aligntype,i) then
  424. internalerror(2003010305);
  425. AsmWrite(#9'.align '+tostr(i));
  426. last_align := i;
  427. end;
  428. AsmLn;
  429. end;
  430. end;
  431. ait_section :
  432. begin
  433. if tai_section(hp).sectype<>sec_none then
  434. WriteSection(tai_section(hp).sectype,tai_section(hp).name^)
  435. else
  436. begin
  437. {$ifdef EXTDEBUG}
  438. AsmWrite(target_asm.comment);
  439. AsmWriteln(' sec_none');
  440. {$endif EXTDEBUG}
  441. end;
  442. end;
  443. ait_datablock :
  444. begin
  445. if target_info.system=system_powerpc_darwin then
  446. begin
  447. {On Mac OS X you can't have common symbols in a shared
  448. library, since those are in the TEXT section and the text section is
  449. read-only in shared libraries (so it can be shared among different
  450. processes). The alternate code creates some kind of common symbols in
  451. the data segment. The generic code no longer uses common symbols, but
  452. this doesn't work on Mac OS X as well.}
  453. if tai_datablock(hp).is_global then
  454. begin
  455. asmwrite('.globl ');
  456. asmwriteln(tai_datablock(hp).sym.name);
  457. asmwriteln('.data');
  458. asmwrite('.zerofill __DATA, __common, ');
  459. asmwrite(tai_datablock(hp).sym.name);
  460. asmwriteln(', '+tostr(tai_datablock(hp).size)+','+tostr(last_align));
  461. if not(CurrSecType in [sec_data,sec_none]) then
  462. writesection(CurrSecType,'');
  463. end
  464. else
  465. begin
  466. asmwrite(#9'.lcomm'#9);
  467. asmwrite(tai_datablock(hp).sym.name);
  468. asmwrite(','+tostr(tai_datablock(hp).size));
  469. asmwrite(','+tostr(last_align));
  470. asmwriteln('');
  471. end
  472. end
  473. else
  474. begin
  475. if Tai_datablock(hp).is_global then
  476. begin
  477. asmwrite(#9'.globl ');
  478. asmwriteln(Tai_datablock(hp).sym.name);
  479. end;
  480. if (tf_needs_symbol_type in target_info.flags) then
  481. asmwriteln(#9'.type '+Tai_datablock(hp).sym.name+',@object');
  482. if (tf_needs_symbol_size in target_info.flags) and (Tai_datablock(hp).sym.size > 0) then
  483. asmwriteln(#9'.size '+Tai_datablock(hp).sym.name+','+tostr(Tai_datablock(hp).size));
  484. asmwrite(Tai_datablock(hp).sym.name);
  485. asmwriteln(':');
  486. asmwriteln(#9'.zero '+tostr(Tai_datablock(hp).size));
  487. end;
  488. end;
  489. {$ifndef cpu64bit}
  490. ait_const_128bit :
  491. begin
  492. internalerror(200404291);
  493. end;
  494. ait_const_64bit :
  495. begin
  496. if assigned(tai_const(hp).sym) then
  497. internalerror(200404292);
  498. AsmWrite(ait_const2str[ait_const_32bit]);
  499. if target_info.endian = endian_little then
  500. begin
  501. AsmWrite(tostr(longint(lo(tai_const(hp).value))));
  502. AsmWrite(',');
  503. AsmWrite(tostr(longint(hi(tai_const(hp).value))));
  504. end
  505. else
  506. begin
  507. AsmWrite(tostr(longint(hi(tai_const(hp).value))));
  508. AsmWrite(',');
  509. AsmWrite(tostr(longint(lo(tai_const(hp).value))));
  510. end;
  511. AsmLn;
  512. end;
  513. {$endif cpu64bit}
  514. ait_const_uleb128bit,
  515. ait_const_sleb128bit,
  516. {$ifdef cpu64bit}
  517. ait_const_128bit,
  518. ait_const_64bit,
  519. {$endif cpu64bit}
  520. ait_const_32bit,
  521. ait_const_16bit,
  522. ait_const_8bit,
  523. ait_const_rva_symbol,
  524. ait_const_indirect_symbol :
  525. begin
  526. if (target_info.system in [system_powerpc_darwin,system_i386_darwin]) and
  527. (hp.typ in [ait_const_uleb128bit,ait_const_sleb128bit]) then
  528. begin
  529. AsmWrite(ait_const2str[ait_const_8bit]);
  530. case hp.typ of
  531. ait_const_uleb128bit:
  532. WriteDecodedUleb128(aword(tai_const(hp).value));
  533. ait_const_sleb128bit:
  534. WriteDecodedSleb128(aint(tai_const(hp).value));
  535. end
  536. end
  537. else
  538. begin
  539. AsmWrite(ait_const2str[hp.typ]);
  540. consttyp:=hp.typ;
  541. l:=0;
  542. t := '';
  543. repeat
  544. if assigned(tai_const(hp).sym) then
  545. begin
  546. if assigned(tai_const(hp).endsym) then
  547. begin
  548. if (target_info.system in [system_powerpc_darwin,system_i386_darwin]) then
  549. begin
  550. s := NextSetLabel;
  551. t := #9'.set '+s+','+tai_const(hp).endsym.name+'-'+tai_const(hp).sym.name;
  552. end
  553. else
  554. s:=tai_const(hp).endsym.name+'-'+tai_const(hp).sym.name
  555. end
  556. else
  557. s:=tai_const(hp).sym.name;
  558. if tai_const(hp).value<>0 then
  559. s:=s+tostr_with_plus(tai_const(hp).value);
  560. end
  561. else
  562. s:=tostr(tai_const(hp).value);
  563. AsmWrite(s);
  564. inc(l,length(s));
  565. { Values with symbols are written on a single line to improve
  566. reading of the .s file (PFV) }
  567. if assigned(tai_const(hp).sym) or
  568. not(CurrSecType in [sec_data,sec_rodata]) or
  569. (l>line_length) or
  570. (hp.next=nil) or
  571. (tai(hp.next).typ<>consttyp) or
  572. assigned(tai_const(hp.next).sym) then
  573. break;
  574. hp:=tai(hp.next);
  575. AsmWrite(',');
  576. until false;
  577. if (t <> '') then
  578. begin
  579. AsmLn;
  580. AsmWrite(t);
  581. end;
  582. end;
  583. AsmLn;
  584. end;
  585. {$ifdef cpuextended}
  586. ait_real_80bit :
  587. begin
  588. if do_line then
  589. AsmWriteLn(target_asm.comment+'value: '+extended2str(tai_real_80bit(hp).value));
  590. { Make sure e is a extended type, bestreal could be
  591. a different type (bestreal) !! (PFV) }
  592. e:=tai_real_80bit(hp).value;
  593. AsmWrite(#9'.byte'#9);
  594. for i:=0 to 9 do
  595. begin
  596. if i<>0 then
  597. AsmWrite(',');
  598. AsmWrite(tostr(t80bitarray(e)[i]));
  599. end;
  600. AsmLn;
  601. end;
  602. {$endif cpuextended}
  603. ait_real_64bit :
  604. begin
  605. if do_line then
  606. AsmWriteLn(target_asm.comment+'value: '+double2str(tai_real_64bit(hp).value));
  607. d:=tai_real_64bit(hp).value;
  608. { swap the values to correct endian if required }
  609. if source_info.endian <> target_info.endian then
  610. swap64bitarray(t64bitarray(d));
  611. AsmWrite(#9'.byte'#9);
  612. {$ifdef arm}
  613. { on a real arm cpu, it's already hi/lo swapped }
  614. {$ifndef cpuarm}
  615. if tai_real_64bit(hp).formatoptions=fo_hiloswapped then
  616. begin
  617. for i:=4 to 7 do
  618. begin
  619. if i<>4 then
  620. AsmWrite(',');
  621. AsmWrite(tostr(t64bitarray(d)[i]));
  622. end;
  623. for i:=0 to 3 do
  624. begin
  625. AsmWrite(',');
  626. AsmWrite(tostr(t64bitarray(d)[i]));
  627. end;
  628. end
  629. else
  630. {$endif cpuarm}
  631. {$endif arm}
  632. begin
  633. for i:=0 to 7 do
  634. begin
  635. if i<>0 then
  636. AsmWrite(',');
  637. AsmWrite(tostr(t64bitarray(d)[i]));
  638. end;
  639. end;
  640. AsmLn;
  641. end;
  642. ait_real_32bit :
  643. begin
  644. if do_line then
  645. AsmWriteLn(target_asm.comment+'value: '+single2str(tai_real_32bit(hp).value));
  646. sin:=tai_real_32bit(hp).value;
  647. { swap the values to correct endian if required }
  648. if source_info.endian <> target_info.endian then
  649. swap32bitarray(t32bitarray(sin));
  650. AsmWrite(#9'.byte'#9);
  651. for i:=0 to 3 do
  652. begin
  653. if i<>0 then
  654. AsmWrite(',');
  655. AsmWrite(tostr(t32bitarray(sin)[i]));
  656. end;
  657. AsmLn;
  658. end;
  659. ait_comp_64bit :
  660. begin
  661. if do_line then
  662. AsmWriteLn(target_asm.comment+'value: '+extended2str(tai_comp_64bit(hp).value));
  663. AsmWrite(#9'.byte'#9);
  664. {$ifdef FPC}
  665. co:=comp(tai_comp_64bit(hp).value);
  666. {$else}
  667. co:=tai_comp_64bit(hp).value;
  668. {$endif}
  669. { swap the values to correct endian if required }
  670. if source_info.endian <> target_info.endian then
  671. swap64bitarray(t64bitarray(co));
  672. for i:=0 to 7 do
  673. begin
  674. if i<>0 then
  675. AsmWrite(',');
  676. AsmWrite(tostr(t64bitarray(co)[i]));
  677. end;
  678. AsmLn;
  679. end;
  680. ait_string :
  681. begin
  682. pos:=0;
  683. for i:=1 to tai_string(hp).len do
  684. begin
  685. if pos=0 then
  686. begin
  687. AsmWrite(#9'.ascii'#9'"');
  688. pos:=20;
  689. end;
  690. ch:=tai_string(hp).str[i-1];
  691. case ch of
  692. #0, {This can't be done by range, because a bug in FPC}
  693. #1..#31,
  694. #128..#255 : s:='\'+tostr(ord(ch) shr 6)+tostr((ord(ch) and 63) shr 3)+tostr(ord(ch) and 7);
  695. '"' : s:='\"';
  696. '\' : s:='\\';
  697. else
  698. s:=ch;
  699. end;
  700. AsmWrite(s);
  701. inc(pos,length(s));
  702. if (pos>line_length) or (i=tai_string(hp).len) then
  703. begin
  704. AsmWriteLn('"');
  705. pos:=0;
  706. end;
  707. end;
  708. end;
  709. ait_label :
  710. begin
  711. if (tai_label(hp).l.is_used) then
  712. begin
  713. if tai_label(hp).l.defbind=AB_GLOBAL then
  714. begin
  715. AsmWrite('.globl'#9);
  716. AsmWriteLn(tai_label(hp).l.name);
  717. end;
  718. AsmWrite(tai_label(hp).l.name);
  719. AsmWriteLn(':');
  720. end;
  721. end;
  722. ait_symbol :
  723. begin
  724. if tai_symbol(hp).is_global then
  725. begin
  726. AsmWrite('.globl'#9);
  727. AsmWriteLn(tai_symbol(hp).sym.name);
  728. end;
  729. if (target_info.system = system_powerpc64_linux) and
  730. (tai_symbol(hp).sym.typ = AT_FUNCTION) then
  731. begin
  732. AsmWriteLn('.section "opd", "aw"');
  733. AsmWriteLn('.align 3');
  734. AsmWriteLn(tai_symbol(hp).sym.name + ':');
  735. AsmWriteLn('.quad .' + tai_symbol(hp).sym.name + ', .TOC.@tocbase, 0');
  736. AsmWriteLn('.previous');
  737. AsmWriteLn('.size ' + tai_symbol(hp).sym.name + ', 24');
  738. AsmWriteLn('.globl .' + tai_symbol(hp).sym.name);
  739. AsmWriteLn('.type .' + tai_symbol(hp).sym.name + ', @function');
  740. { the dotted name is the name of the actual function }
  741. AsmWrite('.');
  742. end
  743. else
  744. begin
  745. if (target_info.system <> system_arm_linux) then
  746. begin
  747. sepChar := '@';
  748. end
  749. else
  750. begin
  751. sepChar := '#';
  752. end;
  753. if (tf_needs_symbol_type in target_info.flags) then
  754. begin
  755. AsmWrite(#9'.type'#9 + tai_symbol(hp).sym.name);
  756. if (needsObject(tai_symbol(hp))) then
  757. begin
  758. AsmWriteLn(',' + sepChar + 'object');
  759. end
  760. else
  761. begin
  762. AsmWriteLn(',' + sepChar + 'function');
  763. end;
  764. end;
  765. if (tf_needs_symbol_size in target_info.flags) and (tai_symbol(hp).sym.size > 0) then begin
  766. AsmWriteLn(#9'.size'#9 + tai_symbol(hp).sym.name + ', ' + tostr(tai_symbol(hp).sym.size));
  767. end;
  768. end;
  769. AsmWriteLn(tai_symbol(hp).sym.name + ':');
  770. end;
  771. ait_symbol_end :
  772. begin
  773. if tf_needs_symbol_size in target_info.flags then
  774. begin
  775. s:=target_asm.labelprefix+'e'+tostr(symendcount);
  776. inc(symendcount);
  777. AsmWriteLn(s+':');
  778. AsmWrite(#9'.size'#9);
  779. if (target_info.system = system_powerpc64_linux) and (tai_symbol_end(hp).sym.typ = AT_FUNCTION) then
  780. begin
  781. AsmWrite('.');
  782. end;
  783. AsmWrite(tai_symbol_end(hp).sym.name);
  784. AsmWrite(', '+s+' - ');
  785. if (target_info.system = system_powerpc64_linux) and (tai_symbol_end(hp).sym.typ = AT_FUNCTION) then
  786. begin
  787. AsmWrite('.');
  788. end;
  789. AsmWriteLn(tai_symbol_end(hp).sym.name);
  790. end;
  791. end;
  792. ait_instruction :
  793. begin
  794. WriteInstruction(hp);
  795. end;
  796. ait_stab :
  797. begin
  798. if assigned(tai_stab(hp).str) then
  799. begin
  800. AsmWrite(#9'.'+stabtypestr[tai_stab(hp).stabtype]+' ');
  801. AsmWritePChar(tai_stab(hp).str);
  802. AsmLn;
  803. end;
  804. end;
  805. ait_force_line,
  806. ait_function_name : ;
  807. ait_cutobject :
  808. begin
  809. if SmartAsm then
  810. begin
  811. { only reset buffer if nothing has changed }
  812. if AsmSize=AsmStartSize then
  813. AsmClear
  814. else
  815. begin
  816. AsmClose;
  817. DoAssemble;
  818. AsmCreate(tai_cutobject(hp).place);
  819. end;
  820. { avoid empty files }
  821. while assigned(hp.next) and (tai(hp.next).typ in [ait_cutobject,ait_section,ait_comment]) do
  822. begin
  823. if tai(hp.next).typ=ait_section then
  824. CurrSecType:=tai_section(hp.next).sectype;
  825. hp:=tai(hp.next);
  826. end;
  827. if CurrSecType<>sec_none then
  828. WriteSection(CurrSecType,'');
  829. AsmStartSize:=AsmSize;
  830. end;
  831. end;
  832. ait_marker :
  833. if tai_marker(hp).kind=InlineStart then
  834. inc(InlineLevel)
  835. else if tai_marker(hp).kind=InlineEnd then
  836. dec(InlineLevel);
  837. ait_directive :
  838. begin
  839. AsmWrite('.'+directivestr[tai_directive(hp).directive]+' ');
  840. if assigned(tai_directive(hp).name) then
  841. AsmWrite(tai_directive(hp).name^);
  842. AsmLn;
  843. end;
  844. else
  845. internalerror(10000);
  846. end;
  847. hp:=tai(hp.next);
  848. end;
  849. end;
  850. procedure TGNUAssembler.WriteExtraHeader;
  851. begin
  852. end;
  853. procedure TGNUAssembler.WriteAsmList;
  854. var
  855. p:dirstr;
  856. n:namestr;
  857. e:extstr;
  858. hal : tasmlist;
  859. begin
  860. {$ifdef EXTDEBUG}
  861. if assigned(current_module.mainsource) then
  862. Comment(V_Debug,'Start writing gas-styled assembler output for '+current_module.mainsource^);
  863. {$endif}
  864. CurrSecType:=sec_none;
  865. FillChar(lastfileinfo,sizeof(lastfileinfo),0);
  866. LastInfile:=nil;
  867. if assigned(current_module.mainsource) then
  868. {$IFDEF USE_SYSUTILS}
  869. begin
  870. p := SplitPath(current_module.mainsource^);
  871. n := SplitName(current_module.mainsource^);
  872. e := SplitExtension(current_module.mainsource^);
  873. end
  874. {$ELSE USE_SYSUTILS}
  875. fsplit(current_module.mainsource^,p,n,e)
  876. {$ENDIF USE_SYSUTILS}
  877. else
  878. begin
  879. p:=inputdir;
  880. n:=inputfile;
  881. e:=inputextension;
  882. end;
  883. { to get symify to work }
  884. AsmWriteLn(#9'.file "'+FixFileName(n+e)+'"');
  885. WriteExtraHeader;
  886. AsmStartSize:=AsmSize;
  887. symendcount:=0;
  888. for hal:=low(Tasmlist) to high(Tasmlist) do
  889. begin
  890. AsmWriteLn(target_asm.comment+'Begin asmlist '+TasmlistStr[hal]);
  891. writetree(asmlist[hal]);
  892. AsmWriteLn(target_asm.comment+'End asmlist '+TasmlistStr[hal]);
  893. end;
  894. AsmLn;
  895. {$ifdef EXTDEBUG}
  896. if assigned(current_module.mainsource) then
  897. Comment(V_Debug,'Done writing gas-styled assembler output for '+current_module.mainsource^);
  898. {$endif EXTDEBUG}
  899. end;
  900. end.