ag386int.pas 34 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942
  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. nolinetai =[ait_label,
  301. ait_regalloc,ait_tempalloc,
  302. {$ifdef GDB}
  303. ait_stabn,ait_stabs,ait_stab_function_name,
  304. {$endif GDB}
  305. ait_cut,ait_marker,ait_align,ait_section];
  306. var
  307. s,
  308. prefix,
  309. suffix : string;
  310. hp : tai;
  311. counter,
  312. lines,
  313. InlineLevel : longint;
  314. i,j,l : longint;
  315. consttyp : taitype;
  316. found,
  317. do_line,DoNotSplitLine,
  318. quoted : boolean;
  319. sep : char;
  320. begin
  321. if not assigned(p) then
  322. exit;
  323. { lineinfo is only needed for codesegment (PFV) }
  324. do_line:=((cs_asm_source in aktglobalswitches) or
  325. (cs_lineinfo in aktmoduleswitches))
  326. and (p=codesegment);
  327. InlineLevel:=0;
  328. DoNotSplitLine:=false;
  329. hp:=tai(p.first);
  330. while assigned(hp) do
  331. begin
  332. if do_line and not(hp.typ in nolinetai) and
  333. not DoNotSplitLine then
  334. begin
  335. { load infile }
  336. if lastfileinfo.fileindex<>hp.fileinfo.fileindex then
  337. begin
  338. infile:=current_module.sourcefiles.get_file(hp.fileinfo.fileindex);
  339. if assigned(infile) then
  340. begin
  341. { open only if needed !! }
  342. if (cs_asm_source in aktglobalswitches) then
  343. infile.open;
  344. end;
  345. { avoid unnecessary reopens of the same file !! }
  346. lastfileinfo.fileindex:=hp.fileinfo.fileindex;
  347. { be sure to change line !! }
  348. lastfileinfo.line:=-1;
  349. end;
  350. { write source }
  351. if (cs_asm_source in aktglobalswitches) and
  352. assigned(infile) then
  353. begin
  354. if (infile<>lastinfile) then
  355. begin
  356. AsmWriteLn(target_asm.comment+'['+infile.name^+']');
  357. if assigned(lastinfile) then
  358. lastinfile.close;
  359. end;
  360. if (hp.fileinfo.line<>lastfileinfo.line) and
  361. ((hp.fileinfo.line<infile.maxlinebuf) or (InlineLevel>0)) then
  362. begin
  363. if (hp.fileinfo.line<>0) and
  364. ((infile.linebuf^[hp.fileinfo.line]>=0) or (InlineLevel>0)) then
  365. AsmWriteLn(target_asm.comment+'['+tostr(hp.fileinfo.line)+'] '+
  366. fixline(infile.GetLineStr(hp.fileinfo.line)));
  367. { set it to a negative value !
  368. to make that is has been read already !! PM }
  369. if (infile.linebuf^[hp.fileinfo.line]>=0) then
  370. infile.linebuf^[hp.fileinfo.line]:=-infile.linebuf^[hp.fileinfo.line]-1;
  371. end;
  372. end;
  373. lastfileinfo:=hp.fileinfo;
  374. lastinfile:=infile;
  375. end;
  376. DoNotSplitLine:=false;
  377. case hp.typ of
  378. ait_comment : Begin
  379. AsmWrite(target_asm.comment);
  380. AsmWritePChar(tai_comment(hp).str);
  381. AsmLn;
  382. End;
  383. ait_regalloc :
  384. begin
  385. if (cs_asm_regalloc in aktglobalswitches) then
  386. AsmWriteLn(target_asm.comment+'Register '+std_reg2str[tai_regalloc(hp).reg]+
  387. allocstr[tai_regalloc(hp).allocation]);
  388. end;
  389. ait_tempalloc :
  390. begin
  391. if (cs_asm_tempalloc in aktglobalswitches) then
  392. begin
  393. {$ifdef EXTDEBUG}
  394. if assigned(tai_tempalloc(hp).problem) then
  395. AsmWriteLn(target_asm.comment+tai_tempalloc(hp).problem^+' ('+tostr(tai_tempalloc(hp).temppos)+','+
  396. tostr(tai_tempalloc(hp).tempsize)+')')
  397. else
  398. {$endif EXTDEBUG}
  399. AsmWriteLn(target_asm.comment+'Temp '+tostr(tai_tempalloc(hp).temppos)+','+
  400. tostr(tai_tempalloc(hp).tempsize)+allocstr[tai_tempalloc(hp).allocation]);
  401. end;
  402. end;
  403. ait_section : begin
  404. if LasTSec<>sec_none then
  405. AsmWriteLn('_'+target_asm.secnames[LasTSec]+#9#9'ENDS');
  406. if tai_section(hp).sec<>sec_none then
  407. begin
  408. AsmLn;
  409. AsmWriteLn('_'+target_asm.secnames[tai_section(hp).sec]+#9#9+
  410. 'SEGMENT'#9'PARA PUBLIC USE32 '''+
  411. target_asm.secnames[tai_section(hp).sec]+'''');
  412. end;
  413. LasTSec:=tai_section(hp).sec;
  414. end;
  415. ait_align : begin
  416. { CAUSES PROBLEMS WITH THE SEGMENT DEFINITION }
  417. { SEGMENT DEFINITION SHOULD MATCH TYPE OF ALIGN }
  418. { HERE UNDER TASM! }
  419. AsmWriteLn(#9'ALIGN '+tostr(tai_align(hp).aligntype));
  420. end;
  421. ait_datablock : begin
  422. if tai_datablock(hp).is_global then
  423. AsmWriteLn(#9'PUBLIC'#9+tai_datablock(hp).sym.name);
  424. AsmWriteLn(PadTabs(tai_datablock(hp).sym.name,#0)+'DB'#9+tostr(tai_datablock(hp).size)+' DUP(?)');
  425. end;
  426. ait_const_32bit,
  427. ait_const_8bit,
  428. ait_const_16bit : begin
  429. AsmWrite(ait_const2str[hp.typ]+tostr(tai_const(hp).value));
  430. consttyp:=hp.typ;
  431. l:=0;
  432. repeat
  433. found:=(not (tai(hp.next)=nil)) and (tai(hp.next).typ=consttyp);
  434. if found then
  435. begin
  436. hp:=tai(hp.next);
  437. s:=','+tostr(tai_const(hp).value);
  438. AsmWrite(s);
  439. inc(l,length(s));
  440. end;
  441. until (not found) or (l>line_length);
  442. AsmLn;
  443. end;
  444. ait_const_symbol : begin
  445. AsmWriteLn(#9#9'DD'#9'offset '+tai_const_symbol(hp).sym.name);
  446. if tai_const_symbol(hp).offset>0 then
  447. AsmWrite('+'+tostr(tai_const_symbol(hp).offset))
  448. else if tai_const_symbol(hp).offset<0 then
  449. AsmWrite(tostr(tai_const_symbol(hp).offset));
  450. AsmLn;
  451. end;
  452. ait_const_rva : begin
  453. AsmWriteLn(#9#9'RVA'#9+tai_const_symbol(hp).sym.name);
  454. end;
  455. ait_real_32bit : AsmWriteLn(#9#9'DD'#9+single2str(tai_real_32bit(hp).value));
  456. ait_real_64bit : AsmWriteLn(#9#9'DQ'#9+double2str(tai_real_64bit(hp).value));
  457. ait_real_80bit : AsmWriteLn(#9#9'DT'#9+extended2str(tai_real_80bit(hp).value));
  458. ait_comp_64bit : AsmWriteLn(#9#9'DQ'#9+comp2str(tai_real_80bit(hp).value));
  459. ait_string : begin
  460. counter := 0;
  461. lines := tai_string(hp).len div line_length;
  462. { separate lines in different parts }
  463. if tai_string(hp).len > 0 then
  464. Begin
  465. for j := 0 to lines-1 do
  466. begin
  467. AsmWrite(#9#9'DB'#9);
  468. quoted:=false;
  469. for i:=counter to counter+line_length do
  470. begin
  471. { it is an ascii character. }
  472. if (ord(tai_string(hp).str[i])>31) and
  473. (ord(tai_string(hp).str[i])<128) and
  474. (tai_string(hp).str[i]<>'"') then
  475. begin
  476. if not(quoted) then
  477. begin
  478. if i>counter then
  479. AsmWrite(',');
  480. AsmWrite('"');
  481. end;
  482. AsmWrite(tai_string(hp).str[i]);
  483. quoted:=true;
  484. end { if > 31 and < 128 and ord('"') }
  485. else
  486. begin
  487. if quoted then
  488. AsmWrite('"');
  489. if i>counter then
  490. AsmWrite(',');
  491. quoted:=false;
  492. AsmWrite(tostr(ord(tai_string(hp).str[i])));
  493. end;
  494. end; { end for i:=0 to... }
  495. if quoted then AsmWrite('"');
  496. AsmWrite(target_info.newline);
  497. counter := counter+line_length;
  498. end; { end for j:=0 ... }
  499. { do last line of lines }
  500. AsmWrite(#9#9'DB'#9);
  501. quoted:=false;
  502. for i:=counter to tai_string(hp).len-1 do
  503. begin
  504. { it is an ascii character. }
  505. if (ord(tai_string(hp).str[i])>31) and
  506. (ord(tai_string(hp).str[i])<128) and
  507. (tai_string(hp).str[i]<>'"') then
  508. begin
  509. if not(quoted) then
  510. begin
  511. if i>counter then
  512. AsmWrite(',');
  513. AsmWrite('"');
  514. end;
  515. AsmWrite(tai_string(hp).str[i]);
  516. quoted:=true;
  517. end { if > 31 and < 128 and " }
  518. else
  519. begin
  520. if quoted then
  521. AsmWrite('"');
  522. if i>counter then
  523. AsmWrite(',');
  524. quoted:=false;
  525. AsmWrite(tostr(ord(tai_string(hp).str[i])));
  526. end;
  527. end; { end for i:=0 to... }
  528. if quoted then
  529. AsmWrite('"');
  530. end;
  531. AsmLn;
  532. end;
  533. ait_label : begin
  534. if tai_label(hp).l.is_used then
  535. begin
  536. AsmWrite(tai_label(hp).l.name);
  537. if assigned(hp.next) and not(tai(hp.next).typ in
  538. [ait_const_32bit,ait_const_16bit,ait_const_8bit,
  539. ait_const_symbol,ait_const_rva,
  540. ait_real_32bit,ait_real_64bit,ait_real_80bit,ait_comp_64bit,ait_string]) then
  541. AsmWriteLn(':')
  542. else
  543. DoNotSplitLine:=true;
  544. end;
  545. end;
  546. ait_direct : begin
  547. AsmWritePChar(tai_direct(hp).str);
  548. AsmLn;
  549. end;
  550. ait_symbol : begin
  551. if tai_symbol(hp).is_global then
  552. AsmWriteLn(#9'PUBLIC'#9+tai_symbol(hp).sym.name);
  553. AsmWrite(tai_symbol(hp).sym.name);
  554. if assigned(hp.next) and not(tai(hp.next).typ in
  555. [ait_const_32bit,ait_const_16bit,ait_const_8bit,
  556. ait_const_symbol,ait_const_rva,
  557. ait_real_32bit,ait_real_64bit,ait_real_80bit,ait_comp_64bit,ait_string]) then
  558. AsmWriteLn(':')
  559. end;
  560. ait_symbol_end : begin
  561. end;
  562. ait_instruction : begin
  563. taicpu(hp).CheckNonCommutativeOpcodes;
  564. { We need intel order, no At&t }
  565. taicpu(hp).SetOperandOrder(op_intel);
  566. { Reset }
  567. suffix:='';
  568. prefix:= '';
  569. s:='';
  570. { We need to explicitely set
  571. word prefix to get selectors
  572. to be pushed in 2 bytes PM }
  573. if (taicpu(hp).opsize=S_W) and
  574. ((taicpu(hp).opcode=A_PUSH) or
  575. (taicpu(hp).opcode=A_POP)) and
  576. (taicpu(hp).oper[0].typ=top_reg) and
  577. ((taicpu(hp).oper[0].reg>=firstsreg) and
  578. (taicpu(hp).oper[0].reg<=lastsreg)) then
  579. AsmWriteln(#9#9'DB'#9'066h');
  580. { added prefix instructions, must be on same line as opcode }
  581. if (taicpu(hp).ops = 0) and
  582. ((taicpu(hp).opcode = A_REP) or
  583. (taicpu(hp).opcode = A_LOCK) or
  584. (taicpu(hp).opcode = A_REPE) or
  585. (taicpu(hp).opcode = A_REPNZ) or
  586. (taicpu(hp).opcode = A_REPZ) or
  587. (taicpu(hp).opcode = A_REPNE)) then
  588. Begin
  589. prefix:=std_op2str[taicpu(hp).opcode]+#9;
  590. hp:=tai(hp.next);
  591. { this is theorically impossible... }
  592. if hp=nil then
  593. begin
  594. s:=#9#9+prefix;
  595. AsmWriteLn(s);
  596. break;
  597. end;
  598. { nasm prefers prefix on a line alone
  599. AsmWriteln(#9#9+prefix); but not masm PM
  600. prefix:=''; }
  601. if (aktoutputformat = as_i386_masm) then
  602. begin
  603. AsmWriteln(s);
  604. prefix:='';
  605. end;
  606. end
  607. else
  608. prefix:= '';
  609. if taicpu(hp).ops<>0 then
  610. begin
  611. if is_calljmp(taicpu(hp).opcode) then
  612. s:=#9+getopstr_jmp(taicpu(hp).oper[0],taicpu(hp).opsize)
  613. else
  614. begin
  615. for i:=0to taicpu(hp).ops-1 do
  616. begin
  617. if i=0 then
  618. sep:=#9
  619. else
  620. sep:=',';
  621. s:=s+sep+getopstr(taicpu(hp).oper[i],taicpu(hp).opsize,taicpu(hp).opcode,(i=2));
  622. end;
  623. end;
  624. end;
  625. AsmWriteLn(#9#9+prefix+std_op2str[taicpu(hp).opcode]+cond2str[taicpu(hp).condition]+suffix+s);
  626. end;
  627. {$ifdef GDB}
  628. ait_stabn,
  629. ait_stabs,
  630. ait_force_line,
  631. ait_stab_function_name : ;
  632. {$endif GDB}
  633. ait_cut : begin
  634. { only reset buffer if nothing has changed }
  635. if AsmSize=AsmStartSize then
  636. AsmClear
  637. else
  638. begin
  639. if LasTSec<>sec_none then
  640. AsmWriteLn('_'+target_asm.secnames[LasTSec]+#9#9'ENDS');
  641. AsmLn;
  642. AsmWriteLn(#9'END');
  643. AsmClose;
  644. DoAssemble;
  645. AsmCreate(tai_cut(hp).place);
  646. end;
  647. { avoid empty files }
  648. while assigned(hp.next) and (tai(hp.next).typ in [ait_cut,ait_section,ait_comment]) do
  649. begin
  650. if tai(hp.next).typ=ait_section then
  651. begin
  652. lasTSec:=tai_section(hp.next).sec;
  653. end;
  654. hp:=tai(hp.next);
  655. end;
  656. AsmWriteLn(#9'.386p');
  657. AsmWriteLn('DGROUP'#9'GROUP'#9'_BSS,_DATA');
  658. AsmWriteLn(#9'ASSUME'#9'CS:_CODE,ES:DGROUP,DS:DGROUP,SS:DGROUP');
  659. { I was told that this isn't necesarry because }
  660. { the labels generated by FPC are unique (FK) }
  661. { AsmWriteLn(#9'LOCALS '+target_asm.labelprefix); }
  662. if lasTSec<>sec_none then
  663. AsmWriteLn('_'+target_asm.secnames[lasTSec]+#9#9+
  664. 'SEGMENT'#9'PARA PUBLIC USE32 '''+
  665. target_asm.secnames[lasTSec]+'''');
  666. AsmStartSize:=AsmSize;
  667. end;
  668. ait_marker :
  669. begin
  670. if tai_marker(hp).kind=InlineStart then
  671. inc(InlineLevel)
  672. else if tai_marker(hp).kind=InlineEnd then
  673. dec(InlineLevel);
  674. end;
  675. else
  676. internalerror(10000);
  677. end;
  678. hp:=tai(hp.next);
  679. end;
  680. end;
  681. var
  682. currentasmlist : TExternalAssembler;
  683. procedure writeexternal(p:tnamedindexitem;arg:pointer);
  684. begin
  685. if tasmsymbol(p).defbind=AB_EXTERNAL then
  686. begin
  687. if (aktoutputformat = as_i386_masm) then
  688. currentasmlist.AsmWriteln(#9'EXTRN'#9+p.name
  689. +': NEAR')
  690. else
  691. currentasmlist.AsmWriteln(#9'EXTRN'#9+p.name);
  692. end;
  693. end;
  694. procedure T386IntelAssembler.WriteExternals;
  695. begin
  696. currentasmlist:=self;
  697. objectlibrary.symbolsearch.foreach_static({$ifdef fpcprocvar}@{$endif}writeexternal,nil);
  698. end;
  699. function t386intelassembler.DoAssemble : boolean;
  700. var f : file;
  701. begin
  702. DoAssemble:=Inherited DoAssemble;
  703. { masm does not seem to recognize specific extensions and uses .obj allways PM }
  704. if (aktoutputformat = as_i386_masm) then
  705. begin
  706. if not(cs_asm_extern in aktglobalswitches) then
  707. begin
  708. if Not FileExists(objfile) and
  709. FileExists(ForceExtension(objfile,'.obj')) then
  710. begin
  711. Assign(F,ForceExtension(objfile,'.obj'));
  712. Rename(F,objfile);
  713. end;
  714. end
  715. else
  716. AsmRes.AddAsmCommand('mv',ForceExtension(objfile,'.obj')+' '+objfile,objfile);
  717. end;
  718. end;
  719. procedure T386IntelAssembler.WriteAsmList;
  720. begin
  721. {$ifdef EXTDEBUG}
  722. if assigned(current_module.mainsource) then
  723. comment(v_info,'Start writing intel-styled assembler output for '+current_module.mainsource^);
  724. {$endif}
  725. LasTSec:=sec_none;
  726. AsmWriteLn(#9'.386p');
  727. { masm 6.11 does not seem to like LOCALS PM }
  728. if (aktoutputformat = as_i386_tasm) then
  729. begin
  730. AsmWriteLn(#9'LOCALS '+target_asm.labelprefix);
  731. end;
  732. AsmWriteLn('DGROUP'#9'GROUP'#9'_BSS,_DATA');
  733. AsmWriteLn(#9'ASSUME'#9'CS:_CODE,ES:DGROUP,DS:DGROUP,SS:DGROUP');
  734. AsmLn;
  735. WriteExternals;
  736. { INTEL ASM doesn't support stabs
  737. WriteTree(debuglist);}
  738. WriteTree(codesegment);
  739. WriteTree(datasegment);
  740. WriteTree(consts);
  741. WriteTree(rttilist);
  742. WriteTree(resourcestringlist);
  743. WriteTree(bsssegment);
  744. AsmWriteLn(#9'END');
  745. AsmLn;
  746. {$ifdef EXTDEBUG}
  747. if assigned(current_module.mainsource) then
  748. comment(v_info,'Done writing intel-styled assembler output for '+current_module.mainsource^);
  749. {$endif EXTDEBUG}
  750. end;
  751. {*****************************************************************************
  752. Initialize
  753. *****************************************************************************}
  754. const
  755. as_i386_tasm_info : tasminfo =
  756. (
  757. id : as_i386_tasm;
  758. idtxt : 'TASM';
  759. asmbin : 'tasm';
  760. asmcmd : '/m2 /ml $ASM $OBJ';
  761. supported_target : system_any; { what should I write here ?? }
  762. outputbinary: false;
  763. allowdirect : true;
  764. needar : true;
  765. labelprefix_only_inside_procedure : true;
  766. labelprefix : '@@';
  767. comment : '; ';
  768. secnames : ('',
  769. 'CODE','DATA','BSS',
  770. '','','','','','',
  771. '','','')
  772. );
  773. as_i386_masm_info : tasminfo =
  774. (
  775. id : as_i386_masm;
  776. idtxt : 'MASM';
  777. asmbin : 'masm';
  778. asmcmd : '/c /Cp $ASM /Fo$OBJ';
  779. supported_target : system_any; { what should I write here ?? }
  780. outputbinary: false;
  781. allowdirect : true;
  782. needar : true;
  783. labelprefix_only_inside_procedure : false;
  784. labelprefix : '@@';
  785. comment : '; ';
  786. secnames : ('',
  787. 'CODE','DATA','BSS',
  788. '','','','','','',
  789. '','','')
  790. );
  791. initialization
  792. RegisterAssembler(as_i386_tasm_info,T386IntelAssembler);
  793. RegisterAssembler(as_i386_masm_info,T386IntelAssembler);
  794. end.
  795. {
  796. $Log$
  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. }