aggas.pas 41 KB

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