ag386int.pas 38 KB

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