ag386nsm.pas 35 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056
  1. {
  2. $Id$
  3. Copyright (c) 1998-2002 by Florian Klaempfl
  4. This unit implements an asmoutput class for the Nasm assembler with
  5. Intel syntax for the i386+
  6. This program is free software; you can redistribute it and/or modify
  7. it under the terms of the GNU General Public License as published by
  8. the Free Software Foundation; either version 2 of the License, or
  9. (at your option) any later version.
  10. This program is distributed in the hope that it will be useful,
  11. but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. GNU General Public License for more details.
  14. You should have received a copy of the GNU General Public License
  15. along with this program; if not, write to the Free Software
  16. Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  17. ****************************************************************************
  18. }
  19. unit ag386nsm;
  20. {$i fpcdefs.inc}
  21. interface
  22. uses
  23. cpubase,
  24. aasmbase,aasmtai,aasmcpu,assemble;
  25. type
  26. T386NasmAssembler = class(texternalassembler)
  27. private
  28. procedure WriteReference(var ref : treference);
  29. procedure WriteOper(const o:toper;s : topsize; opcode: tasmop;ops:longint;dest : boolean);
  30. procedure WriteOper_jmp(const o:toper; op : tasmop);
  31. public
  32. procedure WriteTree(p:taasmoutput);override;
  33. procedure WriteAsmList;override;
  34. procedure WriteExternals;
  35. end;
  36. implementation
  37. uses
  38. {$ifdef delphi}
  39. sysutils,
  40. {$endif}
  41. cutils,globtype,globals,systems,cclasses,
  42. fmodule,finput,verbose,cpuinfo,ag386int
  43. ;
  44. const
  45. line_length = 64;
  46. int_nasmreg2str : reg2strtable = ('',
  47. 'eax','ecx','edx','ebx','esp','ebp','esi','edi',
  48. 'ax','cx','dx','bx','sp','bp','si','di',
  49. 'al','cl','dl','bl','ah','ch','bh','dh',
  50. 'cs','ds','es','ss','fs','gs',
  51. 'st0','st0','st1','st2','st3','st4','st5','st6','st7',
  52. 'dr0','dr1','dr2','dr3','dr6','dr7',
  53. 'cr0','cr2','cr3','cr4',
  54. 'tr3','tr4','tr5','tr6','tr7',
  55. 'mm0','mm1','mm2','mm3','mm4','mm5','mm6','mm7',
  56. 'xmm0','xmm1','xmm2','xmm3','xmm4','xmm5','xmm6','xmm7'
  57. );
  58. var
  59. lastfileinfo : tfileposinfo;
  60. infile,
  61. lastinfile : tinputfile;
  62. function fixline(s:string):string;
  63. {
  64. return s with all leading and ending spaces and tabs removed
  65. }
  66. var
  67. i,j,k : longint;
  68. begin
  69. i:=length(s);
  70. while (i>0) and (s[i] in [#9,' ']) do
  71. dec(i);
  72. j:=1;
  73. while (j<i) and (s[j] in [#9,' ']) do
  74. inc(j);
  75. for k:=j to i do
  76. if s[k] in [#0..#31,#127..#255] then
  77. s[k]:='.';
  78. fixline:=Copy(s,j,i-j+1);
  79. end;
  80. function single2str(d : single) : string;
  81. var
  82. hs : string;
  83. p : byte;
  84. begin
  85. str(d,hs);
  86. { nasm expects a lowercase e }
  87. p:=pos('E',hs);
  88. if p>0 then
  89. hs[p]:='e';
  90. p:=pos('+',hs);
  91. if p>0 then
  92. delete(hs,p,1);
  93. single2str:=lower(hs);
  94. end;
  95. function double2str(d : double) : string;
  96. var
  97. hs : string;
  98. p : byte;
  99. begin
  100. str(d,hs);
  101. { nasm expects a lowercase e }
  102. p:=pos('E',hs);
  103. if p>0 then
  104. hs[p]:='e';
  105. p:=pos('+',hs);
  106. if p>0 then
  107. delete(hs,p,1);
  108. double2str:=lower(hs);
  109. end;
  110. function extended2str(e : extended) : string;
  111. var
  112. hs : string;
  113. p : byte;
  114. begin
  115. str(e,hs);
  116. { nasm expects a lowercase e }
  117. p:=pos('E',hs);
  118. if p>0 then
  119. hs[p]:='e';
  120. p:=pos('+',hs);
  121. if p>0 then
  122. delete(hs,p,1);
  123. extended2str:=lower(hs);
  124. end;
  125. function comp2str(d : bestreal) : string;
  126. type
  127. pdouble = ^double;
  128. var
  129. c : comp;
  130. dd : pdouble;
  131. begin
  132. {$ifdef FPC}
  133. c:=comp(d);
  134. {$else}
  135. c:=d;
  136. {$endif}
  137. dd:=pdouble(@c); { this makes a bitwise copy of c into a double }
  138. comp2str:=double2str(dd^);
  139. end;
  140. function sizestr(s:topsize;dest:boolean):string;
  141. begin
  142. case s of
  143. S_B : sizestr:='byte ';
  144. S_W : sizestr:='word ';
  145. S_L : sizestr:='dword ';
  146. S_IS : sizestr:='word ';
  147. S_IL : sizestr:='dword ';
  148. S_IQ : sizestr:='qword ';
  149. S_FS : sizestr:='dword ';
  150. S_FL : sizestr:='qword ';
  151. S_FX : sizestr:='tword ';
  152. S_BW : if dest then
  153. sizestr:='word '
  154. else
  155. sizestr:='byte ';
  156. S_BL : if dest then
  157. sizestr:='dword '
  158. else
  159. sizestr:='byte ';
  160. S_WL : if dest then
  161. sizestr:='dword '
  162. else
  163. sizestr:='word ';
  164. else { S_NO }
  165. sizestr:='';
  166. end;
  167. end;
  168. Function PadTabs(const p:string;addch:char):string;
  169. var
  170. s : string;
  171. i : longint;
  172. begin
  173. i:=length(p);
  174. if addch<>#0 then
  175. begin
  176. inc(i);
  177. s:=p+addch;
  178. end
  179. else
  180. s:=p;
  181. if i<8 then
  182. PadTabs:=s+#9#9
  183. else
  184. PadTabs:=s+#9;
  185. end;
  186. {****************************************************************************
  187. T386NasmAssembler
  188. ****************************************************************************}
  189. procedure T386NasmAssembler.WriteReference(var ref : treference);
  190. var
  191. first,no_s,no_b,no_i : boolean;
  192. begin
  193. with ref do
  194. begin
  195. no_s:=(segment.enum=R_NO) or ((segment.enum=R_INTREGISTER) and (segment.number=NR_NO));
  196. no_b:=(base.enum=R_NO) or ((base.enum=R_INTREGISTER) and (base.number=NR_NO));
  197. no_i:=(index.enum=R_NO) or ((index.enum=R_INTREGISTER) and (index.number=NR_NO));
  198. AsmWrite('[');
  199. first:=true;
  200. inc(offset,offsetfixup);
  201. offsetfixup:=0;
  202. if not no_s then
  203. if segment.enum=R_INTREGISTER then
  204. asmwrite(intel_regname(segment.number))
  205. else
  206. asmwrite(std_reg2str[segment.enum]+':');
  207. if assigned(symbol) then
  208. begin
  209. AsmWrite(symbol.name);
  210. first:=false;
  211. end;
  212. if not no_b then
  213. begin
  214. if not(first) then
  215. AsmWrite('+')
  216. else
  217. first:=false;
  218. if base.enum=R_INTREGISTER then
  219. asmwrite(intel_regname(base.number))
  220. else
  221. asmwrite(int_nasmreg2str[base.enum]);
  222. end;
  223. if not no_i then
  224. begin
  225. if not(first) then
  226. AsmWrite('+')
  227. else
  228. first:=false;
  229. if index.enum=R_INTREGISTER then
  230. asmwrite(intel_regname(index.number))
  231. else
  232. AsmWrite(int_nasmreg2str[index.enum]);
  233. if scalefactor<>0 then
  234. AsmWrite('*'+tostr(scalefactor));
  235. end;
  236. if offset<0 then
  237. begin
  238. AsmWrite(tostr(offset));
  239. first:=false;
  240. end
  241. else if (offset>0) then
  242. begin
  243. AsmWrite('+'+tostr(offset));
  244. first:=false;
  245. end;
  246. if first then
  247. AsmWrite('0');
  248. AsmWrite(']');
  249. end;
  250. end;
  251. procedure T386NasmAssembler.WriteOper(const o:toper;s : topsize; opcode: tasmop;ops:longint;dest : boolean);
  252. begin
  253. case o.typ of
  254. top_reg :
  255. begin
  256. if o.reg.enum=R_INTREGISTER then
  257. asmwrite(intel_regname(o.reg.number))
  258. else
  259. asmwrite(int_nasmreg2str[o.reg.enum]);
  260. end;
  261. top_const :
  262. begin
  263. if (ops=1) and (opcode<>A_RET) then
  264. AsmWrite(sizestr(s,dest));
  265. AsmWrite(tostr(longint(o.val)));
  266. end;
  267. top_symbol :
  268. begin
  269. asmwrite('dword ');
  270. if assigned(o.sym) then
  271. begin
  272. asmwrite(o.sym.name);
  273. if o.symofs=0 then
  274. exit;
  275. end;
  276. if o.symofs>0 then
  277. asmwrite('+');
  278. asmwrite(tostr(o.symofs))
  279. end;
  280. top_ref :
  281. begin
  282. if not ((opcode = A_LEA) or (opcode = A_LGS) or
  283. (opcode = A_LSS) or (opcode = A_LFS) or
  284. (opcode = A_LES) or (opcode = A_LDS) or
  285. (opcode = A_SHR) or (opcode = A_SHL) or
  286. (opcode = A_SAR) or (opcode = A_SAL) or
  287. (opcode = A_OUT) or (opcode = A_IN)) then
  288. AsmWrite(sizestr(s,dest));
  289. WriteReference(o.ref^);
  290. end;
  291. else
  292. internalerror(10001);
  293. end;
  294. end;
  295. procedure T386NasmAssembler.WriteOper_jmp(const o:toper; op : tasmop);
  296. begin
  297. case o.typ of
  298. top_reg :
  299. begin
  300. if o.reg.enum=R_INTREGISTER then
  301. asmwrite(intel_regname(o.reg.number))
  302. else
  303. asmwrite(int_nasmreg2str[o.reg.enum]);
  304. end;
  305. top_ref :
  306. WriteReference(o.ref^);
  307. top_const :
  308. AsmWrite(tostr(longint(o.val)));
  309. top_symbol :
  310. begin
  311. if not(
  312. (op=A_JCXZ) or (op=A_JECXZ) or
  313. (op=A_LOOP) or (op=A_LOOPE) or
  314. (op=A_LOOPNE) or (op=A_LOOPNZ) or
  315. (op=A_LOOPZ)
  316. ) then
  317. AsmWrite('NEAR ');
  318. AsmWrite(o.sym.name);
  319. if o.symofs>0 then
  320. AsmWrite('+'+tostr(o.symofs))
  321. else
  322. if o.symofs<0 then
  323. AsmWrite(tostr(o.symofs));
  324. end;
  325. else
  326. internalerror(10001);
  327. end;
  328. end;
  329. var
  330. LasTSec : TSection;
  331. const
  332. ait_const2str:array[ait_const_32bit..ait_const_8bit] of string[8]=
  333. (#9'DD'#9,#9'DW'#9,#9'DB'#9);
  334. procedure T386NasmAssembler.WriteTree(p:taasmoutput);
  335. const
  336. allocstr : array[boolean] of string[10]=(' released',' allocated');
  337. var
  338. s : string;
  339. hp : tai;
  340. hp1 : tailineinfo;
  341. counter,
  342. lines,
  343. i,j,l : longint;
  344. InlineLevel : longint;
  345. consttyp : taitype;
  346. found,
  347. do_line,
  348. quoted : boolean;
  349. regstr:string[6];
  350. begin
  351. if not assigned(p) then
  352. exit;
  353. InlineLevel:=0;
  354. { lineinfo is only needed for codesegment (PFV) }
  355. do_line:=(cs_asm_source in aktglobalswitches) or
  356. ((cs_lineinfo in aktmoduleswitches)
  357. and (p=codesegment));
  358. hp:=tai(p.first);
  359. while assigned(hp) do
  360. begin
  361. if not(hp.typ in SkipLineInfo) then
  362. begin
  363. hp1:=hp as tailineinfo;
  364. aktfilepos:=hp1.fileinfo;
  365. if do_line then
  366. begin
  367. { load infile }
  368. if lastfileinfo.fileindex<>hp1.fileinfo.fileindex then
  369. begin
  370. infile:=current_module.sourcefiles.get_file(hp1.fileinfo.fileindex);
  371. if assigned(infile) then
  372. begin
  373. { open only if needed !! }
  374. if (cs_asm_source in aktglobalswitches) then
  375. infile.open;
  376. end;
  377. { avoid unnecessary reopens of the same file !! }
  378. lastfileinfo.fileindex:=hp1.fileinfo.fileindex;
  379. { be sure to change line !! }
  380. lastfileinfo.line:=-1;
  381. end;
  382. { write source }
  383. if (cs_asm_source in aktglobalswitches) and
  384. assigned(infile) then
  385. begin
  386. if (infile<>lastinfile) then
  387. begin
  388. AsmWriteLn(target_asm.comment+'['+infile.name^+']');
  389. if assigned(lastinfile) then
  390. lastinfile.close;
  391. end;
  392. if (hp1.fileinfo.line<>lastfileinfo.line) and
  393. ((hp1.fileinfo.line<infile.maxlinebuf) or (InlineLevel>0)) then
  394. begin
  395. if (hp1.fileinfo.line<>0) and
  396. ((infile.linebuf^[hp1.fileinfo.line]>=0) or (InlineLevel>0)) then
  397. AsmWriteLn(target_asm.comment+'['+tostr(hp1.fileinfo.line)+'] '+
  398. fixline(infile.GetLineStr(hp1.fileinfo.line)));
  399. { set it to a negative value !
  400. to make that is has been read already !! PM }
  401. if (infile.linebuf^[hp1.fileinfo.line]>=0) then
  402. infile.linebuf^[hp1.fileinfo.line]:=-infile.linebuf^[hp1.fileinfo.line]-1;
  403. end;
  404. end;
  405. lastfileinfo:=hp1.fileinfo;
  406. lastinfile:=infile;
  407. end;
  408. end;
  409. case hp.typ of
  410. ait_comment :
  411. Begin
  412. AsmWrite(target_asm.comment);
  413. AsmWritePChar(tai_comment(hp).str);
  414. AsmLn;
  415. End;
  416. ait_regalloc :
  417. begin
  418. if tai_regalloc(hp).reg.enum=R_INTREGISTER then
  419. regstr:=intel_regname(tai_regalloc(hp).reg.number)
  420. else
  421. regstr:=std_reg2str[tai_regalloc(hp).reg.enum];
  422. if (cs_asm_regalloc in aktglobalswitches) then
  423. AsmWriteLn(#9#9+target_asm.comment+'Register '+regstr+
  424. allocstr[tai_regalloc(hp).allocation]);
  425. end;
  426. ait_tempalloc :
  427. begin
  428. if (cs_asm_tempalloc in aktglobalswitches) then
  429. begin
  430. {$ifdef EXTDEBUG}
  431. if assigned(tai_tempalloc(hp).problem) then
  432. AsmWriteLn(target_asm.comment+tai_tempalloc(hp).problem^+' ('+tostr(tai_tempalloc(hp).temppos)+','+
  433. tostr(tai_tempalloc(hp).tempsize)+')')
  434. else
  435. {$endif EXTDEBUG}
  436. AsmWriteLn(target_asm.comment+'Temp '+tostr(tai_tempalloc(hp).temppos)+','+
  437. tostr(tai_tempalloc(hp).tempsize)+allocstr[tai_tempalloc(hp).allocation]);
  438. end;
  439. end;
  440. ait_section :
  441. begin
  442. if tai_section(hp).sec<>sec_none then
  443. begin
  444. AsmLn;
  445. AsmWriteLn('SECTION '+target_asm.secnames[tai_section(hp).sec]);
  446. end;
  447. LasTSec:=tai_section(hp).sec;
  448. end;
  449. ait_align :
  450. begin
  451. { nasm gives warnings when it finds align in bss as it
  452. wants to store data }
  453. if lastsec<>sec_bss then
  454. AsmWriteLn(#9'ALIGN '+tostr(tai_align(hp).aligntype));
  455. end;
  456. ait_datablock :
  457. begin
  458. if tai_datablock(hp).is_global then
  459. begin
  460. AsmWrite(#9'GLOBAL ');
  461. AsmWriteLn(tai_datablock(hp).sym.name);
  462. end;
  463. AsmWrite(PadTabs(tai_datablock(hp).sym.name,':'));
  464. AsmWriteLn('RESB'#9+tostr(tai_datablock(hp).size));
  465. end;
  466. ait_const_32bit,
  467. ait_const_16bit,
  468. ait_const_8bit :
  469. begin
  470. AsmWrite(ait_const2str[hp.typ]+tostr(tai_const(hp).value));
  471. consttyp:=hp.typ;
  472. l:=0;
  473. repeat
  474. found:=(not (tai(hp.next)=nil)) and (tai(hp.next).typ=consttyp);
  475. if found then
  476. begin
  477. hp:=tai(hp.next);
  478. s:=','+tostr(tai_const(hp).value);
  479. AsmWrite(s);
  480. inc(l,length(s));
  481. end;
  482. until (not found) or (l>line_length);
  483. AsmLn;
  484. end;
  485. ait_const_symbol :
  486. begin
  487. AsmWrite(#9#9'DD'#9);
  488. AsmWrite(tai_const_symbol(hp).sym.name);
  489. if tai_const_symbol(hp).offset>0 then
  490. AsmWrite('+'+tostr(tai_const_symbol(hp).offset))
  491. else if tai_const_symbol(hp).offset<0 then
  492. AsmWrite(tostr(tai_const_symbol(hp).offset));
  493. AsmLn;
  494. end;
  495. ait_const_rva :
  496. begin
  497. AsmWrite(#9#9'RVA'#9);
  498. AsmWriteLn(tai_const_symbol(hp).sym.name);
  499. end;
  500. ait_real_32bit :
  501. AsmWriteLn(#9#9'DD'#9+single2str(tai_real_32bit(hp).value));
  502. ait_real_64bit :
  503. AsmWriteLn(#9#9'DQ'#9+double2str(tai_real_64bit(hp).value));
  504. ait_real_80bit :
  505. AsmWriteLn(#9#9'DT'#9+extended2str(tai_real_80bit(hp).value));
  506. ait_comp_64bit :
  507. AsmWriteLn(#9#9'DQ'#9+comp2str(tai_real_80bit(hp).value));
  508. ait_string :
  509. begin
  510. counter := 0;
  511. lines := tai_string(hp).len div line_length;
  512. { separate lines in different parts }
  513. if tai_string(hp).len > 0 then
  514. Begin
  515. for j := 0 to lines-1 do
  516. begin
  517. AsmWrite(#9#9'DB'#9);
  518. quoted:=false;
  519. for i:=counter to counter+line_length-1 do
  520. begin
  521. { it is an ascii character. }
  522. if (ord(tai_string(hp).str[i])>31) and
  523. (ord(tai_string(hp).str[i])<128) and
  524. (tai_string(hp).str[i]<>'"') then
  525. begin
  526. if not(quoted) then
  527. begin
  528. if i>counter then
  529. AsmWrite(',');
  530. AsmWrite('"');
  531. end;
  532. AsmWrite(tai_string(hp).str[i]);
  533. quoted:=true;
  534. end { if > 31 and < 128 and ord('"') }
  535. else
  536. begin
  537. if quoted then
  538. AsmWrite('"');
  539. if i>counter then
  540. AsmWrite(',');
  541. quoted:=false;
  542. AsmWrite(tostr(ord(tai_string(hp).str[i])));
  543. end;
  544. end; { end for i:=0 to... }
  545. if quoted then AsmWrite('"');
  546. AsmWrite(target_info.newline);
  547. inc(counter,line_length);
  548. end; { end for j:=0 ... }
  549. { do last line of lines }
  550. if counter<tai_string(hp).len then
  551. AsmWrite(#9#9'DB'#9);
  552. quoted:=false;
  553. for i:=counter to tai_string(hp).len-1 do
  554. begin
  555. { it is an ascii character. }
  556. if (ord(tai_string(hp).str[i])>31) and
  557. (ord(tai_string(hp).str[i])<128) and
  558. (tai_string(hp).str[i]<>'"') then
  559. begin
  560. if not(quoted) then
  561. begin
  562. if i>counter then
  563. AsmWrite(',');
  564. AsmWrite('"');
  565. end;
  566. AsmWrite(tai_string(hp).str[i]);
  567. quoted:=true;
  568. end { if > 31 and < 128 and " }
  569. else
  570. begin
  571. if quoted then
  572. AsmWrite('"');
  573. if i>counter then
  574. AsmWrite(',');
  575. quoted:=false;
  576. AsmWrite(tostr(ord(tai_string(hp).str[i])));
  577. end;
  578. end; { end for i:=0 to... }
  579. if quoted then
  580. AsmWrite('"');
  581. end;
  582. AsmLn;
  583. end;
  584. ait_label :
  585. begin
  586. if tai_label(hp).l.is_used then
  587. AsmWriteLn(tai_label(hp).l.name+':');
  588. end;
  589. ait_direct :
  590. begin
  591. AsmWritePChar(tai_direct(hp).str);
  592. AsmLn;
  593. end;
  594. ait_symbol :
  595. begin
  596. if tai_symbol(hp).is_global then
  597. begin
  598. AsmWrite(#9'GLOBAL ');
  599. AsmWriteLn(tai_symbol(hp).sym.name);
  600. end;
  601. AsmWrite(tai_symbol(hp).sym.name);
  602. if assigned(hp.next) and not(tai(hp.next).typ in
  603. [ait_const_32bit,ait_const_16bit,ait_const_8bit,
  604. ait_const_symbol,ait_const_rva,
  605. ait_real_32bit,ait_real_64bit,ait_real_80bit,ait_comp_64bit,ait_string]) then
  606. AsmWriteLn(':')
  607. end;
  608. ait_symbol_end : ;
  609. ait_instruction :
  610. begin
  611. taicpu(hp).CheckNonCommutativeOpcodes;
  612. { We need intel order, no At&t }
  613. taicpu(hp).SetOperandOrder(op_intel);
  614. s:='';
  615. if ((taicpu(hp).opcode=A_FADDP) or
  616. (taicpu(hp).opcode=A_FMULP))
  617. and (taicpu(hp).ops=0) then
  618. begin
  619. taicpu(hp).ops:=2;
  620. taicpu(hp).oper[0].typ:=top_reg;
  621. taicpu(hp).oper[0].reg.enum:=R_ST1;
  622. taicpu(hp).oper[1].typ:=top_reg;
  623. taicpu(hp).oper[1].reg.enum:=R_ST;
  624. end;
  625. if taicpu(hp).opcode=A_FWAIT then
  626. AsmWriteln(#9#9'DB'#9'09bh')
  627. else
  628. begin
  629. { We need to explicitely set
  630. word prefix to get selectors
  631. to be pushed in 2 bytes PM }
  632. if (taicpu(hp).opsize=S_W) and
  633. ((taicpu(hp).opcode=A_PUSH) or
  634. (taicpu(hp).opcode=A_POP)) and
  635. (taicpu(hp).oper[0].typ=top_reg) and
  636. ((taicpu(hp).oper[0].reg.enum in [firstsreg..lastsreg])) then
  637. AsmWriteln(#9#9'DB'#9'066h');
  638. AsmWrite(#9#9+std_op2str[taicpu(hp).opcode]+cond2str[taicpu(hp).condition]);
  639. if taicpu(hp).ops<>0 then
  640. begin
  641. if is_calljmp(taicpu(hp).opcode) then
  642. begin
  643. AsmWrite(#9);
  644. WriteOper_jmp(taicpu(hp).oper[0],taicpu(hp).opcode);
  645. end
  646. else
  647. begin
  648. for i:=0 to taicpu(hp).ops-1 do
  649. begin
  650. if i=0 then
  651. AsmWrite(#9)
  652. else
  653. AsmWrite(',');
  654. WriteOper(taicpu(hp).oper[i],taicpu(hp).opsize,taicpu(hp).opcode,taicpu(hp).ops,(i=2));
  655. end;
  656. end;
  657. end;
  658. AsmLn;
  659. end;
  660. end;
  661. {$ifdef GDB}
  662. ait_stabn,
  663. ait_stabs,
  664. ait_force_line,
  665. ait_stab_function_name : ;
  666. {$endif GDB}
  667. ait_cut :
  668. begin
  669. { only reset buffer if nothing has changed }
  670. if AsmSize=AsmStartSize then
  671. AsmClear
  672. else
  673. begin
  674. AsmClose;
  675. DoAssemble;
  676. AsmCreate(tai_cut(hp).place);
  677. end;
  678. { avoid empty files }
  679. while assigned(hp.next) and (tai(hp.next).typ in [ait_cut,ait_section,ait_comment]) do
  680. begin
  681. if tai(hp.next).typ=ait_section then
  682. lasTSec:=tai_section(hp.next).sec;
  683. hp:=tai(hp.next);
  684. end;
  685. if lasTSec<>sec_none then
  686. AsmWriteLn('SECTION '+target_asm.secnames[lasTSec]);
  687. AsmStartSize:=AsmSize;
  688. end;
  689. ait_marker :
  690. if tai_marker(hp).kind=InlineStart then
  691. inc(InlineLevel)
  692. else if tai_marker(hp).kind=InlineEnd then
  693. dec(InlineLevel);
  694. else
  695. internalerror(10000);
  696. end;
  697. hp:=tai(hp.next);
  698. end;
  699. end;
  700. var
  701. currentasmlist : TExternalAssembler;
  702. procedure writeexternal(p:tnamedindexitem;arg:pointer);
  703. begin
  704. if tasmsymbol(p).defbind=AB_EXTERNAL then
  705. currentasmlist.AsmWriteln('EXTERN'#9+p.name);
  706. end;
  707. procedure T386NasmAssembler.WriteExternals;
  708. begin
  709. currentasmlist:=self;
  710. objectlibrary.symbolsearch.foreach_static({$ifdef fpcprocvar}@{$endif}writeexternal,nil);
  711. end;
  712. procedure T386NasmAssembler.WriteAsmList;
  713. begin
  714. {$ifdef EXTDEBUG}
  715. if assigned(current_module.mainsource) then
  716. comment(v_info,'Start writing nasm-styled assembler output for '+current_module.mainsource^);
  717. {$endif}
  718. LasTSec:=sec_none;
  719. AsmWriteLn('BITS 32');
  720. AsmLn;
  721. lastfileinfo.line:=-1;
  722. lastfileinfo.fileindex:=0;
  723. lastinfile:=nil;
  724. WriteExternals;
  725. { Nasm doesn't support stabs
  726. WriteTree(debuglist);}
  727. WriteTree(codesegment);
  728. WriteTree(datasegment);
  729. WriteTree(consts);
  730. WriteTree(rttilist);
  731. WriteTree(resourcestringlist);
  732. WriteTree(bsssegment);
  733. Writetree(importssection);
  734. { exports are written by DLLTOOL
  735. if we use it so don't insert it twice (PM) }
  736. if not UseDeffileForExport and assigned(exportssection) then
  737. Writetree(exportssection);
  738. Writetree(resourcesection);
  739. AsmLn;
  740. {$ifdef EXTDEBUG}
  741. if assigned(current_module.mainsource) then
  742. comment(v_info,'Done writing nasm-styled assembler output for '+current_module.mainsource^);
  743. {$endif EXTDEBUG}
  744. end;
  745. {*****************************************************************************
  746. Initialize
  747. *****************************************************************************}
  748. const
  749. as_i386_nasmcoff_info : tasminfo =
  750. (
  751. id : as_i386_nasmcoff;
  752. idtxt : 'NASMCOFF';
  753. asmbin : 'nasm';
  754. asmcmd : '-f coff -o $OBJ $ASM';
  755. supported_target : system_i386_go32v2;
  756. outputbinary: false;
  757. allowdirect : true;
  758. needar : true;
  759. labelprefix_only_inside_procedure: false;
  760. labelprefix : '..@';
  761. comment : '; ';
  762. secnames : ('',
  763. '.text','.data','.bss',
  764. '.idata2','.idata4','.idata5','.idata6','.idata7','.edata',
  765. '.stab','.stabstr','')
  766. );
  767. as_i386_nasmwin32_info : tasminfo =
  768. (
  769. id : as_i386_nasmwin32;
  770. idtxt : 'NASMWIN32';
  771. asmbin : 'nasm';
  772. asmcmd : '-f win32 -o $OBJ $ASM';
  773. supported_target : system_i386_win32;
  774. outputbinary: false;
  775. allowdirect : true;
  776. needar : true;
  777. labelprefix_only_inside_procedure: false;
  778. labelprefix : '..@';
  779. comment : '; ';
  780. secnames : ('',
  781. '.text','.data','.bss',
  782. '.idata2','.idata4','.idata5','.idata6','.idata7','.edata',
  783. '.stab','.stabstr','')
  784. );
  785. as_i386_nasmobj_info : tasminfo =
  786. (
  787. id : as_i386_nasmobj;
  788. idtxt : 'NASMOBJ';
  789. asmbin : 'nasm';
  790. asmcmd : '-f obj -o $OBJ $ASM';
  791. supported_target : system_any; { what should I write here ?? }
  792. outputbinary: false;
  793. allowdirect : true;
  794. needar : true;
  795. labelprefix_only_inside_procedure: false;
  796. labelprefix : '..@';
  797. comment : '; ';
  798. secnames : ('',
  799. '.text','.data','.bss',
  800. '.idata2','.idata4','.idata5','.idata6','.idata7','.edata',
  801. '.stab','.stabstr','')
  802. );
  803. as_i386_nasmwdosx_info : tasminfo =
  804. (
  805. id : as_i386_nasmwdosx;
  806. idtxt : 'NASMWDOSX';
  807. asmbin : 'nasm';
  808. asmcmd : '-f win32 -o $OBJ $ASM';
  809. supported_target : system_i386_wdosx;
  810. outputbinary: false;
  811. allowdirect : true;
  812. needar : true;
  813. labelprefix_only_inside_procedure: false;
  814. labelprefix : '..@';
  815. comment : '; ';
  816. secnames : ('',
  817. '.text','.data','.bss',
  818. '.idata2','.idata4','.idata5','.idata6','.idata7','.edata',
  819. '.stab','.stabstr','')
  820. );
  821. as_i386_nasmelf_info : tasminfo =
  822. (
  823. id : as_i386_nasmelf;
  824. idtxt : 'NASMELF';
  825. asmbin : 'nasm';
  826. asmcmd : '-f elf -o $OBJ $ASM';
  827. supported_target : system_i386_linux;
  828. outputbinary: false;
  829. allowdirect : true;
  830. needar : true;
  831. labelprefix_only_inside_procedure: false;
  832. labelprefix : '..@';
  833. comment : '; ';
  834. secnames : ('',
  835. '.text','.data','.bss',
  836. '.idata2','.idata4','.idata5','.idata6','.idata7','.edata',
  837. '.stab','.stabstr','')
  838. );
  839. initialization
  840. RegisterAssembler(as_i386_nasmcoff_info,T386NasmAssembler);
  841. RegisterAssembler(as_i386_nasmwin32_info,T386NasmAssembler);
  842. RegisterAssembler(as_i386_nasmwdosx_info,T386NasmAssembler);
  843. RegisterAssembler(as_i386_nasmobj_info,T386NasmAssembler);
  844. RegisterAssembler(as_i386_nasmelf_info,T386NasmAssembler);
  845. end.
  846. {
  847. $Log$
  848. Revision 1.36 2003-07-06 15:31:21 daniel
  849. * Fixed register allocator. *Lots* of fixes.
  850. Revision 1.35 2003/06/03 13:01:59 daniel
  851. * Register allocator finished
  852. Revision 1.34 2003/05/26 19:37:57 peter
  853. * don't generate align in .bss
  854. Revision 1.33 2003/04/22 10:09:35 daniel
  855. + Implemented the actual register allocator
  856. + Scratch registers unavailable when new register allocator used
  857. + maybe_save/maybe_restore unavailable when new register allocator used
  858. Revision 1.32 2003/03/08 13:59:17 daniel
  859. * Work to handle new register notation in ag386nsm
  860. + Added newra version of Ti386moddivnode
  861. Revision 1.31 2003/03/08 08:59:07 daniel
  862. + $define newra will enable new register allocator
  863. + getregisterint will return imaginary registers with $newra
  864. + -sr switch added, will skip register allocation so you can see
  865. the direct output of the code generator before register allocation
  866. Revision 1.30 2003/01/08 18:43:57 daniel
  867. * Tregister changed into a record
  868. Revision 1.29 2002/12/24 18:10:34 peter
  869. * Long symbol names support
  870. Revision 1.28 2002/11/17 16:31:59 carl
  871. * memory optimization (3-4%) : cleanup of tai fields,
  872. cleanup of tdef and tsym fields.
  873. * make it work for m68k
  874. Revision 1.27 2002/11/15 01:58:56 peter
  875. * merged changes from 1.0.7 up to 04-11
  876. - -V option for generating bug report tracing
  877. - more tracing for option parsing
  878. - errors for cdecl and high()
  879. - win32 import stabs
  880. - win32 records<=8 are returned in eax:edx (turned off by default)
  881. - heaptrc update
  882. - more info for temp management in .s file with EXTDEBUG
  883. Revision 1.26 2002/08/18 20:06:28 peter
  884. * inlining is now also allowed in interface
  885. * renamed write/load to ppuwrite/ppuload
  886. * tnode storing in ppu
  887. * nld,ncon,nbas are already updated for storing in ppu
  888. Revision 1.25 2002/08/12 15:08:41 carl
  889. + stab register indexes for powerpc (moved from gdb to cpubase)
  890. + tprocessor enumeration moved to cpuinfo
  891. + linker in target_info is now a class
  892. * many many updates for m68k (will soon start to compile)
  893. - removed some ifdef or correct them for correct cpu
  894. Revision 1.24 2002/08/11 14:32:29 peter
  895. * renamed current_library to objectlibrary
  896. Revision 1.23 2002/08/11 13:24:16 peter
  897. * saving of asmsymbols in ppu supported
  898. * asmsymbollist global is removed and moved into a new class
  899. tasmlibrarydata that will hold the info of a .a file which
  900. corresponds with a single module. Added librarydata to tmodule
  901. to keep the library info stored for the module. In the future the
  902. objectfiles will also be stored to the tasmlibrarydata class
  903. * all getlabel/newasmsymbol and friends are moved to the new class
  904. Revision 1.22 2002/07/26 21:15:43 florian
  905. * rewrote the system handling
  906. Revision 1.21 2002/07/01 18:46:29 peter
  907. * internal linker
  908. * reorganized aasm layer
  909. Revision 1.20 2002/05/18 13:34:21 peter
  910. * readded missing revisions
  911. Revision 1.19 2002/05/16 19:46:50 carl
  912. + defines.inc -> fpcdefs.inc to avoid conflicts if compiling by hand
  913. + try to fix temp allocation (still in ifdef)
  914. + generic constructor calls
  915. + start of tassembler / tmodulebase class cleanup
  916. Revision 1.17 2002/05/12 16:53:16 peter
  917. * moved entry and exitcode to ncgutil and cgobj
  918. * foreach gets extra argument for passing local data to the
  919. iterator function
  920. * -CR checks also class typecasts at runtime by changing them
  921. into as
  922. * fixed compiler to cycle with the -CR option
  923. * fixed stabs with elf writer, finally the global variables can
  924. be watched
  925. * removed a lot of routines from cga unit and replaced them by
  926. calls to cgobj
  927. * u32bit-s32bit updates for and,or,xor nodes. When one element is
  928. u32bit then the other is typecasted also to u32bit without giving
  929. a rangecheck warning/error.
  930. * fixed pascal calling method with reversing also the high tree in
  931. the parast, detected by tcalcst3 test
  932. Revision 1.16 2002/04/15 19:12:09 carl
  933. + target_info.size_of_pointer -> pointer_size
  934. + some cleanup of unused types/variables
  935. * move several constants from cpubase to their specific units
  936. (where they are used)
  937. + att_Reg2str -> gas_reg2str
  938. + int_reg2str -> std_reg2str
  939. Revision 1.15 2002/04/14 16:58:41 carl
  940. + att_reg2str -> gas_reg2str
  941. Revision 1.14 2002/04/04 18:27:37 carl
  942. + added wdosx support (patch from Pavel)
  943. Revision 1.13 2002/04/02 17:11:33 peter
  944. * tlocation,treference update
  945. * LOC_CONSTANT added for better constant handling
  946. * secondadd splitted in multiple routines
  947. * location_force_reg added for loading a location to a register
  948. of a specified size
  949. * secondassignment parses now first the right and then the left node
  950. (this is compatible with Kylix). This saves a lot of push/pop especially
  951. with string operations
  952. * adapted some routines to use the new cg methods
  953. }