ag386int.pas 37 KB

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