ag386int.pas 34 KB

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