ag386int.pas 37 KB

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