ag386nsm.pas 36 KB

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