ag386int.pas 38 KB

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