agx86int.pas 32 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996
  1. {
  2. Copyright (c) 1998-2002 by Florian Klaempfl
  3. This unit implements an asmoutput class for Intel syntax with Intel i386+
  4. This program is free software; you can redistribute it and/or modify
  5. it under the terms of the GNU General Public License as published by
  6. the Free Software Foundation; either version 2 of the License, or
  7. (at your option) any later version.
  8. This program is distributed in the hope that it will be useful,
  9. but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11. GNU General Public License for more details.
  12. You should have received a copy of the GNU General Public License
  13. along with this program; if not, write to the Free Software
  14. Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  15. ****************************************************************************
  16. }
  17. {
  18. This unit implements an asmoutput class for Intel syntax with Intel i386+
  19. }
  20. unit agx86int;
  21. {$i fpcdefs.inc}
  22. interface
  23. uses
  24. cpubase,
  25. aasmbase,aasmtai,aasmdata,aasmcpu,assemble,cgutils;
  26. type
  27. Tx86IntelAssembler = class(TExternalAssembler)
  28. private
  29. procedure WriteReference(var ref : treference);
  30. procedure WriteOper(const o:toper;s : topsize; opcode: tasmop;dest : boolean);
  31. procedure WriteOper_jmp(const o:toper;s : topsize);
  32. public
  33. procedure WriteTree(p:TAsmList);override;
  34. procedure WriteAsmList;override;
  35. Function DoAssemble:boolean;override;
  36. procedure WriteExternals;
  37. end;
  38. implementation
  39. uses
  40. SysUtils,
  41. cutils,globtype,globals,systems,cclasses,
  42. verbose,finput,fmodule,script,cpuinfo,
  43. itx86int,
  44. cgbase
  45. ;
  46. const
  47. line_length = 70;
  48. secnames : array[TAsmSectiontype] of string[4] = ('','',
  49. 'CODE','DATA','DATA','DATA','BSS','',
  50. '','','','','','',
  51. '','','','',
  52. '',
  53. '',
  54. '',
  55. '',
  56. '',
  57. '','','','',
  58. '',
  59. '',
  60. '',
  61. '',
  62. '',
  63. '',
  64. '',
  65. '',
  66. '',
  67. '',
  68. '',
  69. '',
  70. '',
  71. '',
  72. '',
  73. '',
  74. '',
  75. '',
  76. '',
  77. '',
  78. '',
  79. '',
  80. '',
  81. '',
  82. '',
  83. '',
  84. '',
  85. '',
  86. '',
  87. '',
  88. '',
  89. '',
  90. '',
  91. '',
  92. '',
  93. '',
  94. '',
  95. ''
  96. );
  97. secnamesml64 : array[TAsmSectiontype] of string[7] = ('','',
  98. '_TEXT','_DATE','_DATA','_DATA','_BSS','',
  99. '','','','',
  100. 'idata$2','idata$4','idata$5','idata$6','idata$7','edata',
  101. '',
  102. '',
  103. '',
  104. '',
  105. '',
  106. '','','','',
  107. '',
  108. '',
  109. '',
  110. '',
  111. '',
  112. '',
  113. '',
  114. '',
  115. '',
  116. '',
  117. '',
  118. '',
  119. '',
  120. '',
  121. '',
  122. '',
  123. '',
  124. '',
  125. '',
  126. '',
  127. '',
  128. '',
  129. '',
  130. '',
  131. '',
  132. '',
  133. '',
  134. '',
  135. '',
  136. '',
  137. '',
  138. '',
  139. '',
  140. '',
  141. '',
  142. '',
  143. '',
  144. ''
  145. );
  146. function single2str(d : single) : string;
  147. var
  148. hs : string;
  149. p : byte;
  150. begin
  151. str(d,hs);
  152. { nasm expects a lowercase e }
  153. p:=pos('E',hs);
  154. if p>0 then
  155. hs[p]:='e';
  156. p:=pos('+',hs);
  157. if p>0 then
  158. delete(hs,p,1);
  159. single2str:=lower(hs);
  160. end;
  161. function double2str(d : double) : string;
  162. var
  163. hs : string;
  164. p : byte;
  165. begin
  166. str(d,hs);
  167. { nasm expects a lowercase e }
  168. p:=pos('E',hs);
  169. if p>0 then
  170. hs[p]:='e';
  171. p:=pos('+',hs);
  172. if p>0 then
  173. delete(hs,p,1);
  174. double2str:=lower(hs);
  175. end;
  176. function extended2str(e : extended) : string;
  177. var
  178. hs : string;
  179. p : byte;
  180. begin
  181. str(e,hs);
  182. { nasm expects a lowercase e }
  183. p:=pos('E',hs);
  184. if p>0 then
  185. hs[p]:='e';
  186. p:=pos('+',hs);
  187. if p>0 then
  188. delete(hs,p,1);
  189. extended2str:=lower(hs);
  190. end;
  191. function comp2str(d : bestreal) : string;
  192. type
  193. pdouble = ^double;
  194. var
  195. c : comp;
  196. dd : pdouble;
  197. begin
  198. c:=comp(d);
  199. dd:=pdouble(@c); { this makes a bitwise copy of c into a double }
  200. comp2str:=double2str(dd^);
  201. end;
  202. {****************************************************************************
  203. tx86IntelAssembler
  204. ****************************************************************************}
  205. procedure tx86IntelAssembler.WriteReference(var ref : treference);
  206. var
  207. first : boolean;
  208. begin
  209. with ref do
  210. begin
  211. first:=true;
  212. if segment<>NR_NO then
  213. AsmWrite(masm_regname(segment)+':[')
  214. else
  215. AsmWrite('[');
  216. if assigned(symbol) then
  217. begin
  218. if (target_asm.id = as_i386_tasm) then
  219. AsmWrite('dword ptr ');
  220. AsmWrite(symbol.name);
  221. first:=false;
  222. end;
  223. if (base<>NR_NO) then
  224. begin
  225. if not(first) then
  226. AsmWrite('+')
  227. else
  228. first:=false;
  229. AsmWrite(masm_regname(base));
  230. end;
  231. if (index<>NR_NO) then
  232. begin
  233. if not(first) then
  234. AsmWrite('+')
  235. else
  236. first:=false;
  237. AsmWrite(masm_regname(index));
  238. if scalefactor<>0 then
  239. AsmWrite('*'+tostr(scalefactor));
  240. end;
  241. if offset<0 then
  242. begin
  243. AsmWrite(tostr(offset));
  244. first:=false;
  245. end
  246. else if (offset>0) then
  247. begin
  248. AsmWrite('+'+tostr(offset));
  249. first:=false;
  250. end;
  251. if first then
  252. AsmWrite('0');
  253. AsmWrite(']');
  254. end;
  255. end;
  256. procedure tx86IntelAssembler.WriteOper(const o:toper;s : topsize; opcode: tasmop;dest : boolean);
  257. begin
  258. case o.typ of
  259. top_reg :
  260. AsmWrite(masm_regname(o.reg));
  261. top_const :
  262. AsmWrite(tostr(o.val));
  263. top_ref :
  264. begin
  265. if o.ref^.refaddr=addr_no then
  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_Q : AsmWrite('qword 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_T,
  282. S_FX : AsmWrite('tbyte ptr ');
  283. S_BW : if dest then
  284. AsmWrite('word ptr ')
  285. else
  286. AsmWrite('byte ptr ');
  287. S_BL : if dest then
  288. AsmWrite('dword ptr ')
  289. else
  290. AsmWrite('byte ptr ');
  291. S_WL : if dest then
  292. AsmWrite('dword ptr ')
  293. else
  294. AsmWrite('word ptr ');
  295. {$ifdef x86_64}
  296. S_BQ : if dest then
  297. AsmWrite('qword ptr ')
  298. else
  299. AsmWrite('byte ptr ');
  300. S_WQ : if dest then
  301. AsmWrite('qword ptr ')
  302. else
  303. AsmWrite('word ptr ');
  304. S_LQ : if dest then
  305. AsmWrite('qword ptr ')
  306. else
  307. AsmWrite('dword ptr ');
  308. S_XMM: AsmWrite('xmmword ptr ');
  309. {$endif x86_64}
  310. end;
  311. end;
  312. WriteReference(o.ref^);
  313. end
  314. else
  315. begin
  316. AsmWrite('offset ');
  317. if assigned(o.ref^.symbol) then
  318. AsmWrite(o.ref^.symbol.name);
  319. if o.ref^.offset>0 then
  320. AsmWrite('+'+tostr(o.ref^.offset))
  321. else
  322. if o.ref^.offset<0 then
  323. AsmWrite(tostr(o.ref^.offset))
  324. else
  325. if not(assigned(o.ref^.symbol)) then
  326. AsmWrite('0');
  327. end;
  328. end;
  329. else
  330. internalerror(2005060510);
  331. end;
  332. end;
  333. procedure tx86IntelAssembler.WriteOper_jmp(const o:toper;s : topsize);
  334. begin
  335. case o.typ of
  336. top_reg :
  337. AsmWrite(masm_regname(o.reg));
  338. top_const :
  339. AsmWrite(tostr(o.val));
  340. top_ref :
  341. { what about lcall or ljmp ??? }
  342. begin
  343. if o.ref^.refaddr=addr_no then
  344. begin
  345. if (target_asm.id <> as_i386_tasm) then
  346. begin
  347. if s=S_FAR then
  348. AsmWrite('far ptr ')
  349. else
  350. {$ifdef x86_64}
  351. AsmWrite('qword ptr ');
  352. {$else x86_64}
  353. AsmWrite('dword ptr ');
  354. {$endif x86_64}
  355. end;
  356. WriteReference(o.ref^);
  357. end
  358. else
  359. begin
  360. AsmWrite(o.ref^.symbol.name);
  361. if o.ref^.offset>0 then
  362. AsmWrite('+'+tostr(o.ref^.offset))
  363. else
  364. if o.ref^.offset<0 then
  365. AsmWrite(tostr(o.ref^.offset));
  366. end;
  367. end;
  368. else
  369. internalerror(2005060511);
  370. end;
  371. end;
  372. const
  373. ait_const2str : array[aitconst_128bit..aitconst_secrel32_symbol] of string[20]=(
  374. #9''#9,#9'DQ'#9,#9'DD'#9,#9'DW'#9,#9'DB'#9,
  375. #9'FIXMESLEB',#9'FIXEMEULEB',
  376. #9'DD RVA'#9,#9'DD SECREL32'#9
  377. );
  378. Function PadTabs(const p:string;addch:char):string;
  379. var
  380. s : string;
  381. i : longint;
  382. begin
  383. i:=length(p);
  384. if addch<>#0 then
  385. begin
  386. inc(i);
  387. s:=p+addch;
  388. end
  389. else
  390. s:=p;
  391. if i<8 then
  392. PadTabs:=s+#9#9
  393. else
  394. PadTabs:=s+#9;
  395. end;
  396. procedure tx86IntelAssembler.WriteTree(p:TAsmList);
  397. const
  398. regallocstr : array[tregalloctype] of string[10]=(' allocated',' released',' sync',' resized');
  399. tempallocstr : array[boolean] of string[10]=(' released',' allocated');
  400. var
  401. s,
  402. prefix,
  403. suffix : string;
  404. hp : tai;
  405. counter,
  406. lines,
  407. InlineLevel : longint;
  408. i,j,l : longint;
  409. consttype : taiconst_type;
  410. do_line,DoNotSplitLine,
  411. quoted : boolean;
  412. begin
  413. if not assigned(p) then
  414. exit;
  415. { lineinfo is only needed for al_procedures (PFV) }
  416. do_line:=((cs_asm_source in current_settings.globalswitches) or
  417. (cs_lineinfo in current_settings.moduleswitches))
  418. and (p=current_asmdata.asmlists[al_procedures]);
  419. InlineLevel:=0;
  420. DoNotSplitLine:=false;
  421. hp:=tai(p.first);
  422. while assigned(hp) do
  423. begin
  424. prefetch(pointer(hp.next)^);
  425. if not(hp.typ in SkipLineInfo) then
  426. begin
  427. current_filepos:=tailineinfo(hp).fileinfo;
  428. { no line info for inlined code }
  429. if do_line and (inlinelevel=0) and not DoNotSplitLine then
  430. WriteSourceLine(hp as tailineinfo);
  431. end;
  432. DoNotSplitLine:=false;
  433. case hp.typ of
  434. ait_comment :
  435. Begin
  436. AsmWrite(target_asm.comment);
  437. AsmWritePChar(tai_comment(hp).str);
  438. AsmLn;
  439. End;
  440. ait_regalloc :
  441. begin
  442. if (cs_asm_regalloc in current_settings.globalswitches) then
  443. AsmWriteLn(target_asm.comment+'Register '+masm_regname(tai_regalloc(hp).reg)+
  444. regallocstr[tai_regalloc(hp).ratype]);
  445. end;
  446. ait_tempalloc :
  447. begin
  448. if (cs_asm_tempalloc in current_settings.globalswitches) then
  449. WriteTempalloc(tai_tempalloc(hp));
  450. end;
  451. ait_section :
  452. begin
  453. if tai_section(hp).sectype<>sec_none then
  454. begin
  455. if target_asm.id=as_x86_64_masm then
  456. begin
  457. if LasTSecType<>sec_none then
  458. AsmWriteLn(secnamesml64[LasTSecType]+#9#9'ENDS');
  459. AsmLn;
  460. AsmWriteLn(secnamesml64[tai_section(hp).sectype]+#9+'SEGMENT')
  461. end
  462. else
  463. begin
  464. if LasTSecType<>sec_none then
  465. AsmWriteLn('_'+secnames[LasTSecType]+#9#9'ENDS');
  466. AsmLn;
  467. AsmWriteLn('_'+secnames[tai_section(hp).sectype]+#9#9+
  468. 'SEGMENT'#9'PARA PUBLIC USE32 '''+
  469. secnames[tai_section(hp).sectype]+'''');
  470. end;
  471. end;
  472. LasTSecType:=tai_section(hp).sectype;
  473. end;
  474. ait_align :
  475. begin
  476. { CAUSES PROBLEMS WITH THE SEGMENT DEFINITION }
  477. { SEGMENT DEFINITION SHOULD MATCH TYPE OF ALIGN }
  478. { HERE UNDER TASM! }
  479. if tai_align_abstract(hp).aligntype>1 then
  480. AsmWriteLn(#9'ALIGN '+tostr(tai_align_abstract(hp).aligntype));
  481. end;
  482. ait_datablock :
  483. 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:
  489. begin
  490. consttype:=tai_const(hp).consttype;
  491. case consttype of
  492. aitconst_uleb128bit,
  493. aitconst_sleb128bit,
  494. aitconst_128bit,
  495. aitconst_64bit,
  496. aitconst_32bit,
  497. aitconst_16bit,
  498. aitconst_8bit,
  499. aitconst_rva_symbol,
  500. aitconst_secrel32_symbol :
  501. begin
  502. AsmWrite(ait_const2str[consttype]);
  503. l:=0;
  504. repeat
  505. if assigned(tai_const(hp).sym) then
  506. begin
  507. if assigned(tai_const(hp).endsym) then
  508. s:=tai_const(hp).endsym.name+'-'+tai_const(hp).sym.name
  509. else
  510. s:=tai_const(hp).sym.name;
  511. if tai_const(hp).value<>0 then
  512. s:=s+tostr_with_plus(tai_const(hp).value);
  513. end
  514. else
  515. s:=tostr(tai_const(hp).value);
  516. AsmWrite(s);
  517. inc(l,length(s));
  518. if (l>line_length) or
  519. (hp.next=nil) or
  520. (tai(hp.next).typ<>ait_const) or
  521. (tai_const(hp.next).consttype<>consttype) then
  522. break;
  523. hp:=tai(hp.next);
  524. AsmWrite(',');
  525. until false;
  526. AsmLn;
  527. end;
  528. else
  529. internalerror(200704253);
  530. end;
  531. end;
  532. ait_real_32bit :
  533. AsmWriteLn(#9#9'DD'#9+single2str(tai_real_32bit(hp).value));
  534. ait_real_64bit :
  535. AsmWriteLn(#9#9'DQ'#9+double2str(tai_real_64bit(hp).value));
  536. ait_real_80bit :
  537. AsmWriteLn(#9#9'DT'#9+extended2str(tai_real_80bit(hp).value));
  538. ait_comp_64bit :
  539. AsmWriteLn(#9#9'DQ'#9+extended2str(tai_comp_64bit(hp).value));
  540. ait_string :
  541. begin
  542. counter := 0;
  543. lines := tai_string(hp).len div line_length;
  544. { separate lines in different parts }
  545. if tai_string(hp).len > 0 then
  546. Begin
  547. for j := 0 to lines-1 do
  548. begin
  549. AsmWrite(#9#9'DB'#9);
  550. quoted:=false;
  551. for i:=counter to counter+line_length-1 do
  552. begin
  553. { it is an ascii character. }
  554. if (ord(tai_string(hp).str[i])>31) and
  555. (ord(tai_string(hp).str[i])<128) and
  556. (tai_string(hp).str[i]<>'"') then
  557. begin
  558. if not(quoted) then
  559. begin
  560. if i>counter then
  561. AsmWrite(',');
  562. AsmWrite('"');
  563. end;
  564. AsmWrite(tai_string(hp).str[i]);
  565. quoted:=true;
  566. end { if > 31 and < 128 and ord('"') }
  567. else
  568. begin
  569. if quoted then
  570. AsmWrite('"');
  571. if i>counter then
  572. AsmWrite(',');
  573. quoted:=false;
  574. AsmWrite(tostr(ord(tai_string(hp).str[i])));
  575. end;
  576. end; { end for i:=0 to... }
  577. if quoted then AsmWrite('"');
  578. AsmWrite(target_info.newline);
  579. counter := counter+line_length;
  580. end; { end for j:=0 ... }
  581. { do last line of lines }
  582. if counter<tai_string(hp).len then
  583. AsmWrite(#9#9'DB'#9);
  584. quoted:=false;
  585. for i:=counter to tai_string(hp).len-1 do
  586. begin
  587. { it is an ascii character. }
  588. if (ord(tai_string(hp).str[i])>31) and
  589. (ord(tai_string(hp).str[i])<128) and
  590. (tai_string(hp).str[i]<>'"') then
  591. begin
  592. if not(quoted) then
  593. begin
  594. if i>counter then
  595. AsmWrite(',');
  596. AsmWrite('"');
  597. end;
  598. AsmWrite(tai_string(hp).str[i]);
  599. quoted:=true;
  600. end { if > 31 and < 128 and " }
  601. else
  602. begin
  603. if quoted then
  604. AsmWrite('"');
  605. if i>counter then
  606. AsmWrite(',');
  607. quoted:=false;
  608. AsmWrite(tostr(ord(tai_string(hp).str[i])));
  609. end;
  610. end; { end for i:=0 to... }
  611. if quoted then
  612. AsmWrite('"');
  613. end;
  614. AsmLn;
  615. end;
  616. ait_label :
  617. begin
  618. if tai_label(hp).labsym.is_used then
  619. begin
  620. AsmWrite(tai_label(hp).labsym.name);
  621. if assigned(hp.next) and not(tai(hp.next).typ in
  622. [ait_const,
  623. ait_real_32bit,ait_real_64bit,ait_real_80bit,ait_comp_64bit,ait_string]) then
  624. AsmWriteLn(':')
  625. else
  626. DoNotSplitLine:=true;
  627. end;
  628. end;
  629. ait_symbol :
  630. begin
  631. if tai_symbol(hp).has_value then
  632. internalerror(2009090802);
  633. if tai_symbol(hp).is_global then
  634. AsmWriteLn(#9'PUBLIC'#9+tai_symbol(hp).sym.name);
  635. AsmWrite(tai_symbol(hp).sym.name);
  636. if assigned(hp.next) and not(tai(hp.next).typ in
  637. [ait_const,
  638. ait_real_32bit,ait_real_64bit,ait_real_80bit,ait_comp_64bit,ait_string]) then
  639. AsmWriteLn(':')
  640. end;
  641. ait_symbol_end :
  642. begin
  643. end;
  644. ait_instruction :
  645. begin
  646. taicpu(hp).CheckNonCommutativeOpcodes;
  647. taicpu(hp).SetOperandOrder(op_intel);
  648. { Reset }
  649. suffix:='';
  650. prefix:= '';
  651. { We need to explicitely set
  652. word prefix to get selectors
  653. to be pushed in 2 bytes PM }
  654. if (taicpu(hp).opsize=S_W) and
  655. (
  656. (
  657. (taicpu(hp).opcode=A_PUSH) or
  658. (taicpu(hp).opcode=A_POP)
  659. ) and
  660. (taicpu(hp).oper[0]^.typ=top_reg) and
  661. is_segment_reg(taicpu(hp).oper[0]^.reg)
  662. ) then
  663. AsmWriteln(#9#9'DB'#9'066h');
  664. { added prefix instructions, must be on same line as opcode }
  665. if (taicpu(hp).ops = 0) and
  666. ((taicpu(hp).opcode = A_REP) or
  667. (taicpu(hp).opcode = A_LOCK) or
  668. (taicpu(hp).opcode = A_REPE) or
  669. (taicpu(hp).opcode = A_REPNZ) or
  670. (taicpu(hp).opcode = A_REPZ) or
  671. (taicpu(hp).opcode = A_REPNE)) then
  672. Begin
  673. prefix:=std_op2str[taicpu(hp).opcode]+#9;
  674. { there can be a stab inbetween when the opcode was on
  675. a different line in the source code }
  676. repeat
  677. hp:=tai(hp.next);
  678. until (hp=nil) or (hp.typ=ait_instruction);
  679. { this is theorically impossible... }
  680. if hp=nil then
  681. begin
  682. AsmWriteLn(#9#9+prefix);
  683. break;
  684. end;
  685. { nasm prefers prefix on a line alone
  686. AsmWriteln(#9#9+prefix); but not masm PM
  687. prefix:=''; }
  688. if target_asm.id in [as_i386_nasmcoff,as_i386_nasmwin32,as_i386_nasmwdosx,
  689. as_i386_nasmelf,as_i386_nasmobj,as_i386_nasmbeos,as_i386_nasmhaiku] then
  690. begin
  691. AsmWriteln(prefix);
  692. prefix:='';
  693. end;
  694. end
  695. else
  696. prefix:= '';
  697. if (target_asm.id = as_i386_wasm) and
  698. (taicpu(hp).opsize=S_W) and
  699. (taicpu(hp).opcode=A_PUSH) and
  700. (taicpu(hp).oper[0]^.typ=top_const) then
  701. begin
  702. AsmWriteln(#9#9'DB 66h,68h ; pushw imm16');
  703. AsmWrite(#9#9'DW');
  704. end
  705. else if (target_asm.id=as_x86_64_masm) and
  706. (taicpu(hp).opcode=A_MOVQ) then
  707. AsmWrite(#9#9'mov')
  708. else
  709. AsmWrite(#9#9+prefix+std_op2str[taicpu(hp).opcode]+cond2str[taicpu(hp).condition]+suffix);
  710. if taicpu(hp).ops<>0 then
  711. begin
  712. if is_calljmp(taicpu(hp).opcode) then
  713. begin
  714. AsmWrite(#9);
  715. WriteOper_jmp(taicpu(hp).oper[0]^,taicpu(hp).opsize);
  716. end
  717. else
  718. begin
  719. for i:=0to taicpu(hp).ops-1 do
  720. begin
  721. if i=0 then
  722. AsmWrite(#9)
  723. else
  724. AsmWrite(',');
  725. WriteOper(taicpu(hp).oper[i]^,taicpu(hp).opsize,taicpu(hp).opcode,(i=2));
  726. end;
  727. end;
  728. end;
  729. AsmLn;
  730. end;
  731. ait_stab,
  732. ait_force_line,
  733. ait_function_name : ;
  734. ait_cutobject :
  735. begin
  736. { only reset buffer if nothing has changed }
  737. if AsmSize=AsmStartSize then
  738. AsmClear
  739. else
  740. begin
  741. if LasTSecType<>sec_none then
  742. AsmWriteLn('_'+secnames[LasTSecType]+#9#9'ENDS');
  743. AsmLn;
  744. AsmWriteLn(#9'END');
  745. AsmClose;
  746. DoAssemble;
  747. AsmCreate(tai_cutobject(hp).place);
  748. end;
  749. { avoid empty files }
  750. while assigned(hp.next) and (tai(hp.next).typ in [ait_cutobject,ait_section,ait_comment]) do
  751. begin
  752. if tai(hp.next).typ=ait_section then
  753. lasTSecType:=tai_section(hp.next).sectype;
  754. hp:=tai(hp.next);
  755. end;
  756. AsmWriteLn(#9'.386p');
  757. AsmWriteLn('DGROUP'#9'GROUP'#9'_BSS,_DATA');
  758. AsmWriteLn(#9'ASSUME'#9'CS:_CODE,ES:DGROUP,DS:DGROUP,SS:DGROUP');
  759. { I was told that this isn't necesarry because }
  760. { the labels generated by FPC are unique (FK) }
  761. { AsmWriteLn(#9'LOCALS '+target_asm.labelprefix); }
  762. if lasTSectype<>sec_none then
  763. AsmWriteLn('_'+secnames[lasTSectype]+#9#9+
  764. 'SEGMENT'#9'PARA PUBLIC USE32 '''+
  765. secnames[lasTSectype]+'''');
  766. AsmStartSize:=AsmSize;
  767. end;
  768. ait_marker :
  769. begin
  770. if tai_marker(hp).kind=mark_NoLineInfoStart then
  771. inc(InlineLevel)
  772. else if tai_marker(hp).kind=mark_NoLineInfoEnd then
  773. dec(InlineLevel);
  774. end;
  775. ait_directive :
  776. begin
  777. case tai_directive(hp).directive of
  778. asd_nasm_import :
  779. AsmWrite('import ');
  780. asd_extern :
  781. AsmWrite('EXTRN ');
  782. else
  783. internalerror(200509192);
  784. end;
  785. if assigned(tai_directive(hp).name) then
  786. AsmWrite(tai_directive(hp).name^);
  787. AsmLn;
  788. end;
  789. else
  790. internalerror(10000);
  791. end;
  792. hp:=tai(hp.next);
  793. end;
  794. end;
  795. procedure tx86intelassembler.WriteExternals;
  796. var
  797. sym : TAsmSymbol;
  798. i : longint;
  799. begin
  800. for i:=0 to current_asmdata.AsmSymbolDict.Count-1 do
  801. begin
  802. sym:=TAsmSymbol(current_asmdata.AsmSymbolDict[i]);
  803. if sym.bind=AB_EXTERNAL then
  804. begin
  805. case target_asm.id of
  806. as_i386_masm,
  807. as_i386_wasm :
  808. AsmWriteln(#9'EXTRN'#9+sym.name+': NEAR');
  809. as_x86_64_masm :
  810. AsmWriteln(#9'EXTRN'#9+sym.name+': PROC');
  811. else
  812. AsmWriteln(#9'EXTRN'#9+sym.name);
  813. end;
  814. end;
  815. end;
  816. end;
  817. function tx86intelassembler.DoAssemble : boolean;
  818. var
  819. masmobjfn : string;
  820. begin
  821. DoAssemble:=Inherited DoAssemble;
  822. { masm does not seem to recognize specific extensions and uses .obj allways PM }
  823. if (target_asm.id in [as_i386_masm,as_i386_wasm]) then
  824. begin
  825. masmobjfn:=ChangeFileExt(objfilename,'.obj');
  826. if not(cs_asm_extern in current_settings.globalswitches) then
  827. begin
  828. if Not FileExists(objfilename) and
  829. FileExists(masmobjfn) then
  830. RenameFile(masmobjfn,objfilename);
  831. end
  832. else
  833. AsmRes.AddAsmCommand('mv',masmobjfn+' '+objfilename,objfilename);
  834. end;
  835. end;
  836. procedure tx86IntelAssembler.WriteAsmList;
  837. var
  838. hal : tasmlisttype;
  839. begin
  840. {$ifdef EXTDEBUG}
  841. if assigned(current_module.mainsource) then
  842. comment(v_info,'Start writing intel-styled assembler output for '+current_module.mainsource^);
  843. {$endif}
  844. if target_asm.id<>as_x86_64_masm then
  845. begin
  846. AsmWriteLn(#9'.386p');
  847. { masm 6.11 does not seem to like LOCALS PM }
  848. if (target_asm.id = as_i386_tasm) then
  849. begin
  850. AsmWriteLn(#9'LOCALS '+target_asm.labelprefix);
  851. end;
  852. AsmWriteLn('DGROUP'#9'GROUP'#9'_BSS,_DATA');
  853. AsmWriteLn(#9'ASSUME'#9'CS:_CODE,ES:DGROUP,DS:DGROUP,SS:DGROUP');
  854. AsmLn;
  855. end;
  856. WriteExternals;
  857. for hal:=low(TasmlistType) to high(TasmlistType) do
  858. begin
  859. AsmWriteLn(target_asm.comment+'Begin asmlist '+AsmListTypeStr[hal]);
  860. writetree(current_asmdata.asmlists[hal]);
  861. AsmWriteLn(target_asm.comment+'End asmlist '+AsmListTypeStr[hal]);
  862. end;
  863. { better do this at end of WriteTree, but then there comes a trouble with
  864. al_const which does not have leading ait_section and thus goes out of segment }
  865. { TODO: probably ml64 needs 'closing' last section, too }
  866. if LastSecType <> sec_none then
  867. AsmWriteLn('_'+secnames[LasTSecType]+#9#9'ENDS');
  868. LastSecType := sec_none;
  869. AsmWriteLn(#9'END');
  870. AsmLn;
  871. {$ifdef EXTDEBUG}
  872. if assigned(current_module.mainsource) then
  873. comment(v_info,'Done writing intel-styled assembler output for '+current_module.mainsource^);
  874. {$endif EXTDEBUG}
  875. end;
  876. {*****************************************************************************
  877. Initialize
  878. *****************************************************************************}
  879. const
  880. {$ifdef i386}
  881. as_i386_tasm_info : tasminfo =
  882. (
  883. id : as_i386_tasm;
  884. idtxt : 'TASM';
  885. asmbin : 'tasm';
  886. asmcmd : '/m2 /ml $ASM $OBJ';
  887. supported_targets : [system_i386_GO32V2,system_i386_Win32,system_i386_wdosx,system_i386_watcom,system_i386_wince];
  888. flags : [af_allowdirect,af_needar,af_labelprefix_only_inside_procedure];
  889. labelprefix : '@@';
  890. comment : '; ';
  891. );
  892. as_i386_masm_info : tasminfo =
  893. (
  894. id : as_i386_masm;
  895. idtxt : 'MASM';
  896. asmbin : 'masm';
  897. asmcmd : '/c /Cp $ASM /Fo$OBJ';
  898. supported_targets : [system_i386_GO32V2,system_i386_Win32,system_i386_wdosx,system_i386_watcom,system_i386_wince];
  899. flags : [af_allowdirect,af_needar];
  900. labelprefix : '@@';
  901. comment : '; ';
  902. );
  903. as_i386_wasm_info : tasminfo =
  904. (
  905. id : as_i386_wasm;
  906. idtxt : 'WASM';
  907. asmbin : 'wasm';
  908. asmcmd : '$ASM -6s -fp6 -ms -zq -Fo=$OBJ';
  909. supported_targets : [system_i386_watcom];
  910. flags : [af_allowdirect,af_needar];
  911. labelprefix : '@@';
  912. comment : '; ';
  913. );
  914. {$endif i386}
  915. {$ifdef x86_64}
  916. as_x86_64_masm_info : tasminfo =
  917. (
  918. id : as_x86_64_masm;
  919. idtxt : 'MASM';
  920. asmbin : 'ml64';
  921. asmcmd : '/c /Cp $ASM /Fo$OBJ';
  922. supported_targets : [system_x86_64_win64];
  923. flags : [af_allowdirect,af_needar];
  924. labelprefix : '@@';
  925. comment : '; ';
  926. );
  927. {$endif x86_64}
  928. initialization
  929. {$ifdef x86_64}
  930. RegisterAssembler(as_x86_64_masm_info,tx86IntelAssembler);
  931. {$endif x86_64}
  932. {$ifdef i386}
  933. RegisterAssembler(as_i386_tasm_info,tx86IntelAssembler);
  934. RegisterAssembler(as_i386_masm_info,tx86IntelAssembler);
  935. RegisterAssembler(as_i386_wasm_info,tx86IntelAssembler);
  936. {$endif i386}
  937. end.