agx86int.pas 42 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209
  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,constexp,
  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. function single2str(d : single) : string; override;
  34. function double2str(d : double) : string; override;
  35. function extended2str(e : extended) : string; override;
  36. function comp2str(d : bestreal) : string;
  37. procedure WriteTree(p:TAsmList);override;
  38. procedure WriteAsmList;override;
  39. Function DoAssemble:boolean;override;
  40. procedure WriteExternals;
  41. end;
  42. implementation
  43. uses
  44. SysUtils,math,
  45. cutils,globtype,globals,systems,cclasses,
  46. verbose,cscript,cpuinfo,
  47. itx86int,
  48. cgbase
  49. {$ifdef EXTDEBUG}
  50. ,fmodule
  51. {$endif EXTDEBUG}
  52. ;
  53. const
  54. line_length = 70;
  55. max_tokens : longint = 25;
  56. (*
  57. wasm_cpu_name : array[tcputype] of string = (
  58. {$if defined(x86_64)}
  59. 'IA64', // cpu_none,
  60. '686', // cpu_athlon64,
  61. '686', // cpu_core_i,
  62. '686', // cpu_core_avx,
  63. '686' // cpu_core_avx2
  64. {$elseif defined(i386)}
  65. 'IA64', // cpu_none,
  66. '386', // cpu_386,
  67. '486', // cpu_486,
  68. '586', // cpu_Pentium,
  69. '686', // cpu_Pentium2,
  70. '686', // cpu_Pentium3,
  71. '686', // cpu_Pentium4,
  72. '686', // cpu_PentiumM,
  73. '686', // cpu_core_i,
  74. '686', // cpu_core_avx,
  75. '686' // cpu_core_avx2
  76. {$elseif defined(i8086)}
  77. 'IA64', // cpu_none
  78. '8086', // cpu_8086
  79. '186', // cpu_186
  80. '286', // cpu_286
  81. '386', // cpu_386
  82. '486', // cpu_486
  83. '586', // cpu_Pentium
  84. '686', // cpu_Pentium2
  85. '686', // cpu_Pentium3
  86. '686', // cpu_Pentium4
  87. '686' // cpu_PentiumM
  88. {$endif}
  89. );
  90. *)
  91. secnames : array[TAsmSectiontype] of string[4] = ('','',
  92. 'CODE','DATA','DATA','DATA','BSS','TLS',
  93. '','','','','','',
  94. '','','','',
  95. '',
  96. '',
  97. '',
  98. '',
  99. '',
  100. '','','','','','',
  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. );
  147. secnamesml64 : array[TAsmSectiontype] of string[7] = ('','',
  148. '_TEXT','_DATA','_DATA','_DATA','_BSS','_TLS',
  149. '','','','',
  150. 'idata$2','idata$4','idata$5','idata$6','idata$7','edata',
  151. '',
  152. '',
  153. '',
  154. '',
  155. '',
  156. '','','','','','',
  157. '',
  158. '',
  159. '',
  160. '',
  161. '',
  162. '',
  163. '',
  164. '',
  165. '',
  166. '',
  167. '',
  168. '',
  169. '',
  170. '',
  171. '',
  172. '',
  173. '',
  174. '',
  175. '',
  176. '',
  177. '',
  178. '',
  179. '',
  180. '',
  181. '',
  182. '',
  183. '',
  184. '',
  185. '',
  186. '',
  187. '',
  188. '',
  189. '',
  190. '',
  191. '',
  192. '',
  193. '',
  194. '',
  195. '',
  196. '',
  197. '',
  198. '',
  199. '',
  200. '',
  201. ''
  202. );
  203. function TX86IntelAssembler.single2str(d : single) : string;
  204. var
  205. hs : string;
  206. p : byte;
  207. begin
  208. str(d,hs);
  209. { nasm expects a lowercase e }
  210. p:=pos('E',hs);
  211. if p>0 then
  212. hs[p]:='e';
  213. p:=pos('+',hs);
  214. if p>0 then
  215. delete(hs,p,1);
  216. single2str:=lower(hs);
  217. end;
  218. function TX86IntelAssembler.double2str(d : double) : string;
  219. var
  220. hs : string;
  221. p : byte;
  222. begin
  223. str(d,hs);
  224. { nasm expects a lowercase e }
  225. p:=pos('E',hs);
  226. if p>0 then
  227. hs[p]:='e';
  228. p:=pos('+',hs);
  229. if p>0 then
  230. delete(hs,p,1);
  231. double2str:=lower(hs);
  232. end;
  233. function TX86IntelAssembler.extended2str(e : extended) : string;
  234. var
  235. hs : string;
  236. p : byte;
  237. begin
  238. str(e,hs);
  239. { nasm expects a lowercase e }
  240. p:=pos('E',hs);
  241. if p>0 then
  242. hs[p]:='e';
  243. p:=pos('+',hs);
  244. if p>0 then
  245. delete(hs,p,1);
  246. extended2str:=lower(hs);
  247. end;
  248. function TX86IntelAssembler.comp2str(d : bestreal) : string;
  249. type
  250. pdouble = ^double;
  251. var
  252. c : comp;
  253. dd : pdouble;
  254. begin
  255. c:=comp(d);
  256. dd:=pdouble(@c); { this makes a bitwise copy of c into a double }
  257. comp2str:=double2str(dd^);
  258. end;
  259. { MASM supports aligns up to 8192 }
  260. function alignstr(b : longint) : string;
  261. begin
  262. case b of
  263. 1: result:='BYTE';
  264. 2: result:='WORD';
  265. 4: result:='DWORD';
  266. 0,
  267. 16: result:='PARA';
  268. 256: result:='PAGE';
  269. else
  270. result:='ALIGN('+tostr(b)+')';
  271. end;
  272. end;
  273. {****************************************************************************
  274. tx86IntelAssembler
  275. ****************************************************************************}
  276. procedure tx86IntelAssembler.WriteReference(var ref : treference);
  277. var
  278. first : boolean;
  279. begin
  280. with ref do
  281. begin
  282. first:=true;
  283. if segment<>NR_NO then
  284. writer.AsmWrite(masm_regname(segment)+':[')
  285. else
  286. writer.AsmWrite('[');
  287. if assigned(symbol) then
  288. begin
  289. if (asminfo^.id = as_i386_tasm) then
  290. writer.AsmWrite('dword ptr ');
  291. writer.AsmWrite(ApplyAsmSymbolRestrictions(symbol.name));
  292. first:=false;
  293. end;
  294. if (base<>NR_NO) then
  295. begin
  296. if not(first) then
  297. writer.AsmWrite('+')
  298. else
  299. first:=false;
  300. {$ifdef x86_64}
  301. { ml64 needs [$+foo] instead of [rip+foo] }
  302. if (base=NR_RIP) and (asminfo^.id=as_x86_64_masm) then
  303. writer.AsmWrite('$')
  304. else
  305. {$endif x86_64}
  306. writer.AsmWrite(masm_regname(base));
  307. end;
  308. if (index<>NR_NO) then
  309. begin
  310. if not(first) then
  311. writer.AsmWrite('+')
  312. else
  313. first:=false;
  314. writer.AsmWrite(masm_regname(index));
  315. if scalefactor<>0 then
  316. writer.AsmWrite('*'+tostr(scalefactor));
  317. end;
  318. if offset<0 then
  319. begin
  320. writer.AsmWrite(tostr(offset));
  321. first:=false;
  322. end
  323. else if (offset>0) then
  324. begin
  325. writer.AsmWrite('+'+tostr(offset));
  326. first:=false;
  327. end;
  328. if first then
  329. writer.AsmWrite('0');
  330. writer.AsmWrite(']');
  331. end;
  332. end;
  333. procedure tx86IntelAssembler.WriteOper(const o:toper;s : topsize; opcode: tasmop;dest : boolean);
  334. begin
  335. case o.typ of
  336. top_reg :
  337. writer.AsmWrite(masm_regname(o.reg));
  338. top_const :
  339. writer.AsmWrite(tostr(o.val));
  340. top_ref :
  341. begin
  342. if o.ref^.refaddr in [addr_no,addr_pic,addr_pic_no_got] then
  343. begin
  344. if ((opcode <> A_LGS) and (opcode <> A_LSS) and
  345. (opcode <> A_LFS)
  346. {$ifndef x86_64}
  347. and (opcode <> A_LDS) and (opcode <> A_LES)
  348. {$endif x86_64}
  349. ) then
  350. Begin
  351. case s of
  352. S_B : writer.AsmWrite('byte ptr ');
  353. S_W : writer.AsmWrite('word ptr ');
  354. S_L : writer.AsmWrite('dword ptr ');
  355. S_Q : writer.AsmWrite('qword ptr ');
  356. S_IS : writer.AsmWrite('word ptr ');
  357. S_IL : writer.AsmWrite('dword ptr ');
  358. S_IQ : writer.AsmWrite('qword ptr ');
  359. S_FS : writer.AsmWrite('dword ptr ');
  360. S_FL : writer.AsmWrite('qword ptr ');
  361. S_T,
  362. S_FX : writer.AsmWrite('tbyte ptr ');
  363. S_BW : if dest then
  364. writer.AsmWrite('word ptr ')
  365. else
  366. writer.AsmWrite('byte ptr ');
  367. S_BL : if dest then
  368. writer.AsmWrite('dword ptr ')
  369. else
  370. writer.AsmWrite('byte ptr ');
  371. S_WL : if dest then
  372. writer.AsmWrite('dword ptr ')
  373. else
  374. writer.AsmWrite('word ptr ');
  375. S_XMM: writer.AsmWrite('xmmword ptr ');
  376. S_YMM: writer.AsmWrite('ymmword ptr ');
  377. S_ZMM: writer.AsmWrite('zmmword ptr ');
  378. {$ifdef x86_64}
  379. S_BQ : if dest then
  380. writer.AsmWrite('qword ptr ')
  381. else
  382. writer.AsmWrite('byte ptr ');
  383. S_WQ : if dest then
  384. writer.AsmWrite('qword ptr ')
  385. else
  386. writer.AsmWrite('word ptr ');
  387. S_LQ : if dest then
  388. writer.AsmWrite('qword ptr ')
  389. else
  390. writer.AsmWrite('dword ptr ');
  391. {$endif x86_64}
  392. else
  393. ;
  394. end;
  395. end;
  396. WriteReference(o.ref^);
  397. end
  398. else
  399. begin
  400. writer.AsmWrite('offset ');
  401. if assigned(o.ref^.symbol) then
  402. writer.AsmWrite(ApplyAsmSymbolRestrictions(o.ref^.symbol.name));
  403. if o.ref^.offset>0 then
  404. writer.AsmWrite('+'+tostr(o.ref^.offset))
  405. else
  406. if o.ref^.offset<0 then
  407. writer.AsmWrite(tostr(o.ref^.offset))
  408. else
  409. if not(assigned(o.ref^.symbol)) then
  410. writer.AsmWrite('0');
  411. end;
  412. end;
  413. else
  414. internalerror(2005060510);
  415. end;
  416. end;
  417. procedure tx86IntelAssembler.WriteOper_jmp(const o:toper;s : topsize);
  418. begin
  419. case o.typ of
  420. top_reg :
  421. writer.AsmWrite(masm_regname(o.reg));
  422. top_const :
  423. writer.AsmWrite(tostr(o.val));
  424. top_ref :
  425. { what about lcall or ljmp ??? }
  426. begin
  427. if o.ref^.refaddr=addr_no then
  428. begin
  429. if (asminfo^.id <> as_i386_tasm) then
  430. begin
  431. if s=S_FAR then
  432. writer.AsmWrite('far ptr ')
  433. else
  434. {$ifdef x86_64}
  435. writer.AsmWrite('qword ptr ');
  436. {$else x86_64}
  437. writer.AsmWrite('dword ptr ');
  438. {$endif x86_64}
  439. end;
  440. WriteReference(o.ref^);
  441. end
  442. else
  443. begin
  444. writer.AsmWrite(ApplyAsmSymbolRestrictions(o.ref^.symbol.name));
  445. if o.ref^.offset>0 then
  446. writer.AsmWrite('+'+tostr(o.ref^.offset))
  447. else
  448. if o.ref^.offset<0 then
  449. writer.AsmWrite(tostr(o.ref^.offset));
  450. end;
  451. end;
  452. else
  453. internalerror(2005060511);
  454. end;
  455. end;
  456. const
  457. ait_const2str : array[aitconst_128bit..aitconst_64bit_unaligned] of string[20]=(
  458. #9''#9,#9'DQ'#9,#9'DD'#9,#9'DW'#9,#9'DB'#9,
  459. #9'FIXMESLEB',#9'FIXEMEULEB',
  460. #9'DD RVA'#9,#9'DD SECREL32'#9,
  461. #9'FIXME',#9'FIXME',#9'FIXME',#9'FIXME',
  462. #9'DW'#9,#9'DD'#9,#9'DQ'#9
  463. );
  464. Function PadTabs(const p:string;addch:char):string;
  465. var
  466. s : string;
  467. i : longint;
  468. begin
  469. i:=length(p);
  470. if addch<>#0 then
  471. begin
  472. inc(i);
  473. s:=p+addch;
  474. end
  475. else
  476. s:=p;
  477. if i<8 then
  478. PadTabs:=s+#9#9
  479. else
  480. PadTabs:=s+#9;
  481. end;
  482. procedure tx86IntelAssembler.WriteTree(p:TAsmList);
  483. var
  484. s,
  485. prefix,
  486. suffix : string;
  487. hp,nhp : tai;
  488. cpu: tcputype;
  489. counter,
  490. lines, tokens,
  491. InlineLevel : longint;
  492. i,j,l : longint;
  493. consttype : taiconst_type;
  494. do_line,DoNotSplitLine,
  495. quoted : boolean;
  496. fixed_opcode: TAsmOp;
  497. begin
  498. if not assigned(p) then
  499. exit;
  500. { lineinfo is only needed for al_procedures (PFV) }
  501. do_line:=((cs_asm_source in current_settings.globalswitches) or
  502. (cs_lineinfo in current_settings.moduleswitches))
  503. and (p=current_asmdata.asmlists[al_procedures]);
  504. InlineLevel:=0;
  505. DoNotSplitLine:=false;
  506. hp:=tai(p.first);
  507. while assigned(hp) do
  508. begin
  509. prefetch(pointer(hp.next)^);
  510. if not(hp.typ in SkipLineInfo) then
  511. begin
  512. current_filepos:=tailineinfo(hp).fileinfo;
  513. { no line info for inlined code }
  514. if do_line and (inlinelevel=0) and not DoNotSplitLine then
  515. WriteSourceLine(hp as tailineinfo);
  516. end;
  517. DoNotSplitLine:=false;
  518. case hp.typ of
  519. ait_section :
  520. begin
  521. ResetSourceLines;
  522. if tai_section(hp).sectype<>sec_none then
  523. begin
  524. if asminfo^.id=as_x86_64_masm then
  525. begin
  526. if LasTSecType<>sec_none then
  527. writer.AsmWriteLn(secnamesml64[LasTSecType]+#9#9'ENDS');
  528. writer.AsmLn;
  529. writer.AsmWriteLn(secnamesml64[tai_section(hp).sectype]+#9+'SEGMENT')
  530. end
  531. else
  532. begin
  533. if LasTSecType<>sec_none then
  534. writer.AsmWriteLn('_'+secnames[LasTSecType]+#9#9'ENDS');
  535. writer.AsmLn;
  536. if (asminfo^.id=as_i386_wasm) then
  537. s:='DWORD'
  538. else
  539. s:=alignstr(tai_section(hp).secalign);
  540. writer.AsmWriteLn('_'+secnames[tai_section(hp).sectype]+#9#9+
  541. 'SEGMENT'#9+s+' PUBLIC USE32 '''+
  542. secnames[tai_section(hp).sectype]+'''');
  543. end;
  544. end;
  545. LasTSecType:=tai_section(hp).sectype;
  546. end;
  547. ait_align :
  548. begin
  549. { CAUSES PROBLEMS WITH THE SEGMENT DEFINITION }
  550. { SEGMENT DEFINITION SHOULD MATCH TYPE OF ALIGN }
  551. { HERE UNDER TASM! }
  552. if tai_align_abstract(hp).aligntype>1 then
  553. writer.AsmWriteLn(#9'ALIGN '+tostr(tai_align_abstract(hp).aligntype));
  554. end;
  555. ait_datablock :
  556. begin
  557. if tai_datablock(hp).is_global then
  558. writer.AsmWriteLn(#9'PUBLIC'#9+ApplyAsmSymbolRestrictions(tai_datablock(hp).sym.name));
  559. writer.AsmWriteLn(PadTabs(ApplyAsmSymbolRestrictions(tai_datablock(hp).sym.name),#0)+'DB'#9+tostr(tai_datablock(hp).size)+' DUP(?)');
  560. end;
  561. ait_const:
  562. begin
  563. consttype:=tai_const(hp).consttype;
  564. case consttype of
  565. aitconst_uleb128bit,
  566. aitconst_sleb128bit,
  567. aitconst_128bit,
  568. aitconst_64bit,
  569. aitconst_32bit,
  570. aitconst_16bit,
  571. aitconst_8bit,
  572. aitconst_16bit_unaligned,
  573. aitconst_32bit_unaligned,
  574. aitconst_64bit_unaligned,
  575. aitconst_rva_symbol,
  576. aitconst_secrel32_symbol :
  577. begin
  578. writer.AsmWrite(ait_const2str[consttype]);
  579. l:=0;
  580. tokens:=1;
  581. repeat
  582. if assigned(tai_const(hp).sym) then
  583. begin
  584. if assigned(tai_const(hp).endsym) then
  585. s:=ApplyAsmSymbolRestrictions(tai_const(hp).endsym.name)+'-'+ApplyAsmSymbolRestrictions(tai_const(hp).sym.name)
  586. else
  587. s:=ApplyAsmSymbolRestrictions(tai_const(hp).sym.name);
  588. if tai_const(hp).value<>0 then
  589. s:=s+tostr_with_plus(tai_const(hp).value);
  590. end
  591. else
  592. s:=tostr(tai_const(hp).value);
  593. writer.AsmWrite(s);
  594. inc(l,length(s));
  595. inc(tokens);
  596. if (l>line_length) or
  597. (tokens>max_tokens) or
  598. (hp.next=nil) or
  599. (tai(hp.next).typ<>ait_const) or
  600. (tai_const(hp.next).consttype<>consttype) then
  601. break;
  602. hp:=tai(hp.next);
  603. writer.AsmWrite(',');
  604. until false;
  605. { Substract section start for secrel32 type }
  606. if consttype=aitconst_secrel32_symbol then
  607. writer.AsmWrite(' - $$');
  608. writer.AsmLn;
  609. end;
  610. else
  611. internalerror(200704253);
  612. end;
  613. end;
  614. ait_realconst:
  615. begin
  616. case tai_realconst(hp).realtyp of
  617. aitrealconst_s32bit:
  618. begin
  619. if (asminfo^.id = as_i386_wasm) and (IsInfinite(tai_realconst(hp).value.s32val)) then
  620. begin
  621. { Watcom Wasm does not handle Infinity }
  622. if Sign(tai_realconst(hp).value.s32val)=PositiveValue then
  623. writer.AsmWriteln(#9#9'DB'#9'0,0,80h,7Fh')
  624. else
  625. writer.AsmWriteln(#9#9'DW'#9'0,0,80h,FFh');
  626. end
  627. else if (asminfo^.id = as_i386_wasm) and (IsNan(tai_realconst(hp).value.s32val)) then
  628. writer.AsmWriteln(#9#9'DB'#9'1,0,80h,7Fh')
  629. else
  630. writer.AsmWriteLn(#9#9'DD'#9+single2str(tai_realconst(hp).value.s32val));
  631. end;
  632. aitrealconst_s64bit:
  633. begin
  634. if (asminfo^.id = as_i386_wasm) and (IsInfinite(tai_realconst(hp).value.s64val)) then
  635. begin
  636. { Watcom Wasm does not handle Infinity }
  637. if Sign(tai_realconst(hp).value.s64val)=PositiveValue then
  638. writer.AsmWriteln(#9#9'DW'#9'0,0,0,7FF0h')
  639. else
  640. writer.AsmWriteln(#9#9'DW'#9'0,0,0,FFF0h');
  641. end
  642. else if (asminfo^.id = as_i386_wasm) and (IsNan(tai_realconst(hp).value.s64val)) then
  643. writer.AsmWriteln(#9#9'DW'#9'0,0,0,0,7FF8h')
  644. else
  645. writer.AsmWriteLn(#9#9'DQ'#9+double2str(tai_realconst(hp).value.s64val));
  646. end;
  647. aitrealconst_s80bit:
  648. if (asminfo^.id = as_i386_wasm) and (IsInfinite(tai_realconst(hp).value.s80val)) then
  649. begin
  650. { Watcom Wasm does not handle Infinity }
  651. if Sign(tai_realconst(hp).value.s80val)=PositiveValue then
  652. writer.AsmWriteln(#9#9'DW'#9'0,0,0,8000h,7FFFh')
  653. else
  654. writer.AsmWriteln(#9#9'DW'#9'0,0,0,8000h,FFFFh');
  655. end
  656. else if (asminfo^.id = as_i386_wasm) and (IsNan(tai_realconst(hp).value.s80val)) then
  657. writer.AsmWriteln(#9#9'DW'#9'0,0,0,0xC000,0x7FFF')
  658. else
  659. writer.AsmWriteLn(#9#9'DT'#9+extended2str(tai_realconst(hp).value.s80val));
  660. aitrealconst_s64comp:
  661. writer.AsmWriteLn(#9#9'DQ'#9+extended2str(tai_realconst(hp).value.s64compval));
  662. else
  663. internalerror(2014050606);
  664. end;
  665. end;
  666. ait_string :
  667. begin
  668. counter := 0;
  669. lines := tai_string(hp).len div line_length;
  670. { separate lines in different parts }
  671. if tai_string(hp).len > 0 then
  672. Begin
  673. for j := 0 to lines-1 do
  674. begin
  675. writer.AsmWrite(#9#9'DB'#9);
  676. quoted:=false;
  677. for i:=counter to counter+line_length-1 do
  678. begin
  679. { it is an ascii character. }
  680. if (ord(tai_string(hp).str[i])>31) and
  681. (ord(tai_string(hp).str[i])<128) and
  682. (tai_string(hp).str[i]<>'"') then
  683. begin
  684. if not(quoted) then
  685. begin
  686. if i>counter then
  687. writer.AsmWrite(',');
  688. writer.AsmWrite('"');
  689. end;
  690. writer.AsmWrite(tai_string(hp).str[i]);
  691. quoted:=true;
  692. end { if > 31 and < 128 and ord('"') }
  693. else
  694. begin
  695. if quoted then
  696. writer.AsmWrite('"');
  697. if i>counter then
  698. writer.AsmWrite(',');
  699. quoted:=false;
  700. writer.AsmWrite(tostr(ord(tai_string(hp).str[i])));
  701. end;
  702. end; { end for i:=0 to... }
  703. if quoted then writer.AsmWrite('"');
  704. writer.AsmWrite(target_info.newline);
  705. counter := counter+line_length;
  706. end; { end for j:=0 ... }
  707. { do last line of lines }
  708. if counter<tai_string(hp).len then
  709. writer.AsmWrite(#9#9'DB'#9);
  710. quoted:=false;
  711. for i:=counter to tai_string(hp).len-1 do
  712. begin
  713. { it is an ascii character. }
  714. if (ord(tai_string(hp).str[i])>31) and
  715. (ord(tai_string(hp).str[i])<128) and
  716. (tai_string(hp).str[i]<>'"') then
  717. begin
  718. if not(quoted) then
  719. begin
  720. if i>counter then
  721. writer.AsmWrite(',');
  722. writer.AsmWrite('"');
  723. end;
  724. writer.AsmWrite(tai_string(hp).str[i]);
  725. quoted:=true;
  726. end { if > 31 and < 128 and " }
  727. else
  728. begin
  729. if quoted then
  730. writer.AsmWrite('"');
  731. if i>counter then
  732. writer.AsmWrite(',');
  733. quoted:=false;
  734. writer.AsmWrite(tostr(ord(tai_string(hp).str[i])));
  735. end;
  736. end; { end for i:=0 to... }
  737. if quoted then
  738. writer.AsmWrite('"');
  739. end;
  740. writer.AsmLn;
  741. end;
  742. ait_label :
  743. begin
  744. if tai_label(hp).labsym.is_used then
  745. begin
  746. writer.AsmWrite(ApplyAsmSymbolRestrictions(tai_label(hp).labsym.name));
  747. if not assigned(hp.next) or not(tai(hp.next).typ in
  748. [ait_const,ait_realconst,ait_string]) then
  749. writer.AsmWriteLn(':')
  750. else
  751. DoNotSplitLine:=true;
  752. end;
  753. end;
  754. ait_symbol :
  755. begin
  756. if tai_symbol(hp).has_value then
  757. internalerror(2009090802);
  758. { wasm is case insensitive, we need to use only uppercase version
  759. if both a lowercase and an uppercase version are provided }
  760. if (asminfo^.id = as_i386_wasm) then
  761. begin
  762. nhp:=tai(hp.next);
  763. while assigned(nhp) and (nhp.typ in [ait_function_name,ait_force_line]) do
  764. nhp:=tai(nhp.next);
  765. if assigned(nhp) and (tai(nhp).typ=ait_symbol) and
  766. (lower(tai_symbol(nhp).sym.name)=tai_symbol(hp).sym.name) then
  767. begin
  768. writer.AsmWriteln(asminfo^.comment+' '+tai_symbol(hp).sym.name+' removed');
  769. hp:=tai(nhp);
  770. end;
  771. end;
  772. if tai_symbol(hp).is_global then
  773. writer.AsmWriteLn(#9'PUBLIC'#9+ApplyAsmSymbolRestrictions(tai_symbol(hp).sym.name));
  774. writer.AsmWrite(ApplyAsmSymbolRestrictions(tai_symbol(hp).sym.name));
  775. if not assigned(hp.next) or not(tai(hp.next).typ in
  776. [ait_const,ait_realconst,ait_string]) then
  777. writer.AsmWriteLn(':');
  778. end;
  779. ait_symbol_end :
  780. begin
  781. end;
  782. ait_instruction :
  783. begin
  784. fixed_opcode:=taicpu(hp).FixNonCommutativeOpcodes;
  785. taicpu(hp).SetOperandOrder(op_intel);
  786. { Reset }
  787. suffix:='';
  788. prefix:= '';
  789. { We need to explicitely set
  790. word prefix to get selectors
  791. to be pushed in 2 bytes PM }
  792. if (taicpu(hp).opsize=S_W) and
  793. (
  794. (
  795. (fixed_opcode=A_PUSH) or
  796. (fixed_opcode=A_POP)
  797. ) and
  798. (taicpu(hp).oper[0]^.typ=top_reg) and
  799. is_segment_reg(taicpu(hp).oper[0]^.reg)
  800. ) then
  801. writer.AsmWriteln(#9#9'DB'#9'066h');
  802. { added prefix instructions, must be on same line as opcode }
  803. if (taicpu(hp).ops = 0) and
  804. ((fixed_opcode = A_REP) or
  805. (fixed_opcode = A_LOCK) or
  806. (fixed_opcode = A_REPE) or
  807. (fixed_opcode = A_REPNZ) or
  808. (fixed_opcode = A_REPZ) or
  809. (fixed_opcode = A_REPNE)) then
  810. Begin
  811. prefix:=std_op2str[fixed_opcode]+#9;
  812. { there can be a stab inbetween when the opcode was on
  813. a different line in the source code }
  814. repeat
  815. hp:=tai(hp.next);
  816. until (hp=nil) or (hp.typ=ait_instruction);
  817. { next instruction ... }
  818. fixed_opcode:=taicpu(hp).FixNonCommutativeOpcodes;
  819. taicpu(hp).SetOperandOrder(op_intel);
  820. { this is theorically impossible... }
  821. if hp=nil then
  822. begin
  823. writer.AsmWriteLn(#9#9+prefix);
  824. break;
  825. end;
  826. { nasm prefers prefix on a line alone
  827. writer.AsmWriteln(#9#9+prefix); but not masm PM
  828. prefix:=''; }
  829. if asminfo^.id in [as_i386_nasmcoff,as_i386_nasmwin32,as_i386_nasmwdosx,
  830. as_i386_nasmelf,as_i386_nasmobj,as_i386_nasmbeos,as_i386_nasmhaiku] then
  831. begin
  832. writer.AsmWriteln(prefix);
  833. prefix:='';
  834. end;
  835. end
  836. else
  837. prefix:= '';
  838. if (asminfo^.id = as_i386_wasm) and
  839. (taicpu(hp).opsize=S_W) and
  840. (fixed_opcode=A_PUSH) and
  841. (taicpu(hp).oper[0]^.typ=top_const) then
  842. begin
  843. writer.AsmWriteln(#9#9'DB 66h,68h ; pushw imm16');
  844. writer.AsmWrite(#9#9'DW');
  845. end
  846. else if (asminfo^.id=as_x86_64_masm) and
  847. (fixed_opcode=A_MOVQ) then
  848. writer.AsmWrite(#9#9'mov')
  849. {$ifdef I386}
  850. else if (asminfo^.id = as_i386_wasm) and ((fixed_opcode=A_RETD)
  851. or (fixed_opcode=A_RETND) or (fixed_opcode=A_RETFD)) then
  852. begin
  853. { no 'd' suffix for Watcom assembler }
  854. case fixed_opcode of
  855. A_RETD:
  856. writer.AsmWrite(#9#9'ret');
  857. A_RETND:
  858. writer.AsmWrite(#9#9'retn');
  859. A_RETFD:
  860. writer.AsmWrite(#9#9'retf');
  861. else
  862. internalerror(2019050907);
  863. end
  864. end
  865. {$endif I386}
  866. else
  867. writer.AsmWrite(#9#9+prefix+std_op2str[fixed_opcode]+cond2str[taicpu(hp).condition]+suffix);
  868. if taicpu(hp).ops<>0 then
  869. begin
  870. if is_calljmp(fixed_opcode) then
  871. begin
  872. writer.AsmWrite(#9);
  873. WriteOper_jmp(taicpu(hp).oper[0]^,taicpu(hp).opsize);
  874. end
  875. else
  876. begin
  877. for i:=0to taicpu(hp).ops-1 do
  878. begin
  879. if i=0 then
  880. writer.AsmWrite(#9)
  881. else
  882. writer.AsmWrite(',');
  883. WriteOper(taicpu(hp).oper[i]^,taicpu(hp).opsize,fixed_opcode,(i=2));
  884. end;
  885. end;
  886. end;
  887. writer.AsmLn;
  888. end;
  889. ait_stab,
  890. ait_force_line,
  891. ait_function_name : ;
  892. ait_cutobject :
  893. begin
  894. { only reset buffer if nothing has changed }
  895. if not writer.ClearIfEmpty then
  896. begin
  897. if LasTSecType<>sec_none then
  898. writer.AsmWriteLn('_'+secnames[LasTSecType]+#9#9'ENDS');
  899. writer.AsmLn;
  900. writer.AsmWriteLn(#9'END');
  901. writer.AsmClose;
  902. DoAssemble;
  903. writer.AsmCreate(tai_cutobject(hp).place);
  904. end;
  905. { avoid empty files }
  906. while assigned(hp.next) and (tai(hp.next).typ in [ait_cutobject,ait_section,ait_comment]) do
  907. begin
  908. if tai(hp.next).typ=ait_section then
  909. lasTSecType:=tai_section(hp.next).sectype;
  910. hp:=tai(hp.next);
  911. end;
  912. if (asminfo^.id = as_i386_wasm) then
  913. begin
  914. writer.AsmWriteLn(#9'.686p');
  915. writer.AsmWriteLn(#9'.xmm');
  916. end
  917. else
  918. writer.AsmWriteLn(#9'.386p');
  919. {$ifdef i8086}
  920. writer.AsmWriteLn('DGROUP'#9'GROUP'#9'_BSS,_DATA');
  921. writer.AsmWriteLn(#9'ASSUME'#9'CS:_CODE,ES:DGROUP,DS:DGROUP,SS:DGROUP');
  922. {$endif i8086}
  923. { I was told that this isn't necesarry because }
  924. { the labels generated by FPC are unique (FK) }
  925. { writer.AsmWriteLn(#9'LOCALS '+asminfo^.labelprefix); }
  926. { TODO: PARA is incorrect, must use actual section align }
  927. if lasTSectype<>sec_none then
  928. writer.AsmWriteLn('_'+secnames[lasTSectype]+#9#9+
  929. 'SEGMENT'#9'PARA PUBLIC USE32 '''+
  930. secnames[lasTSectype]+'''');
  931. writer.MarkEmpty;
  932. end;
  933. ait_marker :
  934. begin
  935. if tai_marker(hp).kind=mark_NoLineInfoStart then
  936. inc(InlineLevel)
  937. else if tai_marker(hp).kind=mark_NoLineInfoEnd then
  938. dec(InlineLevel);
  939. end;
  940. ait_directive :
  941. begin
  942. case tai_directive(hp).directive of
  943. asd_nasm_import :
  944. begin
  945. writer.AsmWrite('import ');
  946. writer.AsmWrite(tai_directive(hp).name);
  947. writer.AsmLn;
  948. end;
  949. asd_extern :
  950. begin
  951. writer.AsmWrite('EXTRN ');
  952. writer.AsmWrite(tai_directive(hp).name);
  953. writer.AsmLn;
  954. end;
  955. asd_cpu :
  956. begin
  957. if (asminfo^.id = as_i386_wasm) then
  958. begin
  959. {writer.AsmWrite('.');}
  960. for cpu:=low(tcputype) to high(tcputype) do
  961. begin
  962. if tai_directive(hp).name=CPUTypeStr[CPU] then
  963. begin
  964. { writer.AsmWriteLn(wasm_cpu_name[cpu]); }
  965. break;
  966. end;
  967. end;
  968. end
  969. else
  970. begin
  971. { TODO: implement this properly for TASM/MASM/WASM (.686p, etc.) }
  972. writer.AsmWrite(asminfo^.comment+' CPU ');
  973. writer.AsmWrite(tai_directive(hp).name);
  974. writer.AsmLn;
  975. end;
  976. end
  977. else
  978. internalerror(200509192);
  979. end;
  980. end;
  981. ait_seh_directive :
  982. { Ignore for now };
  983. else
  984. if not WriteComments(hp) then
  985. internalerror(2020100802);
  986. end;
  987. hp:=tai(hp.next);
  988. end;
  989. end;
  990. procedure tx86intelassembler.WriteExternals;
  991. var
  992. sym : TAsmSymbol;
  993. i : longint;
  994. begin
  995. for i:=0 to current_asmdata.AsmSymbolDict.Count-1 do
  996. begin
  997. sym:=TAsmSymbol(current_asmdata.AsmSymbolDict[i]);
  998. if sym.bind in [AB_EXTERNAL,AB_EXTERNAL_INDIRECT] then
  999. begin
  1000. case asminfo^.id of
  1001. as_i386_masm,
  1002. as_i386_wasm :
  1003. writer.AsmWriteln(#9'EXTRN'#9+ApplyAsmSymbolRestrictions(sym.name)+': NEAR');
  1004. as_x86_64_masm :
  1005. writer.AsmWriteln(#9'EXTRN'#9+ApplyAsmSymbolRestrictions(sym.name)+': PROC');
  1006. else
  1007. writer.AsmWriteln(#9'EXTRN'#9+ApplyAsmSymbolRestrictions(sym.name));
  1008. end;
  1009. end;
  1010. end;
  1011. end;
  1012. function tx86intelassembler.DoAssemble : boolean;
  1013. var
  1014. masmobjfn : string;
  1015. begin
  1016. DoAssemble:=Inherited DoAssemble;
  1017. { masm does not seem to recognize specific extensions and uses .obj allways PM }
  1018. if (asminfo^.id in [as_i386_masm,as_i386_wasm]) then
  1019. begin
  1020. masmobjfn:=ChangeFileExt(objfilename,'.obj');
  1021. if not(cs_asm_extern in current_settings.globalswitches) then
  1022. begin
  1023. if Not FileExists(objfilename) and
  1024. FileExists(masmobjfn) then
  1025. RenameFile(masmobjfn,objfilename);
  1026. end
  1027. else
  1028. AsmRes.AddAsmCommand('mv',masmobjfn+' '+objfilename,objfilename);
  1029. end;
  1030. end;
  1031. procedure tx86IntelAssembler.WriteAsmList;
  1032. var
  1033. hal : tasmlisttype;
  1034. begin
  1035. {$ifdef EXTDEBUG}
  1036. if current_module.mainsource<>'' then
  1037. comment(v_info,'Start writing intel-styled assembler output for '+current_module.mainsource);
  1038. {$endif}
  1039. if asminfo^.id<>as_x86_64_masm then
  1040. begin
  1041. if (asminfo^.id = as_i386_wasm) then
  1042. begin
  1043. writer.AsmWriteLn(#9'.686p');
  1044. writer.AsmWriteLn(#9'.xmm');
  1045. end
  1046. else
  1047. writer.AsmWriteLn(#9'.386p');
  1048. { masm 6.11 does not seem to like LOCALS PM }
  1049. if (asminfo^.id = as_i386_tasm) then
  1050. begin
  1051. writer.AsmWriteLn(#9'LOCALS '+asminfo^.labelprefix);
  1052. end;
  1053. {$ifdef i8086}
  1054. writer.AsmWriteLn('DGROUP'#9'GROUP'#9'_BSS,_DATA');
  1055. writer.AsmWriteLn(#9'ASSUME'#9'CS:_CODE,ES:DGROUP,DS:DGROUP,SS:DGROUP');
  1056. {$endif i8086}
  1057. writer.AsmLn;
  1058. end;
  1059. WriteExternals;
  1060. for hal:=low(TasmlistType) to high(TasmlistType) do
  1061. begin
  1062. writer.AsmWriteLn(asminfo^.comment+'Begin asmlist '+AsmListTypeStr[hal]);
  1063. writetree(current_asmdata.asmlists[hal]);
  1064. writer.AsmWriteLn(asminfo^.comment+'End asmlist '+AsmListTypeStr[hal]);
  1065. end;
  1066. { better do this at end of WriteTree, but then there comes a trouble with
  1067. al_const which does not have leading ait_section and thus goes out of segment }
  1068. if LastSecType <> sec_none then
  1069. begin
  1070. if asminfo^.id=as_x86_64_masm then
  1071. writer.AsmWriteLn(secnamesml64[LasTSecType]+#9#9'ENDS')
  1072. else
  1073. writer.AsmWriteLn('_'+secnames[LasTSecType]+#9#9'ENDS');
  1074. end;
  1075. LastSecType := sec_none;
  1076. writer.AsmWriteLn(#9'END');
  1077. writer.AsmLn;
  1078. {$ifdef EXTDEBUG}
  1079. if current_module.mainsource<>'' then
  1080. comment(v_info,'Done writing intel-styled assembler output for '+current_module.mainsource);
  1081. {$endif EXTDEBUG}
  1082. end;
  1083. {*****************************************************************************
  1084. Initialize
  1085. *****************************************************************************}
  1086. const
  1087. {$ifdef i386}
  1088. as_i386_tasm_info : tasminfo =
  1089. (
  1090. id : as_i386_tasm;
  1091. idtxt : 'TASM';
  1092. asmbin : 'tasm';
  1093. asmcmd : '/m2 /ml $EXTRAOPT $ASM $OBJ';
  1094. supported_targets : [system_i386_GO32V2,system_i386_Win32,system_i386_wdosx,system_i386_watcom,system_i386_wince];
  1095. flags : [af_needar,af_labelprefix_only_inside_procedure];
  1096. labelprefix : '@@';
  1097. labelmaxlen : -1;
  1098. comment : '; ';
  1099. dollarsign: '$';
  1100. );
  1101. as_i386_masm_info : tasminfo =
  1102. (
  1103. id : as_i386_masm;
  1104. idtxt : 'MASM';
  1105. asmbin : 'masm';
  1106. asmcmd : '/c /Cp $EXTRAOPT $ASM /Fo$OBJ';
  1107. supported_targets : [system_i386_GO32V2,system_i386_Win32,system_i386_wdosx,system_i386_watcom,system_i386_wince];
  1108. flags : [af_needar];
  1109. labelprefix : '@@';
  1110. labelmaxlen : -1;
  1111. comment : '; ';
  1112. dollarsign: '$';
  1113. );
  1114. as_i386_wasm_info : tasminfo =
  1115. (
  1116. id : as_i386_wasm;
  1117. idtxt : 'WASM';
  1118. asmbin : 'wasm';
  1119. asmcmd : '$ASM $EXTRAOPT -6s -fp6 -ms -zq -Fo=$OBJ';
  1120. supported_targets : [system_i386_watcom];
  1121. flags : [af_needar];
  1122. labelprefix : '@@';
  1123. labelmaxlen : 247;
  1124. comment : '; ';
  1125. dollarsign: '$';
  1126. );
  1127. {$endif i386}
  1128. {$ifdef x86_64}
  1129. as_x86_64_masm_info : tasminfo =
  1130. (
  1131. id : as_x86_64_masm;
  1132. idtxt : 'MASM';
  1133. asmbin : 'ml64';
  1134. asmcmd : '/c /Cp $EXTRAOPT $ASM /Fo$OBJ';
  1135. supported_targets : [system_x86_64_win64];
  1136. flags : [af_needar];
  1137. labelprefix : '@@';
  1138. labelmaxlen : -1;
  1139. comment : '; ';
  1140. dollarsign: '$';
  1141. );
  1142. {$endif x86_64}
  1143. initialization
  1144. {$ifdef x86_64}
  1145. RegisterAssembler(as_x86_64_masm_info,tx86IntelAssembler);
  1146. {$endif x86_64}
  1147. {$ifdef i386}
  1148. RegisterAssembler(as_i386_tasm_info,tx86IntelAssembler);
  1149. RegisterAssembler(as_i386_masm_info,tx86IntelAssembler);
  1150. RegisterAssembler(as_i386_wasm_info,tx86IntelAssembler);
  1151. {$endif i386}
  1152. end.