ag386int.pas 39 KB

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