ag386int.pas 37 KB

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