ag386nsm.pas 35 KB

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