ag386int.pas 36 KB

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