ag386int.pas 37 KB

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