ag386nsm.pas 35 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065
  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. begin
  260. if o.reg.enum>high(Toldregister) then
  261. internalerror(01010101);
  262. asmwrite(int_nasmreg2str[o.reg.enum]);
  263. end;
  264. end;
  265. top_const :
  266. begin
  267. if (ops=1) and (opcode<>A_RET) then
  268. AsmWrite(sizestr(s,dest));
  269. AsmWrite(tostr(longint(o.val)));
  270. end;
  271. top_symbol :
  272. begin
  273. asmwrite('dword ');
  274. if assigned(o.sym) then
  275. begin
  276. asmwrite(o.sym.name);
  277. if o.symofs=0 then
  278. exit;
  279. end;
  280. if o.symofs>0 then
  281. asmwrite('+');
  282. asmwrite(tostr(o.symofs))
  283. end;
  284. top_ref :
  285. begin
  286. if not ((opcode = A_LEA) or (opcode = A_LGS) or
  287. (opcode = A_LSS) or (opcode = A_LFS) or
  288. (opcode = A_LES) or (opcode = A_LDS) or
  289. (opcode = A_SHR) or (opcode = A_SHL) or
  290. (opcode = A_SAR) or (opcode = A_SAL) or
  291. (opcode = A_OUT) or (opcode = A_IN)) then
  292. AsmWrite(sizestr(s,dest));
  293. WriteReference(o.ref^);
  294. end;
  295. else
  296. internalerror(10001);
  297. end;
  298. end;
  299. procedure T386NasmAssembler.WriteOper_jmp(const o:toper; op : tasmop);
  300. begin
  301. case o.typ of
  302. top_reg :
  303. begin
  304. if o.reg.enum=R_INTREGISTER then
  305. asmwrite(intel_regname(o.reg.number))
  306. else
  307. asmwrite(int_nasmreg2str[o.reg.enum]);
  308. end;
  309. top_ref :
  310. WriteReference(o.ref^);
  311. top_const :
  312. AsmWrite(tostr(longint(o.val)));
  313. top_symbol :
  314. begin
  315. if not(
  316. (op=A_JCXZ) or (op=A_JECXZ) or
  317. (op=A_LOOP) or (op=A_LOOPE) or
  318. (op=A_LOOPNE) or (op=A_LOOPNZ) or
  319. (op=A_LOOPZ)
  320. ) then
  321. AsmWrite('NEAR ');
  322. AsmWrite(o.sym.name);
  323. if o.symofs>0 then
  324. AsmWrite('+'+tostr(o.symofs))
  325. else
  326. if o.symofs<0 then
  327. AsmWrite(tostr(o.symofs));
  328. end;
  329. else
  330. internalerror(10001);
  331. end;
  332. end;
  333. var
  334. LasTSec : TSection;
  335. const
  336. ait_const2str:array[ait_const_32bit..ait_const_8bit] of string[8]=
  337. (#9'DD'#9,#9'DW'#9,#9'DB'#9);
  338. procedure T386NasmAssembler.WriteTree(p:taasmoutput);
  339. const
  340. allocstr : array[boolean] of string[10]=(' released',' allocated');
  341. var
  342. s : string;
  343. hp : tai;
  344. hp1 : tailineinfo;
  345. counter,
  346. lines,
  347. i,j,l : longint;
  348. InlineLevel : longint;
  349. consttyp : taitype;
  350. found,
  351. do_line,
  352. quoted : boolean;
  353. regstr:string[6];
  354. begin
  355. if not assigned(p) then
  356. exit;
  357. InlineLevel:=0;
  358. { lineinfo is only needed for codesegment (PFV) }
  359. do_line:=(cs_asm_source in aktglobalswitches) or
  360. ((cs_lineinfo in aktmoduleswitches)
  361. and (p=codesegment));
  362. hp:=tai(p.first);
  363. while assigned(hp) do
  364. begin
  365. if not(hp.typ in SkipLineInfo) then
  366. begin
  367. hp1:=hp as tailineinfo;
  368. aktfilepos:=hp1.fileinfo;
  369. if do_line then
  370. begin
  371. { load infile }
  372. if lastfileinfo.fileindex<>hp1.fileinfo.fileindex then
  373. begin
  374. infile:=current_module.sourcefiles.get_file(hp1.fileinfo.fileindex);
  375. if assigned(infile) then
  376. begin
  377. { open only if needed !! }
  378. if (cs_asm_source in aktglobalswitches) then
  379. infile.open;
  380. end;
  381. { avoid unnecessary reopens of the same file !! }
  382. lastfileinfo.fileindex:=hp1.fileinfo.fileindex;
  383. { be sure to change line !! }
  384. lastfileinfo.line:=-1;
  385. end;
  386. { write source }
  387. if (cs_asm_source in aktglobalswitches) and
  388. assigned(infile) then
  389. begin
  390. if (infile<>lastinfile) then
  391. begin
  392. AsmWriteLn(target_asm.comment+'['+infile.name^+']');
  393. if assigned(lastinfile) then
  394. lastinfile.close;
  395. end;
  396. if (hp1.fileinfo.line<>lastfileinfo.line) and
  397. ((hp1.fileinfo.line<infile.maxlinebuf) or (InlineLevel>0)) then
  398. begin
  399. if (hp1.fileinfo.line<>0) and
  400. ((infile.linebuf^[hp1.fileinfo.line]>=0) or (InlineLevel>0)) then
  401. AsmWriteLn(target_asm.comment+'['+tostr(hp1.fileinfo.line)+'] '+
  402. fixline(infile.GetLineStr(hp1.fileinfo.line)));
  403. { set it to a negative value !
  404. to make that is has been read already !! PM }
  405. if (infile.linebuf^[hp1.fileinfo.line]>=0) then
  406. infile.linebuf^[hp1.fileinfo.line]:=-infile.linebuf^[hp1.fileinfo.line]-1;
  407. end;
  408. end;
  409. lastfileinfo:=hp1.fileinfo;
  410. lastinfile:=infile;
  411. end;
  412. end;
  413. case hp.typ of
  414. ait_comment :
  415. Begin
  416. AsmWrite(target_asm.comment);
  417. AsmWritePChar(tai_comment(hp).str);
  418. AsmLn;
  419. End;
  420. ait_regalloc :
  421. begin
  422. if tai_regalloc(hp).reg.enum=R_INTREGISTER then
  423. regstr:=intel_regname(tai_regalloc(hp).reg.number)
  424. else
  425. regstr:=std_reg2str[tai_regalloc(hp).reg.enum];
  426. if (cs_asm_regalloc in aktglobalswitches) then
  427. AsmWriteLn(#9#9+target_asm.comment+'Register '+regstr+
  428. allocstr[tai_regalloc(hp).allocation]);
  429. end;
  430. ait_tempalloc :
  431. begin
  432. if (cs_asm_tempalloc in aktglobalswitches) then
  433. begin
  434. {$ifdef EXTDEBUG}
  435. if assigned(tai_tempalloc(hp).problem) then
  436. AsmWriteLn(target_asm.comment+tai_tempalloc(hp).problem^+' ('+tostr(tai_tempalloc(hp).temppos)+','+
  437. tostr(tai_tempalloc(hp).tempsize)+')')
  438. else
  439. {$endif EXTDEBUG}
  440. AsmWriteLn(target_asm.comment+'Temp '+tostr(tai_tempalloc(hp).temppos)+','+
  441. tostr(tai_tempalloc(hp).tempsize)+allocstr[tai_tempalloc(hp).allocation]);
  442. end;
  443. end;
  444. ait_section :
  445. begin
  446. if tai_section(hp).sec<>sec_none then
  447. begin
  448. AsmLn;
  449. AsmWriteLn('SECTION '+target_asm.secnames[tai_section(hp).sec]);
  450. end;
  451. LasTSec:=tai_section(hp).sec;
  452. end;
  453. ait_align :
  454. begin
  455. { nasm gives warnings when it finds align in bss as it
  456. wants to store data }
  457. if lastsec<>sec_bss then
  458. AsmWriteLn(#9'ALIGN '+tostr(tai_align(hp).aligntype));
  459. end;
  460. ait_datablock :
  461. begin
  462. if tai_datablock(hp).is_global then
  463. begin
  464. AsmWrite(#9'GLOBAL ');
  465. AsmWriteLn(tai_datablock(hp).sym.name);
  466. end;
  467. AsmWrite(PadTabs(tai_datablock(hp).sym.name,':'));
  468. AsmWriteLn('RESB'#9+tostr(tai_datablock(hp).size));
  469. end;
  470. ait_const_32bit,
  471. ait_const_16bit,
  472. ait_const_8bit :
  473. begin
  474. AsmWrite(ait_const2str[hp.typ]+tostr(tai_const(hp).value));
  475. consttyp:=hp.typ;
  476. l:=0;
  477. repeat
  478. found:=(not (tai(hp.next)=nil)) and (tai(hp.next).typ=consttyp);
  479. if found then
  480. begin
  481. hp:=tai(hp.next);
  482. s:=','+tostr(tai_const(hp).value);
  483. AsmWrite(s);
  484. inc(l,length(s));
  485. end;
  486. until (not found) or (l>line_length);
  487. AsmLn;
  488. end;
  489. ait_const_symbol :
  490. begin
  491. AsmWrite(#9#9'DD'#9);
  492. AsmWrite(tai_const_symbol(hp).sym.name);
  493. if tai_const_symbol(hp).offset>0 then
  494. AsmWrite('+'+tostr(tai_const_symbol(hp).offset))
  495. else if tai_const_symbol(hp).offset<0 then
  496. AsmWrite(tostr(tai_const_symbol(hp).offset));
  497. AsmLn;
  498. end;
  499. ait_const_rva :
  500. begin
  501. AsmWrite(#9#9'RVA'#9);
  502. AsmWriteLn(tai_const_symbol(hp).sym.name);
  503. end;
  504. ait_real_32bit :
  505. AsmWriteLn(#9#9'DD'#9+single2str(tai_real_32bit(hp).value));
  506. ait_real_64bit :
  507. AsmWriteLn(#9#9'DQ'#9+double2str(tai_real_64bit(hp).value));
  508. ait_real_80bit :
  509. AsmWriteLn(#9#9'DT'#9+extended2str(tai_real_80bit(hp).value));
  510. ait_comp_64bit :
  511. AsmWriteLn(#9#9'DQ'#9+comp2str(tai_real_80bit(hp).value));
  512. ait_string :
  513. begin
  514. counter := 0;
  515. lines := tai_string(hp).len div line_length;
  516. { separate lines in different parts }
  517. if tai_string(hp).len > 0 then
  518. Begin
  519. for j := 0 to lines-1 do
  520. begin
  521. AsmWrite(#9#9'DB'#9);
  522. quoted:=false;
  523. for i:=counter to counter+line_length-1 do
  524. begin
  525. { it is an ascii character. }
  526. if (ord(tai_string(hp).str[i])>31) and
  527. (ord(tai_string(hp).str[i])<128) and
  528. (tai_string(hp).str[i]<>'"') then
  529. begin
  530. if not(quoted) then
  531. begin
  532. if i>counter then
  533. AsmWrite(',');
  534. AsmWrite('"');
  535. end;
  536. AsmWrite(tai_string(hp).str[i]);
  537. quoted:=true;
  538. end { if > 31 and < 128 and ord('"') }
  539. else
  540. begin
  541. if quoted then
  542. AsmWrite('"');
  543. if i>counter then
  544. AsmWrite(',');
  545. quoted:=false;
  546. AsmWrite(tostr(ord(tai_string(hp).str[i])));
  547. end;
  548. end; { end for i:=0 to... }
  549. if quoted then AsmWrite('"');
  550. AsmWrite(target_info.newline);
  551. inc(counter,line_length);
  552. end; { end for j:=0 ... }
  553. { do last line of lines }
  554. if counter<tai_string(hp).len then
  555. AsmWrite(#9#9'DB'#9);
  556. quoted:=false;
  557. for i:=counter to tai_string(hp).len-1 do
  558. begin
  559. { it is an ascii character. }
  560. if (ord(tai_string(hp).str[i])>31) and
  561. (ord(tai_string(hp).str[i])<128) and
  562. (tai_string(hp).str[i]<>'"') then
  563. begin
  564. if not(quoted) then
  565. begin
  566. if i>counter then
  567. AsmWrite(',');
  568. AsmWrite('"');
  569. end;
  570. AsmWrite(tai_string(hp).str[i]);
  571. quoted:=true;
  572. end { if > 31 and < 128 and " }
  573. else
  574. begin
  575. if quoted then
  576. AsmWrite('"');
  577. if i>counter then
  578. AsmWrite(',');
  579. quoted:=false;
  580. AsmWrite(tostr(ord(tai_string(hp).str[i])));
  581. end;
  582. end; { end for i:=0 to... }
  583. if quoted then
  584. AsmWrite('"');
  585. end;
  586. AsmLn;
  587. end;
  588. ait_label :
  589. begin
  590. if tai_label(hp).l.is_used then
  591. AsmWriteLn(tai_label(hp).l.name+':');
  592. end;
  593. ait_direct :
  594. begin
  595. AsmWritePChar(tai_direct(hp).str);
  596. AsmLn;
  597. end;
  598. ait_symbol :
  599. begin
  600. if tai_symbol(hp).is_global then
  601. begin
  602. AsmWrite(#9'GLOBAL ');
  603. AsmWriteLn(tai_symbol(hp).sym.name);
  604. end;
  605. AsmWrite(tai_symbol(hp).sym.name);
  606. if assigned(hp.next) and not(tai(hp.next).typ in
  607. [ait_const_32bit,ait_const_16bit,ait_const_8bit,
  608. ait_const_symbol,ait_const_rva,
  609. ait_real_32bit,ait_real_64bit,ait_real_80bit,ait_comp_64bit,ait_string]) then
  610. AsmWriteLn(':')
  611. end;
  612. ait_symbol_end : ;
  613. ait_instruction :
  614. begin
  615. taicpu(hp).CheckNonCommutativeOpcodes;
  616. { We need intel order, no At&t }
  617. taicpu(hp).SetOperandOrder(op_intel);
  618. s:='';
  619. if ((taicpu(hp).opcode=A_FADDP) or
  620. (taicpu(hp).opcode=A_FMULP))
  621. and (taicpu(hp).ops=0) then
  622. begin
  623. taicpu(hp).ops:=2;
  624. taicpu(hp).oper[0].typ:=top_reg;
  625. taicpu(hp).oper[0].reg.enum:=R_ST1;
  626. taicpu(hp).oper[1].typ:=top_reg;
  627. taicpu(hp).oper[1].reg.enum:=R_ST;
  628. end;
  629. if taicpu(hp).opcode=A_FWAIT then
  630. AsmWriteln(#9#9'DB'#9'09bh')
  631. else
  632. begin
  633. { We need to explicitely set
  634. word prefix to get selectors
  635. to be pushed in 2 bytes PM }
  636. if (taicpu(hp).opsize=S_W) and
  637. ((taicpu(hp).opcode=A_PUSH) or
  638. (taicpu(hp).opcode=A_POP)) and
  639. (taicpu(hp).oper[0].typ=top_reg) and
  640. ((taicpu(hp).oper[0].reg.enum in [firstsreg..lastsreg])) then
  641. AsmWriteln(#9#9'DB'#9'066h');
  642. AsmWrite(#9#9+std_op2str[taicpu(hp).opcode]+cond2str[taicpu(hp).condition]);
  643. if taicpu(hp).ops<>0 then
  644. begin
  645. if is_calljmp(taicpu(hp).opcode) then
  646. begin
  647. AsmWrite(#9);
  648. WriteOper_jmp(taicpu(hp).oper[0],taicpu(hp).opcode);
  649. end
  650. else
  651. begin
  652. for i:=0 to taicpu(hp).ops-1 do
  653. begin
  654. if i=0 then
  655. AsmWrite(#9)
  656. else
  657. AsmWrite(',');
  658. WriteOper(taicpu(hp).oper[i],taicpu(hp).opsize,taicpu(hp).opcode,taicpu(hp).ops,(i=2));
  659. end;
  660. end;
  661. end;
  662. AsmLn;
  663. end;
  664. end;
  665. {$ifdef GDB}
  666. ait_stabn,
  667. ait_stabs,
  668. ait_force_line,
  669. ait_stab_function_name : ;
  670. {$endif GDB}
  671. ait_cut :
  672. begin
  673. { only reset buffer if nothing has changed }
  674. if AsmSize=AsmStartSize then
  675. AsmClear
  676. else
  677. begin
  678. AsmClose;
  679. DoAssemble;
  680. AsmCreate(tai_cut(hp).place);
  681. end;
  682. { avoid empty files }
  683. while assigned(hp.next) and (tai(hp.next).typ in [ait_cut,ait_section,ait_comment]) do
  684. begin
  685. if tai(hp.next).typ=ait_section then
  686. lasTSec:=tai_section(hp.next).sec;
  687. hp:=tai(hp.next);
  688. end;
  689. if lasTSec<>sec_none then
  690. AsmWriteLn('SECTION '+target_asm.secnames[lasTSec]);
  691. AsmStartSize:=AsmSize;
  692. end;
  693. ait_marker :
  694. if tai_marker(hp).kind=InlineStart then
  695. inc(InlineLevel)
  696. else if tai_marker(hp).kind=InlineEnd then
  697. dec(InlineLevel);
  698. else
  699. internalerror(10000);
  700. end;
  701. hp:=tai(hp.next);
  702. end;
  703. end;
  704. var
  705. currentasmlist : TExternalAssembler;
  706. procedure writeexternal(p:tnamedindexitem;arg:pointer);
  707. begin
  708. if tasmsymbol(p).defbind=AB_EXTERNAL then
  709. currentasmlist.AsmWriteln('EXTERN'#9+p.name);
  710. end;
  711. procedure T386NasmAssembler.WriteExternals;
  712. begin
  713. currentasmlist:=self;
  714. objectlibrary.symbolsearch.foreach_static({$ifdef fpcprocvar}@{$endif}writeexternal,nil);
  715. end;
  716. procedure T386NasmAssembler.WriteAsmList;
  717. begin
  718. {$ifdef EXTDEBUG}
  719. if assigned(current_module.mainsource) then
  720. comment(v_info,'Start writing nasm-styled assembler output for '+current_module.mainsource^);
  721. {$endif}
  722. LasTSec:=sec_none;
  723. AsmWriteLn('BITS 32');
  724. AsmLn;
  725. lastfileinfo.line:=-1;
  726. lastfileinfo.fileindex:=0;
  727. lastinfile:=nil;
  728. WriteExternals;
  729. { Nasm doesn't support stabs
  730. WriteTree(debuglist);}
  731. WriteTree(codesegment);
  732. WriteTree(datasegment);
  733. WriteTree(consts);
  734. WriteTree(rttilist);
  735. WriteTree(resourcestringlist);
  736. WriteTree(bsssegment);
  737. Writetree(importssection);
  738. { exports are written by DLLTOOL
  739. if we use it so don't insert it twice (PM) }
  740. if not UseDeffileForExport and assigned(exportssection) then
  741. Writetree(exportssection);
  742. Writetree(resourcesection);
  743. AsmLn;
  744. {$ifdef EXTDEBUG}
  745. if assigned(current_module.mainsource) then
  746. comment(v_info,'Done writing nasm-styled assembler output for '+current_module.mainsource^);
  747. {$endif EXTDEBUG}
  748. end;
  749. {*****************************************************************************
  750. Initialize
  751. *****************************************************************************}
  752. const
  753. as_i386_nasmcoff_info : tasminfo =
  754. (
  755. id : as_i386_nasmcoff;
  756. idtxt : 'NASMCOFF';
  757. asmbin : 'nasm';
  758. asmcmd : '-f coff -o $OBJ $ASM';
  759. supported_target : system_i386_go32v2;
  760. outputbinary: false;
  761. allowdirect : true;
  762. needar : true;
  763. labelprefix_only_inside_procedure: false;
  764. labelprefix : '..@';
  765. comment : '; ';
  766. secnames : ('',
  767. '.text','.data','.bss',
  768. '.idata2','.idata4','.idata5','.idata6','.idata7','.edata',
  769. '.stab','.stabstr','')
  770. );
  771. as_i386_nasmwin32_info : tasminfo =
  772. (
  773. id : as_i386_nasmwin32;
  774. idtxt : 'NASMWIN32';
  775. asmbin : 'nasm';
  776. asmcmd : '-f win32 -o $OBJ $ASM';
  777. supported_target : system_i386_win32;
  778. outputbinary: false;
  779. allowdirect : true;
  780. needar : true;
  781. labelprefix_only_inside_procedure: false;
  782. labelprefix : '..@';
  783. comment : '; ';
  784. secnames : ('',
  785. '.text','.data','.bss',
  786. '.idata2','.idata4','.idata5','.idata6','.idata7','.edata',
  787. '.stab','.stabstr','')
  788. );
  789. as_i386_nasmobj_info : tasminfo =
  790. (
  791. id : as_i386_nasmobj;
  792. idtxt : 'NASMOBJ';
  793. asmbin : 'nasm';
  794. asmcmd : '-f obj -o $OBJ $ASM';
  795. supported_target : system_any; { what should I write here ?? }
  796. outputbinary: false;
  797. allowdirect : true;
  798. needar : true;
  799. labelprefix_only_inside_procedure: false;
  800. labelprefix : '..@';
  801. comment : '; ';
  802. secnames : ('',
  803. '.text','.data','.bss',
  804. '.idata2','.idata4','.idata5','.idata6','.idata7','.edata',
  805. '.stab','.stabstr','')
  806. );
  807. as_i386_nasmwdosx_info : tasminfo =
  808. (
  809. id : as_i386_nasmwdosx;
  810. idtxt : 'NASMWDOSX';
  811. asmbin : 'nasm';
  812. asmcmd : '-f win32 -o $OBJ $ASM';
  813. supported_target : system_i386_wdosx;
  814. outputbinary: false;
  815. allowdirect : true;
  816. needar : true;
  817. labelprefix_only_inside_procedure: false;
  818. labelprefix : '..@';
  819. comment : '; ';
  820. secnames : ('',
  821. '.text','.data','.bss',
  822. '.idata2','.idata4','.idata5','.idata6','.idata7','.edata',
  823. '.stab','.stabstr','')
  824. );
  825. as_i386_nasmelf_info : tasminfo =
  826. (
  827. id : as_i386_nasmelf;
  828. idtxt : 'NASMELF';
  829. asmbin : 'nasm';
  830. asmcmd : '-f elf -o $OBJ $ASM';
  831. supported_target : system_i386_linux;
  832. outputbinary: false;
  833. allowdirect : true;
  834. needar : true;
  835. labelprefix_only_inside_procedure: false;
  836. labelprefix : '..@';
  837. comment : '; ';
  838. secnames : ('',
  839. '.text','.data','.bss',
  840. '.idata2','.idata4','.idata5','.idata6','.idata7','.edata',
  841. '.stab','.stabstr','')
  842. );
  843. initialization
  844. RegisterAssembler(as_i386_nasmcoff_info,T386NasmAssembler);
  845. RegisterAssembler(as_i386_nasmwin32_info,T386NasmAssembler);
  846. RegisterAssembler(as_i386_nasmwdosx_info,T386NasmAssembler);
  847. RegisterAssembler(as_i386_nasmobj_info,T386NasmAssembler);
  848. RegisterAssembler(as_i386_nasmelf_info,T386NasmAssembler);
  849. end.
  850. {
  851. $Log$
  852. Revision 1.37 2003-08-09 18:56:54 daniel
  853. * cs_regalloc renamed to cs_regvars to avoid confusion with register
  854. allocator
  855. * Some preventive changes to i386 spillinh code
  856. Revision 1.36 2003/07/06 15:31:21 daniel
  857. * Fixed register allocator. *Lots* of fixes.
  858. Revision 1.35 2003/06/03 13:01:59 daniel
  859. * Register allocator finished
  860. Revision 1.34 2003/05/26 19:37:57 peter
  861. * don't generate align in .bss
  862. Revision 1.33 2003/04/22 10:09:35 daniel
  863. + Implemented the actual register allocator
  864. + Scratch registers unavailable when new register allocator used
  865. + maybe_save/maybe_restore unavailable when new register allocator used
  866. Revision 1.32 2003/03/08 13:59:17 daniel
  867. * Work to handle new register notation in ag386nsm
  868. + Added newra version of Ti386moddivnode
  869. Revision 1.31 2003/03/08 08:59:07 daniel
  870. + $define newra will enable new register allocator
  871. + getregisterint will return imaginary registers with $newra
  872. + -sr switch added, will skip register allocation so you can see
  873. the direct output of the code generator before register allocation
  874. Revision 1.30 2003/01/08 18:43:57 daniel
  875. * Tregister changed into a record
  876. Revision 1.29 2002/12/24 18:10:34 peter
  877. * Long symbol names support
  878. Revision 1.28 2002/11/17 16:31:59 carl
  879. * memory optimization (3-4%) : cleanup of tai fields,
  880. cleanup of tdef and tsym fields.
  881. * make it work for m68k
  882. Revision 1.27 2002/11/15 01:58:56 peter
  883. * merged changes from 1.0.7 up to 04-11
  884. - -V option for generating bug report tracing
  885. - more tracing for option parsing
  886. - errors for cdecl and high()
  887. - win32 import stabs
  888. - win32 records<=8 are returned in eax:edx (turned off by default)
  889. - heaptrc update
  890. - more info for temp management in .s file with EXTDEBUG
  891. Revision 1.26 2002/08/18 20:06:28 peter
  892. * inlining is now also allowed in interface
  893. * renamed write/load to ppuwrite/ppuload
  894. * tnode storing in ppu
  895. * nld,ncon,nbas are already updated for storing in ppu
  896. Revision 1.25 2002/08/12 15:08:41 carl
  897. + stab register indexes for powerpc (moved from gdb to cpubase)
  898. + tprocessor enumeration moved to cpuinfo
  899. + linker in target_info is now a class
  900. * many many updates for m68k (will soon start to compile)
  901. - removed some ifdef or correct them for correct cpu
  902. Revision 1.24 2002/08/11 14:32:29 peter
  903. * renamed current_library to objectlibrary
  904. Revision 1.23 2002/08/11 13:24:16 peter
  905. * saving of asmsymbols in ppu supported
  906. * asmsymbollist global is removed and moved into a new class
  907. tasmlibrarydata that will hold the info of a .a file which
  908. corresponds with a single module. Added librarydata to tmodule
  909. to keep the library info stored for the module. In the future the
  910. objectfiles will also be stored to the tasmlibrarydata class
  911. * all getlabel/newasmsymbol and friends are moved to the new class
  912. Revision 1.22 2002/07/26 21:15:43 florian
  913. * rewrote the system handling
  914. Revision 1.21 2002/07/01 18:46:29 peter
  915. * internal linker
  916. * reorganized aasm layer
  917. Revision 1.20 2002/05/18 13:34:21 peter
  918. * readded missing revisions
  919. Revision 1.19 2002/05/16 19:46:50 carl
  920. + defines.inc -> fpcdefs.inc to avoid conflicts if compiling by hand
  921. + try to fix temp allocation (still in ifdef)
  922. + generic constructor calls
  923. + start of tassembler / tmodulebase class cleanup
  924. Revision 1.17 2002/05/12 16:53:16 peter
  925. * moved entry and exitcode to ncgutil and cgobj
  926. * foreach gets extra argument for passing local data to the
  927. iterator function
  928. * -CR checks also class typecasts at runtime by changing them
  929. into as
  930. * fixed compiler to cycle with the -CR option
  931. * fixed stabs with elf writer, finally the global variables can
  932. be watched
  933. * removed a lot of routines from cga unit and replaced them by
  934. calls to cgobj
  935. * u32bit-s32bit updates for and,or,xor nodes. When one element is
  936. u32bit then the other is typecasted also to u32bit without giving
  937. a rangecheck warning/error.
  938. * fixed pascal calling method with reversing also the high tree in
  939. the parast, detected by tcalcst3 test
  940. Revision 1.16 2002/04/15 19:12:09 carl
  941. + target_info.size_of_pointer -> pointer_size
  942. + some cleanup of unused types/variables
  943. * move several constants from cpubase to their specific units
  944. (where they are used)
  945. + att_Reg2str -> gas_reg2str
  946. + int_reg2str -> std_reg2str
  947. Revision 1.15 2002/04/14 16:58:41 carl
  948. + att_reg2str -> gas_reg2str
  949. Revision 1.14 2002/04/04 18:27:37 carl
  950. + added wdosx support (patch from Pavel)
  951. Revision 1.13 2002/04/02 17:11:33 peter
  952. * tlocation,treference update
  953. * LOC_CONSTANT added for better constant handling
  954. * secondadd splitted in multiple routines
  955. * location_force_reg added for loading a location to a register
  956. of a specified size
  957. * secondassignment parses now first the right and then the left node
  958. (this is compatible with Kylix). This saves a lot of push/pop especially
  959. with string operations
  960. * adapted some routines to use the new cg methods
  961. }