ag386int.pas 34 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943
  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 aasmbase,aasmtai,aasmcpu,assemble;
  25. type
  26. T386IntelAssembler = class(TExternalAssembler)
  27. procedure WriteTree(p:TAAsmoutput);override;
  28. procedure WriteAsmList;override;
  29. Function DoAssemble:boolean;override;
  30. procedure WriteExternals;
  31. end;
  32. implementation
  33. uses
  34. {$ifdef delphi}
  35. sysutils,
  36. {$endif}
  37. cutils,globtype,globals,systems,cclasses,
  38. verbose,cpubase,finput,fmodule,script,cpuinfo
  39. ;
  40. const
  41. line_length = 70;
  42. function single2str(d : single) : string;
  43. var
  44. hs : string;
  45. p : byte;
  46. begin
  47. str(d,hs);
  48. { nasm expects a lowercase e }
  49. p:=pos('E',hs);
  50. if p>0 then
  51. hs[p]:='e';
  52. p:=pos('+',hs);
  53. if p>0 then
  54. delete(hs,p,1);
  55. single2str:=lower(hs);
  56. end;
  57. function double2str(d : double) : string;
  58. var
  59. hs : string;
  60. p : byte;
  61. begin
  62. str(d,hs);
  63. { nasm expects a lowercase e }
  64. p:=pos('E',hs);
  65. if p>0 then
  66. hs[p]:='e';
  67. p:=pos('+',hs);
  68. if p>0 then
  69. delete(hs,p,1);
  70. double2str:=lower(hs);
  71. end;
  72. function extended2str(e : extended) : string;
  73. var
  74. hs : string;
  75. p : byte;
  76. begin
  77. str(e,hs);
  78. { nasm expects a lowercase e }
  79. p:=pos('E',hs);
  80. if p>0 then
  81. hs[p]:='e';
  82. p:=pos('+',hs);
  83. if p>0 then
  84. delete(hs,p,1);
  85. extended2str:=lower(hs);
  86. end;
  87. function comp2str(d : bestreal) : string;
  88. type
  89. pdouble = ^double;
  90. var
  91. c : comp;
  92. dd : pdouble;
  93. begin
  94. {$ifdef FPC}
  95. c:=comp(d);
  96. {$else}
  97. c:=d;
  98. {$endif}
  99. dd:=pdouble(@c); { this makes a bitwise copy of c into a double }
  100. comp2str:=double2str(dd^);
  101. end;
  102. function getreferencestring(var ref : treference) : string;
  103. var
  104. s : string;
  105. first : boolean;
  106. begin
  107. with ref do
  108. begin
  109. first:=true;
  110. inc(offset,offsetfixup);
  111. offsetfixup:=0;
  112. if ref.segment<>R_NO then
  113. s:=std_reg2str[segment]+':['
  114. else
  115. s:='[';
  116. if assigned(symbol) then
  117. begin
  118. if (aktoutputformat = as_i386_tasm) then
  119. s:=s+'dword ptr ';
  120. s:=s+symbol.name;
  121. first:=false;
  122. end;
  123. if (base<>R_NO) then
  124. begin
  125. if not(first) then
  126. s:=s+'+'
  127. else
  128. first:=false;
  129. s:=s+std_reg2str[base];
  130. end;
  131. if (index<>R_NO) then
  132. begin
  133. if not(first) then
  134. s:=s+'+'
  135. else
  136. first:=false;
  137. s:=s+std_reg2str[index];
  138. if scalefactor<>0 then
  139. s:=s+'*'+tostr(scalefactor);
  140. end;
  141. if offset<0 then
  142. s:=s+tostr(offset)
  143. else if (offset>0) then
  144. s:=s+'+'+tostr(offset);
  145. if s[length(s)]='[' then
  146. s:=s+'0';
  147. s:=s+']';
  148. end;
  149. getreferencestring:=s;
  150. end;
  151. function getopstr(const o:toper;s : topsize; opcode: tasmop;dest : boolean) : string;
  152. var
  153. hs : string;
  154. begin
  155. case o.typ of
  156. top_reg :
  157. getopstr:=std_reg2str[o.reg];
  158. top_const :
  159. getopstr:=tostr(longint(o.val));
  160. top_symbol :
  161. begin
  162. if assigned(o.sym) then
  163. hs:='offset '+o.sym.name
  164. else
  165. hs:='offset ';
  166. if o.symofs>0 then
  167. hs:=hs+'+'+tostr(o.symofs)
  168. else
  169. if o.symofs<0 then
  170. hs:=hs+tostr(o.symofs)
  171. else
  172. if not(assigned(o.sym)) then
  173. hs:=hs+'0';
  174. getopstr:=hs;
  175. end;
  176. top_ref :
  177. begin
  178. hs:=getreferencestring(o.ref^);
  179. if ((opcode <> A_LGS) and (opcode <> A_LSS) and
  180. (opcode <> A_LFS) and (opcode <> A_LDS) and
  181. (opcode <> A_LES)) then
  182. Begin
  183. case s of
  184. S_B : hs:='byte ptr '+hs;
  185. S_W : hs:='word ptr '+hs;
  186. S_L : hs:='dword ptr '+hs;
  187. S_IS : hs:='word ptr '+hs;
  188. S_IL : hs:='dword ptr '+hs;
  189. S_IQ : hs:='qword ptr '+hs;
  190. S_FS : hs:='dword ptr '+hs;
  191. S_FL : hs:='qword ptr '+hs;
  192. S_FX : hs:='tbyte ptr '+hs;
  193. S_BW : if dest then
  194. hs:='word ptr '+hs
  195. else
  196. hs:='byte ptr '+hs;
  197. S_BL : if dest then
  198. hs:='dword ptr '+hs
  199. else
  200. hs:='byte ptr '+hs;
  201. S_WL : if dest then
  202. hs:='dword ptr '+hs
  203. else
  204. hs:='word ptr '+hs;
  205. end;
  206. end;
  207. getopstr:=hs;
  208. end;
  209. else
  210. internalerror(10001);
  211. end;
  212. end;
  213. function getopstr_jmp(const o:toper;s : topsize) : string;
  214. var
  215. hs : string;
  216. begin
  217. case o.typ of
  218. top_reg :
  219. getopstr_jmp:=std_reg2str[o.reg];
  220. top_const :
  221. getopstr_jmp:=tostr(longint(o.val));
  222. top_symbol :
  223. begin
  224. hs:=o.sym.name;
  225. if o.symofs>0 then
  226. hs:=hs+'+'+tostr(o.symofs)
  227. else
  228. if o.symofs<0 then
  229. hs:=hs+tostr(o.symofs);
  230. getopstr_jmp:=hs;
  231. end;
  232. top_ref :
  233. { what about lcall or ljmp ??? }
  234. begin
  235. if (aktoutputformat = as_i386_tasm) then
  236. hs:=''
  237. else
  238. begin
  239. if s=S_FAR then
  240. hs:='far ptr '
  241. else
  242. hs:='dword ptr ';
  243. end;
  244. getopstr_jmp:=hs+getreferencestring(o.ref^);
  245. end;
  246. else
  247. internalerror(10001);
  248. end;
  249. end;
  250. function fixline(s:string):string;
  251. {
  252. return s with all leading and ending spaces and tabs removed
  253. }
  254. var
  255. i,j,k : longint;
  256. begin
  257. i:=length(s);
  258. while (i>0) and (s[i] in [#9,' ']) do
  259. dec(i);
  260. j:=1;
  261. while (j<i) and (s[j] in [#9,' ']) do
  262. inc(j);
  263. for k:=j to i do
  264. if s[k] in [#0..#31,#127..#255] then
  265. s[k]:='.';
  266. fixline:=Copy(s,j,i-j+1);
  267. end;
  268. {****************************************************************************
  269. T386IntelAssembler
  270. ****************************************************************************}
  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. sep : char;
  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. { We need intel order, no At&t }
  561. taicpu(hp).SetOperandOrder(op_intel);
  562. { Reset }
  563. suffix:='';
  564. prefix:= '';
  565. s:='';
  566. { We need to explicitely set
  567. word prefix to get selectors
  568. to be pushed in 2 bytes PM }
  569. if (taicpu(hp).opsize=S_W) and
  570. ((taicpu(hp).opcode=A_PUSH) or
  571. (taicpu(hp).opcode=A_POP)) and
  572. (taicpu(hp).oper[0].typ=top_reg) and
  573. ((taicpu(hp).oper[0].reg>=firstsreg) and
  574. (taicpu(hp).oper[0].reg<=lastsreg)) 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. s:=#9#9+prefix;
  591. AsmWriteLn(s);
  592. break;
  593. end;
  594. { nasm prefers prefix on a line alone
  595. AsmWriteln(#9#9+prefix); but not masm PM
  596. prefix:=''; }
  597. if (aktoutputformat = as_i386_masm) then
  598. begin
  599. AsmWriteln(s);
  600. prefix:='';
  601. end;
  602. end
  603. else
  604. prefix:= '';
  605. if taicpu(hp).ops<>0 then
  606. begin
  607. if is_calljmp(taicpu(hp).opcode) then
  608. s:=#9+getopstr_jmp(taicpu(hp).oper[0],taicpu(hp).opsize)
  609. else
  610. begin
  611. for i:=0to taicpu(hp).ops-1 do
  612. begin
  613. if i=0 then
  614. sep:=#9
  615. else
  616. sep:=',';
  617. s:=s+sep+getopstr(taicpu(hp).oper[i],taicpu(hp).opsize,taicpu(hp).opcode,(i=2));
  618. end;
  619. end;
  620. end;
  621. AsmWriteLn(#9#9+prefix+std_op2str[taicpu(hp).opcode]+cond2str[taicpu(hp).condition]+suffix+s);
  622. end;
  623. {$ifdef GDB}
  624. ait_stabn,
  625. ait_stabs,
  626. ait_force_line,
  627. ait_stab_function_name : ;
  628. {$endif GDB}
  629. ait_cut : begin
  630. { only reset buffer if nothing has changed }
  631. if AsmSize=AsmStartSize then
  632. AsmClear
  633. else
  634. begin
  635. if LasTSec<>sec_none then
  636. AsmWriteLn('_'+target_asm.secnames[LasTSec]+#9#9'ENDS');
  637. AsmLn;
  638. AsmWriteLn(#9'END');
  639. AsmClose;
  640. DoAssemble;
  641. AsmCreate(tai_cut(hp).place);
  642. end;
  643. { avoid empty files }
  644. while assigned(hp.next) and (tai(hp.next).typ in [ait_cut,ait_section,ait_comment]) do
  645. begin
  646. if tai(hp.next).typ=ait_section then
  647. begin
  648. lasTSec:=tai_section(hp.next).sec;
  649. end;
  650. hp:=tai(hp.next);
  651. end;
  652. AsmWriteLn(#9'.386p');
  653. AsmWriteLn('DGROUP'#9'GROUP'#9'_BSS,_DATA');
  654. AsmWriteLn(#9'ASSUME'#9'CS:_CODE,ES:DGROUP,DS:DGROUP,SS:DGROUP');
  655. { I was told that this isn't necesarry because }
  656. { the labels generated by FPC are unique (FK) }
  657. { AsmWriteLn(#9'LOCALS '+target_asm.labelprefix); }
  658. if lasTSec<>sec_none then
  659. AsmWriteLn('_'+target_asm.secnames[lasTSec]+#9#9+
  660. 'SEGMENT'#9'PARA PUBLIC USE32 '''+
  661. target_asm.secnames[lasTSec]+'''');
  662. AsmStartSize:=AsmSize;
  663. end;
  664. ait_marker :
  665. begin
  666. if tai_marker(hp).kind=InlineStart then
  667. inc(InlineLevel)
  668. else if tai_marker(hp).kind=InlineEnd then
  669. dec(InlineLevel);
  670. end;
  671. else
  672. internalerror(10000);
  673. end;
  674. hp:=tai(hp.next);
  675. end;
  676. end;
  677. var
  678. currentasmlist : TExternalAssembler;
  679. procedure writeexternal(p:tnamedindexitem;arg:pointer);
  680. begin
  681. if tasmsymbol(p).defbind=AB_EXTERNAL then
  682. begin
  683. if (aktoutputformat = as_i386_masm) then
  684. currentasmlist.AsmWriteln(#9'EXTRN'#9+p.name
  685. +': NEAR')
  686. else
  687. currentasmlist.AsmWriteln(#9'EXTRN'#9+p.name);
  688. end;
  689. end;
  690. procedure T386IntelAssembler.WriteExternals;
  691. begin
  692. currentasmlist:=self;
  693. objectlibrary.symbolsearch.foreach_static({$ifdef fpcprocvar}@{$endif}writeexternal,nil);
  694. end;
  695. function t386intelassembler.DoAssemble : boolean;
  696. var f : file;
  697. begin
  698. DoAssemble:=Inherited DoAssemble;
  699. { masm does not seem to recognize specific extensions and uses .obj allways PM }
  700. if (aktoutputformat = as_i386_masm) then
  701. begin
  702. if not(cs_asm_extern in aktglobalswitches) then
  703. begin
  704. if Not FileExists(objfile) and
  705. FileExists(ForceExtension(objfile,'.obj')) then
  706. begin
  707. Assign(F,ForceExtension(objfile,'.obj'));
  708. Rename(F,objfile);
  709. end;
  710. end
  711. else
  712. AsmRes.AddAsmCommand('mv',ForceExtension(objfile,'.obj')+' '+objfile,objfile);
  713. end;
  714. end;
  715. procedure T386IntelAssembler.WriteAsmList;
  716. begin
  717. {$ifdef EXTDEBUG}
  718. if assigned(current_module.mainsource) then
  719. comment(v_info,'Start writing intel-styled assembler output for '+current_module.mainsource^);
  720. {$endif}
  721. LasTSec:=sec_none;
  722. AsmWriteLn(#9'.386p');
  723. { masm 6.11 does not seem to like LOCALS PM }
  724. if (aktoutputformat = as_i386_tasm) then
  725. begin
  726. AsmWriteLn(#9'LOCALS '+target_asm.labelprefix);
  727. end;
  728. AsmWriteLn('DGROUP'#9'GROUP'#9'_BSS,_DATA');
  729. AsmWriteLn(#9'ASSUME'#9'CS:_CODE,ES:DGROUP,DS:DGROUP,SS:DGROUP');
  730. AsmLn;
  731. WriteExternals;
  732. { INTEL ASM doesn't support stabs
  733. WriteTree(debuglist);}
  734. WriteTree(codesegment);
  735. WriteTree(datasegment);
  736. WriteTree(consts);
  737. WriteTree(rttilist);
  738. WriteTree(resourcestringlist);
  739. WriteTree(bsssegment);
  740. AsmWriteLn(#9'END');
  741. AsmLn;
  742. {$ifdef EXTDEBUG}
  743. if assigned(current_module.mainsource) then
  744. comment(v_info,'Done writing intel-styled assembler output for '+current_module.mainsource^);
  745. {$endif EXTDEBUG}
  746. end;
  747. {*****************************************************************************
  748. Initialize
  749. *****************************************************************************}
  750. const
  751. as_i386_tasm_info : tasminfo =
  752. (
  753. id : as_i386_tasm;
  754. idtxt : 'TASM';
  755. asmbin : 'tasm';
  756. asmcmd : '/m2 /ml $ASM $OBJ';
  757. supported_target : system_any; { what should I write here ?? }
  758. outputbinary: false;
  759. allowdirect : true;
  760. needar : true;
  761. labelprefix_only_inside_procedure : true;
  762. labelprefix : '@@';
  763. comment : '; ';
  764. secnames : ('',
  765. 'CODE','DATA','BSS',
  766. '','','','','','',
  767. '','','')
  768. );
  769. as_i386_masm_info : tasminfo =
  770. (
  771. id : as_i386_masm;
  772. idtxt : 'MASM';
  773. asmbin : 'masm';
  774. asmcmd : '/c /Cp $ASM /Fo$OBJ';
  775. supported_target : system_any; { what should I write here ?? }
  776. outputbinary: false;
  777. allowdirect : true;
  778. needar : true;
  779. labelprefix_only_inside_procedure : false;
  780. labelprefix : '@@';
  781. comment : '; ';
  782. secnames : ('',
  783. 'CODE','DATA','BSS',
  784. '','','','','','',
  785. '','','')
  786. );
  787. initialization
  788. RegisterAssembler(as_i386_tasm_info,T386IntelAssembler);
  789. RegisterAssembler(as_i386_masm_info,T386IntelAssembler);
  790. end.
  791. {
  792. $Log$
  793. Revision 1.30 2002-11-17 16:31:58 carl
  794. * memory optimization (3-4%) : cleanup of tai fields,
  795. cleanup of tdef and tsym fields.
  796. * make it work for m68k
  797. Revision 1.29 2002/11/15 01:58:56 peter
  798. * merged changes from 1.0.7 up to 04-11
  799. - -V option for generating bug report tracing
  800. - more tracing for option parsing
  801. - errors for cdecl and high()
  802. - win32 import stabs
  803. - win32 records<=8 are returned in eax:edx (turned off by default)
  804. - heaptrc update
  805. - more info for temp management in .s file with EXTDEBUG
  806. Revision 1.28 2002/08/20 21:40:44 florian
  807. + target macos for ppc added
  808. + frame work for mpw assembler output
  809. Revision 1.27 2002/08/18 20:06:28 peter
  810. * inlining is now also allowed in interface
  811. * renamed write/load to ppuwrite/ppuload
  812. * tnode storing in ppu
  813. * nld,ncon,nbas are already updated for storing in ppu
  814. Revision 1.26 2002/08/12 15:08:41 carl
  815. + stab register indexes for powerpc (moved from gdb to cpubase)
  816. + tprocessor enumeration moved to cpuinfo
  817. + linker in target_info is now a class
  818. * many many updates for m68k (will soon start to compile)
  819. - removed some ifdef or correct them for correct cpu
  820. Revision 1.25 2002/08/11 14:32:29 peter
  821. * renamed current_library to objectlibrary
  822. Revision 1.24 2002/08/11 13:24:16 peter
  823. * saving of asmsymbols in ppu supported
  824. * asmsymbollist global is removed and moved into a new class
  825. tasmlibrarydata that will hold the info of a .a file which
  826. corresponds with a single module. Added librarydata to tmodule
  827. to keep the library info stored for the module. In the future the
  828. objectfiles will also be stored to the tasmlibrarydata class
  829. * all getlabel/newasmsymbol and friends are moved to the new class
  830. Revision 1.23 2002/07/26 21:15:43 florian
  831. * rewrote the system handling
  832. Revision 1.22 2002/07/01 18:46:29 peter
  833. * internal linker
  834. * reorganized aasm layer
  835. Revision 1.21 2002/05/18 13:34:21 peter
  836. * readded missing revisions
  837. Revision 1.20 2002/05/16 19:46:50 carl
  838. + defines.inc -> fpcdefs.inc to avoid conflicts if compiling by hand
  839. + try to fix temp allocation (still in ifdef)
  840. + generic constructor calls
  841. + start of tassembler / tmodulebase class cleanup
  842. Revision 1.18 2002/05/12 16:53:16 peter
  843. * moved entry and exitcode to ncgutil and cgobj
  844. * foreach gets extra argument for passing local data to the
  845. iterator function
  846. * -CR checks also class typecasts at runtime by changing them
  847. into as
  848. * fixed compiler to cycle with the -CR option
  849. * fixed stabs with elf writer, finally the global variables can
  850. be watched
  851. * removed a lot of routines from cga unit and replaced them by
  852. calls to cgobj
  853. * u32bit-s32bit updates for and,or,xor nodes. When one element is
  854. u32bit then the other is typecasted also to u32bit without giving
  855. a rangecheck warning/error.
  856. * fixed pascal calling method with reversing also the high tree in
  857. the parast, detected by tcalcst3 test
  858. Revision 1.17 2002/04/15 19:12:09 carl
  859. + target_info.size_of_pointer -> pointer_size
  860. + some cleanup of unused types/variables
  861. * move several constants from cpubase to their specific units
  862. (where they are used)
  863. + att_Reg2str -> gas_reg2str
  864. + int_reg2str -> std_reg2str
  865. Revision 1.16 2002/04/04 19:06:07 peter
  866. * removed unused units
  867. * use tlocation.size in cg.a_*loc*() routines
  868. Revision 1.15 2002/04/02 17:11:33 peter
  869. * tlocation,treference update
  870. * LOC_CONSTANT added for better constant handling
  871. * secondadd splitted in multiple routines
  872. * location_force_reg added for loading a location to a register
  873. of a specified size
  874. * secondassignment parses now first the right and then the left node
  875. (this is compatible with Kylix). This saves a lot of push/pop especially
  876. with string operations
  877. * adapted some routines to use the new cg methods
  878. }